A context switch is a fundamental part of multitasking real-time operating systems like FreeRTOS. It allows multiple tasks to share a single CPU core while ensuring each task appears to have full and exclusive access to the CPU. When a context switch occurs, the state of the current task is saved and the state of the next task to run is restored. This allows seamless switching between tasks.
What Triggers a Context Switch in FreeRTOS?
There are several events that can trigger a context switch in FreeRTOS:
- Blocking API call – When a task makes a blocking API call like vTaskDelay(), it voluntarily gives up the CPU allowing a context switch to another ready task.
- Completion of task time slice – Each task has a pre-configured time slice. When the time allotted expires, a context switch occurs.
- Higher priority task becomes ready – If a currently running task is preempted due to a higher priority task becoming ready to run, a context switch will happen.
- Interrupt – Hardware interrupts and software interrupts like the PendSV exception will trigger a context switch.
- Mutex give – When a task gives a mutex, a context switch occurs if there is a higher priority task waiting for that mutex.
Context Switch Process
Here are the steps involved during a context switch in FreeRTOS:
- Save context of current task – Processor registers like stack pointer, program counter and other register contents are pushed onto the current task’s stack.
- Select next task to run – Based on priority, state and scheduler logic, the highest priority ready task is selected.
- Restore context of next task – Stored register contents are popped from the stack of new task and loaded into processor registers, restoring its context.
- Jump to next task – The program counter is updated to point to the next task’s code, starting its execution.
Detailed Context Switch Steps
Here is a more detailed look at what happens during each step of a context switch:
- Save Context
- Stack pointer (SP) is pushed onto current task’s stack
- Processor status register and other registers are pushed
- Critical section nesting value is stored
- Current task’s stack pointer is updated
- Select Next Task
- Scheduler algorithm selects highest priority ready task
- Selected task’s stack pointer is moved to processor’s stack pointer register
- Restore Context
- Saved registers and status are popped from new task’s stack
- New task’s critical section nesting value is loaded
- Stack pointer is restored from new task’s stack
- Jump to Next Task
- Program counter is set to resume new task’s code
- Execution begins for next task
Context Switch Time
The time required to perform a context switch is called context switch time or context switching overhead. It depends on:
- Number of registers that must be saved/restored – More registers mean higher overhead.
- Time to save/restore registers – Depends on processor architecture.
- Time taken by scheduler logic – Scheduler may require complex ready task searches.
- Task stack usage – Larger task stacks increase memory access time.
A typical context switch may take hundreds to thousands of clock cycles. Minimizing this time allows increased task parallelism.
Optimizing Context Switches
Here are some ways to optimize context switches in FreeRTOS:
- Minimize unnecessary context switching using features like idle hooks.
- Configure TIME_SLICING setting appropriately. Disable if response time is critical.
- Reduce number of registers saved/restored by optimal compiler settings.
- Use naked pragma to write context switch routines in assembly for faster saving/restoring.
- Assign priorities appropriately to avoid frequent preemption.
- Reduce task stack sizes to only what is needed.
- Tune tick interrupt frequency and clock speed for tradeoff with accuracy.
Context Switch vs Thread Switch
The main differences between a context switch and a thread switch are:
- Context switches can occur between tasks and ISRs. Thread switches only occur between threads.
- Context switches require saving/restoring processor registers and status. Thread switches only require a stack pointer swap.
- Context switches allow true parallelism on multi-core. Thread switches only allow pseudo-parallelism via time slicing on single core.
- Context switch overhead varies based on architecture and compiler. Thread switch overhead is low and consistent.
In summary, context switching is a fundamental mechanism to allow RTOS multitasking on single and multi-core processors. Understanding how it works helps optimize real-time performance.