Bird
Raised Fist0
FreeRTOSprogramming~10 mins

Timer callback execution context in FreeRTOS - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Timer callback execution context
Timer expires
↓
Timer ISR triggers
↓
Timer callback queued to Timer Service Task
↓
Timer Service Task runs callback
↓
Callback executes in Timer Service Task context
↓
Callback completes
↓
Timer Service Task waits for next event
When a FreeRTOS timer expires, its callback is not run in interrupt context but deferred to the Timer Service Task, which executes the callback in its own task context.
Execution Sample
FreeRTOS
void vTimerCallback(TimerHandle_t xTimer) {
    // This runs in Timer Service Task context
    printf("Timer callback running\n");
}

// Timer created and started elsewhere
This code shows a timer callback function that runs in the Timer Service Task context when the timer expires.
Execution Table
StepEventContextActionOutput
1Timer expiresInterruptTimer ISR triggersNo output, ISR queues callback
2Callback queuedInterruptTimer callback queued to Timer Service TaskNo output
3Timer Service Task runsTimer Service TaskCallback function startsPrints: Timer callback running
4Callback completesTimer Service TaskCallback function endsNo output
5Wait for next eventTimer Service TaskTask blocks waitingNo output
💡 Callback completes and Timer Service Task waits for next timer event
Variable Tracker
VariableStartAfter Step 1After Step 2After Step 3Final
Timer ISR FlagFalseTrueTrueFalseFalse
Callback QueuedFalseFalseTrueTrueFalse
Callback RunningFalseFalseFalseTrueFalse
Key Moments - 3 Insights
Why doesn't the timer callback run directly inside the interrupt?
Because the callback runs in the Timer Service Task context, not interrupt context, to avoid long ISR execution and allow safe API calls. See execution_table step 3 where callback runs in task context.
What context does the timer callback run in?
The callback runs in the Timer Service Task context, as shown in execution_table step 3, not in the interrupt context.
What happens if the callback takes too long to run?
It blocks the Timer Service Task, delaying other timer callbacks. This is why callbacks should be short and non-blocking, as implied by the flow in concept_flow.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table, at which step does the timer callback actually start running?
AStep 3
BStep 2
CStep 1
DStep 4
💡 Hint
Check the 'Action' and 'Context' columns in execution_table rows to see when callback starts
According to variable_tracker, when does 'Callback Queued' become true?
AAfter Step 1
BAfter Step 2
CAfter Step 3
DAt Start
💡 Hint
Look at the 'Callback Queued' row and see when it changes from False to True
If the callback ran inside the interrupt, which step would be missing from execution_table?
AStep 1
BStep 3
CStep 2
DStep 5
💡 Hint
Step 2 shows queuing callback to Timer Service Task, which wouldn't happen if callback ran in ISR
Concept Snapshot
FreeRTOS timers run callbacks in Timer Service Task context.
Timer ISR only queues the callback.
Callback runs later in a dedicated task.
This avoids long ISR execution.
Callbacks should be short and non-blocking.
Use Timer Service Task context to safely call FreeRTOS APIs.
Full Transcript
In FreeRTOS, when a timer expires, an interrupt triggers but does not run the callback directly. Instead, the interrupt queues the callback to the Timer Service Task. The Timer Service Task then runs the callback function in its own task context. This design prevents long interrupt routines and allows safe use of FreeRTOS APIs inside the callback. The execution table shows the steps from timer expiry, ISR queuing, callback execution, and waiting for the next event. Variables track the state changes of the ISR flag, callback queuing, and callback running. Key moments clarify why callbacks run in task context and not interrupt context. The visual quiz tests understanding of when and where the callback runs. The snapshot summarizes the key points for quick reference.

Practice

(1/5)
1. In FreeRTOS, where does a timer callback function execute when a timer expires?
easy
A. Inside the main application task context
B. Inside an interrupt service routine (ISR)
C. Inside the timer service task context
D. Inside a hardware timer peripheral

Solution

  1. Step 1: Understand timer callback execution

    Timer callbacks in FreeRTOS run when the timer expires, but not in the main task or ISR context.
  2. Step 2: Identify the correct context

    The timer callback runs inside the timer service task context, which is a dedicated task for handling timers.
  3. Final Answer:

    Inside the timer service task context -> Option C
  4. Quick Check:

    Timer callback context = timer service task [OK]
Hint: Timer callbacks run in timer service task, not main or ISR [OK]
Common Mistakes:
  • Thinking timer callbacks run in ISR context
  • Assuming callbacks run in main application task
  • Confusing hardware timer peripheral with callback context
2. Which of the following is the correct way to define a FreeRTOS timer callback function?
easy
A. void TimerCallback(TimerHandle_t xTimer)
B. void TimerCallback(void)
C. int TimerCallback(int timerId)
D. void TimerCallback(void *param)

Solution

  1. Step 1: Recall FreeRTOS timer callback signature

    The callback function must accept a TimerHandle_t parameter representing the timer.
  2. Step 2: Match the correct function signature

    Only the signature with void TimerCallback(TimerHandle_t xTimer) matches FreeRTOS requirements.
  3. Final Answer:

    void TimerCallback(TimerHandle_t xTimer) -> Option A
  4. Quick Check:

    Callback signature = void func(TimerHandle_t) [OK]
Hint: Timer callbacks take TimerHandle_t parameter only [OK]
Common Mistakes:
  • Using no parameters in callback
  • Using void* or int instead of TimerHandle_t
  • Returning int instead of void
3. Given the following code snippet, what will be printed when the timer expires?
void vTimerCallback(TimerHandle_t xTimer) {
    printf("Timer expired\n");
}

int main() {
    TimerHandle_t xTimer = xTimerCreate("Timer", pdMS_TO_TICKS(1000), pdFALSE, NULL, vTimerCallback);
    xTimerStart(xTimer, 0);
    vTaskDelay(pdMS_TO_TICKS(1500));
    return 0;
}
medium
A. Timer expired
B. No output
C. Compilation error
D. Runtime error

Solution

  1. Step 1: Analyze timer creation and start

    The timer is created with 1 second period, one-shot, and started, but vTaskStartScheduler() is missing.
  2. Step 2: Check scheduler requirement

    FreeRTOS timers require the scheduler (and timer service task) to be running via vTaskStartScheduler(); without it, the callback never executes, producing no output.
  3. Final Answer:

    No output -> Option B
  4. Quick Check:

    Missing vTaskStartScheduler() = no callback execution [OK]
Hint: FreeRTOS timers require vTaskStartScheduler() [OK]
Common Mistakes:
  • Assuming scheduler starts automatically
  • Thinking timer expires without scheduler running
  • Believing vTaskDelay alone allows callback execution
4. Identify the problem in this timer callback code snippet:
void vTimerCallback(TimerHandle_t xTimer) {
    vTaskDelay(pdMS_TO_TICKS(100));
    printf("Timer callback done\n");
}
medium
A. Using vTaskDelay inside timer callback blocks timer service task
B. Missing return statement in callback
C. Incorrect parameter type in callback
D. printf cannot be used in timer callbacks

Solution

  1. Step 1: Understand timer callback context

    Timer callbacks run inside the timer service task, which handles all timers sequentially.
  2. Step 2: Analyze use of vTaskDelay in callback

    Calling vTaskDelay blocks the timer service task, delaying other timers and causing timing issues.
  3. Final Answer:

    Using vTaskDelay inside timer callback blocks timer service task -> Option A
  4. Quick Check:

    Blocking calls in timer callback delay all timers [OK]
Hint: Never block or delay inside timer callbacks [OK]
Common Mistakes:
  • Thinking callbacks can safely block or delay
  • Assuming missing return causes error
  • Believing printf is disallowed in callbacks
5. You want to toggle an LED every 500ms using a FreeRTOS timer. Which approach correctly uses the timer callback without blocking the timer service task?
void vTimerCallback(TimerHandle_t xTimer) {
    // Option 1
    // vTaskDelay(pdMS_TO_TICKS(100));
    // toggleLED();

    // Option 2
    toggleLED();
}

int main() {
    TimerHandle_t xTimer = xTimerCreate("LEDTimer", pdMS_TO_TICKS(500), pdTRUE, NULL, vTimerCallback);
    xTimerStart(xTimer, 0);
    vTaskStartScheduler();
    return 0;
}
hard
A. Use Option 1 with vTaskDelay inside callback
B. Call toggleLED from main task instead of timer
C. Use a blocking delay in main before starting timer
D. Use Option 2 with direct toggleLED call in callback

Solution

  1. Step 1: Review timer callback best practices

    Timer callbacks should be short and non-blocking to avoid delaying other timers.
  2. Step 2: Evaluate options for toggling LED

    Option 1 uses vTaskDelay inside callback, which blocks timer service task. Option 2 calls toggleLED directly without delay, which is correct.
  3. Final Answer:

    Use Option 2 with direct toggleLED call in callback -> Option D
  4. Quick Check:

    Non-blocking callback = direct toggleLED call [OK]
Hint: Keep timer callbacks short and non-blocking [OK]
Common Mistakes:
  • Adding delays inside timer callbacks
  • Trying to toggle LED outside timer context
  • Blocking main task instead of using timer
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard