42 Commits

Author SHA1 Message Date
eeeck aac6d0a8d1 Add license notice
This file was orignally added in v0.0.1, somehow messed up git history and it got deleted. This is a reupload
2026-06-18 16:33:32 +02:00
eeeck 4bf2f52b49 Add GNU GPLv3 license
This license was orignally added in v0.0.1, somehow messed up git history and it got deleted. This is a reupload
2026-06-18 16:32:02 +02:00
eeeck 61374d00f1 Disable debug flag by default 2026-06-18 16:09:18 +02:00
eeeck 5b5edc2ead Merge pull request 'Implement task for sending CAN data via UART' (#21) from dev_serial-send into main
Reviewed-on: erickahmed/j1939_logger#21
2026-06-18 15:35:22 +02:00
eeeck adcdc8b340 Fix spacing 2026-06-18 15:15:52 +02:00
eeeck 2880ae64dc Check semaphore acquire status 2026-06-18 15:05:50 +02:00
eeeck 33a2cc8fb4 Enable USART1 global interrupt 2026-06-18 15:02:19 +02:00
eeeck 41de3851f2 Implement better ciclical method for dummy CAN frame sent on debug 2026-06-18 14:06:00 +02:00
eeeck 6f8d2a12ea Merge branch 'stm_debug' into dev_serial-send 2026-06-18 13:43:23 +02:00
eeeck 1ad8e5b04f Change define name
- "DEBUG" is also used by STM32 for... something...
2026-06-18 13:38:28 +02:00
eeeck ef034f3195 Add debug dummy CAN frame sent regularly
- Activated by defining DEBUG_DUMMY_FRAME
2026-06-18 13:37:10 +02:00
eeeck 5a91a56e27 Fix spacing 2026-06-18 13:25:07 +02:00
eeeck 9f1e7ba267 Move debugger connection check to main 2026-06-18 13:24:33 +02:00
eeeck 9086bf3efb Fix buffer overwrite while DMA is not completed 2026-06-18 13:08:11 +02:00
eeeck 3bf5a8cc19 Fix spacing 2026-06-18 13:05:54 +02:00
eeeck b9c371ed58 Initialize semaphore with count of 1 2026-06-18 13:05:43 +02:00
eeeck 9d96b3d4f2 Start 2026-06-18 12:50:50 +02:00
eeeck bb70e0675a Accept for standard IDs and extended IDs 2026-06-18 09:11:25 +02:00
eeeck 11e50b05e4 Make debug print safer by checking if ST-Link debugger is connected 2026-06-18 09:10:00 +02:00
eeeck e951eaef7c Fix debug prints 2026-06-18 09:07:09 +02:00
eeeck ce25cba61b Fix typo 2026-06-18 09:06:07 +02:00
eeeck 691d5dc1ea Fix baudrates
- They were wrongly calculated on 168MHz but APB1 bus is at 42 MHz (168
  / 4)
2026-06-18 08:49:52 +02:00
eeeck 052d3fc5c0 Enable CAN bus NVIC interrupts with higher priority
- This was blocking the CPU from vectoring to
  HAL_CAN_RxFifo0MsgPendingCallback
2026-06-18 08:44:25 +02:00
eeeck 4967cd9b32 Add USART DMA in Normal mode from CubeMX 2026-06-18 08:29:21 +02:00
eeeck 825ddc6961 Add debug print after 1s of no CAN traffic 2026-06-18 08:28:56 +02:00
eeeck 604e9e603b Add USART DMA in Normal mode from CubeMX 2026-06-18 06:21:41 +02:00
eeeck 7b30c3cedd Fix declaration bug 2026-06-17 21:27:26 +02:00
eeeck 8d0b508ff6 Merge branch 'dev_debug' into dev_serial-send 2026-06-17 20:52:23 +02:00
eeeck 4afa6702fb Return exact length 2026-06-17 20:33:38 +02:00
eeeck 907c0b170d Move to PFP block in main.c and use more standard logic 2026-06-17 20:33:22 +02:00
eeeck 60849ebb78 Testing: SDIO stuff deactivated until implemented
- Goes into error handling
2026-06-17 20:32:36 +02:00
eeeck aeb553994c Update LED struct 2026-06-17 20:14:56 +02:00
eeeck 5e28758a5e Use serial mode instad of JTAG 2026-06-17 20:09:45 +02:00
eeeck 9980dafb5c Initialize JTAG hardware
- To debug with ST-Link
2026-06-17 18:27:55 +02:00
eeeck 1d70a35f95 Move to proper block 2026-06-17 18:26:01 +02:00
eeeck 5c8961efa7 Include stdint 2026-06-17 18:16:13 +02:00
eeeck 17c500e39a Add debug messages for UART 2026-06-17 18:11:46 +02:00
eeeck 6ad1acc2ee Removing duplicate, again... 2026-06-17 18:07:22 +02:00
eeeck 91218e782e Include main header 2026-06-17 18:05:45 +02:00
eeeck 63e3e81986 Fix spacing 2026-06-17 18:05:04 +02:00
eeeck 84ea393dd6 Implement ITM debug via ST-Link
- Enable Instrumentation Trace Macroblock
- Remove PB3 initialization conflict with ITM
- Add a bunch of debug prints
2026-06-17 18:04:48 +02:00
eeeck d69cb0231b Removing duplicate, again... 2026-06-17 08:41:19 +02:00
11 changed files with 282 additions and 503 deletions
+10 -2
View File
@@ -26,11 +26,11 @@ extern "C" {
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal.h"
#include "canlog.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdint.h>
#include "canlog.h"
/* USER CODE END Includes */
/* Exported types ------------------------------------------------------------*/
@@ -45,7 +45,15 @@ extern "C" {
/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */
//#define DEBUG_ITM
//#define DEBUG_DUMMY_FRAME
#ifdef DEBUG_ITM
#include <stdio.h>
#define DEBUG_PRINT(...) printf(__VA_ARGS__)
#else
#define DEBUG_PRINT(...)
#endif
/* USER CODE END EM */
/* Exported functions prototypes ---------------------------------------------*/
+2
View File
@@ -52,10 +52,12 @@ void MemManage_Handler(void);
void BusFault_Handler(void);
void UsageFault_Handler(void);
void DebugMon_Handler(void);
void USART1_IRQHandler(void);
void SDIO_IRQHandler(void);
void TIM6_DAC_IRQHandler(void);
void DMA2_Stream3_IRQHandler(void);
void DMA2_Stream6_IRQHandler(void);
void DMA2_Stream7_IRQHandler(void);
/* USER CODE BEGIN EFP */
/* USER CODE END EFP */
-435
View File
@@ -1,435 +0,0 @@
/**
******************************************************************************
* @file newlib_lock_glue.c
* @author STMicroelectronics
* @brief Implementation of newlib lock interface
*
* @details This file implements locking glue necessary to protect C library
* functions and initialization of local static objects in C++.
* Lock strategies are defined in stm32_lock.h that implements
* different level of thread-safety.
*
* For more information about which C functions need which of these
* low level functions, please consult the newlib libc manual,
* see https://sourceware.org/newlib/libc.html
*
* For more information about the one-time construction API for C++,
* see https://itanium-cxx-abi.github.io/cxx-abi/abi.html#once-ctor
*
******************************************************************************
* @attention
*
* Copyright (c) 2026 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#if !defined (__GNUC__) || defined (__CC_ARM)
#error "newlib_lock_glue.c" should be used with GNU Compilers only
#endif /* !defined (__GNUC__) || defined (__CC_ARM) */
/* Includes ------------------------------------------------------------------*/
#include <cmsis_compiler.h>
/* Private functions prototypes ----------------------------------------------*/
__WEAK void Error_Handler(void);
/* Private functions ---------------------------------------------------------*/
/**
* @brief Global Error_Handler
*/
__WEAK void Error_Handler(void)
{
/* Not used if it exists in project */
while (1);
}
#ifdef __SINGLE_THREAD__
#warning C library is in single-threaded mode. Please take care when using C library functions in threaded contexts
#else
/* Includes ------------------------------------------------------------------*/
#include <newlib.h>
#include <stdatomic.h>
#include "stm32_lock.h"
/**
* @defgroup _newlib_lock_functions newlib library locks
* @see https://sourceware.org/newlib/libc.html
* @{
*/
#if __NEWLIB__ >= 3 && defined (_RETARGETABLE_LOCKING)
#include <errno.h>
#include <stdlib.h>
#include <sys/lock.h>
/* Private macros ------------------------------------------------------------*/
/** See struct __lock definition */
#define STM32_LOCK_PARAMETER(lock) (&(lock)->lock_data)
/* shared variables for bare metal allow lock ------------------------------------------------------*/
#if defined(STM32_THREAD_SAFE_BAREMETAL_ALLOW_LOCKS) && (STM32_THREAD_SAFE_BAREMETAL_ALLOW_LOCKS != 0)
uint32_t gflag = 0;
uint32_t call_counter = 0;
#endif /* defined(STM32_THREAD_SAFE_BAREMETAL_ALLOW_LOCKS) && (STM32_THREAD_SAFE_BAREMETAL_ALLOW_LOCKS != 0) */
/* Private variables ---------------------------------------------------------*/
struct __lock
{
LockingData_t lock_data; /**< The STM32 lock instance */
};
/** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */
struct __lock __lock___sinit_recursive_mutex = { LOCKING_DATA_INIT };
/** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */
struct __lock __lock___sfp_recursive_mutex = { LOCKING_DATA_INIT };
/** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */
struct __lock __lock___atexit_recursive_mutex = { LOCKING_DATA_INIT };
/** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */
struct __lock __lock___at_quick_exit_mutex = { LOCKING_DATA_INIT };
/** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */
struct __lock __lock___malloc_recursive_mutex = { LOCKING_DATA_INIT };
/** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */
struct __lock __lock___env_recursive_mutex = { LOCKING_DATA_INIT };
/** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */
struct __lock __lock___tz_mutex = { LOCKING_DATA_INIT };
/** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */
struct __lock __lock___dd_hash_mutex = { LOCKING_DATA_INIT };
/** Implementing mutex from <a href="https://sourceware.org/git/?p=newlib-cygwin.git;a=blob_plain;f=newlib/libc/misc/lock.c">newlib/libc/misc/lock.c</a> */
struct __lock __lock___arc4random_mutex = { LOCKING_DATA_INIT };
/* Private functions ---------------------------------------------------------*/
/**
* @brief Initialize lock
* @param lock The lock
*/
void __retarget_lock_init(_LOCK_T *lock)
{
__retarget_lock_init_recursive(lock);
}
/**
* @brief Initialize recursive lock
* @param lock The lock
*/
void __retarget_lock_init_recursive(_LOCK_T *lock)
{
if (lock == NULL)
{
errno = EINVAL;
return;
}
*lock = (_LOCK_T)malloc(sizeof(struct __lock));
if (*lock != NULL)
{
stm32_lock_init(STM32_LOCK_PARAMETER(*lock));
return;
}
/* Unable to allocate memory */
STM32_LOCK_BLOCK();
}
/**
* @brief Close lock
* @param lock The lock
*/
void __retarget_lock_close(_LOCK_T lock)
{
__retarget_lock_close_recursive(lock);
}
/**
* @brief Close recursive lock
* @param lock The lock
*/
void __retarget_lock_close_recursive(_LOCK_T lock)
{
free(lock);
}
/**
* @brief Acquire lock
* @param lock The lock
*/
void __retarget_lock_acquire(_LOCK_T lock)
{
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
stm32_lock_acquire(STM32_LOCK_PARAMETER(lock));
}
/**
* @brief Acquire recursive lock
* @param lock The lock
*/
void __retarget_lock_acquire_recursive(_LOCK_T lock)
{
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
stm32_lock_acquire(STM32_LOCK_PARAMETER(lock));
}
/**
* @brief Try acquire lock
* @param lock The lock
* @return 0 always
*/
int __retarget_lock_try_acquire(_LOCK_T lock)
{
__retarget_lock_acquire(lock);
return 0;
}
/**
* @brief Try acquire recursive lock
* @param lock The lock
* @return 0 always
*/
int __retarget_lock_try_acquire_recursive(_LOCK_T lock)
{
__retarget_lock_acquire_recursive(lock);
return 0;
}
/**
* @brief Release lock
* @param lock The lock
*/
void __retarget_lock_release(_LOCK_T lock)
{
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
stm32_lock_release(STM32_LOCK_PARAMETER(lock));
}
/**
* @brief Release recursive lock
* @param lock The lock
*/
void __retarget_lock_release_recursive(_LOCK_T lock)
{
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock);
stm32_lock_release(STM32_LOCK_PARAMETER(lock));
}
#else
#warning This makes malloc, env, and TZ calls thread-safe, not the entire newlib
/* Includes ------------------------------------------------------------------*/
#include <reent.h>
/* Private variables ---------------------------------------------------------*/
/** Mutex used in __malloc_lock and __malloc_unlock */
static LockingData_t __lock___malloc_recursive_mutex = LOCKING_DATA_INIT;
/** Mutex used in __env_lock and __env_unlock */
static LockingData_t __lock___env_recursive_mutex = LOCKING_DATA_INIT;
/** Mutex used in __tz_lock and __tz_unlock */
static LockingData_t __lock___tz_mutex = LOCKING_DATA_INIT;
/* Private functions ---------------------------------------------------------*/
#if __STD_C
/**
* @brief Acquire malloc lock
* @param reent The reentrance struct
*/
void __malloc_lock(struct _reent *reent)
{
STM32_LOCK_UNUSED(reent);
stm32_lock_acquire(&__lock___malloc_recursive_mutex);
}
/**
* @brief Release malloc lock
* @param reent The reentrance struct
*/
void __malloc_unlock(struct _reent *reent)
{
STM32_LOCK_UNUSED(reent);
stm32_lock_release(&__lock___malloc_recursive_mutex);
}
#else
/**
* @brief Acquire malloc lock
*/
void __malloc_lock()
{
stm32_lock_acquire(&__lock___malloc_recursive_mutex);
}
/**
* @brief Release malloc lock
*/
void __malloc_unlock()
{
stm32_lock_release(&__lock___malloc_recursive_mutex);
}
#endif /* __STD_C */
/**
* @brief Acquire env lock
* @param reent The reentrance struct
*/
void __env_lock(struct _reent *reent)
{
STM32_LOCK_UNUSED(reent);
stm32_lock_acquire(&__lock___env_recursive_mutex);
}
/**
* @brief Release env lock
* @param reent The reentrance struct
*/
void __env_unlock(struct _reent *reent)
{
STM32_LOCK_UNUSED(reent);
stm32_lock_release(&__lock___env_recursive_mutex);
}
/**
* @brief Acquire tz lock
*/
void __tz_lock()
{
stm32_lock_acquire(&__lock___tz_mutex);
}
/**
* @brief Release tz lock
*/
void __tz_unlock()
{
stm32_lock_release(&__lock___tz_mutex);
}
#endif /* __NEWLIB__ >= 3 && defined (_RETARGETABLE_LOCKING) */
/**
* @}
*/
/**
* @defgroup __cxa_guard_ GNU C++ one-time construction API
* @see https://itanium-cxx-abi.github.io/cxx-abi/abi.html#once-ctor
*
* When building for C++, please make sure that <tt>-fno-threadsafe-statics</tt> is not passed to the compiler
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/** The guard object is created by the C++ compiler and is 32 bit for ARM EABI. */
typedef struct
{
atomic_uchar initialized; /**< Indicate if object is initialized */
uint8_t acquired; /**< Ensure non-recursive lock */
uint16_t unused; /**< Padding */
} __attribute__((packed)) CxaGuardObject_t;
/* Private variables ---------------------------------------------------------*/
/** Mutex used in __cxa_guard_acquire, __cxa_guard_release and __cxa_guard_abort */
static LockingData_t __cxa_guard_mutex = LOCKING_DATA_INIT;
/* Private functions prototype ---------------------------------------------------------*/
int __cxa_guard_acquire(CxaGuardObject_t *guard_object);
void __cxa_guard_abort(CxaGuardObject_t *guard_object);
void __cxa_guard_release(CxaGuardObject_t *guard_object);
/* Private functions ---------------------------------------------------------*/
/**
* @brief Acquire __cxa_guard mutex
* @param guard_object Guard object
* @return 0 if object is initialized, else initialization of object required
*/
int __cxa_guard_acquire(CxaGuardObject_t *guard_object)
{
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(guard_object);
if (atomic_load(&guard_object->initialized) == 0)
{
/* Object needs initialization, lock threading context */
stm32_lock_acquire(&__cxa_guard_mutex);
if (atomic_load(&guard_object->initialized) == 0)
{
/* Object needs initialization */
if (guard_object->acquired)
{
/* Object initialization already in progress */
STM32_LOCK_BLOCK();
}
/* Lock acquired */
guard_object->acquired = 1;
return 1;
}
else
{
/* Object initialized in another thread */
stm32_lock_release(&__cxa_guard_mutex);
}
}
/* Object already initialized */
return 0;
}
/**
* @brief Abort __cxa_guard mutex
* @param guard_object Guard object
*/
void __cxa_guard_abort(CxaGuardObject_t *guard_object)
{
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(guard_object);
if (guard_object->acquired)
{
/* Release lock */
guard_object->acquired = 0;
stm32_lock_release(&__cxa_guard_mutex);
}
else
{
/* Trying to release non-acquired lock */
STM32_LOCK_BLOCK();
}
}
/**
* @brief Release __cxa_guard mutex
* @param guard_object Guard object
*/
void __cxa_guard_release(CxaGuardObject_t *guard_object)
{
STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(guard_object);
/* Object initialized */
atomic_store(&guard_object->initialized, 1);
/* Release lock */
__cxa_guard_abort(guard_object);
}
/**
* @}
*/
#endif /* __SINGLE_THREAD__ */
+14 -8
View File
@@ -15,6 +15,7 @@
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "canlog.h"
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "cmsis_os.h"
@@ -50,11 +51,9 @@ void CAN_Logger_Init(CAN_HandleTypeDef *hcan1, CAN_HandleTypeDef *hcan2)
filter.FilterBank = 0;
if (HAL_CAN_ConfigFilter(hcan1, &filter) != HAL_OK) Error_Handler();
if (HAL_CAN_Start(hcan1) != HAL_OK) Error_Handler();
filter.FilterBank = 14;
if (HAL_CAN_ConfigFilter(hcan2, &filter) != HAL_OK) Error_Handler();
if (HAL_CAN_Start(hcan2) != HAL_OK) Error_Handler();
}
/* END CAN_Logger_Init */
@@ -76,7 +75,8 @@ void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
// TODO: manage the case of FIFO overflow
if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rxHeader, data) != HAL_OK) return;
message.id = rxHeader.ExtId;
if (rxHeader.IDE == CAN_ID_EXT) message.id = rxHeader.ExtId;
else message.id = rxHeader.StdId;
message.dlc = rxHeader.DLC;
message.isExtended = (rxHeader.IDE == CAN_ID_EXT);
message.source = (hcan->Instance == CAN1) ? 1 : 2;
@@ -112,17 +112,23 @@ void vCANListener(void *argument)
osMessageQueueId_t queue = (hcan->Instance == CAN1) ? xCAN1RxQueue : xCAN2RxQueue;
CanMessage_t message;
if (HAL_CAN_Start(hcan) != HAL_OK) Error_Handler();
HAL_CAN_ActivateNotification(hcan, CAN_IT_RX_FIFO0_MSG_PENDING);
uint32_t irqn = (hcan->Instance == CAN1) ? CAN1_RX0_IRQn : CAN2_RX0_IRQn;
HAL_NVIC_SetPriority(irqn, 6, 0);
HAL_NVIC_EnableIRQ(irqn);
for (;;)
{
if (osMessageQueueGet(queue, &message, NULL, osWaitForever) == osOK)
{
if (osMessageQueueGet(queue, &message, NULL, 1000) == osOK)
{
// J1939 decoding
// RELAY: Push to the UART queue
osMessageQueuePut(xUARTQueue, &message, 0U, 0U);
}
osMessageQueuePut(xUARTQueue, &message, 0U, 0U);
}
else DEBUG_PRINT("No CAN yet!\r\n");
}
}
/* END vCANListener */
+51 -10
View File
@@ -32,7 +32,7 @@ extern osMessageQueueId_t xUARTQueue;
* @param arguments: buffer, source, message
* @retval None
*/
static void format_can_message(char *buf, uint8_t source, const CanMessage_t *message)
static int format_can_message(char *buf, uint8_t source, const CanMessage_t *message)
{
const char hex[] = "0123456789ABCDEF";
@@ -72,6 +72,9 @@ static void format_can_message(char *buf, uint8_t source, const CanMessage_t *me
buf[idx++] = '\r';
buf[idx++] = '\n';
buf[idx] = '\0';
return idx;
}
/* END format_can_message */
@@ -98,17 +101,55 @@ void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
*/
void vUARTLogger(void *argument)
{
CanMessage_t message;
char tx_buffer[45];
CanMessage_t message;
char tx_buffer[45];
for (;;)
{
if (osMessageQueueGet(xUARTQueue, &message, NULL, osWaitForever) == osOK)
#ifdef DEBUG_DUMMY_FRAME
CanMessage_t dummy_frame = {
.id = 0x0CF00400, // J1939 EEC1 ID
.dlc = 8, // 8 bytes of data
.isExtended = 1, // 29-bit Extended ID
.source = 1, // CAN1
.payload = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22}
};
#endif
for (;;)
{
DEBUG_PRINT("Waiting for CAN traffic...\r\n");
#ifdef DEBUG_DUMMY_FRAME
uint32_t queue_timeout = 1000U;
#else
uint32_t queue_timeout = osWaitForever;
#endif
#ifdef DEBUG_DUMMY_FRAME
osMessageQueuePut(xUARTQueue, &dummy_frame, 0U, 0U);
osDelay(1000);
#endif
if (osMessageQueueGet(xUARTQueue, &message, NULL, queue_timeout) == osOK)
{
if (osSemaphoreAcquire(xUARTDMASemaphore, queue_timeout) == osOK)
{
format_can_message(tx_buffer, message.source, &message); // Assuming you add 'source' to the struct
HAL_UART_Transmit_DMA(&huart1, (uint8_t*)tx_buffer, 44);
osSemaphoreAcquire(xUARTDMASemaphore, osWaitForever);
int len = format_can_message(tx_buffer, message.source, &message);
if (HAL_UART_Transmit_DMA(&huart1, (uint8_t*)tx_buffer, len) == HAL_OK)
{
DEBUG_PRINT("CAN frame sent via UART\r\n");
}
else
{
osSemaphoreRelease(xUARTDMASemaphore);
DEBUG_PRINT("HAL error, CAN frame NOT sent!\r\n");
}
}
}
else
{
DEBUG_PRINT("ERROR: Semaphore timeout! UART might be stuck in BUSY state.\r\n");
}
}
}
}
/* END vUARTLoggerListen */
+58 -32
View File
@@ -46,11 +46,12 @@ DMA_HandleTypeDef hdma_sdio_rx;
DMA_HandleTypeDef hdma_sdio_tx;
UART_HandleTypeDef huart1;
DMA_HandleTypeDef hdma_usart1_tx;
/* USER CODE BEGIN PV */
LED_Config led_can1 = {GPIOB, GPIO_PIN_2};
LED_Config led_can2 = {GPIOB, GPIO_PIN_5};
LED_Config led_error = {GPIOB, GPIO_PIN_3};
LED_Config led_can1 = {GPIOB, GPIO_PIN_5};
LED_Config led_can2 = {GPIOB, GPIO_PIN_6};
LED_Config led_error = {GPIOB, GPIO_PIN_7};
osThreadId_t xCAN1rxTask;
osThreadId_t xCAN2rxTask;
@@ -76,6 +77,11 @@ static void MX_SDIO_SD_Init(void);
static void MX_USART1_UART_Init(void);
/* USER CODE BEGIN PFP */
int _write(int file, char *ptr, int len)
{
for (int i = 0; i < len; i++) ITM_SendChar((*ptr++));
return len;
}
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
@@ -91,7 +97,15 @@ int main(void)
{
/* USER CODE BEGIN 1 */
if (CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk)
{
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
ITM->LAR = 0xC5ACCE55;
ITM->TER = 1 << 0;
ITM->TCR = ITM_TCR_ITMENA_Msk | ITM_TCR_SYNCENA_Msk | ITM_TCR_SWOENA_Msk;
}
DEBUG_PRINT("Booting system\r\n");
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
@@ -100,6 +114,7 @@ int main(void)
HAL_Init();
/* USER CODE BEGIN Init */
DEBUG_PRINT("Configuring system clock\r\n");
/* USER CODE END Init */
@@ -107,7 +122,7 @@ int main(void)
SystemClock_Config();
/* USER CODE BEGIN SysInit */
DEBUG_PRINT("Initializing configured peripherals...\r\n");
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
@@ -118,12 +133,15 @@ int main(void)
MX_SDIO_SD_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
DEBUG_PRINT("Initializing CAN bus logger\r\n");
CAN_Logger_Init(&hcan1, &hcan2);
/* USER CODE END 2 */
/* Init scheduler */
osKernelInitialize();
DEBUG_PRINT("Creating RTOS entities\r\n");
/* USER CODE BEGIN RTOS_TASKS */
const osThreadAttr_t CAN1rxAttributes = {
.name = "CAN1rx",
@@ -156,7 +174,7 @@ int main(void)
/* USER CODE END RTOS_MUTEX */
/* USER CODE BEGIN RTOS_SEMAPHORES */
xUARTDMASemaphore = osSemaphoreNew(1, 0, NULL);
xUARTDMASemaphore = osSemaphoreNew(1, 1, NULL);
if (xUARTDMASemaphore == NULL) Error_Handler();
/* USER CODE END RTOS_SEMAPHORES */
@@ -183,6 +201,7 @@ int main(void)
/* USER CODE END RTOS_EVENTS */
/* Start scheduler */
DEBUG_PRINT("Starting RTOS init scheduler\r\n");
osKernelStart();
/* We should never get here as control is now taken by the scheduler */
@@ -194,6 +213,7 @@ int main(void)
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
DEBUG_PRINT("ERROR: RTOS scheduler crashed!\r\n");
/* USER CODE END 3 */
}
}
@@ -260,7 +280,7 @@ static void MX_CAN1_Init(void)
/* USER CODE END CAN1_Init 1 */
hcan1.Instance = CAN1;
hcan1.Init.Prescaler = 4;
hcan1.Init.Prescaler = 8;
hcan1.Init.Mode = CAN_MODE_SILENT;
hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
hcan1.Init.TimeSeg1 = CAN_BS1_16TQ;
@@ -276,7 +296,7 @@ static void MX_CAN1_Init(void)
Error_Handler();
}
/* USER CODE BEGIN CAN1_Init 2 */
DEBUG_PRINT("CAN1 initialized!\r\n");
/* USER CODE END CAN1_Init 2 */
}
@@ -297,7 +317,7 @@ static void MX_CAN2_Init(void)
/* USER CODE END CAN2_Init 1 */
hcan2.Instance = CAN2;
hcan2.Init.Prescaler = 8;
hcan2.Init.Prescaler = 16;
hcan2.Init.Mode = CAN_MODE_SILENT;
hcan2.Init.SyncJumpWidth = CAN_SJW_1TQ;
hcan2.Init.TimeSeg1 = CAN_BS1_16TQ;
@@ -313,7 +333,7 @@ static void MX_CAN2_Init(void)
Error_Handler();
}
/* USER CODE BEGIN CAN2_Init 2 */
DEBUG_PRINT("CAN2 initialized!\r\n");
/* USER CODE END CAN2_Init 2 */
}
@@ -340,16 +360,16 @@ static void MX_SDIO_SD_Init(void)
hsd.Init.BusWide = SDIO_BUS_WIDE_1B;
hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
hsd.Init.ClockDiv = 0;
if (HAL_SD_Init(&hsd) != HAL_OK)
{
Error_Handler();
}
if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK)
{
Error_Handler();
}
//if (HAL_SD_Init(&hsd) != HAL_OK)
//{
// Error_Handler();
//}
//if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK)
//{
// Error_Handler();
//}
/* USER CODE BEGIN SDIO_Init 2 */
//DEBUG_PRINT("SDIO initialized!\r\n");
/* USER CODE END SDIO_Init 2 */
}
@@ -370,7 +390,7 @@ static void MX_USART1_UART_Init(void)
/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 1152000;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
@@ -382,7 +402,7 @@ static void MX_USART1_UART_Init(void)
Error_Handler();
}
/* USER CODE BEGIN USART1_Init 2 */
DEBUG_PRINT("USART1 initialized!\r\n");
/* USER CODE END USART1_Init 2 */
}
@@ -403,7 +423,13 @@ static void MX_DMA_Init(void)
/* DMA2_Stream6_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn);
/* DMA2_Stream7_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Stream7_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream7_IRQn);
/* USER CODE BEGIN MX_DMA_Init 1 */
DEBUG_PRINT("DMA initialized!\r\n");
/* USER CODE END MX_DMA_Init 1 */
}
/**
@@ -426,7 +452,7 @@ static void MX_GPIO_Init(void)
__HAL_RCC_GPIOD_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_RESET);
/*Configure GPIO pins : PC13 PC14 PC15 PC0
PC1 PC2 PC3 PC4
@@ -446,35 +472,33 @@ static void MX_GPIO_Init(void)
/*Configure GPIO pins : PA0 PA1 PA2 PA3
PA4 PA5 PA6 PA7
PA8 PA11 PA12 PA13
PA14 PA15 */
PA8 PA11 PA12 PA15 */
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7
|GPIO_PIN_8|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13
|GPIO_PIN_14|GPIO_PIN_15;
|GPIO_PIN_8|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pins : PB0 PB1 PB2 PB10
PB11 PB14 PB15 PB6
PB7 */
PB11 PB14 PB15 PB3
PB4 */
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_10
|GPIO_PIN_11|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_6
|GPIO_PIN_7;
|GPIO_PIN_11|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_3
|GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/*Configure GPIO pins : PB3 PB4 PB5 */
GPIO_InitStruct.Pin = GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5;
/*Configure GPIO pins : PB5 PB6 PB7 */
GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* USER CODE BEGIN MX_GPIO_Init_2 */
DEBUG_PRINT("GPIO initialized!\r\n");
/* USER CODE END MX_GPIO_Init_2 */
}
@@ -509,6 +533,8 @@ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
*/
void Error_Handler(void)
{
DEBUG_PRINT("ERROR: entering error handler\r\n");
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
+29
View File
@@ -26,6 +26,8 @@ extern DMA_HandleTypeDef hdma_sdio_rx;
extern DMA_HandleTypeDef hdma_sdio_tx;
extern DMA_HandleTypeDef hdma_usart1_tx;
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN TD */
@@ -371,6 +373,28 @@ void HAL_UART_MspInit(UART_HandleTypeDef* huart)
GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USART1 DMA Init */
/* USART1_TX Init */
hdma_usart1_tx.Instance = DMA2_Stream7;
hdma_usart1_tx.Init.Channel = DMA_CHANNEL_4;
hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart1_tx.Init.Mode = DMA_NORMAL;
hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW;
hdma_usart1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(huart,hdmatx,hdma_usart1_tx);
/* USART1 interrupt Init */
HAL_NVIC_SetPriority(USART1_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
/* USER CODE BEGIN USART1_MspInit 1 */
/* USER CODE END USART1_MspInit 1 */
@@ -401,6 +425,11 @@ void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)
*/
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);
/* USART1 DMA DeInit */
HAL_DMA_DeInit(huart->hdmatx);
/* USART1 interrupt DeInit */
HAL_NVIC_DisableIRQ(USART1_IRQn);
/* USER CODE BEGIN USART1_MspDeInit 1 */
/* USER CODE END USART1_MspDeInit 1 */
+30
View File
@@ -58,6 +58,8 @@
extern DMA_HandleTypeDef hdma_sdio_rx;
extern DMA_HandleTypeDef hdma_sdio_tx;
extern SD_HandleTypeDef hsd;
extern DMA_HandleTypeDef hdma_usart1_tx;
extern UART_HandleTypeDef huart1;
extern TIM_HandleTypeDef htim6;
/* USER CODE BEGIN EV */
@@ -162,6 +164,20 @@ void DebugMon_Handler(void)
/* please refer to the startup file (startup_stm32f4xx.s). */
/******************************************************************************/
/**
* @brief This function handles USART1 global interrupt.
*/
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
/**
* @brief This function handles SDIO global interrupt.
*/
@@ -218,6 +234,20 @@ void DMA2_Stream6_IRQHandler(void)
/* USER CODE END DMA2_Stream6_IRQn 1 */
}
/**
* @brief This function handles DMA2 stream7 global interrupt.
*/
void DMA2_Stream7_IRQHandler(void)
{
/* USER CODE BEGIN DMA2_Stream7_IRQn 0 */
/* USER CODE END DMA2_Stream7_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_usart1_tx);
/* USER CODE BEGIN DMA2_Stream7_IRQn 1 */
/* USER CODE END DMA2_Stream7_IRQn 1 */
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
+38
View File
@@ -0,0 +1,38 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. https://fsf.org/
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
+15
View File
@@ -0,0 +1,15 @@
# Third-Party Notices
This project is built with open source components and includes third-party software:
## 1. Original Application Code
- **Copyright (c) 2026 Erick Ahmed**
- **License:** [GNU General Public License v3.0](https://git.erickahmed.com/erickahmed/j1939_logger/src/branch/main/LICENSE.md)
## 2. STM32F4 HAL Drivers
- **Copyright (c) 2016 STMicroelectronics**
- **License:** [BSD 3-Clause License](https://git.erickahmed.com/erickahmed/j1939_logger/src/branch/main/Drivers/STM32F4xx_HAL_Driver/LICENSE.txt)
## 3. STM32 CMSIS
- **Copyright (c) 2017 STMicroelectronics**
- **License:** [Apache License 2.0](https://git.erickahmed.com/erickahmed/j1939_logger/src/branch/main/Drivers/CMSIS/LICENSE.txt)
+35 -16
View File
@@ -20,7 +20,8 @@ CAN2.Mode=CAN_MODE_SILENT
CAN2.Prescaler=8
Dma.Request0=SDIO_RX
Dma.Request1=SDIO_TX
Dma.RequestsNb=2
Dma.Request2=USART1_TX
Dma.RequestsNb=3
Dma.SDIO_RX.0.Direction=DMA_PERIPH_TO_MEMORY
Dma.SDIO_RX.0.FIFOMode=DMA_FIFOMODE_ENABLE
Dma.SDIO_RX.0.FIFOThreshold=DMA_FIFO_THRESHOLD_FULL
@@ -47,6 +48,16 @@ Dma.SDIO_TX.1.PeriphDataAlignment=DMA_PDATAALIGN_WORD
Dma.SDIO_TX.1.PeriphInc=DMA_PINC_DISABLE
Dma.SDIO_TX.1.Priority=DMA_PRIORITY_LOW
Dma.SDIO_TX.1.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode,FIFOThreshold,MemBurst,PeriphBurst
Dma.USART1_TX.2.Direction=DMA_MEMORY_TO_PERIPH
Dma.USART1_TX.2.FIFOMode=DMA_FIFOMODE_DISABLE
Dma.USART1_TX.2.Instance=DMA2_Stream7
Dma.USART1_TX.2.MemDataAlignment=DMA_MDATAALIGN_BYTE
Dma.USART1_TX.2.MemInc=DMA_MINC_ENABLE
Dma.USART1_TX.2.Mode=DMA_NORMAL
Dma.USART1_TX.2.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
Dma.USART1_TX.2.PeriphInc=DMA_PINC_DISABLE
Dma.USART1_TX.2.Priority=DMA_PRIORITY_LOW
Dma.USART1_TX.2.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode
FREERTOS.FootprintOK=true
FREERTOS.IPParameters=Tasks01,configUSE_NEWLIB_REENTRANT,FootprintOK
FREERTOS.Tasks01=DefaultTask,49,128,can_listen,Default,NULL,Dynamic,NULL,NULL
@@ -70,22 +81,24 @@ Mcu.Name=STM32F405RGTx
Mcu.Package=LQFP64
Mcu.Pin0=PB12
Mcu.Pin1=PB13
Mcu.Pin10=PB3
Mcu.Pin11=PB4
Mcu.Pin10=PC12
Mcu.Pin11=PD2
Mcu.Pin12=PB5
Mcu.Pin13=PB8
Mcu.Pin14=PB9
Mcu.Pin15=VP_FREERTOS_VS_CMSIS_V2
Mcu.Pin16=VP_SYS_VS_tim6
Mcu.Pin13=PB6
Mcu.Pin14=PB7
Mcu.Pin15=PB8
Mcu.Pin16=PB9
Mcu.Pin17=VP_FREERTOS_VS_CMSIS_V2
Mcu.Pin18=VP_SYS_VS_tim6
Mcu.Pin2=PC8
Mcu.Pin3=PC9
Mcu.Pin4=PA9
Mcu.Pin5=PA10
Mcu.Pin6=PC10
Mcu.Pin7=PC11
Mcu.Pin8=PC12
Mcu.Pin9=PD2
Mcu.PinsNb=17
Mcu.Pin6=PA13
Mcu.Pin7=PA14
Mcu.Pin8=PC10
Mcu.Pin9=PC11
Mcu.PinsNb=19
Mcu.ThirdPartyNb=0
Mcu.UserConstants=
Mcu.UserName=STM32F405RGTx
@@ -94,6 +107,7 @@ MxDb.Version=DB.6.0.170
NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false
NVIC.DMA2_Stream3_IRQn=true\:5\:0\:false\:false\:true\:true\:false\:true\:true
NVIC.DMA2_Stream6_IRQn=true\:5\:0\:false\:false\:true\:true\:false\:true\:true
NVIC.DMA2_Stream7_IRQn=true\:5\:0\:false\:false\:true\:true\:false\:true\:true
NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false
NVIC.ForceEnableDMAVector=true
NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false
@@ -110,21 +124,26 @@ NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:false\:true\:false\:true\:false
NVIC.TIM6_DAC_IRQn=true\:15\:0\:false\:false\:true\:false\:false\:true\:true
NVIC.TimeBase=TIM6_DAC_IRQn
NVIC.TimeBaseIP=TIM6
NVIC.USART1_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true
NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false
PA10.Mode=Asynchronous
PA10.Signal=USART1_RX
PA13.Mode=Serial_Wire
PA13.Signal=SYS_JTMS-SWDIO
PA14.Mode=Serial_Wire
PA14.Signal=SYS_JTCK-SWCLK
PA9.Mode=Asynchronous
PA9.Signal=USART1_TX
PB12.Mode=CAN_Activate
PB12.Signal=CAN2_RX
PB13.Mode=CAN_Activate
PB13.Signal=CAN2_TX
PB3.Locked=true
PB3.Signal=GPIO_Output
PB4.Locked=true
PB4.Signal=GPIO_Output
PB5.Locked=true
PB5.Signal=GPIO_Output
PB6.Locked=true
PB6.Signal=GPIO_Output
PB7.Locked=true
PB7.Signal=GPIO_Output
PB8.Mode=CAN_Activate
PB8.Signal=CAN1_RX
PB9.Locked=true