diff --git a/Core/Src/ThreadSafe/newlib_lock_glue.c b/Core/Src/ThreadSafe/newlib_lock_glue.c new file mode 100644 index 0000000..744d87e --- /dev/null +++ b/Core/Src/ThreadSafe/newlib_lock_glue.c @@ -0,0 +1,435 @@ +/** + ****************************************************************************** + * @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__ */ diff --git a/Core/Src/ThreadSafe/stm32_lock.h b/Core/Src/ThreadSafe/stm32_lock.h new file mode 100644 index 0000000..cdb400a --- /dev/null +++ b/Core/Src/ThreadSafe/stm32_lock.h @@ -0,0 +1,375 @@ +/** + ****************************************************************************** + * @file stm32_lock.h + * @author STMicroelectronics + * @brief STMicroelectronics lock mechanisms + * + * @details + * This implementation supports the following strategies for handling + * thread-safe locks. The strategy can be explicitly selected by + * defining \STM32_THREAD_SAFE_STRATEGY = \ in the project. + * Please look at the '_lock_glue.c' file for more details. + * + * 1. User defined thread-safe implementation. + * User defined solution for handling thread-safety. + *
+ * NOTE: The stubs in stm32_lock_user.h needs to be implemented to gain + * thread-safety. + * + * 2. [DEFAULT] Allow lock usage from interrupts. + * This implementation will ensure thread-safety by disabling all interrupts + * during e.g. calls to malloc. + *
+ * NOTE: Disabling all interrupts creates interrupt latency which + * might not be desired for this application! + * + * 3. Deny lock usage from interrupts. + * This implementation assumes single thread of execution. + *
+ * NOTE: Thread-safety dependent functions will enter an infinity loop + * if used in interrupt context. + * + * 4. Allow lock usage from interrupts. Implemented using FreeRTOS locks. + * This implementation will ensure thread-safety by entering RTOS ISR capable + * critical sections during e.g. calls to malloc. + * By default this implementation supports 2 levels of recursive locking. + * Adding additional levels requires 4 bytes per lock per level of RAM. + *
+ * NOTE: Interrupts with high priority are not disabled. This implies + * that the lock is not thread-safe from high priority interrupts! + * + * 5. Deny lock usage from interrupts. Implemented using FreeRTOS locks. + * This implementation will ensure thread-safety by suspending all tasks + * during e.g. calls to malloc. + *
+ * NOTE: Thread-safety dependent functions will enter an infinity loop + * if used in interrupt context. + * + ****************************************************************************** + * @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. + * + ****************************************************************************** + */ + +#ifndef __STM32_LOCK_H__ +#define __STM32_LOCK_H__ + +/* Includes ------------------------------------------------------------------*/ +#include +#include +#include + +#ifndef STM32_THREAD_SAFE_STRATEGY +#define STM32_THREAD_SAFE_STRATEGY 2 /**< Assume strategy 2 if not specified */ +#endif /* STM32_THREAD_SAFE_STRATEGY */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Function prototypes -------------------------------------------------------*/ +void Error_Handler(void); + +/* Public macros -------------------------------------------------------------*/ +/** Blocks execution */ +#define STM32_LOCK_BLOCK() \ + do \ + { \ + __disable_irq(); \ + Error_Handler(); \ + while (1); \ + } while (0) + +/** Blocks execution if argument is NULL */ +#define STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(x) \ + do \ + { \ + if ((x) == NULL) \ + { \ + STM32_LOCK_BLOCK(); \ + } \ + } while (0) + +/** Blocks execution if in interrupt context */ +#define STM32_LOCK_BLOCK_IF_INTERRUPT_CONTEXT() \ + do \ + { \ + if (__get_IPSR()) \ + { \ + STM32_LOCK_BLOCK(); \ + } \ + } while (0) + +/** Hide unused parameter warning from compiler */ +#define STM32_LOCK_UNUSED(var) (void)var + +/** Size of array */ +#define STM32_LOCK_ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) + +#if STM32_THREAD_SAFE_STRATEGY == 1 +/* + * User defined thread-safe implementation. + */ + +/* Includes ----------------------------------------------------------------*/ +/** STM32 lock API version */ +#define STM32_LOCK_API 1 +#include "stm32_lock_user.h" +#undef STM32_LOCK_API + +#elif STM32_THREAD_SAFE_STRATEGY == 2 +/* + * Allow lock usage from interrupts. + */ + +/* Private defines ---------------------------------------------------------*/ +/** Initialize members in instance of LockingData_t structure */ +#define LOCKING_DATA_INIT { 0, 0 } + +/* Private typedef ---------------------------------------------------------*/ +typedef struct +{ + uint8_t flag; /**< Backup of PRIMASK.PM at nesting level 0 */ + uint8_t counter; /**< Nesting level */ +} LockingData_t; + +/* Private functions -------------------------------------------------------*/ + +/** + * @brief Initialize STM32 lock + * @param lock The lock to init + */ +static inline void stm32_lock_init(LockingData_t *lock) +{ + STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); + lock->flag = 0; + lock->counter = 0; +} + +/** + * @brief Acquire STM32 lock + * @param lock The lock to acquire + */ +static inline void stm32_lock_acquire(LockingData_t *lock) +{ + uint8_t flag = (uint8_t)(__get_PRIMASK() & 0x1); /* PRIMASK.PM */ + __disable_irq(); + __DSB(); + __ISB(); + STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); + if (lock->counter == 0) + { + lock->flag = flag; + } + else if (lock->counter == UINT8_MAX) + { + STM32_LOCK_BLOCK(); + } + lock->counter++; +} + +/** + * @brief Release STM32 lock + * @param lock The lock to release + */ +static inline void stm32_lock_release(LockingData_t *lock) +{ + STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); + if (lock->counter == 0) + { + STM32_LOCK_BLOCK(); + } + lock->counter--; + if (lock->counter == 0 && lock->flag == 0) + { + __enable_irq(); + } +} + +#elif STM32_THREAD_SAFE_STRATEGY == 3 +/* + * Deny lock usage from interrupts. + */ + +/* Private defines ---------------------------------------------------------*/ +/** Initialize members in instance of LockingData_t structure */ +#define LOCKING_DATA_INIT 0 + +/* Private typedef ---------------------------------------------------------*/ +typedef uint8_t LockingData_t; /**< Unused */ + +/* Private functions -------------------------------------------------------*/ + +/** + * @brief Initialize STM32 lock + * @param lock The lock to init + */ +static inline void stm32_lock_init(LockingData_t *lock) +{ + STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); +} + +/** + * @brief Acquire STM32 lock + * @param lock The lock to acquire + */ +static inline void stm32_lock_acquire(LockingData_t *lock) +{ + STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); + STM32_LOCK_BLOCK_IF_INTERRUPT_CONTEXT(); +} + +/** + * @brief Release ST lock + * @param lock The lock to release + */ +static inline void stm32_lock_release(LockingData_t *lock) +{ + STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); + STM32_LOCK_BLOCK_IF_INTERRUPT_CONTEXT(); +} + +#elif STM32_THREAD_SAFE_STRATEGY == 4 +/* + * Allow lock usage from interrupts. Implemented using FreeRTOS locks. + */ + +/* Includes ----------------------------------------------------------------*/ +#include +#include + +#if defined (__GNUC__) && !defined (__CC_ARM) && configUSE_NEWLIB_REENTRANT == 0 +#warning Please set configUSE_NEWLIB_REENTRANT to 1 in FreeRTOSConfig.h, otherwise newlib will not be thread-safe +#endif /* defined (__GNUC__) && !defined (__CC_ARM) && configUSE_NEWLIB_REENTRANT == 0 */ + +/* Private defines ---------------------------------------------------------*/ +/** Initialize members in instance of LockingData_t structure */ +#define LOCKING_DATA_INIT { {0, 0}, 0 } +#define STM32_LOCK_MAX_NESTED_LEVELS 2 /**< Max nesting level of interrupts */ +typedef struct +{ + uint32_t basepri[STM32_LOCK_MAX_NESTED_LEVELS]; + uint8_t nesting_level; +} LockingData_t; + +/* Private macros ----------------------------------------------------------*/ +/** Blocks execution if reached max nesting level */ +#define STM32_LOCK_ASSERT_VALID_NESTING_LEVEL(lock) \ + do \ + { \ + if (lock->nesting_level >= STM32_LOCK_ARRAY_SIZE(lock->basepri)) \ + { \ + STM32_LOCK_BLOCK(); \ + } \ + } while (0) + +/* Private functions -------------------------------------------------------*/ + +/** + * @brief Initialize STM32 lock + * @param lock The lock to init + */ +static inline void stm32_lock_init(LockingData_t *lock) +{ + STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); + for (size_t i = 0; i < STM32_LOCK_ARRAY_SIZE(lock->basepri); i++) + { + lock->basepri[i] = 0; + } + lock->nesting_level = 0; +} + +/** + * @brief Acquire STM32 lock + * @param lock The lock to acquire + */ +static inline void stm32_lock_acquire(LockingData_t *lock) +{ + STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); + STM32_LOCK_ASSERT_VALID_NESTING_LEVEL(lock); + lock->basepri[lock->nesting_level++] = taskENTER_CRITICAL_FROM_ISR(); +} + +/** + * @brief Release STM32 lock + * @param lock The lock to release + */ +static inline void stm32_lock_release(LockingData_t *lock) +{ + STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); + lock->nesting_level--; + STM32_LOCK_ASSERT_VALID_NESTING_LEVEL(lock); + taskEXIT_CRITICAL_FROM_ISR(lock->basepri[lock->nesting_level]); +} + +#undef STM32_LOCK_ASSERT_VALID_NESTING_LEVEL +#undef STM32_LOCK_MAX_NESTED_LEVELS + +#elif STM32_THREAD_SAFE_STRATEGY == 5 +/* + * Deny lock usage from interrupts. Implemented using FreeRTOS locks. + */ + +/* Includes ----------------------------------------------------------------*/ +#include +#include +#if defined (__GNUC__) && !defined (__CC_ARM) && configUSE_NEWLIB_REENTRANT == 0 +#warning Please set configUSE_NEWLIB_REENTRANT to 1 in FreeRTOSConfig.h, otherwise newlib will not be thread-safe +#endif /* defined (__GNUC__) && !defined (__CC_ARM) && configUSE_NEWLIB_REENTRANT == 0 */ + +/* Private defines ---------------------------------------------------------*/ +/** Initialize members in instance of LockingData_t structure */ +#define LOCKING_DATA_INIT 0 + +/* Private typedef ---------------------------------------------------------*/ +typedef uint8_t LockingData_t; /**< Unused */ + +/* Private functions -------------------------------------------------------*/ + +/** + * @brief Initialize STM32 lock + * @param lock The lock to init + */ +static inline void stm32_lock_init(LockingData_t *lock) +{ + STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); +} + +/** + * @brief Acquire STM32 lock + * @param lock The lock to acquire + */ +static inline void stm32_lock_acquire(LockingData_t *lock) +{ + STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); + STM32_LOCK_BLOCK_IF_INTERRUPT_CONTEXT(); + vTaskSuspendAll(); +} + +/** + * @brief Release STM32 lock + * @param lock The lock to release + */ +static inline void stm32_lock_release(LockingData_t *lock) +{ + STM32_LOCK_BLOCK_IF_NULL_ARGUMENT(lock); + STM32_LOCK_BLOCK_IF_INTERRUPT_CONTEXT(); + xTaskResumeAll(); +} + +#else +#error Invalid STM32_THREAD_SAFE_STRATEGY specified +#endif /* STM32_THREAD_SAFE_STRATEGY */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* __STM32_LOCK_H__ */ diff --git a/Core/Src/main.c b/Core/Src/main.c index 3e9998a..9e0ca69 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -223,11 +223,11 @@ static void MX_CAN1_Init(void) /* USER CODE END CAN1_Init 1 */ hcan1.Instance = CAN1; - hcan1.Init.Prescaler = 16; - hcan1.Init.Mode = CAN_MODE_NORMAL; + hcan1.Init.Prescaler = 4; + hcan1.Init.Mode = CAN_MODE_SILENT; hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ; - hcan1.Init.TimeSeg1 = CAN_BS1_1TQ; - hcan1.Init.TimeSeg2 = CAN_BS2_1TQ; + hcan1.Init.TimeSeg1 = CAN_BS1_16TQ; + hcan1.Init.TimeSeg2 = CAN_BS2_4TQ; hcan1.Init.TimeTriggeredMode = DISABLE; hcan1.Init.AutoBusOff = DISABLE; hcan1.Init.AutoWakeUp = DISABLE; @@ -260,11 +260,11 @@ static void MX_CAN2_Init(void) /* USER CODE END CAN2_Init 1 */ hcan2.Instance = CAN2; - hcan2.Init.Prescaler = 16; - hcan2.Init.Mode = CAN_MODE_NORMAL; + hcan2.Init.Prescaler = 8; + hcan2.Init.Mode = CAN_MODE_SILENT; hcan2.Init.SyncJumpWidth = CAN_SJW_1TQ; - hcan2.Init.TimeSeg1 = CAN_BS1_1TQ; - hcan2.Init.TimeSeg2 = CAN_BS2_1TQ; + hcan2.Init.TimeSeg1 = CAN_BS1_16TQ; + hcan2.Init.TimeSeg2 = CAN_BS2_4TQ; hcan2.Init.TimeTriggeredMode = DISABLE; hcan2.Init.AutoBusOff = DISABLE; hcan2.Init.AutoWakeUp = DISABLE; @@ -355,6 +355,9 @@ static void MX_GPIO_Init(void) __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 */ @@ -384,15 +387,22 @@ static void MX_GPIO_Init(void) HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /*Configure GPIO pins : PB0 PB1 PB2 PB10 - PB11 PB14 PB15 PB3 - PB4 PB5 PB6 PB7 */ + 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_3 - |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7; + |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 : PB3 PB4 PB5 */ + GPIO_InitStruct.Pin = GPIO_PIN_3|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 */ /* USER CODE END MX_GPIO_Init_2 */ diff --git a/can_logger.ioc b/can_logger.ioc index ee21eb6..01b9b7e 100644 --- a/can_logger.ioc +++ b/can_logger.ioc @@ -2,18 +2,22 @@ CAD.formats= CAD.pinconfig= CAD.provider= -CAN1.BS1=CAN_BS1_1TQ -CAN1.BS2=CAN_BS2_1TQ -CAN1.CalculateBaudRate=875000 -CAN1.CalculateTimeBit=1142 -CAN1.CalculateTimeQuantum=380.95238095238096 -CAN1.IPParameters=CalculateTimeQuantum,CalculateTimeBit,CalculateBaudRate,BS1,BS2 -CAN2.BS1=CAN_BS1_1TQ -CAN2.BS2=CAN_BS2_1TQ -CAN2.CalculateBaudRate=875000 -CAN2.CalculateTimeBit=1142 -CAN2.CalculateTimeQuantum=380.95238095238096 -CAN2.IPParameters=CalculateTimeQuantum,CalculateTimeBit,CalculateBaudRate,BS1,BS2 +CAN1.BS1=CAN_BS1_16TQ +CAN1.BS2=CAN_BS2_4TQ +CAN1.CalculateBaudRate=500000 +CAN1.CalculateTimeBit=2000 +CAN1.CalculateTimeQuantum=95.23809523809524 +CAN1.IPParameters=CalculateTimeQuantum,CalculateTimeBit,CalculateBaudRate,BS1,Prescaler,BS2,Mode +CAN1.Mode=CAN_MODE_SILENT +CAN1.Prescaler=4 +CAN2.BS1=CAN_BS1_16TQ +CAN2.BS2=CAN_BS2_4TQ +CAN2.CalculateBaudRate=250000 +CAN2.CalculateTimeBit=4000 +CAN2.CalculateTimeQuantum=190.47619047619048 +CAN2.IPParameters=CalculateTimeQuantum,CalculateTimeBit,CalculateBaudRate,BS1,Prescaler,BS2,Mode +CAN2.Mode=CAN_MODE_SILENT +CAN2.Prescaler=8 Dma.Request0=SDIO_RX Dma.Request1=SDIO_TX Dma.RequestsNb=2 @@ -64,17 +68,20 @@ Mcu.Name=STM32F405RGTx Mcu.Package=LQFP64 Mcu.Pin0=PB12 Mcu.Pin1=PB13 -Mcu.Pin10=VP_FREERTOS_VS_CMSIS_V2 -Mcu.Pin11=VP_SYS_VS_tim6 +Mcu.Pin10=PB5 +Mcu.Pin11=PB8 +Mcu.Pin12=PB9 +Mcu.Pin13=VP_FREERTOS_VS_CMSIS_V2 +Mcu.Pin14=VP_SYS_VS_tim6 Mcu.Pin2=PC8 Mcu.Pin3=PC9 Mcu.Pin4=PC10 Mcu.Pin5=PC11 Mcu.Pin6=PC12 Mcu.Pin7=PD2 -Mcu.Pin8=PB8 -Mcu.Pin9=PB9 -Mcu.PinsNb=12 +Mcu.Pin8=PB3 +Mcu.Pin9=PB4 +Mcu.PinsNb=15 Mcu.ThirdPartyNb=0 Mcu.UserConstants= Mcu.UserName=STM32F405RGTx @@ -104,6 +111,12 @@ PB12.Mode=CAN_Activate PB12.Signal=CAN2_RX PB13.Mode=CAN_Activate PB13.Signal=CAN2_TX +PB3.Locked=true +PB3.Signal=GPIO_Output +PB4.Locked=true +PB4.Signal=GPIO_Output +PB5.Locked=true +PB5.Signal=GPIO_Output PB8.Mode=CAN_Activate PB8.Signal=CAN1_RX PB9.Locked=true