Data Structure Defintiion
#define MAX_TIMER_SLOTS 4 /* Total number of software timers (IDs 0 to 3) */
typedef enum {
MODE_SINGLE_RUN = 0, /* Executes only once */
MODE_CONTINUOUS_RUN = 1 /* Repeats automatically */
} TimerRunMode;
/* Timer context structure. Members must be declared volatile since they are
accessed concurrently by the ISR and the main application loop,
preventing compiler optimizations from causing inconsistencies. */
typedef struct {
volatile TimerRunMode runMode; /* Timer operating mode */
volatile uint8_t elapsed; /* Expiration flag */
volatile uint32_t ticksRemaining; /* Current countdown value */
volatile uint32_t resetValue; /* Reload value for continuous mode */
} TimerContext;
static TimerContext timerPool[MAX_TIMER_SLOTS];
Initialization
void Timers_Initialize(void) {
for (uint8_t idx = 0; idx < MAX_TIMER_SLOTS; idx++) {
timerPool[idx].ticksRemaining = 0;
timerPool[idx].resetValue = 0;
timerPool[idx].elapsed = 0;
timerPool[idx].runMode = MODE_SINGLE_RUN; /* Default to one-shot mode */
}
/* Configure SysTick to trigger an interrupt every 1ms.
SystemCoreClock represents the core clock frequency (e.g., 400MHz for STM32H7).
SystemCoreClock / 1000 yields a 1000Hz interrupt rate (1ms period). */
SysTick_Config(SystemCoreClock / 1000);
}
One-Shot Timer Activation
bool Timer_StartOneShot(uint8_t slotId, uint32_t duration) {
if (slotId >= MAX_TIMER_SLOTS) {
return false; /* Invalid ID */
}
ENTER_CRITICAL(); /* Disable interrupts to protect shared data */
timerPool[slotId].ticksRemaining = duration;
timerPool[slotId].resetValue = duration; /* Only relevant for continuous mode */
timerPool[slotId].elapsed = 0;
timerPool[slotId].runMode = MODE_SINGLE_RUN;
EXIT_CRITICAL(); /* Re-enable interrupts */
return true;
}
Periodic Timer Activatoin
bool Timer_StartPeriodic(uint8_t slotId, uint32_t interval) {
if (slotId >= MAX_TIMER_SLOTS) {
return false;
}
ENTER_CRITICAL();
timerPool[slotId].ticksRemaining = interval;
timerPool[slotId].resetValue = interval;
timerPool[slotId].elapsed = 0;
timerPool[slotId].runMode = MODE_CONTINUOUS_RUN;
EXIT_CRITICAL();
return true;
}
Timer Deactivation
void Timer_Deactivate(uint8_t slotId) {
if (slotId >= MAX_TIMER_SLOTS) {
return; /* Invalid ID, safely ignored */
}
ENTER_CRITICAL();
timerPool[slotId].ticksRemaining = 0;
timerPool[slotId].elapsed = 0;
timerPool[slotId].runMode = MODE_SINGLE_RUN;
EXIT_CRITICAL();
}
Expiration Check
bool Timer_HasElapsed(uint8_t slotId) {
if (slotId >= MAX_TIMER_SLOTS) {
return false;
}
if (timerPool[slotId].elapsed) {
timerPool[slotId].elapsed = 0; /* Clear flag upon read */
return true;
}
return false;
}
SysTick Interrupt Handler
static void DecrementTimerTicks(TimerContext *ctx) {
if (ctx->ticksRemaining > 0) {
ctx->ticksRemaining--;
if (ctx->ticksRemaining == 0) {
ctx->elapsed = 1;
if (ctx->runMode == MODE_CONTINUOUS_RUN) {
ctx->ticksRemaining = ctx->resetValue;
}
}
}
}
void SysTick_IRQHandler(void) {
for (uint8_t idx = 0; idx < MAX_TIMER_SLOTS; idx++) {
DecrementTimerTicks(&timerPool[idx]);
}
}