NetBurner 3.5.6
PDF Version
Interval Timer

Functions

int IntervalOSSem (OS_SEM *p_toSem, int num_per_sec, int timer=FIRST_UNUSED_TIMER)
 Create a periodic timer that posts to an RTOS semaphore.
 
int IntervalOSFlag (OS_FLAGS *p_toFlag, uint32_t flag_value, int num_per_sec, int timer=FIRST_UNUSED_TIMER)
 Create a periodic timer that sets RTOS flags.
 
int IntervalInterruptCallback (void(*p_toCallbackFunc)(), int num_per_sec, int timer=FIRST_UNUSED_TIMER)
 Create a periodic timer that calls a function from interrupt context.
 
void IntervalStop (int timer_number)
 Stop and release an interval timer.
 

Detailed Description

#include< IntervalTimer.h>


The Interval Timer API provides hardware-based periodic interrupts for real-time applications. Unlike software timers, these use dedicated hardware timer peripherals to generate precise, low-jitter periodic events.

Features

Use Cases

Basic Usage - Semaphore Posting

// Create and initialize a semaphore
OS_SEM timerSem;
timerSem.Init();
// Create interval timer that posts 20 times per second
int timerNumber = IntervalOSSem(&timerSem, 20);
if (timerNumber < 0)
{
iprintf("Error creating interval timer: %d\r\n", timerNumber);
}
else
{
iprintf("Timer %d created successfully\n", timerNumber);
}
// Task waits for periodic semaphore posts
while (running)
{
timerSem.Pend(); // Blocks until timer posts (50ms intervals)
ProcessPeriodicData();
}
// Clean up when done
IntervalStop(timerNumber);
void IntervalStop(int timer_number)
Stop and release an interval timer.
int IntervalOSSem(OS_SEM *p_toSem, int num_per_sec, int timer=FIRST_UNUSED_TIMER)
Create a periodic timer that posts to an RTOS semaphore.

Advanced Usage - Multiple Timers with Different Rates

OS_SEM fastSem, slowSem;
fastSem.Init();
slowSem.Init();
// Fast sampling at 1000 Hz
int fastTimer = IntervalOSSem(&fastSem, 1000);
// Slow processing at 10 Hz
int slowTimer = IntervalOSSem(&slowSem, 10);
// Fast task
DWORD FastTask(void *pd)
{
while (1)
{
fastSem.Pend(); // Every 1ms
ReadSensors();
}
}
// Slow task
DWORD SlowTask(void *pd)
{
while (1)
{
slowSem.Pend(); // Every 100ms
UpdateDisplay();
}
}
// Cleanup
IntervalStop(fastTimer);
IntervalStop(slowTimer);

Interrupt Callback Usage

volatile uint32_t interruptCount = 0;
// Callback runs in interrupt context - keep it fast!
void TimerCallback()
{
interruptCount++;
// Toggle a GPIO pin
Pins[42].toggle();
}
// Setup 100 Hz callback
int timer = IntervalInterruptCallback(TimerCallback, 100);
// Main loop can monitor interrupt count
while (1)
{
OSTimeDly(TICKS_PER_SECOND);
iprintf("Interrupts per second: %lu\n", interruptCount);
interruptCount = 0;
}
IntervalStop(timer);
#define TICKS_PER_SECOND
System clock ticks per second.
Definition constants.h:49
int IntervalInterruptCallback(void(*p_toCallbackFunc)(), int num_per_sec, int timer=FIRST_UNUSED_TIMER)
Create a periodic timer that calls a function from interrupt context.

OS Flag Usage

OS_FLAGS controlFlags;
const uint32_t TIMER_EVENT = 0x0001;
const uint32_t OTHER_EVENT = 0x0002;
// Setup 50 Hz flag posting
int timer = IntervalOSFlag(&controlFlags, TIMER_EVENT, 50);
// Task waits for flags
while (running)
{
uint32_t flags = controlFlags.PendAll(TIMER_EVENT | OTHER_EVENT,
if (flags & TIMER_EVENT)
HandlePeriodicEvent();
if (flags & OTHER_EVENT)
HandleOtherEvent();
}
IntervalStop(timer);
int IntervalOSFlag(OS_FLAGS *p_toFlag, uint32_t flag_value, int num_per_sec, int timer=FIRST_UNUSED_TIMER)
Create a periodic timer that sets RTOS flags.

Important Considerations

Interrupt Context (for IntervalInterruptCallback)

Callback functions execute in interrupt context with the following restrictions:

Frequency Limitations

Timer Resources

Thread Safety

Performance Guidelines

Frequency Use Case Callback Execution Time
20-100 Hz Display updates, slow sensors < 100 us
100-1000 Hz Control loops, fast sampling < 10 us
1000+ Hz High-speed I/O, signal generation < 1 us

Error Codes

Best Practices

  1. Always check return values from Interval functions
  2. Call IntervalStop() when timer no longer needed to free resources
  3. Use semaphores for task sync rather than callbacks when possible
  4. Profile callback execution time to ensure it doesn't exceed period
  5. Avoid dynamic memory allocation in interrupt callbacks
  6. Use volatile for variables shared between interrupts and tasks
  7. Document timer usage in your code to track resource allocation

Common Pitfalls

See also
High Resolution Delay Timer For precise one-shot delays
Stopwatch Timer For measuring time intervals
OSTimeDly() For task-level delays

Function Documentation

◆ IntervalInterruptCallback()

int IntervalInterruptCallback ( void(* p_toCallbackFunc )(),
int num_per_sec,
int timer = FIRST_UNUSED_TIMER )

#include <IntervalTimer.h>

Create a periodic timer that calls a function from interrupt context.

Creates a hardware interval timer that calls the specified callback function at the requested frequency. The callback executes in interrupt context, providing the lowest possible latency and jitter for time-critical operations.

Use with extreme caution. Interrupt callbacks have strict requirements and restrictions. They are appropriate for simple, fast operations like toggling GPIO pins, reading sensors, or updating counters. For most periodic tasks, IntervalOSSem() or IntervalOSFlag() are safer and more appropriate choices.

When to Use Interrupt Callbacks

  • Time-critical operations requiring sub-millisecond response
  • Simple hardware I/O that must occur at precise intervals
  • Generating timing signals or PWM-like patterns
  • High-frequency data acquisition where task overhead is too high

When NOT to Use Interrupt Callbacks

  • Any operation that can be done from a task (use IntervalOSSem instead)
  • Operations requiring significant processing time
  • Code that needs to call blocking functions
  • Complex logic with multiple decision points

Interrupt Context Restrictions

Your callback function MUST NOT:

  • Call blocking functions (Pend(), OSTimeDly(), etc.)
  • Perform long computations (keep under 10 us at typical frequencies)
  • Call printf() or iprintf() (extremely slow)
  • Perform dynamic memory allocation
  • Access non-volatile shared data without proper synchronization
  • Call non-reentrant library functions

Your callback function SHOULD:

  • Complete as quickly as possible (microseconds, not milliseconds)
  • Use volatile for variables shared with tasks
  • Be reentrant and thread-safe
  • Use atomic operations for counters if possible
  • Post to semaphores/flags if triggering task work
Parameters
p_toCallbackFuncPointer to the callback function. Must have signature: void MyCallback(void). The function will be called from interrupt context at the specified frequency. Must remain valid (not be deleted) while timer is active.
num_per_secCallback frequency in Hz (calls per second). Valid range is 20 to platform-dependent maximum. Consider:
  • 20-100 Hz: Low-frequency periodic tasks
  • 100-1000 Hz: Control loops, moderate-speed sampling
  • 1000-10000 Hz: High-speed I/O, signal generation Higher frequencies require shorter execution times.
timerHardware timer number to use. Options:
  • FIRST_UNUSED_TIMER (default, -1): Automatically selects the first available hardware timer
  • 0, 1, 2, etc.: Specific timer number (platform-dependent) Use default unless you need specific timer for hardware reasons.
Returns
On success: Non-negative timer number (0, 1, 2, etc.) that identifies this interval timer. Save this value to pass to IntervalStop(). On failure:
  • -1: No hardware timer available (all timers in use)
  • -2: Invalid num_per_sec (less than 20 Hz)
Note
The callback executes at higher priority than all tasks and most interrupts.
Long callbacks can cause system instability by blocking other interrupts.
If callback execution time exceeds the timer period, interrupts will be missed.
Always call IntervalStop() when done to free the hardware timer resource.
Warning
Callbacks run with interrupts disabled for their priority level. Keep execution time minimal to avoid blocking other system functions.
Do not call any RTOS blocking functions from the callback. This will cause system crashes or undefined behavior.
The callback function pointer must remain valid. Do not use member functions or lambdas unless you understand their lifetime implications.

Example - Simple counter increment (safe):

volatile uint32_t interruptCount = 0;
void CounterCallback()
{
interruptCount++; // Fast, atomic on most platforms
}
void UserMain(void *pd)
{
init();
// Increment counter 1000 times per second
int timer = IntervalInterruptCallback(CounterCallback, 1000);
if (timer < 0)
{
iprintf("Timer creation failed: %d\n", timer);
return;
}
while (1)
{
OSTimeDly(TICKS_PER_SECOND);
uint32_t count = interruptCount; // Read volatile
iprintf("Interrupts per second: %lu\n", count);
interruptCount = 0;
}
}
void init()
System initialization. Ideally called at the beginning of all applications, since the easiest Recover...

Example - GPIO toggling for timing signal (safe):

void TogglePin()
{
Pins[42].toggle(); // Fast GPIO operation
}
// Create 1 kHz square wave on pin 42
int timer = IntervalInterruptCallback(TogglePin, 2000); // 2000 Hz = 1 kHz square wave

Example - ADC sampling with semaphore post (safe):

volatile uint16_t adcValue = 0;
OS_SEM processSem;
void SampleADC()
{
adcValue = ReadADCRegister(); // Fast hardware read
processSem.Post(); // Wake processing task
}
void Setup()
{
processSem.Init();
int timer = IntervalInterruptCallback(SampleADC, 1000); // 1 kHz sampling
}
void ProcessTask(void *pd)
{
while (1)
{
processSem.Pend();
uint16_t value = adcValue; // Read volatile
ProcessSample(value); // Complex processing in task context
}
}

Example - WRONG - Do not do this (unsafe):

void BadCallback()
{
// WRONG: printf is extremely slow (milliseconds)
iprintf("Timer fired\n"); // DON'T DO THIS!
// WRONG: Blocking call in interrupt context
OSTimeDly(1); // DON'T DO THIS!
// WRONG: Complex processing taking too long
for (int i = 0; i < 10000; i++)
ProcessData(); // DON'T DO THIS!
// WRONG: Dynamic memory allocation
char *buffer = new char[100]; // DON'T DO THIS!
}

Example - Measuring callback overhead:

volatile uint32_t maxCallbackTime = 0;
void MonitoredCallback()
{
uint32_t start = GetHighResTimer(); // Platform-specific
// Your time-critical code here
DoFastOperation();
uint32_t elapsed = GetHighResTimer() - start;
if (elapsed > maxCallbackTime)
maxCallbackTime = elapsed;
}
// In main loop, check maxCallbackTime to ensure it's acceptable

Example - Proper synchronization with tasks:

volatile uint32_t sensorValue = 0;
volatile bool newDataReady = false;
OS_SEM dataSem;
void SensorCallback()
{
// Read sensor quickly
sensorValue = ReadSensor();
newDataReady = true;
dataSem.Post(); // Signal task
}
void SensorTask(void *pd)
{
while (1)
{
dataSem.Pend();
if (newDataReady)
{
uint32_t value = sensorValue;
newDataReady = false;
// Process in task context (can be slow)
ProcessSensorData(value);
}
}
}
See also
IntervalStop()
IntervalOSSem()
IntervalOSFlag()

◆ IntervalOSFlag()

int IntervalOSFlag ( OS_FLAGS * p_toFlag,
uint32_t flag_value,
int num_per_sec,
int timer = FIRST_UNUSED_TIMER )

#include <IntervalTimer.h>

Create a periodic timer that sets RTOS flags.

Creates a hardware interval timer that sets the specified flag bit(s) in an OS_FLAGS object at the requested frequency. This is ideal for event notification where multiple event sources need to signal a single task, or when you need to distinguish between different types of periodic events.

Unlike semaphores which simply count posts, flags maintain distinct bit states allowing a task to wait on multiple different events simultaneously and determine which event(s) occurred.

Typical Usage Pattern

  1. Create an OS_FLAGS object
  2. Define flag bit values for different events
  3. Call IntervalOSFlag() to set specific flag bit(s) periodically
  4. Task(s) wait on flags using PendAll(), PendAny(), etc.
  5. Call IntervalStop() when timer is no longer needed
Parameters
p_toFlagPointer to an OS_FLAGS object. The flags object need not be initialized before use (has no Init() method). Must remain valid for the lifetime of the interval timer.
flag_valueThe flag bit(s) to set on each timer period. Can be a single bit (e.g., 0x0001) or multiple bits (e.g., 0x0003). Use bitwise OR to combine multiple flags. Bits are set, not toggled. Common patterns:
  • Single bit: 0x0001, 0x0002, 0x0004, 0x0008, etc.
  • Multiple bits: 0x0003 (bits 0 and 1), 0x000F (bits 0-3)
num_per_secFlag setting frequency in Hz (sets per second). Valid range is 20 to platform-dependent maximum (typically 10,000+). Higher frequencies increase CPU overhead. Common values:
  • 20-50 Hz: UI updates, slow polling
  • 100-500 Hz: Control system events
  • 1000+ Hz: High-speed event signaling
timerHardware timer number to use. Options:
  • FIRST_UNUSED_TIMER (default, -1): Automatically selects the first available hardware timer
  • 0, 1, 2, etc.: Specific timer number (platform-dependent) Use default unless you need specific timer for hardware reasons.
Returns
On success: Non-negative timer number (0, 1, 2, etc.) that identifies this interval timer. Save this value to pass to IntervalStop(). On failure:
  • -1: No hardware timer available (all timers in use)
  • -2: Invalid num_per_sec (less than 20 Hz)
Note
Flags are set (ORed), not cleared. If no task is pending on the flags, they will remain set until a task checks them.
Multiple interval timers can set different flags in the same OS_FLAGS object.
Use flag consumption mode (OSFlagPend with consume option) if you need to clear flags after reading.
Always call IntervalStop() when done to free the hardware timer resource.
Warning
Do not delete or let the flags object go out of scope while the timer is active. Call IntervalStop() first.

Example - Basic flag-based periodic event:

OS_FLAGS eventFlags;
const uint32_t TIMER_EVENT = 0x0001;
int timerNum;
void EventTask(void *pd)
{
// Set flag 50 times per second (20ms period)
timerNum = IntervalOSFlag(&eventFlags, TIMER_EVENT, 50);
if (timerNum < 0)
{
iprintf("Failed to create timer: %d\n", timerNum);
return;
}
while (1)
{
// Wait for timer flag, auto-clear on return
uint32_t flags = eventFlags.Pend(TIMER_EVENT, OS_FLAG_WAIT_SET_ALL);
// This runs exactly 50 times per second
PeriodicProcessing();
}
}

Example - Multiple periodic events with different rates:

OS_FLAGS systemFlags;
const uint32_t FAST_EVENT = 0x0001; // Bit 0
const uint32_t SLOW_EVENT = 0x0002; // Bit 1
int fastTimer, slowTimer;
void Setup()
{
// Fast event: 100 Hz
fastTimer = IntervalOSFlag(&systemFlags, FAST_EVENT, 100);
// Slow event: 10 Hz
slowTimer = IntervalOSFlag(&systemFlags, SLOW_EVENT, 10);
}
void ControlTask(void *pd)
{
while (1)
{
// Wait for either event
uint32_t flags = systemFlags.Pend(FAST_EVENT | SLOW_EVENT,
OS_FLAG_WAIT_SET_ANY |
OS_FLAG_CONSUME);
if (flags & FAST_EVENT)
{
FastProcessing(); // Runs every 10ms
}
if (flags & SLOW_EVENT)
{
SlowProcessing(); // Runs every 100ms
}
}
}
void Cleanup()
{
IntervalStop(fastTimer);
IntervalStop(slowTimer);
}

Example - Combining timer events with other events:

OS_FLAGS controlFlags;
const uint32_t TIMER_EVENT = 0x0001;
const uint32_t BUTTON_EVENT = 0x0002;
const uint32_t NETWORK_EVENT = 0x0004;
int timer = IntervalOSFlag(&controlFlags, TIMER_EVENT, 20);
// Other parts of code can set BUTTON_EVENT or NETWORK_EVENT
void ButtonISR()
{
controlFlags.Post(BUTTON_EVENT);
}
void StateMachine(void *pd)
{
while (1)
{
// Wait for any event
uint32_t events = controlFlags.Pend(TIMER_EVENT |
BUTTON_EVENT |
NETWORK_EVENT,
OS_FLAG_WAIT_SET_ANY |
OS_FLAG_CONSUME);
// Handle each event type
if (events & TIMER_EVENT)
HandlePeriodicUpdate();
if (events & BUTTON_EVENT)
HandleButtonPress();
if (events & NETWORK_EVENT)
HandleNetworkData();
}
}

Example - Watchdog pattern:

OS_FLAGS watchdogFlags;
const uint32_t WATCHDOG_FLAG = 0x0001;
const uint32_t TASK_ALIVE_FLAG = 0x0002;
int watchdogTimer = IntervalOSFlag(&watchdogFlags, WATCHDOG_FLAG, 1); // 1 Hz
void WatchdogTask(void *pd)
{
while (1)
{
uint32_t flags = watchdogFlags.Pend(WATCHDOG_FLAG,
OS_FLAG_WAIT_SET_ALL |
OS_FLAG_CONSUME,
if (flags & WATCHDOG_FLAG)
{
// Check if monitored task is alive
uint32_t status = watchdogFlags.Pend(TASK_ALIVE_FLAG,
OS_FLAG_WAIT_SET_ALL |
OS_FLAG_CONSUME,
0); // No wait
if (!(status & TASK_ALIVE_FLAG))
{
iprintf("ERROR: Monitored task not responding!\n");
HandleTaskFailure();
}
}
}
}
// Monitored task periodically sets its alive flag
void MonitoredTask(void *pd)
{
while (1)
{
DoWork();
watchdogFlags.Post(TASK_ALIVE_FLAG);
OSTimeDly(TICKS_PER_SECOND / 2);
}
}
See also
IntervalStop()
IntervalOSSem()
IntervalInterruptCallback()
OS_FLAGS

◆ IntervalOSSem()

int IntervalOSSem ( OS_SEM * p_toSem,
int num_per_sec,
int timer = FIRST_UNUSED_TIMER )

#include <IntervalTimer.h>

Create a periodic timer that posts to an RTOS semaphore.

Creates a hardware interval timer that posts to the specified semaphore at the requested frequency. This is the preferred method for periodic task synchronization, as it allows tasks to block efficiently on the semaphore while the hardware timer ensures precise timing.

The timer uses a hardware peripheral to generate periodic interrupts. Each interrupt posts to the semaphore, waking any task waiting on it. This provides low-jitter, precise periodic events for time-critical operations.

Typical Usage Pattern

  1. Create and initialize an OS_SEM
  2. Call IntervalOSSem() to start periodic posting
  3. Task(s) call Pend() on the semaphore to wait for each period
  4. Call IntervalStop() when timer is no longer needed
Parameters
p_toSemPointer to an initialized OS_SEM object. The semaphore must be initialized with Init() before passing to this function. Must remain valid for the lifetime of the interval timer.
num_per_secPosting frequency in Hz (posts per second). Valid range is 20 to platform-dependent maximum (typically 10,000+). Higher frequencies increase CPU overhead. Common values:
  • 20-50 Hz: UI updates, slow sensors
  • 100-500 Hz: Control loops, moderate sampling
  • 1000+ Hz: High-speed data acquisition
timerHardware timer number to use. Options:
  • FIRST_UNUSED_TIMER (default, -1): Automatically selects the first available hardware timer
  • 0, 1, 2, etc.: Specific timer number (platform-dependent) Use default unless you need specific timer for hardware reasons.
Returns
On success: Non-negative timer number (0, 1, 2, etc.) that identifies this interval timer. Save this value to pass to IntervalStop(). On failure:
  • -1: No hardware timer available (all timers in use)
  • -2: Invalid num_per_sec (less than 20 Hz)
Note
The semaphore counter will increment each period until a task calls Pend(). If no task is pending, posts accumulate (up to semaphore max count).
Multiple tasks can wait on the same semaphore. The RTOS will wake them according to priority and FIFO order.
Always call IntervalStop() when done to free the hardware timer resource.
Warning
Do not delete or let the semaphore go out of scope while the timer is active. Call IntervalStop() first.
Frequencies above 1000 Hz may consume significant CPU time. Profile your system to ensure adequate CPU remains for other tasks.

Example - Basic periodic task:

OS_SEM periodicSem;
int timerNum;
void PeriodicTask(void *pd)
{
periodicSem.Init();
// Post 100 times per second (10ms period)
timerNum = IntervalOSSem(&periodicSem, 100);
if (timerNum < 0)
{
iprintf("Failed to create timer: %d\n", timerNum);
return;
}
while (1)
{
// Wait for next period
periodicSem.Pend();
// This runs exactly 100 times per second
ProcessData();
}
}
// Cleanup function
void StopPeriodicTask()
{
if (timerNum >= 0)
IntervalStop(timerNum);
}

Example - Multiple tasks synchronized to one timer:

OS_SEM syncSem;
int timer;
void TaskA(void *pd)
{
while (1)
{
syncSem.Pend();
DoTaskAWork(); // Runs every 50ms
}
}
void TaskB(void *pd)
{
while (1)
{
syncSem.Pend();
DoTaskBWork(); // Also runs every 50ms
}
}
void UserMain(void *pd)
{
init();
syncSem.Init(0, 100); // Init with count 0, max 100
// 20 Hz timer (50ms period)
timer = IntervalOSSem(&syncSem, 20);
OSTaskCreate(TaskA, ...);
OSTaskCreate(TaskB, ...);
// Both tasks wake on each timer period
}

Example - Error handling:

OS_SEM sem;
sem.Init();
int timer = IntervalOSSem(&sem, 500);
switch (timer)
{
case -1:
iprintf("ERROR: No hardware timers available\n");
iprintf("Check for timer leaks - are you calling IntervalStop()?\n");
break;
case -2:
iprintf("ERROR: Invalid frequency (minimum 20 Hz)\n");
break;
default:
iprintf("Timer %d created successfully at 500 Hz\n", timer);
break;
}

Example - Timeout with periodic check:

OS_SEM checkSem;
checkSem.Init();
int timer = IntervalOSSem(&checkSem, 10); // Check 10 times/second
bool WaitForConditionWithTimeout(int timeoutSeconds)
{
int checks = timeoutSeconds * 10; // 10 checks per second
for (int i = 0; i < checks; i++)
{
checkSem.Pend();
if (ConditionMet())
{
IntervalStop(timer);
return true;
}
}
IntervalStop(timer);
return false; // Timeout
}
See also
IntervalStop()
IntervalOSFlag()
IntervalInterruptCallback()
OS_SEM

◆ IntervalStop()

void IntervalStop ( int timer_number)

#include <IntervalTimer.h>

Stop and release an interval timer.

Stops the specified interval timer and frees the associated hardware timer resource, making it available for reuse. After calling this function, the timer will no longer generate interrupts, post to semaphores, set flags, or call callbacks.

Always call this function when you no longer need an interval timer. Failing to stop timers causes resource leaks, eventually exhausting the limited number of hardware timers available on the platform.

This function is safe to call from any context (task or interrupt) and is safe to call multiple times on the same timer number (subsequent calls have no effect).

When to Call IntervalStop()

  • When your application no longer needs periodic events
  • Before re-configuring a timer with different parameters
  • In cleanup code before task termination
  • When switching between different operational modes
  • Before system shutdown or reset

Resource Management Pattern

// Setup
int timer = IntervalOSSem(...);
if (timer >= 0)
{
// Use timer
...
// Cleanup
IntervalStop(timer);
}
Parameters
timer_numberThe timer number returned by IntervalOSSem(), IntervalOSFlag(), or IntervalInterruptCallback(). Valid timer numbers are non-negative integers (0, 1, 2, etc.). Negative values are ignored (function returns immediately).
Note
After stopping, the timer number becomes invalid and should not be reused.
For IntervalOSSem(), pending semaphore posts are preserved - the semaphore counter is not cleared by stopping the timer.
For IntervalOSFlag(), flags remain in their current state - they are not cleared by stopping the timer.
For IntervalInterruptCallback(), the callback will not be called again after this function returns, but you must ensure the callback function itself remains valid if it was mid-execution.
This function is thread-safe and can be called from any task or interrupt.
It is safe to call IntervalStop() with an invalid or already-stopped timer number - the function will simply return without error.

Example - Basic cleanup:

OS_SEM timerSem;
int timer;
void StartPeriodicTask()
{
timerSem.Init();
timer = IntervalOSSem(&timerSem, 100);
}
void StopPeriodicTask()
{
if (timer >= 0)
{
IntervalStop(timer);
timer = -1; // Mark as stopped
}
}

Example - RAII-style resource management:

class PeriodicTask
{
private:
OS_SEM sem;
int timerNum;
public:
PeriodicTask(int hz) : timerNum(-1)
{
sem.Init();
timerNum = IntervalOSSem(&sem, hz);
}
~PeriodicTask()
{
if (timerNum >= 0)
IntervalStop(timerNum);
}
void WaitForPeriod()
{
sem.Pend();
}
};
void UsePeriodicTask()
{
PeriodicTask task(50); // 50 Hz
while (running)
{
task.WaitForPeriod();
DoWork();
}
// Timer automatically stopped when task goes out of scope
}

Example - Multiple timers management:

#define MAX_TIMERS 4
int activeTimers[MAX_TIMERS];
int timerCount = 0;
int CreateTimer(...)
{
int timer = IntervalOSSem(...);
if (timer >= 0 && timerCount < MAX_TIMERS)
{
activeTimers[timerCount++] = timer;
}
return timer;
}
void StopAllTimers()
{
for (int i = 0; i < timerCount; i++)
{
IntervalStop(activeTimers[i]);
}
timerCount = 0;
}

Example - Mode switching:

int currentTimer = -1;
void SwitchToFastMode()
{
// Stop old timer if active
if (currentTimer >= 0)
IntervalStop(currentTimer);
// Start new timer at higher frequency
currentTimer = IntervalOSSem(&sem, 1000); // 1 kHz
}
void SwitchToSlowMode()
{
if (currentTimer >= 0)
IntervalStop(currentTimer);
currentTimer = IntervalOSSem(&sem, 10); // 10 Hz
}

Example - Safe shutdown:

volatile bool shutdownRequested = false;
int timer = -1;
void PeriodicTask(void *pd)
{
OS_SEM sem;
sem.Init();
timer = IntervalOSSem(&sem, 100);
if (timer < 0)
{
iprintf("Timer creation failed\n");
return;
}
while (!shutdownRequested)
{
sem.Pend();
DoWork();
}
// Clean shutdown
IntervalStop(timer);
timer = -1;
iprintf("Task shutdown complete\n");
}
void RequestShutdown()
{
shutdownRequested = true;
// Timer will be stopped by the task itself
}

Example - Error recovery:

int timer = -1;
bool RecoverFromError()
{
// Stop old timer if it exists
if (timer >= 0)
{
IntervalStop(timer);
timer = -1;
}
// Try to restart
timer = IntervalOSSem(&sem, 100);
if (timer < 0)
{
iprintf("Recovery failed - no timers available\n");
return false;
}
iprintf("Recovery successful - timer %d\n", timer);
return true;
}
See also
IntervalOSSem()
IntervalOSFlag()
IntervalInterruptCallback()