STM32 Sequencer v1.6.0

stm32_seq.c
Go to the documentation of this file.
1
21 /* Includes ------------------------------------------------------------------*/
22 #include "stm32_seq.h"
23 #include "utilities_conf.h"
24
29 /* Private typedef -----------------------------------------------------------*/
37 typedef struct
38 {
39 uint32_t priority;
40 uint32_t round_robin;
41 } UTIL_SEQ_Priority_t;
42
47 /* Private defines -----------------------------------------------------------*/
48
60 #ifndef UTIL_SEQ_ENTER_CRITICAL_SECTION_IDLE
61 #define UTIL_SEQ_ENTER_CRITICAL_SECTION_IDLE( ) UTIL_SEQ_ENTER_CRITICAL_SECTION( )
62 #endif
63
69 #ifndef UTIL_SEQ_EXIT_CRITICAL_SECTION_IDLE
70 #define UTIL_SEQ_EXIT_CRITICAL_SECTION_IDLE( ) UTIL_SEQ_EXIT_CRITICAL_SECTION( )
71 #endif
72
76 #define UTIL_SEQ_NOTASKRUNNING (0xFFFFFFFFU)
77
81 #define UTIL_SEQ_NO_BIT_SET (0U)
82
86 #define UTIL_SEQ_ALL_BIT_SET (~0U)
87
91 #ifndef UTIL_SEQ_CONF_TASK_NBR
92 #define UTIL_SEQ_CONF_TASK_NBR (32)
93 #endif
94
95 #if UTIL_SEQ_CONF_TASK_NBR > 32
96 #error "UTIL_SEQ_CONF_PRIO_NBR must be less of equal then 32"
97 #endif
98
102 #ifndef UTIL_SEQ_CONF_PRIO_NBR
103 #define UTIL_SEQ_CONF_PRIO_NBR (2)
104 #endif
105
109 #ifndef UTIL_SEQ_MEMSET8
110 #define UTIL_SEQ_MEMSET8( dest, value, size ) UTILS_MEMSET8( dest, value, size )
111 #endif
112
117 /* Private variables ---------------------------------------------------------*/
118
126 static volatile UTIL_SEQ_bm_t TaskSet;
127
131 static volatile UTIL_SEQ_bm_t TaskMask = UTIL_SEQ_ALL_BIT_SET;
132
136 static UTIL_SEQ_bm_t SuperMask = UTIL_SEQ_ALL_BIT_SET;
137
141 static volatile UTIL_SEQ_bm_t EvtSet = UTIL_SEQ_NO_BIT_SET;
142
146 static volatile UTIL_SEQ_bm_t EvtWaited = UTIL_SEQ_NO_BIT_SET;
147
151 static uint32_t CurrentTaskIdx = 0U;
152
156 static void (*TaskCb[UTIL_SEQ_CONF_TASK_NBR])( void );
157
161 static volatile UTIL_SEQ_Priority_t TaskPrio[UTIL_SEQ_CONF_PRIO_NBR];
162
167 /* Private function prototypes -----------------------------------------------*/
171 uint8_t SEQ_BitPosition(uint32_t Value);
172
177 /* Functions Definition ------------------------------------------------------*/
178
182 void UTIL_SEQ_Init( void )
183 {
184 TaskSet = UTIL_SEQ_NO_BIT_SET;
185 TaskMask = UTIL_SEQ_ALL_BIT_SET;
186 SuperMask = UTIL_SEQ_ALL_BIT_SET;
187 EvtSet = UTIL_SEQ_NO_BIT_SET;
188 EvtWaited = UTIL_SEQ_NO_BIT_SET;
189 CurrentTaskIdx = 0U;
190 (void)UTIL_SEQ_MEMSET8((uint8_t *)TaskCb, 0, sizeof(TaskCb));
191 for(uint32_t index = 0; index < UTIL_SEQ_CONF_PRIO_NBR; index++)
192 {
193 TaskPrio[index].priority = 0;
194 TaskPrio[index].round_robin = 0;
195 }
196 UTIL_SEQ_INIT_CRITICAL_SECTION( );
197 }
198
199 void UTIL_SEQ_DeInit( void )
200 {
201 }
202
209 void UTIL_SEQ_Run( UTIL_SEQ_bm_t Mask_bm )
210 {
211 uint32_t counter;
212 UTIL_SEQ_bm_t current_task_set;
213 UTIL_SEQ_bm_t super_mask_backup;
214 UTIL_SEQ_bm_t local_taskset;
215 UTIL_SEQ_bm_t local_evtset;
216 UTIL_SEQ_bm_t local_taskmask;
217 UTIL_SEQ_bm_t local_evtwaited;
218
219 /*
220 * When this function is nested, the mask to be applied cannot be larger than the first call
221 * The mask is always getting smaller and smaller
222 * A copy is made of the mask set by UTIL_SEQ_Run() in case it is called again in the task
223 */
224 super_mask_backup = SuperMask;
225 SuperMask &= Mask_bm;
226
227 /*
228 * There are two independent mask to check:
229 * TaskMask that comes from UTIL_SEQ_PauseTask() / UTIL_SEQ_ResumeTask
230 * SuperMask that comes from UTIL_SEQ_Run
231 * If the waited event is there, exit from UTIL_SEQ_Run() to return to the
232 * waiting task
233 */
234 local_taskset = TaskSet;
235 local_evtset = EvtSet;
236 local_taskmask = TaskMask;
237 local_evtwaited = EvtWaited;
238 while(((local_taskset & local_taskmask & SuperMask) != 0U) && ((local_evtset & local_evtwaited)==0U))
239 {
240 counter = 0U;
241 /*
242 * When a flag is set, the associated bit is set in TaskPrio[counter].priority mask depending
243 * on the priority parameter given from UTIL_SEQ_SetTask()
244 * The while loop is looking for a flag set from the highest priority maskr to the lower
245 */
246 while((TaskPrio[counter].priority & local_taskmask & SuperMask)== 0U)
247 {
248 counter++;
249 }
250
251 current_task_set = TaskPrio[counter].priority & local_taskmask & SuperMask;
252
253 /*
254 * The round_robin register is a mask of allowed flags to be evaluated.
255 * The concept is to make sure that on each round on UTIL_SEQ_Run(), if two same flags are always set,
256 * the sequencer does not run always only the first one.
257 * When a task has been executed, The flag is removed from the round_robin mask.
258 * If on the next UTIL_SEQ_RUN(), the two same flags are set again, the round_robin mask will mask out the first flag
259 * so that the second one can be executed.
260 * Note that the first flag is not removed from the list of pending task but just masked by the round_robin mask
261 *
262 * In the check below, the round_robin mask is reinitialize in case all pending tasks haven been executed at least once
263 */
264 if ((TaskPrio[counter].round_robin & current_task_set) == 0U)
265 {
266 TaskPrio[counter].round_robin = UTIL_SEQ_ALL_BIT_SET;
267 }
268
269 /*
270 * Read the flag index of the task to be executed
271 * Once the index is read, the associated task will be executed even though a higher priority stack is requested
272 * before task execution.
273 */
274 CurrentTaskIdx = (SEQ_BitPosition(current_task_set & TaskPrio[counter].round_robin));
275
276 /*
277 * remove from the roun_robin mask the task that has been selected to be executed
278 */
279 TaskPrio[counter].round_robin &= ~(1U << CurrentTaskIdx);
280
281 UTIL_SEQ_ENTER_CRITICAL_SECTION( );
282 /* remove from the list or pending task the one that has been selected to be executed */
283 TaskSet &= ~(1U << CurrentTaskIdx);
284 /* remove from all priority mask the task that has been selected to be executed */
285 for (counter = UTIL_SEQ_CONF_PRIO_NBR; counter != 0U; counter--)
286 {
287 TaskPrio[counter - 1U].priority &= ~(1U << CurrentTaskIdx);
288 }
289 UTIL_SEQ_EXIT_CRITICAL_SECTION( );
290
291 /* Execute the task */
292 TaskCb[CurrentTaskIdx]( );
293
294 local_taskset = TaskSet;
295 local_evtset = EvtSet;
296 local_taskmask = TaskMask;
297 local_evtwaited = EvtWaited;
298 }
299
300 /* the set of CurrentTaskIdx to no task running allows to call WaitEvt in the Pre/Post ilde context */
301 CurrentTaskIdx = UTIL_SEQ_NOTASKRUNNING;
302 UTIL_SEQ_PreIdle( );
303
304 UTIL_SEQ_ENTER_CRITICAL_SECTION_IDLE( );
305 local_taskset = TaskSet;
306 local_evtset = EvtSet;
307 local_taskmask = TaskMask;
308 if ((local_taskset & local_taskmask & SuperMask) == 0U)
309 {
310 if ((local_evtset & EvtWaited)== 0U)
311 {
312 UTIL_SEQ_Idle( );
313 }
314 }
315 UTIL_SEQ_EXIT_CRITICAL_SECTION_IDLE( );
316
317 UTIL_SEQ_PostIdle( );
318
319 /* restore the mask from UTIL_SEQ_Run() */
320 SuperMask = super_mask_backup;
321
322 return;
323 }
324
325 void UTIL_SEQ_RegTask(UTIL_SEQ_bm_t TaskId_bm, uint32_t Flags, void (*Task)( void ))
326 {
327 (void)Flags;
328 UTIL_SEQ_ENTER_CRITICAL_SECTION();
329
330 TaskCb[SEQ_BitPosition(TaskId_bm)] = Task;
331
332 UTIL_SEQ_EXIT_CRITICAL_SECTION();
333
334 return;
335 }
336
337 void UTIL_SEQ_SetTask( UTIL_SEQ_bm_t TaskId_bm , uint32_t Task_Prio )
338 {
339 UTIL_SEQ_ENTER_CRITICAL_SECTION( );
340
341 TaskSet |= TaskId_bm;
342 TaskPrio[Task_Prio].priority |= TaskId_bm;
343
344 UTIL_SEQ_EXIT_CRITICAL_SECTION( );
345
346 return;
347 }
348
349 uint32_t UTIL_SEQ_IsSchedulableTask( UTIL_SEQ_bm_t TaskId_bm)
350 {
351 uint32_t _status;
352 UTIL_SEQ_bm_t local_taskset;
353
354 UTIL_SEQ_ENTER_CRITICAL_SECTION();
355
356 local_taskset = TaskSet;
357 _status = ((local_taskset & TaskMask & SuperMask & TaskId_bm) == TaskId_bm)? 1U: 0U;
358
359 UTIL_SEQ_EXIT_CRITICAL_SECTION();
360 return _status;
361 }
362
363 void UTIL_SEQ_PauseTask( UTIL_SEQ_bm_t TaskId_bm )
364 {
365 UTIL_SEQ_ENTER_CRITICAL_SECTION( );
366
367 TaskMask &= (~TaskId_bm);
368
369 UTIL_SEQ_EXIT_CRITICAL_SECTION( );
370
371 return;
372 }
373
374 uint32_t UTIL_SEQ_IsPauseTask( UTIL_SEQ_bm_t TaskId_bm )
375 {
376 uint32_t _status;
377 UTIL_SEQ_ENTER_CRITICAL_SECTION( );
378
379 _status = ((TaskMask & TaskId_bm) == TaskId_bm) ? 0u:1u;
380
381 UTIL_SEQ_EXIT_CRITICAL_SECTION( );
382 return _status;
383 }
384
385 void UTIL_SEQ_ResumeTask( UTIL_SEQ_bm_t TaskId_bm )
386 {
387 UTIL_SEQ_ENTER_CRITICAL_SECTION( );
388
389 TaskMask |= TaskId_bm;
390
391 UTIL_SEQ_EXIT_CRITICAL_SECTION( );
392
393 return;
394 }
395
396 void UTIL_SEQ_SetEvt( UTIL_SEQ_bm_t EvtId_bm )
397 {
398 UTIL_SEQ_ENTER_CRITICAL_SECTION( );
399
400 EvtSet |= EvtId_bm;
401
402 UTIL_SEQ_EXIT_CRITICAL_SECTION( );
403
404 return;
405 }
406
407 void UTIL_SEQ_ClrEvt( UTIL_SEQ_bm_t EvtId_bm )
408 {
409 UTIL_SEQ_ENTER_CRITICAL_SECTION( );
410
411 EvtSet &= (~EvtId_bm);
412
413 UTIL_SEQ_EXIT_CRITICAL_SECTION( );
414
415 return;
416 }
417
418 void UTIL_SEQ_WaitEvt(UTIL_SEQ_bm_t EvtId_bm)
419 {
420 UTIL_SEQ_bm_t event_waited_id_backup;
421 UTIL_SEQ_bm_t current_task_idx;
422 UTIL_SEQ_bm_t wait_task_idx;
423 /*
424 * store in local the current_task_id_bm as the global variable CurrentTaskIdx
425 * may be overwritten in case there are nested call of UTIL_SEQ_Run()
426 */
427 current_task_idx = CurrentTaskIdx;
428 if(UTIL_SEQ_NOTASKRUNNING == CurrentTaskIdx)
429 {
430 wait_task_idx = 0u;
431 }
432 else
433 {
434 wait_task_idx = (uint32_t)1u << CurrentTaskIdx;
435 }
436
437 /* backup the event id that was currently waited */
438 event_waited_id_backup = EvtWaited;
439 EvtWaited = EvtId_bm;
440 /*
441 * wait for the new event
442 * note: that means that if the previous waited event occurs, it will not exit
443 * the while loop below.
444 * The system is waiting only for the last waited event.
445 * When it will go out, it will wait again from the previous one.
446 * It case it occurs while waiting for the second one, the while loop will exit immediately
447 */
448
449 while ((EvtSet & EvtId_bm) == 0U)
450 {
451 UTIL_SEQ_EvtIdle(wait_task_idx, EvtId_bm);
452 }
453
454 /*
455 * Restore the CurrentTaskIdx that may have been modified by call of UTIL_SEQ_Run() from UTIL_SEQ_EvtIdle()
456 * This is required so that a second call of UTIL_SEQ_WaitEvt() in the same process pass the correct current_task_id_bm
457 * in the call of UTIL_SEQ_EvtIdle()
458 */
459 CurrentTaskIdx = current_task_idx;
460
461 UTIL_SEQ_ENTER_CRITICAL_SECTION( );
462
463 EvtSet &= (~EvtId_bm);
464
465 UTIL_SEQ_EXIT_CRITICAL_SECTION( );
466
467 EvtWaited = event_waited_id_backup;
468 return;
469 }
470
471 UTIL_SEQ_bm_t UTIL_SEQ_IsEvtPend( void )
472 {
473 UTIL_SEQ_bm_t local_evtwaited = EvtWaited;
474 return (EvtSet & local_evtwaited);
475 }
476
477 __WEAK void UTIL_SEQ_EvtIdle( UTIL_SEQ_bm_t TaskId_bm, UTIL_SEQ_bm_t EvtWaited_bm )
478 {
479 (void)EvtWaited_bm;
480 UTIL_SEQ_Run(~TaskId_bm);
481 return;
482 }
483
484 __WEAK void UTIL_SEQ_Idle( void )
485 {
486 return;
487 }
488
489 __WEAK void UTIL_SEQ_PreIdle( void )
490 {
491 /*
492 * Unless specified by the application, there is nothing to be done
493 */
494 return;
495 }
496
497 __WEAK void UTIL_SEQ_PostIdle( void )
498 {
499 /*
500 * Unless specified by the application, there is nothing to be done
501 */
502 return;
503 }
504
513 #if( __CORTEX_M == 0)
519 uint8_t SEQ_BitPosition(uint32_t Value)
520 {
521 static const uint8_t SEQ_clz_table_4bit[16] = { 4U, 3U, 2U, 2U, 1U, 1U, 1U, 1U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U };
522 uint8_t n = 0U;
523 uint32_t lvalue = Value;
524
525 if ((lvalue & 0xFFFF0000U) == 0U) { n = 16U; lvalue <<= 16U; }
526 if ((lvalue & 0xFF000000U) == 0U) { n += 8U; lvalue <<= 8U; }
527 if ((lvalue & 0xF0000000U) == 0U) { n += 4U; lvalue <<= 4U; }
528
529 n += SEQ_clz_table_4bit[lvalue >> (32-4)];
530
531 return (uint8_t)(31U-n);
532 }
533 #else
539 uint8_t SEQ_BitPosition(uint32_t Value)
540 {
541 return (uint8_t)(31 -__CLZ( Value ));
542 }
543 #endif
544
553 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
UTIL_SEQ_SetEvt
void UTIL_SEQ_SetEvt(UTIL_SEQ_bm_t EvtId_bm)
This function sets an event that is waited with UTIL_SEQ_WaitEvt()
Definition: stm32_seq.c:396
UTIL_SEQ_ClrEvt
void UTIL_SEQ_ClrEvt(UTIL_SEQ_bm_t EvtId_bm)
This function may be used to clear the event before calling UTIL_SEQ_WaitEvt() This API may be useful...
Definition: stm32_seq.c:407
UTIL_SEQ_WaitEvt
void UTIL_SEQ_WaitEvt(UTIL_SEQ_bm_t EvtId_bm)
This function waits for a specific event to be set. The sequencer loops UTIL_SEQ_EvtIdle() until the ...
Definition: stm32_seq.c:418
UTIL_SEQ_PreIdle
__WEAK void UTIL_SEQ_PreIdle(void)
This function is called by the sequencer outside critical section just before calling UTIL_SEQ_Idle( ...
Definition: stm32_seq.c:489
UTIL_SEQ_PostIdle
__WEAK void UTIL_SEQ_PostIdle(void)
This function is called by the sequencer outside critical section either.
Definition: stm32_seq.c:497
UTIL_SEQ_IsSchedulableTask
uint32_t UTIL_SEQ_IsSchedulableTask(UTIL_SEQ_bm_t TaskId_bm)
This function checks if a task could be scheduled.
Definition: stm32_seq.c:349
UTIL_SEQ_Idle
__WEAK void UTIL_SEQ_Idle(void)
This function is called by the sequencer in critical section (PRIMASK bit) when.
Definition: stm32_seq.c:484
UTIL_SEQ_SetTask
void UTIL_SEQ_SetTask(UTIL_SEQ_bm_t TaskId_bm, uint32_t Task_Prio)
This function requests a task to be executed.
Definition: stm32_seq.c:337
UTIL_SEQ_ResumeTask
void UTIL_SEQ_ResumeTask(UTIL_SEQ_bm_t TaskId_bm)
This function allows again a task to be called by the sequencer if set with UTIL_SEQ_SetTask() This i...
Definition: stm32_seq.c:385
UTIL_SEQ_EvtIdle
__WEAK void UTIL_SEQ_EvtIdle(UTIL_SEQ_bm_t TaskId_bm, UTIL_SEQ_bm_t EvtWaited_bm)
This function loops until the waited event is set.
Definition: stm32_seq.c:477
UTIL_SEQ_IsEvtPend
UTIL_SEQ_bm_t UTIL_SEQ_IsEvtPend(void)
This function returns whether the waited event is pending or not It is useful only when the UTIL_SEQ_...
Definition: stm32_seq.c:471
UTIL_SEQ_DeInit
void UTIL_SEQ_DeInit(void)
This function un-initializes the sequencer resources.
Definition: stm32_seq.c:199
UTIL_SEQ_IsPauseTask
uint32_t UTIL_SEQ_IsPauseTask(UTIL_SEQ_bm_t TaskId_bm)
This function allows to know if the task has been put in pause. By default, all tasks are executed by...
Definition: stm32_seq.c:374
UTIL_SEQ_PauseTask
void UTIL_SEQ_PauseTask(UTIL_SEQ_bm_t TaskId_bm)
This function prevents a task to be called by the sequencer even when set with UTIL_SEQ_SetTask() By ...
Definition: stm32_seq.c:363
UTIL_SEQ_RegTask
void UTIL_SEQ_RegTask(UTIL_SEQ_bm_t TaskId_bm, uint32_t Flags, void(*Task)(void))
This function registers a task in the sequencer.
Definition: stm32_seq.c:325
UTIL_SEQ_Run
void UTIL_SEQ_Run(UTIL_SEQ_bm_t Mask_bm)
This function requests the sequencer to execute all pending tasks using round robin mechanism....
Definition: stm32_seq.c:209
UTIL_SEQ_Init
void UTIL_SEQ_Init(void)
This function initializes the sequencer resources.
Definition: stm32_seq.c:182
UTIL_SEQ_bm_t
uint32_t UTIL_SEQ_bm_t
bit mapping of the task. this value is used to represent a list of task (each corresponds to a task).
Definition: stm32_seq.h:45
UTIL_SEQ_CONF_PRIO_NBR
#define UTIL_SEQ_CONF_PRIO_NBR
default value of priority number.
Definition: stm32_seq.c:103
UTIL_SEQ_ALL_BIT_SET
#define UTIL_SEQ_ALL_BIT_SET
define to represent all bits set inside uint32_t mapping
Definition: stm32_seq.c:86
UTIL_SEQ_EXIT_CRITICAL_SECTION_IDLE
#define UTIL_SEQ_EXIT_CRITICAL_SECTION_IDLE()
macro used to exit the critical section when exiting the IDLE function
Definition: stm32_seq.c:70
UTIL_SEQ_ENTER_CRITICAL_SECTION_IDLE
#define UTIL_SEQ_ENTER_CRITICAL_SECTION_IDLE()
macro used to enter the critical section before calling the IDLE function
Definition: stm32_seq.c:61
UTIL_SEQ_NOTASKRUNNING
#define UTIL_SEQ_NOTASKRUNNING
define to represent no task running
Definition: stm32_seq.c:76
UTIL_SEQ_CONF_TASK_NBR
#define UTIL_SEQ_CONF_TASK_NBR
default number of task is default 32 (maximum), can be reduced by redefining in utilities_conf....
Definition: stm32_seq.c:92
UTIL_SEQ_NO_BIT_SET
#define UTIL_SEQ_NO_BIT_SET
define to represent no bit set inside uint32_t mapping
Definition: stm32_seq.c:81
UTIL_SEQ_MEMSET8
#define UTIL_SEQ_MEMSET8(dest, value, size)
default memset function.
Definition: stm32_seq.c:110
SEQ_BitPosition
uint8_t SEQ_BitPosition(uint32_t Value)
return the position of the first bit set to 1
Definition: stm32_seq.c:519
stm32_seq.h
sequencer interface
UTIL_SEQ_Priority_t
structure used to manage task scheduling
Definition: stm32_seq.c:38
UTIL_SEQ_Priority_t::round_robin
uint32_t round_robin
Definition: stm32_seq.c:40
UTIL_SEQ_Priority_t::priority
uint32_t priority
Definition: stm32_seq.c:39