How To Use

Use the Sequencer as follows:

1. Selecting Files

Add the following source and header files to the project:

  • Core (mandatory): sequencer.c and sequencer.h

  • Configuration (optional): seq_user_conf.h (if SEQ_USER_CONFIG is defined)

Required files with default configuration:

/Required files
        ├─ Core/
        │   ├─ sequencer.c
        └─  └─ sequencer.h

Required files with user configuration:

/Required files
        ├─ Core/
        │   ├─ sequencer.c
        │   └─ sequencer.h
        ├─ Config/
        └─  └─ seq_user_conf.h  (if ``SEQ_USER_CONFIG`` is defined, copy this file from template and adapt it)

2. Configuration

2.1. Optional Configuration

Enable the custom configuration header by defining SEQ_USER_CONFIG in the preprocessor options. Copy the template header and adapt it as needed.

The following table summarizes the configurable items in the optional user configuration header seq_user_conf.h:

Config Item

Description

Default Value

Max Value

Min Value

SEQ_CONF_TASK_NBR

Number of task bits

32

32

1

SEQ_CONF_PRIO_NBR

Priority levels (index 0 is highest)

2

32

1

SEQ_ENTER_CRITICAL_SECTION

Macro to enter the critical section

uint32_t primask_bit = __get_PRIMASK( ); __disable_irq( )

N/A

N/A

SEQ_EXIT_CRITICAL_SECTION

Macro to exit the critical section

__set_PRIMASK( primask_bit )

N/A

N/A

SEQ_ENTER_CRITICAL_SECTION_IDLE

Macro to enter the critical section in idle

uint32_t primask_bit = __get_PRIMASK( ); __disable_irq( )

N/A

N/A

SEQ_EXIT_CRITICAL_SECTION_IDLE

Macro to exit the critical section in idle

__set_PRIMASK( primask_bit )

N/A

N/A

SEQ_MEMSET8(dest, value, size)

Macro to fill memory with an 8-bit value

Standard C implementation: memset((dest),(value),(size))

N/A

N/A

Example minimal custom header:

/* Reduce task count to 8 for small app */
#define SEQ_CONF_TASK_NBR   (8U)
/* Two priority levels (0 high / 1 low) */
#define SEQ_CONF_PRIO_NBR   (2U)

/* Simple critical section (disable global IRQ) */
#define SEQ_ENTER_CRITICAL_SECTION()   uint32_t primask_bit = __get_PRIMASK(); __disable_irq()
#define SEQ_EXIT_CRITICAL_SECTION()    __set_PRIMASK(primask_bit)

#define SEQ_ENTER_CRITICAL_SECTION_IDLE()  SEQ_ENTER_CRITICAL_SECTION()
#define SEQ_EXIT_CRITICAL_SECTION_IDLE()   SEQ_EXIT_CRITICAL_SECTION()

3. Sequencer Initialization

Call SEQ_Init() once after the basic hardware initialization and before scheduling tasks.

SEQ_Init();   /* Initialize the Sequencer */

4. Sequencer Usage

After initialization, the following steps are required to use the Sequencer:

  • Define a task function (void (*task)(void)).

  • Register the task in the Sequencer with its ID.

  • Activate the task to make it executable.

  • Start task scheduling by calling SEQ_Run() in the main loop.

The Sequencer is non-preemptive: each task must return control quickly to allow other tasks to be scheduled.

Two task patterns are commonly used: single-action tasks and state-machine tasks.

  • Single-action task: performs a simple action and then returns.

void Task1(void)
{
    /* Perform a simple action */
}
  • State-machine task: advances one step per invocation while maintaining internal state.

void Task2(void)
{
   static uint32_t state = 0;

   switch (state)
   {
      case 0:
        /* Initial actions */
        state = 1;
        break;
      case 1:
        /* Second actions */
        state = 2;
        break;
      case 2:
        /* Final actions */
        state = 0;
        break;
   }

   /* Ready for next step */
   SEQ_SetTask(SEQ_TASK2_ID, 0);
}

Register each task with an ID bit and a callback function.

SEQ_RegTask(SEQ_TASK1_ID, SEQ_RFU, Task1);   /* Register Task1 in the Sequencer */

To schedule work, set the task bit with a priority index (0 = highest):

SEQ_SetTask(SEQ_TASK1_ID, 0);   /* Task1 ready */

Call SEQ_Run() inside the infinite loop.

while (1)
{
  /* Start scheduling */
  SEQ_Run(~0);
}