SoC
  • Home
  • Arm
  • Arm Cortex M0/M0+
  • Arm Cortex M4
  • Arm Cortex M3
  • Contact
Reading: Implementing a Round-Robin Scheduler on Cortex-M
SUBSCRIBE
SoCSoC
Font ResizerAa
  • Home
  • Arm
  • Arm Cortex M0/M0+
  • Arm Cortex M4
Search
  • Home
  • Arm
  • Arm Cortex M0/M0+
  • Arm Cortex M4
Have an existing account? Sign In
Follow US
  • Looking for Something?
  • Privacy Policy
  • About Us
  • Sitemap
  • Contact Us
© S-O-C.ORG, All Rights Reserved.
Arm

Implementing a Round-Robin Scheduler on Cortex-M

Holly Lindsey
Last updated: September 22, 2023 11:49 am
Holly Lindsey 5 Min Read
Share
SHARE

A round-robin scheduler is a scheduling algorithm that sequentially cycles through a list of tasks, giving each task a slice of time to execute before moving on to the next task. Implementing a round-robin scheduler on Cortex-M microcontrollers can provide predictable multitasking capabilities for real-time embedded applications.

Contents
Overview of Round-Robin SchedulingChallenges on Cortex-MScheduler ImplementationTask StructureTask QueueContext SwitchingPreemption TimerScheduler LoopOptimizationsExample CodeConclusion

Overview of Round-Robin Scheduling

The key features of round-robin scheduling are:

  • Tasks are organized in a queue data structure
  • Scheduler cycles through the queue, executing each task for a pre-defined time slice
  • After a task’s time slice expires, it is preempted and moved to the back of the queue
  • Scheduler continues cycling through tasks indefinitely

This ensures that all tasks get equal access to the CPU at regular intervals. The time slice duration is an important parameter that impacts responsiveness and context switching overhead.

Challenges on Cortex-M

Implementing round-robin scheduling on Cortex-M poses some challenges:

  • No built-in scheduler – Cortex-M CPUs have no native scheduling hardware
  • Manual context switching – scheduler must save/restore context when preempting tasks
  • Timers for preemption – need periodic interrupts to trigger preemptions
  • Fixed priority levels – Cortex-M NVIC has fixed interrupt priorities

These factors mean the scheduler must be implemented fully in software. Care must be taken to minimize context switching overhead and maintain deterministic behavior.

Scheduler Implementation

Here is one approach to implementing a round-robin scheduler on Cortex-M:

Task Structure

Each task is defined with a structure containing:

  • Task function pointer
  • Task arguments
  • Task stack pointer
  • Task stack size
  • Task priority

Task Queue

A queue data structure stores the list of tasks to be scheduled. New tasks are added to the back of the queue.

Context Switching

Manually save context (registers, stack pointer) of old task and restore context of new task on preemptions.

Preemption Timer

A periodic SysTick timer triggers an interrupt handler at the end of each time slice to force a context switch.

Scheduler Loop

Main scheduler loop runs the highest priority ready task. It yields to the preemption handler at each time slice.

Optimizations

Some optimizations can improve performance and determinism:

  • Use dedicated stack per task to simplify context switching
  • Adjust time slice duration to balance responsiveness and overhead
  • Consider task priorities when ordering queue
  • Use compiler intrinsics for context switching for speed
  • Configure preemption timer in Cortex-M systick

Example Code

Here is some example pseudo-code to illustrate the implementation: // Task structure struct task { void (*function)(void*); void* args; char* stack; int priority; }; // Task queue task_t tasks[MAX_TASKS]; int head, tail; // Current running task task_t* current; // Scheduler initialization void scheduler_init() { // Setup systick for preemption timer // … // Initialize task queue head = tail = 0; } // Add task to scheduler void scheduler_add(task_t* task) { tasks[tail] = task; tail++; } // Context switching void switch_context(task_t* next) { // Save context of old task // Restore context of next task } // Preemption handler void preempt_handler() { task_t* next = tasks[head]; switch_context(next); head++; if (head >= MAX_TASKS) { head = 0; } } // Scheduler loop void scheduler_run() { while (1) { task_t* next = tasks[head]; switch_context(next); next->function(next->args); // Yield to preemption handler preempt_handler(); } }

This demonstrates the key steps of queueing tasks, timer-based preemption, context switching, and running the scheduler loop. Real implementations would also need to handle task completion, task priorities, and other features.

Conclusion

Implementing a round-robin scheduler on Cortex-M requires careful software design due to the lack of hardware scheduling support. With an efficient preemption timer, optimized context switching, and a well-structured task queue, real-time multitasking can be achieved. The result is a fair and deterministic scheduling mechanism suitable for many embedded applications.

Newsletter Form (#3)

More ARM insights right in your inbox

 


Share This Article
Facebook Twitter Email Copy Link Print
Previous Article Cortex-M Exception Handling and Return Mechanism
Next Article Stack Frame Layout During Cortex-M Interrupts
Leave a comment Leave a comment

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

2k Followers Like
3k Followers Follow
10.1k Followers Pin
- Sponsored-
Ad image

You Might Also Like

Is Arm Cortex-M4 RISC or CISC?

The Arm Cortex-M4 processor is a 32-bit RISC CPU that…

7 Min Read

Arm Cortex Comparison

The ARM Cortex series of processors are widely used in…

7 Min Read

What is ARM Cortex-M1?

The ARM Cortex-M1 processor is a 32-bit reduced instruction set…

7 Min Read

How much memory does the Cortex-M7 have?

The Cortex-M7 is a high-performance microcontroller (MCU) core designed by…

9 Min Read
SoCSoC
  • Looking for Something?
  • Privacy Policy
  • About Us
  • Sitemap
  • Contact Us
Welcome Back!

Sign in to your account