first
This commit is contained in:
6
Utilities/sequencer/LICENSE.txt
Normal file
6
Utilities/sequencer/LICENSE.txt
Normal file
@ -0,0 +1,6 @@
|
||||
This software component is provided to you as part of a software package and
|
||||
applicable license terms are in the Package_license file. If you received this
|
||||
software component outside of a package or without applicable license terms,
|
||||
the terms of the BSD-3-Clause license shall apply.
|
||||
You may obtain a copy of the BSD-3-Clause at:
|
||||
https://opensource.org/licenses/BSD-3-Clause
|
||||
550
Utilities/sequencer/stm32_seq.c
Normal file
550
Utilities/sequencer/stm32_seq.c
Normal file
@ -0,0 +1,550 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @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
|
||||
|
||||
/**
|
||||
* @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
|
||||
|
||||
/**
|
||||
* @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
|
||||
|
||||
#if UTIL_SEQ_CONF_TASK_NBR > 32
|
||||
#error "UTIL_SEQ_CONF_PRIO_NBR must be less of equal then 32"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief default value of priority number.
|
||||
*/
|
||||
#ifndef UTIL_SEQ_CONF_PRIO_NBR
|
||||
#define UTIL_SEQ_CONF_PRIO_NBR (2)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief default memset function.
|
||||
*/
|
||||
#ifndef UTIL_SEQ_MEMSET8
|
||||
#define UTIL_SEQ_MEMSET8( dest, value, size ) UTILS_MEMSET8( dest, value, size )
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/* 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];
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/* 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( );
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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));
|
||||
|
||||
/*
|
||||
* remove from the roun_robin mask the task that has been selected to be executed
|
||||
*/
|
||||
TaskPrio[counter].round_robin &= ~(1U << CurrentTaskIdx);
|
||||
|
||||
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( );
|
||||
|
||||
/* Execute the task */
|
||||
TaskCb[CurrentTaskIdx]( );
|
||||
|
||||
local_taskset = TaskSet;
|
||||
local_evtset = EvtSet;
|
||||
local_taskmask = TaskMask;
|
||||
local_evtwaited = EvtWaited;
|
||||
}
|
||||
|
||||
/* the set of CurrentTaskIdx to no task running allows to call WaitEvt in the Pre/Post ilde context */
|
||||
CurrentTaskIdx = UTIL_SEQ_NOTASKRUNNING;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @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 n = 0U;
|
||||
uint32_t lvalue = Value;
|
||||
|
||||
if ((lvalue & 0xFFFF0000U) == 0U) { n = 16U; lvalue <<= 16U; }
|
||||
if ((lvalue & 0xFF000000U) == 0U) { n += 8U; lvalue <<= 8U; }
|
||||
if ((lvalue & 0xF0000000U) == 0U) { n += 4U; lvalue <<= 4U; }
|
||||
|
||||
n += SEQ_clz_table_4bit[lvalue >> (32-4)];
|
||||
|
||||
return (uint8_t)(31U-n);
|
||||
}
|
||||
#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
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
360
Utilities/sequencer/stm32_seq.h
Normal file
360
Utilities/sequencer/stm32_seq.h
Normal file
@ -0,0 +1,360 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/* 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 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 );
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*__STM32_SEQ_H */
|
||||
|
||||
Reference in New Issue
Block a user