diff options
Diffstat (limited to 'firmware/memory_chip_gone/Utilities')
4 files changed, 1516 insertions, 0 deletions
diff --git a/firmware/memory_chip_gone/Utilities/lpm/tiny_lpm/stm32_lpm.c b/firmware/memory_chip_gone/Utilities/lpm/tiny_lpm/stm32_lpm.c new file mode 100644 index 0000000..8f4e7cd --- /dev/null +++ b/firmware/memory_chip_gone/Utilities/lpm/tiny_lpm/stm32_lpm.c @@ -0,0 +1,258 @@ +/** + ****************************************************************************** + * @file stm32_lpm.c + * @author MCD Application Team + * @brief Low Power Manager + ****************************************************************************** + * @attention + * + * <h2><center>© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.</center></h2> + * + * 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32_lpm.h" +#include "utilities_conf.h" + +/** @addtogroup TINY_LPM + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private macros ------------------------------------------------------------*/ +/** @defgroup TINY_LPM_Private_macros TINY LPM private macros + * @{ + */ + +/** + * @brief macro used to initialized the critical section + */ +#ifndef UTIL_LPM_INIT_CRITICAL_SECTION + #define UTIL_LPM_INIT_CRITICAL_SECTION( ) +#endif + +/** + * @brief macro used to enter the critical section + */ +#ifndef UTIL_LPM_ENTER_CRITICAL_SECTION + #define UTIL_LPM_ENTER_CRITICAL_SECTION( ) UTILS_ENTER_CRITICAL_SECTION( ) +#endif + +/** + * @brief macro used to exit the critical section + */ +#ifndef UTIL_LPM_EXIT_CRITICAL_SECTION + #define UTIL_LPM_EXIT_CRITICAL_SECTION( ) UTILS_EXIT_CRITICAL_SECTION( ) +#endif + +/** + * @brief macro used to enter the critical section when Entering Low Power + * @note this macro is only called inside the function UTIL_LPM_EnterLowPower + * and in a basic configuration shall be identcal to the macro + * UTIL_LPM_EXIT_CRITICAL_SECTION. In general, the request to enter the + * low power mode is already done under a critical section and + * nesting it is useless (in specific implementations not even possible). + * So the users could define their own macro) + */ +#ifndef UTIL_LPM_ENTER_CRITICAL_SECTION_ELP + #define UTIL_LPM_ENTER_CRITICAL_SECTION_ELP( ) UTIL_LPM_ENTER_CRITICAL_SECTION( ) +#endif + +/** + * @brief macro used to exit the critical section when exiting Low Power mode + * @note the behavior of the macro shall be symmetrical with the macro + * UTIL_LPM_ENTER_CRITICAL_SECTION_ELP + */ +#ifndef UTIL_LPM_EXIT_CRITICAL_SECTION_ELP + #define UTIL_LPM_EXIT_CRITICAL_SECTION_ELP( ) UTIL_LPM_EXIT_CRITICAL_SECTION( ) +#endif + +/** + * @} + */ +/* Private function prototypes -----------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private typedef -----------------------------------------------------------*/ +/* Private defines -----------------------------------------------------------*/ +/** @defgroup TINY_LPM_Private_define TINY LPM private defines + * @{ + */ + +/** + * @brief value used to reset the LPM mode + */ +#define UTIL_LPM_NO_BIT_SET (0UL) + +/** + * @} + */ +/* Private macros ------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/** @defgroup TINY_LPM_Private_variables TINY LPM private variables + * @{ + */ + +/** + * @brief value used to represent the LPM state of stop mode + */ +static UTIL_LPM_bm_t StopModeDisable = UTIL_LPM_NO_BIT_SET; + +/** + * @brief value used to represent the LPM state of off mode + */ +static UTIL_LPM_bm_t OffModeDisable = UTIL_LPM_NO_BIT_SET; + +/** + * @} + */ +/* Global variables ----------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Functions Definition ------------------------------------------------------*/ + +/** @addtogroup TINY_LPM_Exported_function + * @{ + */ +void UTIL_LPM_Init( void ) +{ + StopModeDisable = UTIL_LPM_NO_BIT_SET; + OffModeDisable = UTIL_LPM_NO_BIT_SET; + UTIL_LPM_INIT_CRITICAL_SECTION( ); +} + +void UTIL_LPM_DeInit( void ) +{ +} + +void UTIL_LPM_SetStopMode( UTIL_LPM_bm_t lpm_id_bm, UTIL_LPM_State_t state ) +{ + UTIL_LPM_ENTER_CRITICAL_SECTION( ); + + switch( state ) + { + case UTIL_LPM_DISABLE: + { + StopModeDisable |= lpm_id_bm; + break; + } + case UTIL_LPM_ENABLE: + { + StopModeDisable &= ( ~lpm_id_bm ); + break; + } + default : + { + break; + } + } + + UTIL_LPM_EXIT_CRITICAL_SECTION( ); +} + +void UTIL_LPM_SetOffMode( UTIL_LPM_bm_t lpm_id_bm, UTIL_LPM_State_t state ) +{ + UTIL_LPM_ENTER_CRITICAL_SECTION( ); + + switch(state) + { + case UTIL_LPM_DISABLE: + { + OffModeDisable |= lpm_id_bm; + break; + } + case UTIL_LPM_ENABLE: + { + OffModeDisable &= ( ~lpm_id_bm ); + break; + } + default : + { + break; + } + } + + UTIL_LPM_EXIT_CRITICAL_SECTION( ); +} + +UTIL_LPM_Mode_t UTIL_LPM_GetMode( void ) +{ + UTIL_LPM_Mode_t mode_selected; + + UTIL_LPM_ENTER_CRITICAL_SECTION( ); + + if( StopModeDisable != UTIL_LPM_NO_BIT_SET ) + { + /** + * At least one user disallows Stop Mode + */ + mode_selected = UTIL_LPM_SLEEPMODE; + } + else + { + if( OffModeDisable != UTIL_LPM_NO_BIT_SET ) + { + /** + * At least one user disallows Off Mode + */ + mode_selected = UTIL_LPM_STOPMODE; + } + else + { + mode_selected = UTIL_LPM_OFFMODE; + } + } + + UTIL_LPM_EXIT_CRITICAL_SECTION( ); + + return mode_selected; +} + +void UTIL_LPM_EnterLowPower( void ) +{ + UTIL_LPM_ENTER_CRITICAL_SECTION_ELP( ); + + if( StopModeDisable != UTIL_LPM_NO_BIT_SET ) + { + /** + * At least one user disallows Stop Mode + * SLEEP mode is required + */ + UTIL_PowerDriver.EnterSleepMode( ); + UTIL_PowerDriver.ExitSleepMode( ); + } + else + { + if( OffModeDisable != UTIL_LPM_NO_BIT_SET ) + { + /** + * At least one user disallows Off Mode + * STOP mode is required + */ + UTIL_PowerDriver.EnterStopMode( ); + UTIL_PowerDriver.ExitStopMode( ); + } + else + { + /** + * OFF mode is required + */ + UTIL_PowerDriver.EnterOffMode( ); + UTIL_PowerDriver.ExitOffMode( ); + } + } + + UTIL_LPM_EXIT_CRITICAL_SECTION_ELP( ); +} + +/** + * @} + */ + +/** + * @} + */ diff --git a/firmware/memory_chip_gone/Utilities/lpm/tiny_lpm/stm32_lpm.h b/firmware/memory_chip_gone/Utilities/lpm/tiny_lpm/stm32_lpm.h new file mode 100644 index 0000000..a262f9c --- /dev/null +++ b/firmware/memory_chip_gone/Utilities/lpm/tiny_lpm/stm32_lpm.h @@ -0,0 +1,167 @@ +/** + ****************************************************************************** + * @file stm32_lpm.h + * @author MCD Application Team + * @brief Header for stm32_lpm.c module + ****************************************************************************** + * @attention + * + * <h2><center>© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.</center></h2> + * + * 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. + * + ****************************************************************************** +*/ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef STM32_TINY_LPM_H +#define STM32_TINY_LPM_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stdint.h" + +/** @defgroup TINY_LPM TINY LPM + * @{ + */ + +/* Exported typedef ---------------------------------------------------------*/ +/** @defgroup TINY_LPM_Exported_typedef TINY LPM exported typedef + * @{ + */ + +/** + * @brief type definition to represent the bit mask of an LPM mode + */ +typedef uint32_t UTIL_LPM_bm_t; + +/** + * @brief type definition to represent value of an LPM mode + */ +typedef enum +{ + UTIL_LPM_ENABLE=0, + UTIL_LPM_DISABLE, +} UTIL_LPM_State_t; + +/** + * @brief type definition to represent the different type of LPM mode + */ + +typedef enum +{ + UTIL_LPM_SLEEPMODE, + UTIL_LPM_STOPMODE, + UTIL_LPM_OFFMODE, +} UTIL_LPM_Mode_t; + +/** + * @} + */ + +/** @defgroup TINY_LPM_Exported_struct TINY LPM exported struct + * @{ + */ + +/** + * @brief LPM driver definition + */ +struct UTIL_LPM_Driver_s +{ + void (*EnterSleepMode) ( void ); /*!<function to enter the sleep mode */ + void (*ExitSleepMode) ( void ); /*!<function to exit the sleep mode */ + void (*EnterStopMode) ( void ); /*!<function to enter the stop mode */ + void (*ExitStopMode) ( void ); /*!<function to exit the stop mode */ + void (*EnterOffMode) ( void ); /*!<function to enter the off mode */ + void (*ExitOffMode) ( void ); /*!<function to exit the off mode */ +}; + +/** + * @} + */ + +/* External variables --------------------------------------------------------*/ + +/** @defgroup TINY_LPM_Exported_struct TINY LPM exported struct + * @{ + */ + +/** + * @brief LPM driver + * + * @note This structure is defined and initialized in the specific platform + * power implementation + */ +extern const struct UTIL_LPM_Driver_s UTIL_PowerDriver; + +/** + * @} + */ + +/* Exported macros -----------------------------------------------------------*/ +/* Exported functions ------------------------------------------------------- */ + +/** @defgroup TINY_LPM_Exported_function TINY LPM exported functions + * @{ + */ + +/** + * @brief This API Initializes the LPM resources. + */ +void UTIL_LPM_Init( void ); + +/** + * @brief This API Un-Initializes the LPM resources. + */ +void UTIL_LPM_DeInit( void ); + +/** + * @brief This API returns the Low Power Mode selected that will be applied when the system will enter low power mode + * if there is no update between the time the mode is read with this API and the time the system enters + * low power mode. + * @retval the LPM mode based on @ref UTIL_LPM_Mode_t + */ +UTIL_LPM_Mode_t UTIL_LPM_GetMode( void ); + +/** + * @brief This API notifies the low power manager if the specified user allows the Stop mode or not. + * The default mode selection for all users is Stop Mode enabled + * @param lpm_id_bm: identifier of the user ( 1 bit per user ) + * @param state: Specify whether StopMode is allowed or not by this user + */ +void UTIL_LPM_SetStopMode( UTIL_LPM_bm_t lpm_id_bm, UTIL_LPM_State_t state ); + +/** + * @brief This API notifies the low power manager if the specified user allows the Off mode or not. + * The default mode selection for all users is Off mode enabled + * @param lpm_id_bm: identifier of the user ( 1 bit per user ) + * @param state: Specify whether OffMode is allowed or not by this user + */ +void UTIL_LPM_SetOffMode( UTIL_LPM_bm_t lpm_id_bm, UTIL_LPM_State_t state ); + +/** + * @brief This API is called by the low power manager in a critical section (PRIMASK bit set) to allow the + * application to implement dedicated code before entering Low Power Mode + */ +void UTIL_LPM_EnterLowPower( void ); + +/** + *@} + */ + +/** + *@} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* STM32_TINY_LPM_H */ + diff --git a/firmware/memory_chip_gone/Utilities/sequencer/stm32_seq.c b/firmware/memory_chip_gone/Utilities/sequencer/stm32_seq.c new file mode 100644 index 0000000..56fb2c2 --- /dev/null +++ b/firmware/memory_chip_gone/Utilities/sequencer/stm32_seq.c @@ -0,0 +1,686 @@ +/** + ****************************************************************************** + * @file stm32_seq.c + * @author MCD Application Team + * @brief Simple sequencer implementation + ****************************************************************************** + * @attention + * + * <h2><center>© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.</center></h2> + * + * 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32_seq.h" +#include "utilities_conf.h" + +/** @addtogroup SEQUENCER + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/** @defgroup SEQUENCER_Private_type SEQUENCER private type + * @{ + */ + +/** + * @brief structure used to manage task scheduling + */ +typedef struct +{ + uint32_t priority; /*!<bit field of the enabled task. */ + uint32_t round_robin; /*!<mask on the allowed task to be running. */ +} UTIL_SEQ_Priority_t; + +/** + * @} + */ + +/* Private defines -----------------------------------------------------------*/ + +/** @defgroup SEQUENCER_Private_define SEQUENCER private defines + * @{ + */ + +/** + * @brief macro used to enter the critical section before calling the IDLE function + * @note in a basic configuration shall be identical to the macro + * UTIL_SEQ_ENTER_CRITICAL_SECTION. The redefinition of this macro will allow + * to perform specific operation + + */ +#ifndef UTIL_SEQ_ENTER_CRITICAL_SECTION_IDLE +#define UTIL_SEQ_ENTER_CRITICAL_SECTION_IDLE( ) UTIL_SEQ_ENTER_CRITICAL_SECTION( ) +#endif /* UTIL_SEQ_ENTER_CRITICAL_SECTION_IDLE */ + +/** + * @brief macro used to exit the critical section when exiting the IDLE function + * @note the behavior of the macro shall be symmetrical with the macro + * UTIL_SEQ_ENTER_CRITICAL_SECTION_IDLE + */ +#ifndef UTIL_SEQ_EXIT_CRITICAL_SECTION_IDLE +#define UTIL_SEQ_EXIT_CRITICAL_SECTION_IDLE( ) UTIL_SEQ_EXIT_CRITICAL_SECTION( ) +#endif /* UTIL_SEQ_EXIT_CRITICAL_SECTION_IDLE */ + +/** + * @brief define to represent no task running + */ +#define UTIL_SEQ_NOTASKRUNNING (0xFFFFFFFFU) + +/** + * @brief define to represent no bit set inside uint32_t mapping + */ +#define UTIL_SEQ_NO_BIT_SET (0U) + +/** + * @brief define to represent all bits set inside uint32_t mapping + */ +#define UTIL_SEQ_ALL_BIT_SET (~0U) + +/** + * @brief default number of task is default 32 (maximum), can be reduced by redefining in utilities_conf.h + */ +#ifndef UTIL_SEQ_CONF_TASK_NBR +#define UTIL_SEQ_CONF_TASK_NBR (32) +#endif /* UTIL_SEQ_CONF_TASK_NBR */ + +#if UTIL_SEQ_CONF_TASK_NBR > 32 +#error "UTIL_SEQ_CONF_TASK_NBR must be less than or equal to 32" +#endif /* UTIL_SEQ_CONF_TASK_NBR */ + +/** + * @brief default value of priority number. + */ +#ifndef UTIL_SEQ_CONF_PRIO_NBR +#define UTIL_SEQ_CONF_PRIO_NBR (2) +#endif /* UTIL_SEQ_CONF_PRIO_NBR */ + +/** + * @brief default memset function. + */ +#ifndef UTIL_SEQ_MEMSET8 +#define UTIL_SEQ_MEMSET8( dest, value, size ) UTILS_MEMSET8( dest, value, size ) +#endif /* UTIL_SEQ_MEMSET8 */ + +/** + * @} + */ + +/* Private variables ---------------------------------------------------------*/ + +/** @defgroup SEQUENCER_Private_varaible SEQUENCER private variables + * @{ + */ + +/** + * @brief task set. + */ +static volatile UTIL_SEQ_bm_t TaskSet; + +/** + * @brief task mask. + */ +static volatile UTIL_SEQ_bm_t TaskMask = UTIL_SEQ_ALL_BIT_SET; + +/** + * @brief super mask. + */ +static UTIL_SEQ_bm_t SuperMask = UTIL_SEQ_ALL_BIT_SET; + +/** + * @brief evt set mask. + */ +static volatile UTIL_SEQ_bm_t EvtSet = UTIL_SEQ_NO_BIT_SET; + +/** + * @brief evt expected mask. + */ +static volatile UTIL_SEQ_bm_t EvtWaited = UTIL_SEQ_NO_BIT_SET; + +/** + * @brief current task id. + */ +static uint32_t CurrentTaskIdx = 0U; + +/** + * @brief task function registered. + */ +static void (*TaskCb[UTIL_SEQ_CONF_TASK_NBR])( void ); + +/** + * @brief task prio management. + */ +static volatile UTIL_SEQ_Priority_t TaskPrio[UTIL_SEQ_CONF_PRIO_NBR]; + + +/** + * @brief List of the cleared task + */ +static UTIL_SEQ_bm_t TaskClearList = 0; + +/** + * @} + */ + +/* Private function prototypes -----------------------------------------------*/ +/** @defgroup SEQUENCER_Private_function SEQUENCER private functions + * @{ + */ +uint8_t SEQ_BitPosition(uint32_t Value); + +/** + * @} + */ + +/* Functions Definition ------------------------------------------------------*/ + + +/** @addtogroup SEQUENCER_Exported_function SEQUENCER exported functions + * @{ + */ +void UTIL_SEQ_Init( void ) +{ + TaskSet = UTIL_SEQ_NO_BIT_SET; + TaskMask = UTIL_SEQ_ALL_BIT_SET; + SuperMask = UTIL_SEQ_ALL_BIT_SET; + EvtSet = UTIL_SEQ_NO_BIT_SET; + EvtWaited = UTIL_SEQ_NO_BIT_SET; + CurrentTaskIdx = 0U; + (void)UTIL_SEQ_MEMSET8((uint8_t *)TaskCb, 0, sizeof(TaskCb)); + for(uint32_t index = 0; index < UTIL_SEQ_CONF_PRIO_NBR; index++) + { + TaskPrio[index].priority = 0; + TaskPrio[index].round_robin = 0; + } + UTIL_SEQ_INIT_CRITICAL_SECTION( ); + TaskClearList = 0; +} + +void UTIL_SEQ_DeInit( void ) +{ +} + +/** + * This function can be nested. + * That is the reason why many variables that are used only in that function are declared static. + * Note: These variables could have been declared static in the function. + * + */ +void UTIL_SEQ_Run( UTIL_SEQ_bm_t Mask_bm ) +{ + uint32_t counter; + UTIL_SEQ_bm_t current_task_set; + UTIL_SEQ_bm_t super_mask_backup; + UTIL_SEQ_bm_t local_taskset; + UTIL_SEQ_bm_t local_evtset; + UTIL_SEQ_bm_t local_taskmask; + UTIL_SEQ_bm_t local_evtwaited; + uint32_t round_robin[UTIL_SEQ_CONF_PRIO_NBR]; + UTIL_SEQ_bm_t task_starving_list; + + /* + * When this function is nested, the mask to be applied cannot be larger than the first call + * The mask is always getting smaller and smaller + * A copy is made of the mask set by UTIL_SEQ_Run() in case it is called again in the task + */ + super_mask_backup = SuperMask; + SuperMask &= Mask_bm; + + /* + * There are two independent mask to check: + * TaskMask that comes from UTIL_SEQ_PauseTask() / UTIL_SEQ_ResumeTask + * SuperMask that comes from UTIL_SEQ_Run + * If the waited event is there, exit from UTIL_SEQ_Run() to return to the + * waiting task + */ + local_taskset = TaskSet; + local_evtset = EvtSet; + local_taskmask = TaskMask; + local_evtwaited = EvtWaited; + while(((local_taskset & local_taskmask & SuperMask) != 0U) && ((local_evtset & local_evtwaited)==0U)) + { + counter = 0U; + /* + * When a flag is set, the associated bit is set in TaskPrio[counter].priority mask depending + * on the priority parameter given from UTIL_SEQ_SetTask() + * The while loop is looking for a flag set from the highest priority maskr to the lower + */ + while((TaskPrio[counter].priority & local_taskmask & SuperMask)== 0U) + { + counter++; + } + + current_task_set = TaskPrio[counter].priority & local_taskmask & SuperMask; + + /* + * The round_robin register is a mask of allowed flags to be evaluated. + * The concept is to make sure that on each round on UTIL_SEQ_Run(), if two same flags are always set, + * the sequencer does not run always only the first one. + * When a task has been executed, The flag is removed from the round_robin mask. + * If on the next UTIL_SEQ_RUN(), the two same flags are set again, the round_robin mask will + * mask out the first flag so that the second one can be executed. + * Note that the first flag is not removed from the list of pending task but just masked by + * the round_robin mask + * + * In the check below, the round_robin mask is reinitialize in case all pending + * tasks haven been executed at least once + */ + if ((TaskPrio[counter].round_robin & current_task_set) == 0U) + { + TaskPrio[counter].round_robin = UTIL_SEQ_ALL_BIT_SET; + } + + /* + * Compute the Stack Startving List + * This is the list of the task that have been set at least once minus the one that have been cleared ar least once + */ + task_starving_list = TaskSet; + + /* + * Due to the concept of TaskPrio[counter].round_robin and TaskClearList, it could be that at some points in time, + * (when using UTIL_SEQ_WaitEvt()), that there is a situation where at the same time, a bit is set in TaskPrio[counter].round_robin + * and reset in TaskClearList and another bit is set in TaskClearList and reset in TaskPrio[counter].round_robin. + * Such situation shall not happen when evaluating task_starving_list + * At any time, there should not be any bit reset in TaskPrio[counter].round_robin and reset in TaskClearList + * It is correct with regard to the Sequencer Architecture to set in TaskClearList all tasks that are said to be executed from TaskPrio[counter].round_robin + * This synchronizes both information before calculating the CurrentTaskIdx + */ + TaskClearList |= (~TaskPrio[counter].round_robin); + + task_starving_list &= (~TaskClearList); + + /* + * Consider first the starving list and update current_task_set accordingly + */ + if ((task_starving_list & current_task_set) != 0U) + { + current_task_set = (task_starving_list & current_task_set); + } + else + { + /* nothing to do */ + } + + /* + * Reinitialize the Starving List if required + */ + if(task_starving_list == 0) + { + TaskClearList = 0; + } + + /* + * Read the flag index of the task to be executed + * Once the index is read, the associated task will be executed even though a higher priority stack is requested + * before task execution. + */ + CurrentTaskIdx = (SEQ_BitPosition(current_task_set & TaskPrio[counter].round_robin)); + + UTIL_SEQ_ENTER_CRITICAL_SECTION( ); + /* remove from the list or pending task the one that has been selected to be executed */ + TaskSet &= ~(1U << CurrentTaskIdx); + + /* + * remove from all priority mask the task that has been selected to be executed + */ + for (counter = UTIL_SEQ_CONF_PRIO_NBR; counter != 0U; counter--) + { + TaskPrio[counter - 1u].priority &= ~(1U << CurrentTaskIdx); + } + UTIL_SEQ_EXIT_CRITICAL_SECTION( ); + + UTIL_SEQ_PreTask(CurrentTaskIdx); + + /* + * Check that function exists before calling it + */ + if ((CurrentTaskIdx < UTIL_SEQ_CONF_TASK_NBR) && (TaskCb[CurrentTaskIdx] != NULL)) + { + /* + * save the round-robin value to take into account the operation done in UTIL_SEQ_WaitEvt + */ + for (uint32_t index = 0; index < UTIL_SEQ_CONF_PRIO_NBR; index++) + { + TaskPrio[index].round_robin &= ~(1U << CurrentTaskIdx); + round_robin[index] = TaskPrio[index].round_robin; + } + + /* Execute the task */ + TaskCb[CurrentTaskIdx]( ); + + /* + * restore the round-robin context + */ + for (uint32_t index = 0; index < UTIL_SEQ_CONF_PRIO_NBR; index++) + { + TaskPrio[index].round_robin &= round_robin[index]; + } + + UTIL_SEQ_PostTask(CurrentTaskIdx); + + local_taskset = TaskSet; + local_evtset = EvtSet; + local_taskmask = TaskMask; + local_evtwaited = EvtWaited; + + /* + * Update the two list for next round + */ + TaskClearList |= (1U << CurrentTaskIdx); + } + else + { + /* + * must never occurs, it means there is a warning in the system + */ + UTIL_SEQ_CatchWarning(UTIL_SEQ_WARNING_INVALIDTASKID); + } + } + + /* the set of CurrentTaskIdx to no task running allows to call WaitEvt in the Pre/Post ilde context */ + CurrentTaskIdx = UTIL_SEQ_NOTASKRUNNING; + /* if a waited event is present, ignore the IDLE sequence */ + if ((local_evtset & EvtWaited)== 0U) + { + UTIL_SEQ_PreIdle( ); + + UTIL_SEQ_ENTER_CRITICAL_SECTION_IDLE( ); + local_taskset = TaskSet; + local_evtset = EvtSet; + local_taskmask = TaskMask; + if ((local_taskset & local_taskmask & SuperMask) == 0U) + { + if ((local_evtset & EvtWaited)== 0U) + { + UTIL_SEQ_Idle( ); + } + } + UTIL_SEQ_EXIT_CRITICAL_SECTION_IDLE( ); + + UTIL_SEQ_PostIdle( ); + } + + /* restore the mask from UTIL_SEQ_Run() */ + SuperMask = super_mask_backup; + + return; +} + +void UTIL_SEQ_RegTask(UTIL_SEQ_bm_t TaskId_bm, uint32_t Flags, void (*Task)( void )) +{ + (void)Flags; + UTIL_SEQ_ENTER_CRITICAL_SECTION(); + + TaskCb[SEQ_BitPosition(TaskId_bm)] = Task; + + UTIL_SEQ_EXIT_CRITICAL_SECTION(); + + return; +} + +uint32_t UTIL_SEQ_IsRegisteredTask(UTIL_SEQ_bm_t TaskId_bm ) +{ + uint32_t _status = 0; + UTIL_SEQ_ENTER_CRITICAL_SECTION(); + + if ( TaskCb[SEQ_BitPosition(TaskId_bm)] != NULL ) + { + _status = 1; + } + + UTIL_SEQ_EXIT_CRITICAL_SECTION(); + return _status; +} + +void UTIL_SEQ_SetTask( UTIL_SEQ_bm_t TaskId_bm, uint32_t Task_Prio ) +{ + UTIL_SEQ_ENTER_CRITICAL_SECTION( ); + + TaskSet |= TaskId_bm; + TaskPrio[Task_Prio].priority |= TaskId_bm; + + UTIL_SEQ_EXIT_CRITICAL_SECTION( ); + + return; +} + +uint32_t UTIL_SEQ_IsSchedulableTask( UTIL_SEQ_bm_t TaskId_bm) +{ + uint32_t _status; + UTIL_SEQ_bm_t local_taskset; + + UTIL_SEQ_ENTER_CRITICAL_SECTION(); + + local_taskset = TaskSet; + _status = ((local_taskset & TaskMask & SuperMask & TaskId_bm) == TaskId_bm)? 1U: 0U; + + UTIL_SEQ_EXIT_CRITICAL_SECTION(); + return _status; +} + +void UTIL_SEQ_PauseTask( UTIL_SEQ_bm_t TaskId_bm ) +{ + UTIL_SEQ_ENTER_CRITICAL_SECTION( ); + + TaskMask &= (~TaskId_bm); + + UTIL_SEQ_EXIT_CRITICAL_SECTION( ); + + return; +} + +uint32_t UTIL_SEQ_IsPauseTask( UTIL_SEQ_bm_t TaskId_bm ) +{ + uint32_t _status; + UTIL_SEQ_ENTER_CRITICAL_SECTION( ); + + _status = ((TaskMask & TaskId_bm) == TaskId_bm) ? 0u:1u; + + UTIL_SEQ_EXIT_CRITICAL_SECTION( ); + return _status; +} + +void UTIL_SEQ_ResumeTask( UTIL_SEQ_bm_t TaskId_bm ) +{ + UTIL_SEQ_ENTER_CRITICAL_SECTION( ); + + TaskMask |= TaskId_bm; + + UTIL_SEQ_EXIT_CRITICAL_SECTION( ); + + return; +} + +void UTIL_SEQ_SetEvt( UTIL_SEQ_bm_t EvtId_bm ) +{ + UTIL_SEQ_ENTER_CRITICAL_SECTION( ); + + EvtSet |= EvtId_bm; + + UTIL_SEQ_EXIT_CRITICAL_SECTION( ); + + return; +} + +void UTIL_SEQ_ClrEvt( UTIL_SEQ_bm_t EvtId_bm ) +{ + UTIL_SEQ_ENTER_CRITICAL_SECTION( ); + + EvtSet &= (~EvtId_bm); + + UTIL_SEQ_EXIT_CRITICAL_SECTION( ); + + return; +} + +void UTIL_SEQ_WaitEvt(UTIL_SEQ_bm_t EvtId_bm) +{ + UTIL_SEQ_bm_t event_waited_id_backup; + UTIL_SEQ_bm_t current_task_idx; + UTIL_SEQ_bm_t wait_task_idx; + /* + * store in local the current_task_id_bm as the global variable CurrentTaskIdx + * may be overwritten in case there are nested call of UTIL_SEQ_Run() + */ + current_task_idx = CurrentTaskIdx; + if(UTIL_SEQ_NOTASKRUNNING == CurrentTaskIdx) + { + wait_task_idx = 0u; + } + else + { + wait_task_idx = (uint32_t)1u << CurrentTaskIdx; + } + + /* backup the event id that was currently waited */ + event_waited_id_backup = EvtWaited; + EvtWaited = EvtId_bm; + /* + * wait for the new event + * note: that means that if the previous waited event occurs, it will not exit + * the while loop below. + * The system is waiting only for the last waited event. + * When it will go out, it will wait again from the previous one. + * It case it occurs while waiting for the second one, the while loop will exit immediately + */ + + while ((EvtSet & EvtId_bm) == 0U) + { + UTIL_SEQ_EvtIdle(wait_task_idx, EvtId_bm); + } + + /* + * Restore the CurrentTaskIdx that may have been modified by call of UTIL_SEQ_Run() + * from UTIL_SEQ_EvtIdle(). This is required so that a second call of UTIL_SEQ_WaitEvt() + * in the same process pass the correct current_task_id_bm in the call of UTIL_SEQ_EvtIdle() + */ + CurrentTaskIdx = current_task_idx; + + UTIL_SEQ_ENTER_CRITICAL_SECTION( ); + + EvtSet &= (~EvtId_bm); + + UTIL_SEQ_EXIT_CRITICAL_SECTION( ); + + EvtWaited = event_waited_id_backup; + return; +} + +UTIL_SEQ_bm_t UTIL_SEQ_IsEvtPend( void ) +{ + UTIL_SEQ_bm_t local_evtwaited = EvtWaited; + return (EvtSet & local_evtwaited); +} + +__WEAK void UTIL_SEQ_EvtIdle( UTIL_SEQ_bm_t TaskId_bm, UTIL_SEQ_bm_t EvtWaited_bm ) +{ + (void)EvtWaited_bm; + UTIL_SEQ_Run(~TaskId_bm); + return; +} + +__WEAK void UTIL_SEQ_Idle( void ) +{ + return; +} + +__WEAK void UTIL_SEQ_PreIdle( void ) +{ + /* + * Unless specified by the application, there is nothing to be done + */ + return; +} + +__WEAK void UTIL_SEQ_PostIdle( void ) +{ + /* + * Unless specified by the application, there is nothing to be done + */ + return; +} + +__WEAK void UTIL_SEQ_PreTask( uint32_t TaskId ) +{ + (void)TaskId; + return; +} + +__WEAK void UTIL_SEQ_PostTask( uint32_t TaskId ) +{ + (void)TaskId; + return; +} + +__WEAK void UTIL_SEQ_CatchWarning(UTIL_SEQ_WARNING WarningId) +{ + (void)WarningId; + return; +} + +/** + * @} + */ + +/** @addtogroup SEQUENCER_Private_function + * @{ + */ + +#if( __CORTEX_M == 0) +const uint8_t SEQ_clz_table_4bit[16U] = { 4U, 3U, 2U, 2U, 1U, 1U, 1U, 1U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U }; +/** + * @brief return the position of the first bit set to 1 + * @param Value 32 bit value + * @retval bit position + */ +uint8_t SEQ_BitPosition(uint32_t Value) +{ + uint8_t position = 0U; + uint32_t lvalue = Value; + + if ((lvalue & 0xFFFF0000U) == 0U) + { + position = 16U; + lvalue <<= 16U; + } + if ((lvalue & 0xFF000000U) == 0U) + { + position += 8U; + lvalue <<= 8U; + } + if ((lvalue & 0xF0000000U) == 0U) + { + position += 4U; + lvalue <<= 4U; + } + + position += SEQ_clz_table_4bit[lvalue >> (32-4)]; + + return (uint8_t)(31U-position); +} +#else +/** + * @brief return the position of the first bit set to 1 + * @param Value 32 bit value + * @retval bit position + */ +uint8_t SEQ_BitPosition(uint32_t Value) +{ + return (uint8_t)(31 -__CLZ( Value )); +} +#endif /* __CORTEX_M == 0 */ + +/** + * @} + */ + +/** + * @} + */ + diff --git a/firmware/memory_chip_gone/Utilities/sequencer/stm32_seq.h b/firmware/memory_chip_gone/Utilities/sequencer/stm32_seq.h new file mode 100644 index 0000000..05a3b20 --- /dev/null +++ b/firmware/memory_chip_gone/Utilities/sequencer/stm32_seq.h @@ -0,0 +1,405 @@ +/** + ****************************************************************************** + * @file stm32_seq.h + * @author MCD Application Team + * @brief sequencer interface + ****************************************************************************** + * @attention + * + * <h2><center>© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.</center></h2> + * + * 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. + * + ****************************************************************************** + */ + + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef STM32_SEQ_H +#define STM32_SEQ_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stdint.h" + +/** @defgroup SEQUENCER sequencer utilities + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ +/** @defgroup SEQUENCER_Exported_type SEQUENCER exported types + * @{ + */ +/** + * @brief bit mapping of the task. + * this value is used to represent a list of task (each corresponds to a task). + */ +typedef uint32_t UTIL_SEQ_bm_t; + +/** + * @brief lits of the warning of the sequencer. + * this value is used to indicate warning detected during the sequencer execution. + */ +typedef enum { + UTIL_SEQ_WARNING_INVALIDTASKID, +}UTIL_SEQ_WARNING; + +/** + * @} + */ + +/* Exported constants --------------------------------------------------------*/ + +/** @defgroup SEQUENCER_Exported_const SEQUENCER exported constants + * @{ + */ + +/** + * @brief This provides a default value for unused parameter + * + */ +#define UTIL_SEQ_RFU 0 + +/** + * @brief Default value used to start the scheduling. + * + * This informs the sequencer that all tasks registered shall be considered + * + * @note + * This should be used in the application\n + * while(1)\n + * {\n + * UTIL_SEQ_Run( UTIL_SEQ_DEFAULT );\n + * }\n + * + */ +#define UTIL_SEQ_DEFAULT (~0U) + +/** + * @} + */ + +/* External variables --------------------------------------------------------*/ +/* Exported macros -----------------------------------------------------------*/ + +/** @defgroup SEQUENCER_Exported_macro SEQUENCER exported macros + * @{ + */ + +/** + * @brief This macro can be used to define a task with one parameter + * + * @note this is an example of using this macro + * + * task prototype definition + * void FUNCTION_NAME(void *Instance) + * { + * uint8_t _instance = *(uint8_t*) Instance; + * } + * + * task declaration in the application for two instances + * const uint8_t instance1 = 1; + * const uint8_t instance2 = 2; + * UTIL_SEQ_TaskParamDef(FUNCTION_NAME, instance1) + * UTIL_SEQ_TaskParamDef(FUNCTION_NAME, instance2) + * + * task initialization + * UTIL_SEQ_RegTask(1 << 1, 0, UTIL_SEQ_TaskFunction(FUNCTION_NAME,instance2)); + * UTIL_SEQ_RegTask(1 << 10, 0, UTIL_SEQ_TaskFunction(FUNCTION_NAME,instance3)); + * + * Then no change on the management of the task within the application, the instance being managed within the overloaded function + * + */ +#define UTIL_SEQ_TaskParamDef(_FUNC_,_PARAM_VAL_) \ + static void SEQ_FUNC_##_FUNC_##_PARAM_VAL_(void); \ + static void SEQ_FUNC_##_FUNC_##_PARAM_VAL_(void) \ + { \ + static void *SEQ_PARAM_##_FUNC_ = (void*)&_PARAM_VAL_;\ + _FUNC_(SEQ_PARAM_##_FUNC_); \ + } + +/** + * @brief This macro is used to retrieve the function name of the task + */ +#define UTIL_SEQ_TaskFunction(_FUNC_,_PARAM_VAL_) SEQ_FUNC_##_FUNC_##_PARAM_VAL_ + +/** + * @} + */ + +/* Exported functions ------------------------------------------------------- */ + +/** @defgroup SEQUENCER_Exported_function SEQUENCER exported functions + * @{ + */ + +/** + * @brief This function initializes the sequencer resources. + * + * @note It shall not be called from an ISR. + * + */ +void UTIL_SEQ_Init( void ); + +/** + * @brief This function un-initializes the sequencer resources. + * + * @note It shall not be called from an ISR + * + */ +void UTIL_SEQ_DeInit( void ); + +/** + * @brief This function is called by the sequencer in critical section (PRIMASK bit) when + * - there are no more tasks to be executed + * AND + * - there are no pending event or the pending event is still not set + * @note The application should enter low power mode in this function + * When this function is not implemented by the application, the sequencer keeps running a while loop (RUN MODE). + * It shall be called only by the sequencer. + * + */ +void UTIL_SEQ_Idle( void ); + +/** + * @brief This function is called by the sequencer outside critical section just before calling UTIL_SEQ_Idle( ) + * UTIL_SEQ_PreIdle() is considered as the last task executed before calling UTIL_SEQ_Idle( ) + * In case a task or an event is set from an interrupt handler just after UTIL_SEQ_PreIdle() is called, + * UTIL_SEQ_Idle() will not be called. + * + * @note It shall be called only by the sequencer. + * + */ +void UTIL_SEQ_PreIdle( void ); + +/** + * @brief This function is called by the sequencer outside critical section either + * - after calling UTIL_SEQ_Idle( ) + * OR + * - after calling UTIL_SEQ_PreIdle( ) without call to UTIL_SEQ_Idle() due to an incoming task set or event + * requested after UTIL_SEQ_PreIdle() has been called. + * + * @note UTIL_SEQ_PostIdle() is always called if UTIL_SEQ_PreIdle() has been called and never called otherwise. + * It shall be called only by the sequencer. + * + */ +void UTIL_SEQ_PostIdle( void ); + +/** + * @brief This function requests the sequencer to execute all pending tasks using round robin mechanism. + * When no task are pending, it calls UTIL_SEQ_Idle(); + * This function should be called in a while loop in the application + * + * @param Mask_bm list of task (bit mapping) that is be kept in the sequencer list. + * + * @note It shall not be called from an ISR. + * @note The construction of the task must take into account the fact that there is no counting / protection + * on the activation of the task. Thus, when the task is running, it must perform all the operations + * in progress programmed before its call or manage a reprogramming of the task. + * + */ +void UTIL_SEQ_Run( UTIL_SEQ_bm_t Mask_bm ); + +/** + * @brief This function registers a task in the sequencer. + * + * @param TaskId_bm The Id of the task + * @param Flags Flags are reserved param for future use + * @param Task Reference of the function to be executed + * + * @note It may be called from an ISR. + * + */ +void UTIL_SEQ_RegTask( UTIL_SEQ_bm_t TaskId_bm, uint32_t Flags, void (*Task)( void ) ); + +/** + * @brief This function checks if a task is registered + * + * @param TaskId_bm The Id of the task + * It shall be (1<<task_id) where task_id is the number assigned when the task has been registered + * @retval 0 if not 1 if true + */ +uint32_t UTIL_SEQ_IsRegisteredTask( UTIL_SEQ_bm_t TaskId_bm ); + +/** + * @brief This function requests a task to be executed + * + * @param TaskId_bm The Id of the task + * It shall be (1<<task_id) where task_id is the number assigned when the task has been registered + * @param Task_Prio The priority of the task + * It shall a number from 0 (high priority) to 31 (low priority) + * The priority is checked each time the sequencer needs to select a new task to execute + * It does not permit to preempt a running task with lower priority + * + * @note It may be called from an ISR + * + */ +void UTIL_SEQ_SetTask( UTIL_SEQ_bm_t TaskId_bm, uint32_t Task_Prio ); + +/** + * @brief This function checks if a task could be scheduled. + * + * @param TaskId_bm The Id of the task + * It shall be (1<<task_id) where task_id is the number assigned when the task has been registered + * @retval 0 if not 1 if true + * + * @note It may be called from an ISR. + * + */ +uint32_t UTIL_SEQ_IsSchedulableTask( UTIL_SEQ_bm_t TaskId_bm); + +/** + * @brief This function prevents a task to be called by the sequencer even when set with UTIL_SEQ_SetTask() + * By default, all tasks are executed by the sequencer when set with UTIL_SEQ_SetTask() + * When a task is paused, it is moved out from the sequencer list + * + * @param TaskId_bm The Id of the task + * It shall be (1<<task_id) where task_id is the number assigned when the task has been registered + * + * @note It may be called from an ISR. + * + */ +void UTIL_SEQ_PauseTask( UTIL_SEQ_bm_t TaskId_bm ); + +/** + * @brief This function allows to know if the task has been put in pause. + * By default, all tasks are executed by the sequencer when set with UTIL_SEQ_SetTask() + * The exit of the pause shall be done by the function UTIL_SEQ_ResumeTask. + * + * @param TaskId_bm The Id of the task + * It shall be (1<<task_id) where task_id is the number assigned when the task has been registered + * + * @note It may be called from an ISR. + * + */ +uint32_t UTIL_SEQ_IsPauseTask( UTIL_SEQ_bm_t TaskId_bm ); + +/** + * @brief This function allows again a task to be called by the sequencer if set with UTIL_SEQ_SetTask() + * This is used in relation with UTIL_SEQ_PauseTask() + * + * @param TaskId_bm The Id of the task + * It shall be (1<<task_id) where task_id is the number assigned when the task has been registered + * + * @note It may be called from an ISR. + * + */ +void UTIL_SEQ_ResumeTask( UTIL_SEQ_bm_t TaskId_bm ); + +/** + * @brief This function sets an event that is waited with UTIL_SEQ_WaitEvt() + * + * @param EvtId_bm event id bit mask + * + * @note An event shall be a 32 bit mapping where only 1 bit is set + * It may be called from an ISR. + * + */ +void UTIL_SEQ_SetEvt( UTIL_SEQ_bm_t EvtId_bm ); + +/** + * @brief This function may be used to clear the event before calling UTIL_SEQ_WaitEvt() + * This API may be useful when the UTIL_SEQ_SetEvt() is called several time to notify the same event. + * Due to Software Architecture where the timings are hard to control, this may be an unwanted case. + * + * @param EvtId_bm event id bm + * It shall be a bit mapping where only 1 bit is set + * + * @note It may be called from an ISR. + * + */ +void UTIL_SEQ_ClrEvt( UTIL_SEQ_bm_t EvtId_bm ); + +/** + * @brief This function waits for a specific event to be set. The sequencer loops UTIL_SEQ_EvtIdle() until the event is set + * When called recursively, it acts as a First in / Last out mechanism. The sequencer waits for the + * last event requested to be set even though one of the already requested event has been set. + * + * @param EvtId_bm event id bit mask + * It shall be a bit mapping where only 1 bit is set + * + * @note It shall not be called from an ISR. + * @note The construction of the task must take into account the fact that there is no counting / protection on the + * event. Thus, when the task is running, it must perform all the operations in progress programmed before its call + * or manage a reprogramming of the task. + */ +void UTIL_SEQ_WaitEvt( UTIL_SEQ_bm_t EvtId_bm ); + +/** + * @brief This function returns whether the waited event is pending or not + * It is useful only when the UTIL_SEQ_EvtIdle() is overloaded by the application. In that case, when the low + * power mode needs to be executed, the application shall first check whether the waited event is pending + * or not. Both the event checking and the low power mode processing should be done in critical section + * + * @retval 0 when the waited event is not there or the evt_id when the waited event is pending + * + * @note It may be called from an ISR. + * + */ +UTIL_SEQ_bm_t UTIL_SEQ_IsEvtPend( void ); + +/** + * @brief This function loops until the waited event is set + * @param TaskId_bm The task id that is currently running. When task_id_bm = 0, it means UTIL_SEQ_WaitEvt( ) + * has been called outside a registered task (ie at startup before UTIL_SEQ_Run( ) has been called + * @param EvtWaited_bm The event id that is waited. + * + * @note When not implemented by the application, it calls UTIL_SEQ_Run(~TaskId_bm) which means the waited + * task is suspended until the waited event and the other tasks are running or the application enter + * low power mode. + * Else the user can redefine his own function for example call sequencer UTIL_SEQ_Run(0) to suspend all + * the task and let the sequencer enter the low power mode. + * It shall be called only by the sequencer. + * + */ +void UTIL_SEQ_EvtIdle( UTIL_SEQ_bm_t TaskId_bm, UTIL_SEQ_bm_t EvtWaited_bm ); + +/** + * @brief This function is call before a task execution + * @param TaskId The task id. + * + * @note the function is provided to help the debug and + * the default implementation does nothing + * + */ +void UTIL_SEQ_PreTask( uint32_t TaskId ); + +/** + * @brief This function is called after a task execution + * @param TaskId The task id. + * + * @note the function is provided to help the debug and + * the default implementation does nothing + * + */ +void UTIL_SEQ_PostTask( uint32_t TaskId ); + +/** + * @brief This function is called when a warning is detected + * @param WarningId The warning id. + * + * @note the function is provided to help the debug and + * the default implementation does nothing + */ +void UTIL_SEQ_CatchWarning(UTIL_SEQ_WARNING WarningId); + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /*__STM32_SEQ_H */ + |
