diff --git a/.cproject b/.cproject
index 8256f31..79dd84c 100644
--- a/.cproject
+++ b/.cproject
@@ -23,7 +23,7 @@
-
+
@@ -46,6 +46,7 @@
+
@@ -70,6 +72,7 @@
+
-
+
@@ -162,6 +166,7 @@
@@ -181,6 +187,7 @@
diff --git a/.settings/stm32cubeide.project.prefs b/.settings/stm32cubeide.project.prefs
index a53e504..504799c 100644
--- a/.settings/stm32cubeide.project.prefs
+++ b/.settings/stm32cubeide.project.prefs
@@ -1,5 +1,5 @@
635E684B79701B039C64EA45C3F84D30=C8B026EBE17C208F17FB66CE4235156C
66BE74F758C12D739921AEA421D593D3=1
8DF89ED150041C4CBC7CB9A9CAA90856=807DDB2C2702E438DB0EBF3D5AA6AB41
-DC22A860405A8BF2F2C095E5B6529F12=D3CF7BFAB9D98A63886F1AE7AFAEA0B9
+DC22A860405A8BF2F2C095E5B6529F12=1A37C75E31949FC1CF47D46CC4BFA318
eclipse.preferences.version=1
diff --git a/Core/ThreadSafe/newlib_lock_glue.c b/Core/ThreadSafe/newlib_lock_glue.c
new file mode 100644
index 0000000..8d956e4
--- /dev/null
+++ b/Core/ThreadSafe/newlib_lock_glue.c
@@ -0,0 +1,423 @@
+/**
+ ******************************************************************************
+ * @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) 2023 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 ---------------------------------------------------------*/
+
+/**
+ * @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)
+
+/* 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 ---------------------------------------------------------*/
+
+/**
+ * @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/ThreadSafe/stm32_lock.h b/Core/ThreadSafe/stm32_lock.h
new file mode 100644
index 0000000..372c5de
--- /dev/null
+++ b/Core/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) 2023 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/STM32F407VETX_FLASH.ld b/STM32F407VETX_FLASH.ld
index ee22391..16a870a 100644
--- a/STM32F407VETX_FLASH.ld
+++ b/STM32F407VETX_FLASH.ld
@@ -39,8 +39,8 @@ ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */
-_Min_Heap_Size = 0; /* required amount of heap */
-_Min_Stack_Size = 0x3000; /* required amount of stack */
+_Min_Heap_Size = 0x0; /* required amount of heap */
+_Min_Stack_Size = 0x2000; /* required amount of stack */
/* Memories definition */
MEMORY
diff --git a/STM32F407VETX_RAM.ld b/STM32F407VETX_RAM.ld
index d10e01a..f458113 100644
--- a/STM32F407VETX_RAM.ld
+++ b/STM32F407VETX_RAM.ld
@@ -39,8 +39,8 @@ ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */
-_Min_Heap_Size = 0x2000; /* required amount of heap */
-_Min_Stack_Size = 0x1000; /* required amount of stack */
+_Min_Heap_Size = 0x0000; /* required amount of heap */
+_Min_Stack_Size = 0x3000; /* required amount of stack */
/* Memories definition */
MEMORY
diff --git a/dbdb_liquid_path_control_v2.ioc b/dbdb_liquid_path_control_v2.ioc
index a681327..34095b8 100644
--- a/dbdb_liquid_path_control_v2.ioc
+++ b/dbdb_liquid_path_control_v2.ioc
@@ -186,11 +186,12 @@ ProjectManager.DeviceId=STM32F407VETx
ProjectManager.FirmwarePackage=STM32Cube FW_F4 V1.27.1
ProjectManager.FreePins=true
ProjectManager.HalAssertFull=true
-ProjectManager.HeapSize=0x2000
+ProjectManager.HeapSize=0x0000
ProjectManager.KeepUserCode=true
ProjectManager.LastFirmware=true
ProjectManager.LibraryCopy=1
ProjectManager.MainLocation=Core/Src
+ProjectManager.MultiThreaded=true
ProjectManager.NoMain=false
ProjectManager.PreviousToolchain=STM32CubeIDE
ProjectManager.ProjectBuild=false
@@ -198,8 +199,9 @@ ProjectManager.ProjectFileName=dbdb_liquid_path_control_v2.ioc
ProjectManager.ProjectName=dbdb_liquid_path_control_v2
ProjectManager.ProjectStructure=
ProjectManager.RegisterCallBack=
-ProjectManager.StackSize=0x1000
+ProjectManager.StackSize=0x2000
ProjectManager.TargetToolchain=STM32CubeIDE
+ProjectManager.ThreadSafeStrategy=Cortex-M4NS\:Default,
ProjectManager.ToolChainLocation=
ProjectManager.UAScriptAfterPath=
ProjectManager.UAScriptBeforePath=