From d69cb0231b56d62da90c6ce6f2d9ca555210cd52 Mon Sep 17 00:00:00 2001 From: Erick Ahmed Date: Tue, 16 Jun 2026 23:08:51 +0200 Subject: [PATCH 01/13] Removing duplicate, again... --- Core/Src/ThreadSafe/newlib_lock_glue.c | 435 ------------------------- 1 file changed, 435 deletions(-) delete mode 100644 Core/Src/ThreadSafe/newlib_lock_glue.c diff --git a/Core/Src/ThreadSafe/newlib_lock_glue.c b/Core/Src/ThreadSafe/newlib_lock_glue.c deleted file mode 100644 index 744d87e..0000000 --- a/Core/Src/ThreadSafe/newlib_lock_glue.c +++ /dev/null @@ -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 - -/* 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 -#include -#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 -#include -#include - -/* 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 newlib/libc/misc/lock.c */ -struct __lock __lock___sinit_recursive_mutex = { LOCKING_DATA_INIT }; - -/** Implementing mutex from newlib/libc/misc/lock.c */ -struct __lock __lock___sfp_recursive_mutex = { LOCKING_DATA_INIT }; - -/** Implementing mutex from newlib/libc/misc/lock.c */ -struct __lock __lock___atexit_recursive_mutex = { LOCKING_DATA_INIT }; - -/** Implementing mutex from newlib/libc/misc/lock.c */ -struct __lock __lock___at_quick_exit_mutex = { LOCKING_DATA_INIT }; - -/** Implementing mutex from newlib/libc/misc/lock.c */ -struct __lock __lock___malloc_recursive_mutex = { LOCKING_DATA_INIT }; - -/** Implementing mutex from newlib/libc/misc/lock.c */ -struct __lock __lock___env_recursive_mutex = { LOCKING_DATA_INIT }; - -/** Implementing mutex from newlib/libc/misc/lock.c */ -struct __lock __lock___tz_mutex = { LOCKING_DATA_INIT }; - -/** Implementing mutex from newlib/libc/misc/lock.c */ -struct __lock __lock___dd_hash_mutex = { LOCKING_DATA_INIT }; - -/** Implementing mutex from newlib/libc/misc/lock.c */ -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 - -/* 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 -fno-threadsafe-statics 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__ */ -- 2.52.0 From 84ea393dd65e9faef3ba62f79b06c8cdfaa13e65 Mon Sep 17 00:00:00 2001 From: Erick Ahmed Date: Wed, 17 Jun 2026 18:04:48 +0200 Subject: [PATCH 02/13] Implement ITM debug via ST-Link - Enable Instrumentation Trace Macroblock - Remove PB3 initialization conflict with ITM - Add a bunch of debug prints --- Core/Inc/main.h | 18 ++++++++++++++++++ Core/Src/main.c | 33 ++++++++++++++++++++++++--------- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/Core/Inc/main.h b/Core/Inc/main.h index 8f472c0..4cc7d5f 100644 --- a/Core/Inc/main.h +++ b/Core/Inc/main.h @@ -24,6 +24,24 @@ extern "C" { #endif +#define DEBUG +#ifdef DEBUG +static inline void ITM_Print(const char *str) { + while (*str) { + uint32_t timeout = 1000; + while ((ITM->PORT[0].u32 == 0) && (timeout-- > 0)); + + if (timeout > 0) { + ITM->PORT[0].u8 = (uint8_t)(*str); + } + str++; + } +} +#define DEBUG_PRINT(x) ITM_Print(x) +#else +#define DEBUG_PRINT(x) +#endif + /* Includes ------------------------------------------------------------------*/ #include "stm32f4xx_hal.h" #include "canlog.h" diff --git a/Core/Src/main.c b/Core/Src/main.c index 7d631ed..d538f06 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -91,7 +91,11 @@ int main(void) { /* USER CODE BEGIN 1 */ - + 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 +104,7 @@ int main(void) HAL_Init(); /* USER CODE BEGIN Init */ + DEBUG_PRINT("Configuring system clock\r\n"); /* USER CODE END Init */ @@ -107,7 +112,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 +123,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", @@ -183,6 +191,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 +203,7 @@ int main(void) /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ + DEBUG_PRINT("ERROR: RTOS scheduler crashed!\r\n"); /* USER CODE END 3 */ } } @@ -276,7 +286,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 */ } @@ -313,7 +323,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 */ } @@ -349,7 +359,7 @@ static void MX_SDIO_SD_Init(void) Error_Handler(); } /* USER CODE BEGIN SDIO_Init 2 */ - + DEBUG_PRINT("SDIO initialized!\r\n"); /* USER CODE END SDIO_Init 2 */ } @@ -382,7 +392,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 */ } @@ -404,6 +414,9 @@ static void MX_DMA_Init(void) HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 5, 0); HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn); + /* USER CODE BEGIN MX_DMA_Init 1 */ + DEBUG_PRINT("DMA initialized!\r\n"); + /* USER CODE END MX_DMA_Init 1 */ } /** @@ -466,15 +479,15 @@ static void MX_GPIO_Init(void) 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 : PB4 PB5 */ + GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5; 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 +522,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(); -- 2.52.0 From 63e3e81986ec41ec758c72b02d32c76f79002c68 Mon Sep 17 00:00:00 2001 From: Erick Ahmed Date: Wed, 17 Jun 2026 18:05:04 +0200 Subject: [PATCH 03/13] Fix spacing --- Core/Src/canlog.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Core/Src/canlog.c b/Core/Src/canlog.c index f28fd25..7ed115d 100644 --- a/Core/Src/canlog.c +++ b/Core/Src/canlog.c @@ -116,13 +116,13 @@ void vCANListener(void *argument) for (;;) { - if (osMessageQueueGet(queue, &message, NULL, osWaitForever) == osOK) - { + if (osMessageQueueGet(queue, &message, NULL, osWaitForever) == osOK) + { // J1939 decoding // RELAY: Push to the UART queue - osMessageQueuePut(xUARTQueue, &message, 0U, 0U); - } + osMessageQueuePut(xUARTQueue, &message, 0U, 0U); + } } } /* END vCANListener */ -- 2.52.0 From 91218e782e459507cbfdd316d56ba9631d3766db Mon Sep 17 00:00:00 2001 From: Erick Ahmed Date: Wed, 17 Jun 2026 18:05:45 +0200 Subject: [PATCH 04/13] Include main header --- Core/Src/canlog.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/Src/canlog.c b/Core/Src/canlog.c index 7ed115d..4909412 100644 --- a/Core/Src/canlog.c +++ b/Core/Src/canlog.c @@ -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" -- 2.52.0 From 17c500e39af952e6a190e9cfca202848bd918305 Mon Sep 17 00:00:00 2001 From: Erick Ahmed Date: Wed, 17 Jun 2026 18:11:46 +0200 Subject: [PATCH 05/13] Add debug messages for UART --- Core/Src/cansend.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Core/Src/cansend.c b/Core/Src/cansend.c index cbc5a78..3831c7a 100644 --- a/Core/Src/cansend.c +++ b/Core/Src/cansend.c @@ -103,11 +103,14 @@ void vUARTLogger(void *argument) for (;;) { + DEBUG_PRINT("Waiting for CAN traffic...\r\n"); if (osMessageQueueGet(xUARTQueue, &message, NULL, osWaitForever) == osOK) { - format_can_message(tx_buffer, message.source, &message); // Assuming you add 'source' to the struct + DEBUG_PRINT("CAN frame detected\r\n"); + format_can_message(tx_buffer, message.source, &message); HAL_UART_Transmit_DMA(&huart1, (uint8_t*)tx_buffer, 44); osSemaphoreAcquire(xUARTDMASemaphore, osWaitForever); + DEBUG_PRINT("CAN frame sent via UART\r\n"); } } } -- 2.52.0 From 5c8961efa7504d45719381228b744e9c4ab73178 Mon Sep 17 00:00:00 2001 From: Erick Ahmed Date: Wed, 17 Jun 2026 18:16:13 +0200 Subject: [PATCH 06/13] Include stdint --- Core/Inc/main.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Core/Inc/main.h b/Core/Inc/main.h index 4cc7d5f..d174629 100644 --- a/Core/Inc/main.h +++ b/Core/Inc/main.h @@ -24,6 +24,27 @@ extern "C" { #endif +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_hal.h" +#include "canlog.h" + +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ +#include +/* USER CODE END Includes */ + +/* Exported types ------------------------------------------------------------*/ +/* USER CODE BEGIN ET */ + +/* USER CODE END ET */ + +/* Exported constants --------------------------------------------------------*/ +/* USER CODE BEGIN EC */ + +/* USER CODE END EC */ + +/* Exported macro ------------------------------------------------------------*/ +/* USER CODE BEGIN EM */ #define DEBUG #ifdef DEBUG static inline void ITM_Print(const char *str) { -- 2.52.0 From 1d70a35f95e5275c1e8c9a08d7d124eef839f0b1 Mon Sep 17 00:00:00 2001 From: Erick Ahmed Date: Wed, 17 Jun 2026 18:16:20 +0200 Subject: [PATCH 07/13] Move to proper block --- Core/Inc/main.h | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/Core/Inc/main.h b/Core/Inc/main.h index d174629..333d59d 100644 --- a/Core/Inc/main.h +++ b/Core/Inc/main.h @@ -26,7 +26,7 @@ extern "C" { /* Includes ------------------------------------------------------------------*/ #include "stm32f4xx_hal.h" -#include "canlog.h" + /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ @@ -62,29 +62,6 @@ static inline void ITM_Print(const char *str) { #else #define DEBUG_PRINT(x) #endif - -/* Includes ------------------------------------------------------------------*/ -#include "stm32f4xx_hal.h" -#include "canlog.h" - -/* Private includes ----------------------------------------------------------*/ -/* USER CODE BEGIN Includes */ - -/* USER CODE END Includes */ - -/* Exported types ------------------------------------------------------------*/ -/* USER CODE BEGIN ET */ - -/* USER CODE END ET */ - -/* Exported constants --------------------------------------------------------*/ -/* USER CODE BEGIN EC */ - -/* USER CODE END EC */ - -/* Exported macro ------------------------------------------------------------*/ -/* USER CODE BEGIN EM */ - /* USER CODE END EM */ /* Exported functions prototypes ---------------------------------------------*/ -- 2.52.0 From 9980dafb5cc1afbcbb66470c050a020d2aa22123 Mon Sep 17 00:00:00 2001 From: Erick Ahmed Date: Wed, 17 Jun 2026 18:27:19 +0200 Subject: [PATCH 08/13] Initialize JTAG hardware - To debug with ST-Link --- Core/Inc/main.h | 169 +++---- Core/Src/main.c | 1128 +++++++++++++++++++++++------------------------ can_logger.ioc | 62 ++- 3 files changed, 687 insertions(+), 672 deletions(-) diff --git a/Core/Inc/main.h b/Core/Inc/main.h index 333d59d..efa4647 100644 --- a/Core/Inc/main.h +++ b/Core/Inc/main.h @@ -1,84 +1,85 @@ -/* USER CODE BEGIN Header */ -/** - ****************************************************************************** - * @file : main.h - * @brief : Header for main.c file. - * This file contains the common defines of the application. - ****************************************************************************** - * @attention - * - * Copyright (c) 2026 STMicroelectronics. - * Copyright (c) 2026 Erick Ahmed. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - ****************************************************************************** - */ -/* USER CODE END Header */ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __MAIN_H -#define __MAIN_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* Includes ------------------------------------------------------------------*/ -#include "stm32f4xx_hal.h" - - -/* Private includes ----------------------------------------------------------*/ -/* USER CODE BEGIN Includes */ -#include -/* USER CODE END Includes */ - -/* Exported types ------------------------------------------------------------*/ -/* USER CODE BEGIN ET */ - -/* USER CODE END ET */ - -/* Exported constants --------------------------------------------------------*/ -/* USER CODE BEGIN EC */ - -/* USER CODE END EC */ - -/* Exported macro ------------------------------------------------------------*/ -/* USER CODE BEGIN EM */ -#define DEBUG -#ifdef DEBUG -static inline void ITM_Print(const char *str) { - while (*str) { - uint32_t timeout = 1000; - while ((ITM->PORT[0].u32 == 0) && (timeout-- > 0)); - - if (timeout > 0) { - ITM->PORT[0].u8 = (uint8_t)(*str); - } - str++; - } -} -#define DEBUG_PRINT(x) ITM_Print(x) -#else -#define DEBUG_PRINT(x) -#endif -/* USER CODE END EM */ - -/* Exported functions prototypes ---------------------------------------------*/ -void Error_Handler(void); - -/* USER CODE BEGIN EFP */ - -/* USER CODE END EFP */ - -/* Private defines -----------------------------------------------------------*/ - -/* USER CODE BEGIN Private defines */ - -/* USER CODE END Private defines */ - -#ifdef __cplusplus -} -#endif - -#endif /* __MAIN_H */ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file : main.h + * @brief : Header for main.c file. + * This file contains the common defines of the application. + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 STMicroelectronics. + * Copyright (c) 2026 Erick Ahmed. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __MAIN_H +#define __MAIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_hal.h" + + +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ +#include +#include "canlog.h" +/* USER CODE END Includes */ + +/* Exported types ------------------------------------------------------------*/ +/* USER CODE BEGIN ET */ + +/* USER CODE END ET */ + +/* Exported constants --------------------------------------------------------*/ +/* USER CODE BEGIN EC */ + +/* USER CODE END EC */ + +/* Exported macro ------------------------------------------------------------*/ +/* USER CODE BEGIN EM */ +#define DEBUG +#ifdef DEBUG +static inline void ITM_Print(const char *str) { + while (*str) { + uint32_t timeout = 1000; + while ((ITM->PORT[0].u32 == 0) && (timeout-- > 0)); + + if (timeout > 0) { + ITM->PORT[0].u8 = (uint8_t)(*str); + } + str++; + } +} +#define DEBUG_PRINT(x) ITM_Print(x) +#else +#define DEBUG_PRINT(x) +#endif +/* USER CODE END EM */ + +/* Exported functions prototypes ---------------------------------------------*/ +void Error_Handler(void); + +/* USER CODE BEGIN EFP */ + +/* USER CODE END EFP */ + +/* Private defines -----------------------------------------------------------*/ + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +#ifdef __cplusplus +} +#endif + +#endif /* __MAIN_H */ diff --git a/Core/Src/main.c b/Core/Src/main.c index d538f06..bbac8fd 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -1,566 +1,562 @@ -/* USER CODE BEGIN Header */ -/** - ****************************************************************************** - * @file : main.c - * @brief : Main program body - ****************************************************************************** - * @attention - * Copyright (c) 2026 STMicroelectronics. - * Copyright (c) 2026 Erick Ahmed. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - ****************************************************************************** - */ -/* USER CODE END Header */ -/* Includes ------------------------------------------------------------------*/ -#include "main.h" -#include "cmsis_os.h" - -/* Private includes ----------------------------------------------------------*/ -/* USER CODE BEGIN Includes */ -#include "canlog.h" -#include "cansend.h" -/* USER CODE END Includes */ - -/* Private typedef -----------------------------------------------------------*/ -/* USER CODE BEGIN PTD */ -/* USER CODE END PTD */ - -/* Private define ------------------------------------------------------------*/ -/* USER CODE BEGIN PD */ - -/* USER CODE END PD */ - -/* Private macro -------------------------------------------------------------*/ -/* USER CODE BEGIN PM */ - -/* USER CODE END PM */ - -/* Private variables ---------------------------------------------------------*/ -CAN_HandleTypeDef hcan1; -CAN_HandleTypeDef hcan2; - -SD_HandleTypeDef hsd; -DMA_HandleTypeDef hdma_sdio_rx; -DMA_HandleTypeDef hdma_sdio_tx; - -UART_HandleTypeDef huart1; - -/* 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}; - -osThreadId_t xCAN1rxTask; -osThreadId_t xCAN2rxTask; -osThreadId_t xCAN1LedTask; -osThreadId_t xCAN2LedTask; - -osMessageQueueId_t xCAN1RxQueue; -osMessageQueueId_t xCAN2RxQueue; -osMessageQueueId_t xUARTQueue; - -osSemaphoreId_t xUARTDMASemaphore; -osThreadId_t xUartTask; - -/* USER CODE END PV */ - -/* Private function prototypes -----------------------------------------------*/ -void SystemClock_Config(void); -static void MX_GPIO_Init(void); -static void MX_DMA_Init(void); -static void MX_CAN1_Init(void); -static void MX_CAN2_Init(void); -static void MX_SDIO_SD_Init(void); -static void MX_USART1_UART_Init(void); - -/* USER CODE BEGIN PFP */ -/* USER CODE END PFP */ - -/* Private user code ---------------------------------------------------------*/ -/* USER CODE BEGIN 0 */ - -/* USER CODE END 0 */ - -/** - * @brief The application entry point. - * @retval int - */ -int main(void) -{ - - /* USER CODE BEGIN 1 */ - 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--------------------------------------------------------*/ - - /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ - HAL_Init(); - - /* USER CODE BEGIN Init */ - DEBUG_PRINT("Configuring system clock\r\n"); - - /* USER CODE END Init */ - - /* Configure the system clock */ - SystemClock_Config(); - - /* USER CODE BEGIN SysInit */ - DEBUG_PRINT("Initializing configured peripherals...\r\n"); - /* USER CODE END SysInit */ - - /* Initialize all configured peripherals */ - MX_GPIO_Init(); - MX_DMA_Init(); - MX_CAN1_Init(); - MX_CAN2_Init(); - 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", - .stack_size = 128 * 4, - .priority = (osPriority_t) osPriorityRealtime1, - }; - const osThreadAttr_t CAN2rxAttributes = { - .name = "CAN2rx", - .stack_size = 128 * 4, - .priority = (osPriority_t) osPriorityRealtime, - }; - const osThreadAttr_t UartLoggerAttributes = { - .name = "UART_Logger", - .stack_size = 256 * 4, - .priority = (osPriority_t) osPriorityHigh, - }; - const osThreadAttr_t LEDHeartbeatCAN1Attributes = { - .name = "LED_HB_CAN1", - .stack_size = 128 * 4, - .priority = (osPriority_t) osPriorityLow1, - }; - const osThreadAttr_t LEDHeartbeatCAN2Attributes = { - .name = "LED_HB_CAN2", - .stack_size = 128 * 4, - .priority = (osPriority_t) osPriorityLow, - }; - /* USER CODE END RTOS_TASKS */ - - /* USER CODE BEGIN RTOS_MUTEX */ - /* USER CODE END RTOS_MUTEX */ - - /* USER CODE BEGIN RTOS_SEMAPHORES */ - xUARTDMASemaphore = osSemaphoreNew(1, 0, NULL); - if (xUARTDMASemaphore == NULL) Error_Handler(); - /* USER CODE END RTOS_SEMAPHORES */ - - /* USER CODE BEGIN RTOS_TIMERS */ - /* USER CODE END RTOS_TIMERS */ - - /* USER CODE BEGIN RTOS_QUEUES */ - xCAN1RxQueue = osMessageQueueNew(64, sizeof(CanMessage_t), NULL); - xCAN2RxQueue = osMessageQueueNew(64, sizeof(CanMessage_t), NULL); - xUARTQueue = osMessageQueueNew(128, sizeof(CanMessage_t), NULL); - - if (xCAN1RxQueue == NULL || xCAN2RxQueue == NULL || xUARTQueue == NULL) Error_Handler(); - /* USER CODE END RTOS_QUEUES */ - - /* USER CODE BEGIN RTOS_THREADS */ - xCAN1rxTask = osThreadNew(vCANListener, &hcan1, &CAN1rxAttributes); - xCAN2rxTask = osThreadNew(vCANListener, &hcan2, &CAN2rxAttributes); - xUartTask = osThreadNew(vUARTLogger, NULL, &UartLoggerAttributes); - xCAN1LedTask = osThreadNew(vLEDHeartbeat, &led_can1, &LEDHeartbeatCAN1Attributes); - xCAN2LedTask = osThreadNew(vLEDHeartbeat, &led_can2, &LEDHeartbeatCAN2Attributes); - /* USER CODE END RTOS_THREADS */ - - /* USER CODE BEGIN RTOS_EVENTS */ - /* 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 */ - - /* Infinite loop */ - /* USER CODE BEGIN WHILE */ - while (1) - { - /* USER CODE END WHILE */ - - /* USER CODE BEGIN 3 */ - DEBUG_PRINT("ERROR: RTOS scheduler crashed!\r\n"); - /* USER CODE END 3 */ - } -} - -/** - * @brief System Clock Configuration - * @retval None - */ -void SystemClock_Config(void) -{ - RCC_OscInitTypeDef RCC_OscInitStruct = {0}; - RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; - - /** Configure the main internal regulator output voltage - */ - __HAL_RCC_PWR_CLK_ENABLE(); - __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); - - /** Initializes the RCC Oscillators according to the specified parameters - * in the RCC_OscInitTypeDef structure. - */ - RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; - RCC_OscInitStruct.HSIState = RCC_HSI_ON; - RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; - RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; - RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; - RCC_OscInitStruct.PLL.PLLM = 16; - RCC_OscInitStruct.PLL.PLLN = 336; - RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; - RCC_OscInitStruct.PLL.PLLQ = 7; - if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) - { - Error_Handler(); - } - - /** Initializes the CPU, AHB and APB buses clocks - */ - RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK - |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; - RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; - RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; - RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; - RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV4; - - if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) - { - Error_Handler(); - } -} - -/** - * @brief CAN1 Initialization Function - * @param None - * @retval None - */ -static void MX_CAN1_Init(void) -{ - - /* USER CODE BEGIN CAN1_Init 0 */ - - /* USER CODE END CAN1_Init 0 */ - - /* USER CODE BEGIN CAN1_Init 1 */ - - /* USER CODE END CAN1_Init 1 */ - hcan1.Instance = CAN1; - hcan1.Init.Prescaler = 4; - hcan1.Init.Mode = CAN_MODE_SILENT; - hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ; - hcan1.Init.TimeSeg1 = CAN_BS1_16TQ; - hcan1.Init.TimeSeg2 = CAN_BS2_4TQ; - hcan1.Init.TimeTriggeredMode = DISABLE; - hcan1.Init.AutoBusOff = DISABLE; - hcan1.Init.AutoWakeUp = ENABLE; - hcan1.Init.AutoRetransmission = DISABLE; - hcan1.Init.ReceiveFifoLocked = DISABLE; - hcan1.Init.TransmitFifoPriority = DISABLE; - if (HAL_CAN_Init(&hcan1) != HAL_OK) - { - Error_Handler(); - } - /* USER CODE BEGIN CAN1_Init 2 */ - DEBUG_PRINT("CAN1 initialized!\r\n"); - /* USER CODE END CAN1_Init 2 */ - -} - -/** - * @brief CAN2 Initialization Function - * @param None - * @retval None - */ -static void MX_CAN2_Init(void) -{ - - /* USER CODE BEGIN CAN2_Init 0 */ - - /* USER CODE END CAN2_Init 0 */ - - /* USER CODE BEGIN CAN2_Init 1 */ - - /* USER CODE END CAN2_Init 1 */ - hcan2.Instance = CAN2; - hcan2.Init.Prescaler = 8; - hcan2.Init.Mode = CAN_MODE_SILENT; - hcan2.Init.SyncJumpWidth = CAN_SJW_1TQ; - hcan2.Init.TimeSeg1 = CAN_BS1_16TQ; - hcan2.Init.TimeSeg2 = CAN_BS2_4TQ; - hcan2.Init.TimeTriggeredMode = DISABLE; - hcan2.Init.AutoBusOff = DISABLE; - hcan2.Init.AutoWakeUp = ENABLE; - hcan2.Init.AutoRetransmission = DISABLE; - hcan2.Init.ReceiveFifoLocked = DISABLE; - hcan2.Init.TransmitFifoPriority = DISABLE; - if (HAL_CAN_Init(&hcan2) != HAL_OK) - { - Error_Handler(); - } - /* USER CODE BEGIN CAN2_Init 2 */ - DEBUG_PRINT("CAN2 initialized!\r\n"); - /* USER CODE END CAN2_Init 2 */ - -} - -/** - * @brief SDIO Initialization Function - * @param None - * @retval None - */ -static void MX_SDIO_SD_Init(void) -{ - - /* USER CODE BEGIN SDIO_Init 0 */ - - /* USER CODE END SDIO_Init 0 */ - - /* USER CODE BEGIN SDIO_Init 1 */ - - /* USER CODE END SDIO_Init 1 */ - hsd.Instance = SDIO; - hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING; - hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE; - hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE; - 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(); - } - /* USER CODE BEGIN SDIO_Init 2 */ - DEBUG_PRINT("SDIO initialized!\r\n"); - /* USER CODE END SDIO_Init 2 */ - -} - -/** - * @brief USART1 Initialization Function - * @param None - * @retval None - */ -static void MX_USART1_UART_Init(void) -{ - - /* USER CODE BEGIN USART1_Init 0 */ - - /* USER CODE END USART1_Init 0 */ - - /* USER CODE BEGIN USART1_Init 1 */ - - /* USER CODE END USART1_Init 1 */ - huart1.Instance = USART1; - huart1.Init.BaudRate = 1152000; - huart1.Init.WordLength = UART_WORDLENGTH_8B; - huart1.Init.StopBits = UART_STOPBITS_1; - huart1.Init.Parity = UART_PARITY_NONE; - huart1.Init.Mode = UART_MODE_TX_RX; - huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; - huart1.Init.OverSampling = UART_OVERSAMPLING_16; - if (HAL_UART_Init(&huart1) != HAL_OK) - { - Error_Handler(); - } - /* USER CODE BEGIN USART1_Init 2 */ - DEBUG_PRINT("USART1 initialized!\r\n"); - /* USER CODE END USART1_Init 2 */ - -} - -/** - * Enable DMA controller clock - */ -static void MX_DMA_Init(void) -{ - - /* DMA controller clock enable */ - __HAL_RCC_DMA2_CLK_ENABLE(); - - /* DMA interrupt init */ - /* DMA2_Stream3_IRQn interrupt configuration */ - HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 5, 0); - HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn); - /* DMA2_Stream6_IRQn interrupt configuration */ - HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 5, 0); - HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn); - - /* USER CODE BEGIN MX_DMA_Init 1 */ - DEBUG_PRINT("DMA initialized!\r\n"); - /* USER CODE END MX_DMA_Init 1 */ -} - -/** - * @brief GPIO Initialization Function - * @param None - * @retval None - */ -static void MX_GPIO_Init(void) -{ - GPIO_InitTypeDef GPIO_InitStruct = {0}; - /* USER CODE BEGIN MX_GPIO_Init_1 */ - - /* USER CODE END MX_GPIO_Init_1 */ - - /* GPIO Ports Clock Enable */ - __HAL_RCC_GPIOC_CLK_ENABLE(); - __HAL_RCC_GPIOH_CLK_ENABLE(); - __HAL_RCC_GPIOA_CLK_ENABLE(); - __HAL_RCC_GPIOB_CLK_ENABLE(); - __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); - - /*Configure GPIO pins : PC13 PC14 PC15 PC0 - PC1 PC2 PC3 PC4 - PC5 PC6 PC7 */ - GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|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_InitStruct.Mode = GPIO_MODE_ANALOG; - GPIO_InitStruct.Pull = GPIO_NOPULL; - HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); - - /*Configure GPIO pins : PH0 PH1 */ - GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1; - GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; - GPIO_InitStruct.Pull = GPIO_NOPULL; - HAL_GPIO_Init(GPIOH, &GPIO_InitStruct); - - /*Configure GPIO pins : PA0 PA1 PA2 PA3 - PA4 PA5 PA6 PA7 - PA8 PA11 PA12 PA13 - PA14 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_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 */ - 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_InitStruct.Mode = GPIO_MODE_ANALOG; - GPIO_InitStruct.Pull = GPIO_NOPULL; - HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); - - /*Configure GPIO pins : PB4 PB5 */ - GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5; - 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 */ -} - -/* USER CODE BEGIN 4 */ -/* USER CODE END 4 */ - -/** - * @brief Period elapsed callback in non blocking mode - * @note This function is called when TIM6 interrupt took place, inside - * HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment - * a global variable "uwTick" used as application time base. - * @param htim : TIM handle - * @retval None - */ -void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) -{ - /* USER CODE BEGIN Callback 0 */ - - /* USER CODE END Callback 0 */ - if (htim->Instance == TIM6) - { - HAL_IncTick(); - } - /* USER CODE BEGIN Callback 1 */ - - /* USER CODE END Callback 1 */ -} - -/** - * @brief This function is executed in case of error occurrence. - * @retval None - */ -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(); - - //TODO: check if it is necessary to stop FreeRTOS - - uint32_t error_code_can1; - uint32_t error_code_can2; - - if (HAL_CAN_GetState(&hcan1) != HAL_CAN_STATE_READY) error_code_can1 = HAL_CAN_GetError(&hcan1); - if (HAL_CAN_GetState(&hcan2) != HAL_CAN_STATE_READY) error_code_can2 = HAL_CAN_GetError(&hcan2); - - // TODO: write error to SD and/or serial - - HAL_GPIO_WritePin(led_can1.port, led_can1.pin, GPIO_PIN_RESET); - HAL_GPIO_WritePin(led_can2.port, led_can2.pin, GPIO_PIN_RESET); - - while (1) - { - HAL_GPIO_TogglePin(led_error.port, led_error.pin); - HAL_Delay(250); - } - /* USER CODE END Error_Handler_Debug */ -} -#ifdef USE_FULL_ASSERT -/** - * @brief Reports the name of the source file and the source line number - * where the assert_param error has occurred. - * @param file: pointer to the source file name - * @param line: assert_param error line source number - * @retval None - */ -void assert_failed(uint8_t *file, uint32_t line) -{ - /* USER CODE BEGIN 6 */ - /* User can add his own implementation to report the file name and line number, - ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ - /* USER CODE END 6 */ -} -#endif /* USE_FULL_ASSERT */ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file : main.c + * @brief : Main program body + ****************************************************************************** + * @attention + * Copyright (c) 2026 STMicroelectronics. + * Copyright (c) 2026 Erick Ahmed. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + ****************************************************************************** + */ +/* USER CODE END Header */ +/* Includes ------------------------------------------------------------------*/ +#include "main.h" +#include "cmsis_os.h" + +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ +#include "canlog.h" +#include "cansend.h" +/* USER CODE END Includes */ + +/* Private typedef -----------------------------------------------------------*/ +/* USER CODE BEGIN PTD */ +/* USER CODE END PTD */ + +/* Private define ------------------------------------------------------------*/ +/* USER CODE BEGIN PD */ + +/* USER CODE END PD */ + +/* Private macro -------------------------------------------------------------*/ +/* USER CODE BEGIN PM */ + +/* USER CODE END PM */ + +/* Private variables ---------------------------------------------------------*/ +CAN_HandleTypeDef hcan1; +CAN_HandleTypeDef hcan2; + +SD_HandleTypeDef hsd; +DMA_HandleTypeDef hdma_sdio_rx; +DMA_HandleTypeDef hdma_sdio_tx; + +UART_HandleTypeDef huart1; + +/* 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}; + +osThreadId_t xCAN1rxTask; +osThreadId_t xCAN2rxTask; +osThreadId_t xCAN1LedTask; +osThreadId_t xCAN2LedTask; + +osMessageQueueId_t xCAN1RxQueue; +osMessageQueueId_t xCAN2RxQueue; +osMessageQueueId_t xUARTQueue; + +osSemaphoreId_t xUARTDMASemaphore; +osThreadId_t xUartTask; + +/* USER CODE END PV */ + +/* Private function prototypes -----------------------------------------------*/ +void SystemClock_Config(void); +static void MX_GPIO_Init(void); +static void MX_DMA_Init(void); +static void MX_CAN1_Init(void); +static void MX_CAN2_Init(void); +static void MX_SDIO_SD_Init(void); +static void MX_USART1_UART_Init(void); + +/* USER CODE BEGIN PFP */ +/* USER CODE END PFP */ + +/* Private user code ---------------------------------------------------------*/ +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +/** + * @brief The application entry point. + * @retval int + */ +int main(void) +{ + + /* USER CODE BEGIN 1 */ + 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--------------------------------------------------------*/ + + /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ + HAL_Init(); + + /* USER CODE BEGIN Init */ + DEBUG_PRINT("Configuring system clock\r\n"); + + /* USER CODE END Init */ + + /* Configure the system clock */ + SystemClock_Config(); + + /* USER CODE BEGIN SysInit */ + DEBUG_PRINT("Initializing configured peripherals...\r\n"); + /* USER CODE END SysInit */ + + /* Initialize all configured peripherals */ + MX_GPIO_Init(); + MX_DMA_Init(); + MX_CAN1_Init(); + MX_CAN2_Init(); + 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", + .stack_size = 128 * 4, + .priority = (osPriority_t) osPriorityRealtime1, + }; + const osThreadAttr_t CAN2rxAttributes = { + .name = "CAN2rx", + .stack_size = 128 * 4, + .priority = (osPriority_t) osPriorityRealtime, + }; + const osThreadAttr_t UartLoggerAttributes = { + .name = "UART_Logger", + .stack_size = 256 * 4, + .priority = (osPriority_t) osPriorityHigh, + }; + const osThreadAttr_t LEDHeartbeatCAN1Attributes = { + .name = "LED_HB_CAN1", + .stack_size = 128 * 4, + .priority = (osPriority_t) osPriorityLow1, + }; + const osThreadAttr_t LEDHeartbeatCAN2Attributes = { + .name = "LED_HB_CAN2", + .stack_size = 128 * 4, + .priority = (osPriority_t) osPriorityLow, + }; + /* USER CODE END RTOS_TASKS */ + + /* USER CODE BEGIN RTOS_MUTEX */ + /* USER CODE END RTOS_MUTEX */ + + /* USER CODE BEGIN RTOS_SEMAPHORES */ + xUARTDMASemaphore = osSemaphoreNew(1, 0, NULL); + if (xUARTDMASemaphore == NULL) Error_Handler(); + /* USER CODE END RTOS_SEMAPHORES */ + + /* USER CODE BEGIN RTOS_TIMERS */ + /* USER CODE END RTOS_TIMERS */ + + /* USER CODE BEGIN RTOS_QUEUES */ + xCAN1RxQueue = osMessageQueueNew(64, sizeof(CanMessage_t), NULL); + xCAN2RxQueue = osMessageQueueNew(64, sizeof(CanMessage_t), NULL); + xUARTQueue = osMessageQueueNew(128, sizeof(CanMessage_t), NULL); + + if (xCAN1RxQueue == NULL || xCAN2RxQueue == NULL || xUARTQueue == NULL) Error_Handler(); + /* USER CODE END RTOS_QUEUES */ + + /* USER CODE BEGIN RTOS_THREADS */ + xCAN1rxTask = osThreadNew(vCANListener, &hcan1, &CAN1rxAttributes); + xCAN2rxTask = osThreadNew(vCANListener, &hcan2, &CAN2rxAttributes); + xUartTask = osThreadNew(vUARTLogger, NULL, &UartLoggerAttributes); + xCAN1LedTask = osThreadNew(vLEDHeartbeat, &led_can1, &LEDHeartbeatCAN1Attributes); + xCAN2LedTask = osThreadNew(vLEDHeartbeat, &led_can2, &LEDHeartbeatCAN2Attributes); + /* USER CODE END RTOS_THREADS */ + + /* USER CODE BEGIN RTOS_EVENTS */ + /* 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 */ + + /* Infinite loop */ + /* USER CODE BEGIN WHILE */ + while (1) + { + /* USER CODE END WHILE */ + + /* USER CODE BEGIN 3 */ + DEBUG_PRINT("ERROR: RTOS scheduler crashed!\r\n"); + /* USER CODE END 3 */ + } +} + +/** + * @brief System Clock Configuration + * @retval None + */ +void SystemClock_Config(void) +{ + RCC_OscInitTypeDef RCC_OscInitStruct = {0}; + RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; + + /** Configure the main internal regulator output voltage + */ + __HAL_RCC_PWR_CLK_ENABLE(); + __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); + + /** Initializes the RCC Oscillators according to the specified parameters + * in the RCC_OscInitTypeDef structure. + */ + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; + RCC_OscInitStruct.HSIState = RCC_HSI_ON; + RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; + RCC_OscInitStruct.PLL.PLLM = 16; + RCC_OscInitStruct.PLL.PLLN = 336; + RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; + RCC_OscInitStruct.PLL.PLLQ = 7; + if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) + { + Error_Handler(); + } + + /** Initializes the CPU, AHB and APB buses clocks + */ + RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK + |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV4; + + if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) + { + Error_Handler(); + } +} + +/** + * @brief CAN1 Initialization Function + * @param None + * @retval None + */ +static void MX_CAN1_Init(void) +{ + + /* USER CODE BEGIN CAN1_Init 0 */ + + /* USER CODE END CAN1_Init 0 */ + + /* USER CODE BEGIN CAN1_Init 1 */ + + /* USER CODE END CAN1_Init 1 */ + hcan1.Instance = CAN1; + hcan1.Init.Prescaler = 4; + hcan1.Init.Mode = CAN_MODE_SILENT; + hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ; + hcan1.Init.TimeSeg1 = CAN_BS1_16TQ; + hcan1.Init.TimeSeg2 = CAN_BS2_4TQ; + hcan1.Init.TimeTriggeredMode = DISABLE; + hcan1.Init.AutoBusOff = DISABLE; + hcan1.Init.AutoWakeUp = ENABLE; + hcan1.Init.AutoRetransmission = DISABLE; + hcan1.Init.ReceiveFifoLocked = DISABLE; + hcan1.Init.TransmitFifoPriority = DISABLE; + if (HAL_CAN_Init(&hcan1) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN CAN1_Init 2 */ + DEBUG_PRINT("CAN1 initialized!\r\n"); + /* USER CODE END CAN1_Init 2 */ + +} + +/** + * @brief CAN2 Initialization Function + * @param None + * @retval None + */ +static void MX_CAN2_Init(void) +{ + + /* USER CODE BEGIN CAN2_Init 0 */ + + /* USER CODE END CAN2_Init 0 */ + + /* USER CODE BEGIN CAN2_Init 1 */ + + /* USER CODE END CAN2_Init 1 */ + hcan2.Instance = CAN2; + hcan2.Init.Prescaler = 8; + hcan2.Init.Mode = CAN_MODE_SILENT; + hcan2.Init.SyncJumpWidth = CAN_SJW_1TQ; + hcan2.Init.TimeSeg1 = CAN_BS1_16TQ; + hcan2.Init.TimeSeg2 = CAN_BS2_4TQ; + hcan2.Init.TimeTriggeredMode = DISABLE; + hcan2.Init.AutoBusOff = DISABLE; + hcan2.Init.AutoWakeUp = ENABLE; + hcan2.Init.AutoRetransmission = DISABLE; + hcan2.Init.ReceiveFifoLocked = DISABLE; + hcan2.Init.TransmitFifoPriority = DISABLE; + if (HAL_CAN_Init(&hcan2) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN CAN2_Init 2 */ + DEBUG_PRINT("CAN2 initialized!\r\n"); + /* USER CODE END CAN2_Init 2 */ + +} + +/** + * @brief SDIO Initialization Function + * @param None + * @retval None + */ +static void MX_SDIO_SD_Init(void) +{ + + /* USER CODE BEGIN SDIO_Init 0 */ + + /* USER CODE END SDIO_Init 0 */ + + /* USER CODE BEGIN SDIO_Init 1 */ + + /* USER CODE END SDIO_Init 1 */ + hsd.Instance = SDIO; + hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING; + hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE; + hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE; + 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(); + } + /* USER CODE BEGIN SDIO_Init 2 */ + DEBUG_PRINT("SDIO initialized!\r\n"); + /* USER CODE END SDIO_Init 2 */ + +} + +/** + * @brief USART1 Initialization Function + * @param None + * @retval None + */ +static void MX_USART1_UART_Init(void) +{ + + /* USER CODE BEGIN USART1_Init 0 */ + + /* USER CODE END USART1_Init 0 */ + + /* USER CODE BEGIN USART1_Init 1 */ + + /* USER CODE END USART1_Init 1 */ + huart1.Instance = USART1; + huart1.Init.BaudRate = 1152000; + huart1.Init.WordLength = UART_WORDLENGTH_8B; + huart1.Init.StopBits = UART_STOPBITS_1; + huart1.Init.Parity = UART_PARITY_NONE; + huart1.Init.Mode = UART_MODE_TX_RX; + huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; + huart1.Init.OverSampling = UART_OVERSAMPLING_16; + if (HAL_UART_Init(&huart1) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN USART1_Init 2 */ + DEBUG_PRINT("USART1 initialized!\r\n"); + /* USER CODE END USART1_Init 2 */ + +} + +/** + * Enable DMA controller clock + */ +static void MX_DMA_Init(void) +{ + + /* DMA controller clock enable */ + __HAL_RCC_DMA2_CLK_ENABLE(); + + /* DMA interrupt init */ + /* DMA2_Stream3_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn); + /* DMA2_Stream6_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn); + + /* USER CODE BEGIN MX_DMA_Init 1 */ + DEBUG_PRINT("DMA initialized!\r\n"); + /* USER CODE END MX_DMA_Init 1 */ +} + +/** + * @brief GPIO Initialization Function + * @param None + * @retval None + */ +static void MX_GPIO_Init(void) +{ + GPIO_InitTypeDef GPIO_InitStruct = {0}; + /* USER CODE BEGIN MX_GPIO_Init_1 */ + + /* USER CODE END MX_GPIO_Init_1 */ + + /* GPIO Ports Clock Enable */ + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOH_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + + /*Configure GPIO pin Output Level */ + 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 + PC5 PC6 PC7 */ + GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|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_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + /*Configure GPIO pins : PH0 PH1 */ + GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOH, &GPIO_InitStruct); + + /*Configure GPIO pins : PA1 PA2 PA3 PA4 + PA5 PA6 PA7 PA8 + PA11 PA12 */ + GPIO_InitStruct.Pin = 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_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 */ + 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_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /*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 */ +} + +/* USER CODE BEGIN 4 */ +/* USER CODE END 4 */ + +/** + * @brief Period elapsed callback in non blocking mode + * @note This function is called when TIM6 interrupt took place, inside + * HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment + * a global variable "uwTick" used as application time base. + * @param htim : TIM handle + * @retval None + */ +void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) +{ + /* USER CODE BEGIN Callback 0 */ + + /* USER CODE END Callback 0 */ + if (htim->Instance == TIM6) + { + HAL_IncTick(); + } + /* USER CODE BEGIN Callback 1 */ + + /* USER CODE END Callback 1 */ +} + +/** + * @brief This function is executed in case of error occurrence. + * @retval None + */ +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(); + + //TODO: check if it is necessary to stop FreeRTOS + + uint32_t error_code_can1; + uint32_t error_code_can2; + + if (HAL_CAN_GetState(&hcan1) != HAL_CAN_STATE_READY) error_code_can1 = HAL_CAN_GetError(&hcan1); + if (HAL_CAN_GetState(&hcan2) != HAL_CAN_STATE_READY) error_code_can2 = HAL_CAN_GetError(&hcan2); + + // TODO: write error to SD and/or serial + + HAL_GPIO_WritePin(led_can1.port, led_can1.pin, GPIO_PIN_RESET); + HAL_GPIO_WritePin(led_can2.port, led_can2.pin, GPIO_PIN_RESET); + + while (1) + { + HAL_GPIO_TogglePin(led_error.port, led_error.pin); + HAL_Delay(250); + } + /* USER CODE END Error_Handler_Debug */ +} +#ifdef USE_FULL_ASSERT +/** + * @brief Reports the name of the source file and the source line number + * where the assert_param error has occurred. + * @param file: pointer to the source file name + * @param line: assert_param error line source number + * @retval None + */ +void assert_failed(uint8_t *file, uint32_t line) +{ + /* USER CODE BEGIN 6 */ + /* User can add his own implementation to report the file name and line number, + ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ + /* USER CODE END 6 */ +} +#endif /* USE_FULL_ASSERT */ diff --git a/can_logger.ioc b/can_logger.ioc index 29ccd68..6a0354e 100644 --- a/can_logger.ioc +++ b/can_logger.ioc @@ -68,24 +68,30 @@ Mcu.IP8=USART1 Mcu.IPNb=9 Mcu.Name=STM32F405RGTx Mcu.Package=LQFP64 -Mcu.Pin0=PB12 -Mcu.Pin1=PB13 -Mcu.Pin10=PB3 -Mcu.Pin11=PB4 -Mcu.Pin12=PB5 -Mcu.Pin13=PB8 -Mcu.Pin14=PB9 -Mcu.Pin15=VP_FREERTOS_VS_CMSIS_V2 -Mcu.Pin16=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.Pin0=PA0-WKUP +Mcu.Pin1=PB12 +Mcu.Pin10=PC10 +Mcu.Pin11=PC11 +Mcu.Pin12=PC12 +Mcu.Pin13=PD2 +Mcu.Pin14=PB3 +Mcu.Pin15=PB4 +Mcu.Pin16=PB5 +Mcu.Pin17=PB6 +Mcu.Pin18=PB7 +Mcu.Pin19=PB8 +Mcu.Pin2=PB13 +Mcu.Pin20=PB9 +Mcu.Pin21=VP_FREERTOS_VS_CMSIS_V2 +Mcu.Pin22=VP_SYS_VS_tim6 +Mcu.Pin3=PC8 +Mcu.Pin4=PC9 +Mcu.Pin5=PA9 +Mcu.Pin6=PA10 +Mcu.Pin7=PA13 +Mcu.Pin8=PA14 +Mcu.Pin9=PA15 +Mcu.PinsNb=23 Mcu.ThirdPartyNb=0 Mcu.UserConstants= Mcu.UserName=STM32F405RGTx @@ -111,20 +117,32 @@ NVIC.TIM6_DAC_IRQn=true\:15\:0\:false\:false\:true\:false\:false\:true\:true NVIC.TimeBase=TIM6_DAC_IRQn NVIC.TimeBaseIP=TIM6 NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false +PA0-WKUP.Mode=SYS_WakeUp0 +PA0-WKUP.Signal=SYS_WKUP PA10.Mode=Asynchronous PA10.Signal=USART1_RX +PA13.Mode=JTAG_5_pins +PA13.Signal=SYS_JTMS-SWDIO +PA14.Mode=JTAG_5_pins +PA14.Signal=SYS_JTCK-SWCLK +PA15.Mode=JTAG_5_pins +PA15.Signal=SYS_JTDI 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 +PB3.Mode=JTAG_5_pins +PB3.Signal=SYS_JTDO-SWO +PB4.Mode=JTAG_5_pins +PB4.Signal=SYS_JTRST 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 -- 2.52.0 From 5e28758a5eb630790c6d2b580e8d542cd3d93abe Mon Sep 17 00:00:00 2001 From: Erick Ahmed Date: Wed, 17 Jun 2026 19:27:55 +0200 Subject: [PATCH 09/13] Use serial mode instad of JTAG --- Core/Inc/main.h | 1 - Core/Src/main.c | 1126 ++++++++++++++++++++++++----------------------- can_logger.ioc | 56 +-- 3 files changed, 586 insertions(+), 597 deletions(-) diff --git a/Core/Inc/main.h b/Core/Inc/main.h index efa4647..6f36df3 100644 --- a/Core/Inc/main.h +++ b/Core/Inc/main.h @@ -27,7 +27,6 @@ extern "C" { /* Includes ------------------------------------------------------------------*/ #include "stm32f4xx_hal.h" - /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include diff --git a/Core/Src/main.c b/Core/Src/main.c index bbac8fd..c1ce2fe 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -1,562 +1,564 @@ -/* USER CODE BEGIN Header */ -/** - ****************************************************************************** - * @file : main.c - * @brief : Main program body - ****************************************************************************** - * @attention - * Copyright (c) 2026 STMicroelectronics. - * Copyright (c) 2026 Erick Ahmed. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - ****************************************************************************** - */ -/* USER CODE END Header */ -/* Includes ------------------------------------------------------------------*/ -#include "main.h" -#include "cmsis_os.h" - -/* Private includes ----------------------------------------------------------*/ -/* USER CODE BEGIN Includes */ -#include "canlog.h" -#include "cansend.h" -/* USER CODE END Includes */ - -/* Private typedef -----------------------------------------------------------*/ -/* USER CODE BEGIN PTD */ -/* USER CODE END PTD */ - -/* Private define ------------------------------------------------------------*/ -/* USER CODE BEGIN PD */ - -/* USER CODE END PD */ - -/* Private macro -------------------------------------------------------------*/ -/* USER CODE BEGIN PM */ - -/* USER CODE END PM */ - -/* Private variables ---------------------------------------------------------*/ -CAN_HandleTypeDef hcan1; -CAN_HandleTypeDef hcan2; - -SD_HandleTypeDef hsd; -DMA_HandleTypeDef hdma_sdio_rx; -DMA_HandleTypeDef hdma_sdio_tx; - -UART_HandleTypeDef huart1; - -/* 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}; - -osThreadId_t xCAN1rxTask; -osThreadId_t xCAN2rxTask; -osThreadId_t xCAN1LedTask; -osThreadId_t xCAN2LedTask; - -osMessageQueueId_t xCAN1RxQueue; -osMessageQueueId_t xCAN2RxQueue; -osMessageQueueId_t xUARTQueue; - -osSemaphoreId_t xUARTDMASemaphore; -osThreadId_t xUartTask; - -/* USER CODE END PV */ - -/* Private function prototypes -----------------------------------------------*/ -void SystemClock_Config(void); -static void MX_GPIO_Init(void); -static void MX_DMA_Init(void); -static void MX_CAN1_Init(void); -static void MX_CAN2_Init(void); -static void MX_SDIO_SD_Init(void); -static void MX_USART1_UART_Init(void); - -/* USER CODE BEGIN PFP */ -/* USER CODE END PFP */ - -/* Private user code ---------------------------------------------------------*/ -/* USER CODE BEGIN 0 */ - -/* USER CODE END 0 */ - -/** - * @brief The application entry point. - * @retval int - */ -int main(void) -{ - - /* USER CODE BEGIN 1 */ - 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--------------------------------------------------------*/ - - /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ - HAL_Init(); - - /* USER CODE BEGIN Init */ - DEBUG_PRINT("Configuring system clock\r\n"); - - /* USER CODE END Init */ - - /* Configure the system clock */ - SystemClock_Config(); - - /* USER CODE BEGIN SysInit */ - DEBUG_PRINT("Initializing configured peripherals...\r\n"); - /* USER CODE END SysInit */ - - /* Initialize all configured peripherals */ - MX_GPIO_Init(); - MX_DMA_Init(); - MX_CAN1_Init(); - MX_CAN2_Init(); - 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", - .stack_size = 128 * 4, - .priority = (osPriority_t) osPriorityRealtime1, - }; - const osThreadAttr_t CAN2rxAttributes = { - .name = "CAN2rx", - .stack_size = 128 * 4, - .priority = (osPriority_t) osPriorityRealtime, - }; - const osThreadAttr_t UartLoggerAttributes = { - .name = "UART_Logger", - .stack_size = 256 * 4, - .priority = (osPriority_t) osPriorityHigh, - }; - const osThreadAttr_t LEDHeartbeatCAN1Attributes = { - .name = "LED_HB_CAN1", - .stack_size = 128 * 4, - .priority = (osPriority_t) osPriorityLow1, - }; - const osThreadAttr_t LEDHeartbeatCAN2Attributes = { - .name = "LED_HB_CAN2", - .stack_size = 128 * 4, - .priority = (osPriority_t) osPriorityLow, - }; - /* USER CODE END RTOS_TASKS */ - - /* USER CODE BEGIN RTOS_MUTEX */ - /* USER CODE END RTOS_MUTEX */ - - /* USER CODE BEGIN RTOS_SEMAPHORES */ - xUARTDMASemaphore = osSemaphoreNew(1, 0, NULL); - if (xUARTDMASemaphore == NULL) Error_Handler(); - /* USER CODE END RTOS_SEMAPHORES */ - - /* USER CODE BEGIN RTOS_TIMERS */ - /* USER CODE END RTOS_TIMERS */ - - /* USER CODE BEGIN RTOS_QUEUES */ - xCAN1RxQueue = osMessageQueueNew(64, sizeof(CanMessage_t), NULL); - xCAN2RxQueue = osMessageQueueNew(64, sizeof(CanMessage_t), NULL); - xUARTQueue = osMessageQueueNew(128, sizeof(CanMessage_t), NULL); - - if (xCAN1RxQueue == NULL || xCAN2RxQueue == NULL || xUARTQueue == NULL) Error_Handler(); - /* USER CODE END RTOS_QUEUES */ - - /* USER CODE BEGIN RTOS_THREADS */ - xCAN1rxTask = osThreadNew(vCANListener, &hcan1, &CAN1rxAttributes); - xCAN2rxTask = osThreadNew(vCANListener, &hcan2, &CAN2rxAttributes); - xUartTask = osThreadNew(vUARTLogger, NULL, &UartLoggerAttributes); - xCAN1LedTask = osThreadNew(vLEDHeartbeat, &led_can1, &LEDHeartbeatCAN1Attributes); - xCAN2LedTask = osThreadNew(vLEDHeartbeat, &led_can2, &LEDHeartbeatCAN2Attributes); - /* USER CODE END RTOS_THREADS */ - - /* USER CODE BEGIN RTOS_EVENTS */ - /* 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 */ - - /* Infinite loop */ - /* USER CODE BEGIN WHILE */ - while (1) - { - /* USER CODE END WHILE */ - - /* USER CODE BEGIN 3 */ - DEBUG_PRINT("ERROR: RTOS scheduler crashed!\r\n"); - /* USER CODE END 3 */ - } -} - -/** - * @brief System Clock Configuration - * @retval None - */ -void SystemClock_Config(void) -{ - RCC_OscInitTypeDef RCC_OscInitStruct = {0}; - RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; - - /** Configure the main internal regulator output voltage - */ - __HAL_RCC_PWR_CLK_ENABLE(); - __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); - - /** Initializes the RCC Oscillators according to the specified parameters - * in the RCC_OscInitTypeDef structure. - */ - RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; - RCC_OscInitStruct.HSIState = RCC_HSI_ON; - RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; - RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; - RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; - RCC_OscInitStruct.PLL.PLLM = 16; - RCC_OscInitStruct.PLL.PLLN = 336; - RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; - RCC_OscInitStruct.PLL.PLLQ = 7; - if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) - { - Error_Handler(); - } - - /** Initializes the CPU, AHB and APB buses clocks - */ - RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK - |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; - RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; - RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; - RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; - RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV4; - - if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) - { - Error_Handler(); - } -} - -/** - * @brief CAN1 Initialization Function - * @param None - * @retval None - */ -static void MX_CAN1_Init(void) -{ - - /* USER CODE BEGIN CAN1_Init 0 */ - - /* USER CODE END CAN1_Init 0 */ - - /* USER CODE BEGIN CAN1_Init 1 */ - - /* USER CODE END CAN1_Init 1 */ - hcan1.Instance = CAN1; - hcan1.Init.Prescaler = 4; - hcan1.Init.Mode = CAN_MODE_SILENT; - hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ; - hcan1.Init.TimeSeg1 = CAN_BS1_16TQ; - hcan1.Init.TimeSeg2 = CAN_BS2_4TQ; - hcan1.Init.TimeTriggeredMode = DISABLE; - hcan1.Init.AutoBusOff = DISABLE; - hcan1.Init.AutoWakeUp = ENABLE; - hcan1.Init.AutoRetransmission = DISABLE; - hcan1.Init.ReceiveFifoLocked = DISABLE; - hcan1.Init.TransmitFifoPriority = DISABLE; - if (HAL_CAN_Init(&hcan1) != HAL_OK) - { - Error_Handler(); - } - /* USER CODE BEGIN CAN1_Init 2 */ - DEBUG_PRINT("CAN1 initialized!\r\n"); - /* USER CODE END CAN1_Init 2 */ - -} - -/** - * @brief CAN2 Initialization Function - * @param None - * @retval None - */ -static void MX_CAN2_Init(void) -{ - - /* USER CODE BEGIN CAN2_Init 0 */ - - /* USER CODE END CAN2_Init 0 */ - - /* USER CODE BEGIN CAN2_Init 1 */ - - /* USER CODE END CAN2_Init 1 */ - hcan2.Instance = CAN2; - hcan2.Init.Prescaler = 8; - hcan2.Init.Mode = CAN_MODE_SILENT; - hcan2.Init.SyncJumpWidth = CAN_SJW_1TQ; - hcan2.Init.TimeSeg1 = CAN_BS1_16TQ; - hcan2.Init.TimeSeg2 = CAN_BS2_4TQ; - hcan2.Init.TimeTriggeredMode = DISABLE; - hcan2.Init.AutoBusOff = DISABLE; - hcan2.Init.AutoWakeUp = ENABLE; - hcan2.Init.AutoRetransmission = DISABLE; - hcan2.Init.ReceiveFifoLocked = DISABLE; - hcan2.Init.TransmitFifoPriority = DISABLE; - if (HAL_CAN_Init(&hcan2) != HAL_OK) - { - Error_Handler(); - } - /* USER CODE BEGIN CAN2_Init 2 */ - DEBUG_PRINT("CAN2 initialized!\r\n"); - /* USER CODE END CAN2_Init 2 */ - -} - -/** - * @brief SDIO Initialization Function - * @param None - * @retval None - */ -static void MX_SDIO_SD_Init(void) -{ - - /* USER CODE BEGIN SDIO_Init 0 */ - - /* USER CODE END SDIO_Init 0 */ - - /* USER CODE BEGIN SDIO_Init 1 */ - - /* USER CODE END SDIO_Init 1 */ - hsd.Instance = SDIO; - hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING; - hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE; - hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE; - 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(); - } - /* USER CODE BEGIN SDIO_Init 2 */ - DEBUG_PRINT("SDIO initialized!\r\n"); - /* USER CODE END SDIO_Init 2 */ - -} - -/** - * @brief USART1 Initialization Function - * @param None - * @retval None - */ -static void MX_USART1_UART_Init(void) -{ - - /* USER CODE BEGIN USART1_Init 0 */ - - /* USER CODE END USART1_Init 0 */ - - /* USER CODE BEGIN USART1_Init 1 */ - - /* USER CODE END USART1_Init 1 */ - huart1.Instance = USART1; - huart1.Init.BaudRate = 1152000; - huart1.Init.WordLength = UART_WORDLENGTH_8B; - huart1.Init.StopBits = UART_STOPBITS_1; - huart1.Init.Parity = UART_PARITY_NONE; - huart1.Init.Mode = UART_MODE_TX_RX; - huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; - huart1.Init.OverSampling = UART_OVERSAMPLING_16; - if (HAL_UART_Init(&huart1) != HAL_OK) - { - Error_Handler(); - } - /* USER CODE BEGIN USART1_Init 2 */ - DEBUG_PRINT("USART1 initialized!\r\n"); - /* USER CODE END USART1_Init 2 */ - -} - -/** - * Enable DMA controller clock - */ -static void MX_DMA_Init(void) -{ - - /* DMA controller clock enable */ - __HAL_RCC_DMA2_CLK_ENABLE(); - - /* DMA interrupt init */ - /* DMA2_Stream3_IRQn interrupt configuration */ - HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 5, 0); - HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn); - /* DMA2_Stream6_IRQn interrupt configuration */ - HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 5, 0); - HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn); - - /* USER CODE BEGIN MX_DMA_Init 1 */ - DEBUG_PRINT("DMA initialized!\r\n"); - /* USER CODE END MX_DMA_Init 1 */ -} - -/** - * @brief GPIO Initialization Function - * @param None - * @retval None - */ -static void MX_GPIO_Init(void) -{ - GPIO_InitTypeDef GPIO_InitStruct = {0}; - /* USER CODE BEGIN MX_GPIO_Init_1 */ - - /* USER CODE END MX_GPIO_Init_1 */ - - /* GPIO Ports Clock Enable */ - __HAL_RCC_GPIOC_CLK_ENABLE(); - __HAL_RCC_GPIOH_CLK_ENABLE(); - __HAL_RCC_GPIOA_CLK_ENABLE(); - __HAL_RCC_GPIOB_CLK_ENABLE(); - __HAL_RCC_GPIOD_CLK_ENABLE(); - - /*Configure GPIO pin Output Level */ - 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 - PC5 PC6 PC7 */ - GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|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_InitStruct.Mode = GPIO_MODE_ANALOG; - GPIO_InitStruct.Pull = GPIO_NOPULL; - HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); - - /*Configure GPIO pins : PH0 PH1 */ - GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1; - GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; - GPIO_InitStruct.Pull = GPIO_NOPULL; - HAL_GPIO_Init(GPIOH, &GPIO_InitStruct); - - /*Configure GPIO pins : PA1 PA2 PA3 PA4 - PA5 PA6 PA7 PA8 - PA11 PA12 */ - GPIO_InitStruct.Pin = 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_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 */ - 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_InitStruct.Mode = GPIO_MODE_ANALOG; - GPIO_InitStruct.Pull = GPIO_NOPULL; - HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); - - /*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 */ -} - -/* USER CODE BEGIN 4 */ -/* USER CODE END 4 */ - -/** - * @brief Period elapsed callback in non blocking mode - * @note This function is called when TIM6 interrupt took place, inside - * HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment - * a global variable "uwTick" used as application time base. - * @param htim : TIM handle - * @retval None - */ -void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) -{ - /* USER CODE BEGIN Callback 0 */ - - /* USER CODE END Callback 0 */ - if (htim->Instance == TIM6) - { - HAL_IncTick(); - } - /* USER CODE BEGIN Callback 1 */ - - /* USER CODE END Callback 1 */ -} - -/** - * @brief This function is executed in case of error occurrence. - * @retval None - */ -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(); - - //TODO: check if it is necessary to stop FreeRTOS - - uint32_t error_code_can1; - uint32_t error_code_can2; - - if (HAL_CAN_GetState(&hcan1) != HAL_CAN_STATE_READY) error_code_can1 = HAL_CAN_GetError(&hcan1); - if (HAL_CAN_GetState(&hcan2) != HAL_CAN_STATE_READY) error_code_can2 = HAL_CAN_GetError(&hcan2); - - // TODO: write error to SD and/or serial - - HAL_GPIO_WritePin(led_can1.port, led_can1.pin, GPIO_PIN_RESET); - HAL_GPIO_WritePin(led_can2.port, led_can2.pin, GPIO_PIN_RESET); - - while (1) - { - HAL_GPIO_TogglePin(led_error.port, led_error.pin); - HAL_Delay(250); - } - /* USER CODE END Error_Handler_Debug */ -} -#ifdef USE_FULL_ASSERT -/** - * @brief Reports the name of the source file and the source line number - * where the assert_param error has occurred. - * @param file: pointer to the source file name - * @param line: assert_param error line source number - * @retval None - */ -void assert_failed(uint8_t *file, uint32_t line) -{ - /* USER CODE BEGIN 6 */ - /* User can add his own implementation to report the file name and line number, - ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ - /* USER CODE END 6 */ -} -#endif /* USE_FULL_ASSERT */ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file : main.c + * @brief : Main program body + ****************************************************************************** + * @attention + * Copyright (c) 2026 STMicroelectronics. + * Copyright (c) 2026 Erick Ahmed. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + ****************************************************************************** + */ +/* USER CODE END Header */ +/* Includes ------------------------------------------------------------------*/ +#include "main.h" +#include "cmsis_os.h" + +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ +#include "canlog.h" +#include "cansend.h" +/* USER CODE END Includes */ + +/* Private typedef -----------------------------------------------------------*/ +/* USER CODE BEGIN PTD */ +/* USER CODE END PTD */ + +/* Private define ------------------------------------------------------------*/ +/* USER CODE BEGIN PD */ + +/* USER CODE END PD */ + +/* Private macro -------------------------------------------------------------*/ +/* USER CODE BEGIN PM */ + +/* USER CODE END PM */ + +/* Private variables ---------------------------------------------------------*/ +CAN_HandleTypeDef hcan1; +CAN_HandleTypeDef hcan2; + +SD_HandleTypeDef hsd; +DMA_HandleTypeDef hdma_sdio_rx; +DMA_HandleTypeDef hdma_sdio_tx; + +UART_HandleTypeDef huart1; + +/* 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}; + +osThreadId_t xCAN1rxTask; +osThreadId_t xCAN2rxTask; +osThreadId_t xCAN1LedTask; +osThreadId_t xCAN2LedTask; + +osMessageQueueId_t xCAN1RxQueue; +osMessageQueueId_t xCAN2RxQueue; +osMessageQueueId_t xUARTQueue; + +osSemaphoreId_t xUARTDMASemaphore; +osThreadId_t xUartTask; + +/* USER CODE END PV */ + +/* Private function prototypes -----------------------------------------------*/ +void SystemClock_Config(void); +static void MX_GPIO_Init(void); +static void MX_DMA_Init(void); +static void MX_CAN1_Init(void); +static void MX_CAN2_Init(void); +static void MX_SDIO_SD_Init(void); +static void MX_USART1_UART_Init(void); + +/* USER CODE BEGIN PFP */ +/* USER CODE END PFP */ + +/* Private user code ---------------------------------------------------------*/ +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +/** + * @brief The application entry point. + * @retval int + */ +int main(void) +{ + + /* USER CODE BEGIN 1 */ + 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--------------------------------------------------------*/ + + /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ + HAL_Init(); + + /* USER CODE BEGIN Init */ + DEBUG_PRINT("Configuring system clock\r\n"); + + /* USER CODE END Init */ + + /* Configure the system clock */ + SystemClock_Config(); + + /* USER CODE BEGIN SysInit */ + DEBUG_PRINT("Initializing configured peripherals...\r\n"); + /* USER CODE END SysInit */ + + /* Initialize all configured peripherals */ + MX_GPIO_Init(); + MX_DMA_Init(); + MX_CAN1_Init(); + MX_CAN2_Init(); + 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", + .stack_size = 128 * 4, + .priority = (osPriority_t) osPriorityRealtime1, + }; + const osThreadAttr_t CAN2rxAttributes = { + .name = "CAN2rx", + .stack_size = 128 * 4, + .priority = (osPriority_t) osPriorityRealtime, + }; + const osThreadAttr_t UartLoggerAttributes = { + .name = "UART_Logger", + .stack_size = 256 * 4, + .priority = (osPriority_t) osPriorityHigh, + }; + const osThreadAttr_t LEDHeartbeatCAN1Attributes = { + .name = "LED_HB_CAN1", + .stack_size = 128 * 4, + .priority = (osPriority_t) osPriorityLow1, + }; + const osThreadAttr_t LEDHeartbeatCAN2Attributes = { + .name = "LED_HB_CAN2", + .stack_size = 128 * 4, + .priority = (osPriority_t) osPriorityLow, + }; + /* USER CODE END RTOS_TASKS */ + + /* USER CODE BEGIN RTOS_MUTEX */ + /* USER CODE END RTOS_MUTEX */ + + /* USER CODE BEGIN RTOS_SEMAPHORES */ + xUARTDMASemaphore = osSemaphoreNew(1, 0, NULL); + if (xUARTDMASemaphore == NULL) Error_Handler(); + /* USER CODE END RTOS_SEMAPHORES */ + + /* USER CODE BEGIN RTOS_TIMERS */ + /* USER CODE END RTOS_TIMERS */ + + /* USER CODE BEGIN RTOS_QUEUES */ + xCAN1RxQueue = osMessageQueueNew(64, sizeof(CanMessage_t), NULL); + xCAN2RxQueue = osMessageQueueNew(64, sizeof(CanMessage_t), NULL); + xUARTQueue = osMessageQueueNew(128, sizeof(CanMessage_t), NULL); + + if (xCAN1RxQueue == NULL || xCAN2RxQueue == NULL || xUARTQueue == NULL) Error_Handler(); + /* USER CODE END RTOS_QUEUES */ + + /* USER CODE BEGIN RTOS_THREADS */ + xCAN1rxTask = osThreadNew(vCANListener, &hcan1, &CAN1rxAttributes); + xCAN2rxTask = osThreadNew(vCANListener, &hcan2, &CAN2rxAttributes); + xUartTask = osThreadNew(vUARTLogger, NULL, &UartLoggerAttributes); + xCAN1LedTask = osThreadNew(vLEDHeartbeat, &led_can1, &LEDHeartbeatCAN1Attributes); + xCAN2LedTask = osThreadNew(vLEDHeartbeat, &led_can2, &LEDHeartbeatCAN2Attributes); + /* USER CODE END RTOS_THREADS */ + + /* USER CODE BEGIN RTOS_EVENTS */ + /* 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 */ + + /* Infinite loop */ + /* USER CODE BEGIN WHILE */ + while (1) + { + /* USER CODE END WHILE */ + + /* USER CODE BEGIN 3 */ + DEBUG_PRINT("ERROR: RTOS scheduler crashed!\r\n"); + /* USER CODE END 3 */ + } +} + +/** + * @brief System Clock Configuration + * @retval None + */ +void SystemClock_Config(void) +{ + RCC_OscInitTypeDef RCC_OscInitStruct = {0}; + RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; + + /** Configure the main internal regulator output voltage + */ + __HAL_RCC_PWR_CLK_ENABLE(); + __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); + + /** Initializes the RCC Oscillators according to the specified parameters + * in the RCC_OscInitTypeDef structure. + */ + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; + RCC_OscInitStruct.HSIState = RCC_HSI_ON; + RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; + RCC_OscInitStruct.PLL.PLLM = 16; + RCC_OscInitStruct.PLL.PLLN = 336; + RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; + RCC_OscInitStruct.PLL.PLLQ = 7; + if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) + { + Error_Handler(); + } + + /** Initializes the CPU, AHB and APB buses clocks + */ + RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK + |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV4; + + if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) + { + Error_Handler(); + } +} + +/** + * @brief CAN1 Initialization Function + * @param None + * @retval None + */ +static void MX_CAN1_Init(void) +{ + + /* USER CODE BEGIN CAN1_Init 0 */ + + /* USER CODE END CAN1_Init 0 */ + + /* USER CODE BEGIN CAN1_Init 1 */ + + /* USER CODE END CAN1_Init 1 */ + hcan1.Instance = CAN1; + hcan1.Init.Prescaler = 4; + hcan1.Init.Mode = CAN_MODE_SILENT; + hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ; + hcan1.Init.TimeSeg1 = CAN_BS1_16TQ; + hcan1.Init.TimeSeg2 = CAN_BS2_4TQ; + hcan1.Init.TimeTriggeredMode = DISABLE; + hcan1.Init.AutoBusOff = DISABLE; + hcan1.Init.AutoWakeUp = ENABLE; + hcan1.Init.AutoRetransmission = DISABLE; + hcan1.Init.ReceiveFifoLocked = DISABLE; + hcan1.Init.TransmitFifoPriority = DISABLE; + if (HAL_CAN_Init(&hcan1) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN CAN1_Init 2 */ + DEBUG_PRINT("CAN1 initialized!\r\n"); + /* USER CODE END CAN1_Init 2 */ + +} + +/** + * @brief CAN2 Initialization Function + * @param None + * @retval None + */ +static void MX_CAN2_Init(void) +{ + + /* USER CODE BEGIN CAN2_Init 0 */ + + /* USER CODE END CAN2_Init 0 */ + + /* USER CODE BEGIN CAN2_Init 1 */ + + /* USER CODE END CAN2_Init 1 */ + hcan2.Instance = CAN2; + hcan2.Init.Prescaler = 8; + hcan2.Init.Mode = CAN_MODE_SILENT; + hcan2.Init.SyncJumpWidth = CAN_SJW_1TQ; + hcan2.Init.TimeSeg1 = CAN_BS1_16TQ; + hcan2.Init.TimeSeg2 = CAN_BS2_4TQ; + hcan2.Init.TimeTriggeredMode = DISABLE; + hcan2.Init.AutoBusOff = DISABLE; + hcan2.Init.AutoWakeUp = ENABLE; + hcan2.Init.AutoRetransmission = DISABLE; + hcan2.Init.ReceiveFifoLocked = DISABLE; + hcan2.Init.TransmitFifoPriority = DISABLE; + if (HAL_CAN_Init(&hcan2) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN CAN2_Init 2 */ + DEBUG_PRINT("CAN2 initialized!\r\n"); + /* USER CODE END CAN2_Init 2 */ + +} + +/** + * @brief SDIO Initialization Function + * @param None + * @retval None + */ +static void MX_SDIO_SD_Init(void) +{ + + /* USER CODE BEGIN SDIO_Init 0 */ + + /* USER CODE END SDIO_Init 0 */ + + /* USER CODE BEGIN SDIO_Init 1 */ + + /* USER CODE END SDIO_Init 1 */ + hsd.Instance = SDIO; + hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING; + hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE; + hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE; + 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(); + } + /* USER CODE BEGIN SDIO_Init 2 */ + DEBUG_PRINT("SDIO initialized!\r\n"); + /* USER CODE END SDIO_Init 2 */ + +} + +/** + * @brief USART1 Initialization Function + * @param None + * @retval None + */ +static void MX_USART1_UART_Init(void) +{ + + /* USER CODE BEGIN USART1_Init 0 */ + + /* USER CODE END USART1_Init 0 */ + + /* USER CODE BEGIN USART1_Init 1 */ + + /* USER CODE END USART1_Init 1 */ + huart1.Instance = USART1; + huart1.Init.BaudRate = 1152000; + huart1.Init.WordLength = UART_WORDLENGTH_8B; + huart1.Init.StopBits = UART_STOPBITS_1; + huart1.Init.Parity = UART_PARITY_NONE; + huart1.Init.Mode = UART_MODE_TX_RX; + huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; + huart1.Init.OverSampling = UART_OVERSAMPLING_16; + if (HAL_UART_Init(&huart1) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN USART1_Init 2 */ + DEBUG_PRINT("USART1 initialized!\r\n"); + /* USER CODE END USART1_Init 2 */ + +} + +/** + * Enable DMA controller clock + */ +static void MX_DMA_Init(void) +{ + + /* DMA controller clock enable */ + __HAL_RCC_DMA2_CLK_ENABLE(); + + /* DMA interrupt init */ + /* DMA2_Stream3_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn); + /* DMA2_Stream6_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn); + + /* USER CODE BEGIN MX_DMA_Init 1 */ + DEBUG_PRINT("DMA initialized!\r\n"); + /* USER CODE END MX_DMA_Init 1 */ +} + +/** + * @brief GPIO Initialization Function + * @param None + * @retval None + */ +static void MX_GPIO_Init(void) +{ + GPIO_InitTypeDef GPIO_InitStruct = {0}; + /* USER CODE BEGIN MX_GPIO_Init_1 */ + + /* USER CODE END MX_GPIO_Init_1 */ + + /* GPIO Ports Clock Enable */ + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOH_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + + /*Configure GPIO pin Output Level */ + 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 + PC5 PC6 PC7 */ + GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|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_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + /*Configure GPIO pins : PH0 PH1 */ + GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOH, &GPIO_InitStruct); + + /*Configure GPIO pins : PA0 PA1 PA2 PA3 + PA4 PA5 PA6 PA7 + 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_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 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_3 + |GPIO_PIN_4; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /*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 */ +} + +/* USER CODE BEGIN 4 */ +/* USER CODE END 4 */ + +/** + * @brief Period elapsed callback in non blocking mode + * @note This function is called when TIM6 interrupt took place, inside + * HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment + * a global variable "uwTick" used as application time base. + * @param htim : TIM handle + * @retval None + */ +void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) +{ + /* USER CODE BEGIN Callback 0 */ + + /* USER CODE END Callback 0 */ + if (htim->Instance == TIM6) + { + HAL_IncTick(); + } + /* USER CODE BEGIN Callback 1 */ + + /* USER CODE END Callback 1 */ +} + +/** + * @brief This function is executed in case of error occurrence. + * @retval None + */ +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(); + + //TODO: check if it is necessary to stop FreeRTOS + + uint32_t error_code_can1; + uint32_t error_code_can2; + + if (HAL_CAN_GetState(&hcan1) != HAL_CAN_STATE_READY) error_code_can1 = HAL_CAN_GetError(&hcan1); + if (HAL_CAN_GetState(&hcan2) != HAL_CAN_STATE_READY) error_code_can2 = HAL_CAN_GetError(&hcan2); + + // TODO: write error to SD and/or serial + + HAL_GPIO_WritePin(led_can1.port, led_can1.pin, GPIO_PIN_RESET); + HAL_GPIO_WritePin(led_can2.port, led_can2.pin, GPIO_PIN_RESET); + + while (1) + { + HAL_GPIO_TogglePin(led_error.port, led_error.pin); + HAL_Delay(250); + } + /* USER CODE END Error_Handler_Debug */ +} +#ifdef USE_FULL_ASSERT +/** + * @brief Reports the name of the source file and the source line number + * where the assert_param error has occurred. + * @param file: pointer to the source file name + * @param line: assert_param error line source number + * @retval None + */ +void assert_failed(uint8_t *file, uint32_t line) +{ + /* USER CODE BEGIN 6 */ + /* User can add his own implementation to report the file name and line number, + ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ + /* USER CODE END 6 */ +} +#endif /* USE_FULL_ASSERT */ diff --git a/can_logger.ioc b/can_logger.ioc index 6a0354e..d6945da 100644 --- a/can_logger.ioc +++ b/can_logger.ioc @@ -68,30 +68,26 @@ Mcu.IP8=USART1 Mcu.IPNb=9 Mcu.Name=STM32F405RGTx Mcu.Package=LQFP64 -Mcu.Pin0=PA0-WKUP -Mcu.Pin1=PB12 -Mcu.Pin10=PC10 -Mcu.Pin11=PC11 -Mcu.Pin12=PC12 -Mcu.Pin13=PD2 -Mcu.Pin14=PB3 -Mcu.Pin15=PB4 -Mcu.Pin16=PB5 -Mcu.Pin17=PB6 -Mcu.Pin18=PB7 -Mcu.Pin19=PB8 -Mcu.Pin2=PB13 -Mcu.Pin20=PB9 -Mcu.Pin21=VP_FREERTOS_VS_CMSIS_V2 -Mcu.Pin22=VP_SYS_VS_tim6 -Mcu.Pin3=PC8 -Mcu.Pin4=PC9 -Mcu.Pin5=PA9 -Mcu.Pin6=PA10 -Mcu.Pin7=PA13 -Mcu.Pin8=PA14 -Mcu.Pin9=PA15 -Mcu.PinsNb=23 +Mcu.Pin0=PB12 +Mcu.Pin1=PB13 +Mcu.Pin10=PC12 +Mcu.Pin11=PD2 +Mcu.Pin12=PB5 +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=PA13 +Mcu.Pin7=PA14 +Mcu.Pin8=PC10 +Mcu.Pin9=PC11 +Mcu.PinsNb=19 Mcu.ThirdPartyNb=0 Mcu.UserConstants= Mcu.UserName=STM32F405RGTx @@ -117,26 +113,18 @@ NVIC.TIM6_DAC_IRQn=true\:15\:0\:false\:false\:true\:false\:false\:true\:true NVIC.TimeBase=TIM6_DAC_IRQn NVIC.TimeBaseIP=TIM6 NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false -PA0-WKUP.Mode=SYS_WakeUp0 -PA0-WKUP.Signal=SYS_WKUP PA10.Mode=Asynchronous PA10.Signal=USART1_RX -PA13.Mode=JTAG_5_pins +PA13.Mode=Serial_Wire PA13.Signal=SYS_JTMS-SWDIO -PA14.Mode=JTAG_5_pins +PA14.Mode=Serial_Wire PA14.Signal=SYS_JTCK-SWCLK -PA15.Mode=JTAG_5_pins -PA15.Signal=SYS_JTDI PA9.Mode=Asynchronous PA9.Signal=USART1_TX PB12.Mode=CAN_Activate PB12.Signal=CAN2_RX PB13.Mode=CAN_Activate PB13.Signal=CAN2_TX -PB3.Mode=JTAG_5_pins -PB3.Signal=SYS_JTDO-SWO -PB4.Mode=JTAG_5_pins -PB4.Signal=SYS_JTRST PB5.Locked=true PB5.Signal=GPIO_Output PB6.Locked=true -- 2.52.0 From aeb553994c3c797b33a3256821fac33af7fefefd Mon Sep 17 00:00:00 2001 From: Erick Ahmed Date: Wed, 17 Jun 2026 20:14:56 +0200 Subject: [PATCH 10/13] Update LED struct --- Core/Src/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/Src/main.c b/Core/Src/main.c index c1ce2fe..19d2cdf 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -48,9 +48,9 @@ DMA_HandleTypeDef hdma_sdio_tx; UART_HandleTypeDef huart1; /* 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; -- 2.52.0 From 60849ebb787cc154a6c372eafb574730da83a933 Mon Sep 17 00:00:00 2001 From: Erick Ahmed Date: Wed, 17 Jun 2026 20:23:48 +0200 Subject: [PATCH 11/13] Testing: SDIO stuff deactivated until implemented - Goes into error handling --- Core/Src/main.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Core/Src/main.c b/Core/Src/main.c index 19d2cdf..0f21c98 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -350,16 +350,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"); + //DEBUG_PRINT("SDIO initialized!\r\n"); /* USER CODE END SDIO_Init 2 */ } -- 2.52.0 From 907c0b170d4888c3bfffecca2ad8d0a13d0617ab Mon Sep 17 00:00:00 2001 From: Erick Ahmed Date: Wed, 17 Jun 2026 20:33:22 +0200 Subject: [PATCH 12/13] Move to PFP block in main.c and use more standard logic --- Core/Inc/main.h | 158 +++++++++++++++++++++++------------------------- Core/Src/main.c | 6 ++ 2 files changed, 80 insertions(+), 84 deletions(-) diff --git a/Core/Inc/main.h b/Core/Inc/main.h index 6f36df3..58de877 100644 --- a/Core/Inc/main.h +++ b/Core/Inc/main.h @@ -1,84 +1,74 @@ -/* USER CODE BEGIN Header */ -/** - ****************************************************************************** - * @file : main.h - * @brief : Header for main.c file. - * This file contains the common defines of the application. - ****************************************************************************** - * @attention - * - * Copyright (c) 2026 STMicroelectronics. - * Copyright (c) 2026 Erick Ahmed. - * - * SPDX-License-Identifier: GPL-3.0-or-later - * - ****************************************************************************** - */ -/* USER CODE END Header */ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __MAIN_H -#define __MAIN_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* Includes ------------------------------------------------------------------*/ -#include "stm32f4xx_hal.h" - -/* Private includes ----------------------------------------------------------*/ -/* USER CODE BEGIN Includes */ -#include -#include "canlog.h" -/* USER CODE END Includes */ - -/* Exported types ------------------------------------------------------------*/ -/* USER CODE BEGIN ET */ - -/* USER CODE END ET */ - -/* Exported constants --------------------------------------------------------*/ -/* USER CODE BEGIN EC */ - -/* USER CODE END EC */ - -/* Exported macro ------------------------------------------------------------*/ -/* USER CODE BEGIN EM */ -#define DEBUG -#ifdef DEBUG -static inline void ITM_Print(const char *str) { - while (*str) { - uint32_t timeout = 1000; - while ((ITM->PORT[0].u32 == 0) && (timeout-- > 0)); - - if (timeout > 0) { - ITM->PORT[0].u8 = (uint8_t)(*str); - } - str++; - } -} -#define DEBUG_PRINT(x) ITM_Print(x) -#else -#define DEBUG_PRINT(x) -#endif -/* USER CODE END EM */ - -/* Exported functions prototypes ---------------------------------------------*/ -void Error_Handler(void); - -/* USER CODE BEGIN EFP */ - -/* USER CODE END EFP */ - -/* Private defines -----------------------------------------------------------*/ - -/* USER CODE BEGIN Private defines */ - -/* USER CODE END Private defines */ - -#ifdef __cplusplus -} -#endif - -#endif /* __MAIN_H */ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file : main.h + * @brief : Header for main.c file. + * This file contains the common defines of the application. + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 STMicroelectronics. + * Copyright (c) 2026 Erick Ahmed. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __MAIN_H +#define __MAIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_hal.h" + +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ +#include +#include "canlog.h" +/* USER CODE END Includes */ + +/* Exported types ------------------------------------------------------------*/ +/* USER CODE BEGIN ET */ + +/* USER CODE END ET */ + +/* Exported constants --------------------------------------------------------*/ +/* USER CODE BEGIN EC */ + +/* USER CODE END EC */ + +/* Exported macro ------------------------------------------------------------*/ +/* USER CODE BEGIN EM */ +#define DEBUG +#ifdef DEBUG +#include +#define DEBUG_PRINT(...) printf(__VA_ARGS__) +#else +#define DEBUG_PRINT(...) +#endif +/* USER CODE END EM */ + +/* Exported functions prototypes ---------------------------------------------*/ +void Error_Handler(void); + +/* USER CODE BEGIN EFP */ + +/* USER CODE END EFP */ + +/* Private defines -----------------------------------------------------------*/ + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +#ifdef __cplusplus +} +#endif + +#endif /* __MAIN_H */ diff --git a/Core/Src/main.c b/Core/Src/main.c index 0f21c98..8cce2e7 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -76,6 +76,12 @@ 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 ---------------------------------------------------------*/ -- 2.52.0 From 4afa6702fb65ba5ea4c028fd3d32c7f3470f3a9c Mon Sep 17 00:00:00 2001 From: Erick Ahmed Date: Wed, 17 Jun 2026 20:33:38 +0200 Subject: [PATCH 13/13] Return exact length --- Core/Src/cansend.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Core/Src/cansend.c b/Core/Src/cansend.c index 3831c7a..720e4f0 100644 --- a/Core/Src/cansend.c +++ b/Core/Src/cansend.c @@ -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 */ @@ -108,7 +111,7 @@ void vUARTLogger(void *argument) { DEBUG_PRINT("CAN frame detected\r\n"); format_can_message(tx_buffer, message.source, &message); - HAL_UART_Transmit_DMA(&huart1, (uint8_t*)tx_buffer, 44); + HAL_UART_Transmit_DMA(&huart1, (uint8_t*)tx_buffer, len); osSemaphoreAcquire(xUARTDMASemaphore, osWaitForever); DEBUG_PRINT("CAN frame sent via UART\r\n"); } -- 2.52.0