From 48ec9d3d822a13ba97e884d0692d98cff484a436 Mon Sep 17 00:00:00 2001 From: Nikolay Pokhilchenko Date: Wed, 2 Sep 2026 17:40:52 +0300 Subject: [PATCH 1/9] Create 05-FeeRTOS-Porting-Notes.md New chapter for porting notes for peoples making the support of new devices --- .../02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md diff --git a/content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md b/content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md @@ -0,0 +1 @@ + From 206c885e98c1d5a3641036cedd56da76e79f1ad6 Mon Sep 17 00:00:00 2001 From: Nikolay Pokhilchenko Date: Wed, 2 Sep 2026 17:50:07 +0300 Subject: [PATCH 2/9] Update 01-FreeRTOS-porting-guide.md Added a link to FreeRTOS Porting Notes page --- .../02-Kernel/03-Supported-devices/01-FreeRTOS-porting-guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en-us/Documentation/02-Kernel/03-Supported-devices/01-FreeRTOS-porting-guide.md b/content/en-us/Documentation/02-Kernel/03-Supported-devices/01-FreeRTOS-porting-guide.md index 6e16ed09..7d06d0c8 100644 --- a/content/en-us/Documentation/02-Kernel/03-Supported-devices/01-FreeRTOS-porting-guide.md +++ b/content/en-us/Documentation/02-Kernel/03-Supported-devices/01-FreeRTOS-porting-guide.md @@ -116,7 +116,7 @@ directory - NOT absolute paths: Now the difficult bit. Once the project is compiling the portable layer stubs require implementation. It is suggested that pxPortInitialiseStack() is the first function to be implemented. To implement pxPortInitialiseStack() you must first decide upon your task context stack frame structure, which is very architecture dependent. - +Some useful notes about the porting of FreeRTOS are provided on [FreeRTOS Porting Notes](/Documentation/02-Kernel/03-Supported-devices/05-feertos-porting-notes) page. ### Getting Help From 0e857547a0db5cf2d22fc2e2be066b2747c88630 Mon Sep 17 00:00:00 2001 From: Nikolay Pokhilchenko Date: Wed, 2 Sep 2026 18:23:34 +0300 Subject: [PATCH 3/9] Update 05-FeeRTOS-Porting-Notes.md First edit. Header and intro are entered. --- .../05-FeeRTOS-Porting-Notes.md | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md b/content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md index 8b137891..8ba98015 100644 --- a/content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md +++ b/content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md @@ -1 +1,28 @@ +--- +title: "FreeRTOS Porting Notes" +created: 2026-09-02 +categories: + - kernel +description: Some important nuances of Implementing the Stubs +relatedLinks: + - title: Why use FreeRTOS + link: /Why-FreeRTOS/Why-FreeRTOS/ + - title: What is FreeRTOS + link: /Why-FreeRTOS/What-is-FreeRTOS/ + - title: Beginner's guide to FreeRTOS + link: /Documentation/01-FreeRTOS-quick-start/01-Beginners-guide/00-Overview/ + - title: Download FreeRTOS + link: /Documentation/02-Kernel/01-About-the-FreeRTOS-kernel/03-Download-freeRTOS/01-DownloadFreeRTOS/ + - title: Supported devices + link: /Documentation/02-Kernel/03-Supported-devices/00-Supported-devices/ +--- + +### Intro + +Every new architecture of computing platform will require new realization of kernel stubs or adaptations of existing ones if an architecture is close to one of already implemented port. +Look at /FreeRTOS/FreeRTOS-Kernel/portable FreeRTOS source code folder. There are a plenty of templates are provided for most toolchains and architectures. But not all of them are implemented fully and tested. +Porting the FreeRTOS to newer hardware, the software engineer should deeply know the architecture of new system, it's assemble language and new CPU features. +Most important for pre-emptive OS implementation is an exception or interruption mechanism. Some notes about porting the OS are collected here. + +### An importance of serialized interrupt calling and interrupt masking sequence From e60abd5943f8e7f68ca6e4f25be35dc9cb6f5745 Mon Sep 17 00:00:00 2001 From: Nikolay Pokhilchenko Date: Wed, 2 Sep 2026 18:28:40 +0300 Subject: [PATCH 4/9] Update 05-FeeRTOS-Porting-Notes.md --- .../03-Supported-devices/05-FeeRTOS-Porting-Notes.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md b/content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md index 8ba98015..f7628d25 100644 --- a/content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md +++ b/content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md @@ -19,10 +19,10 @@ relatedLinks: ### Intro -Every new architecture of computing platform will require new realization of kernel stubs or adaptations of existing ones if an architecture is close to one of already implemented port. -Look at /FreeRTOS/FreeRTOS-Kernel/portable FreeRTOS source code folder. There are a plenty of templates are provided for most toolchains and architectures. But not all of them are implemented fully and tested. -Porting the FreeRTOS to newer hardware, the software engineer should deeply know the architecture of new system, it's assemble language and new CPU features. -Most important for pre-emptive OS implementation is an exception or interruption mechanism. Some notes about porting the OS are collected here. +Every new architecture of computing platform will require their own kernel stubs - a number of definitions, assemble inserts or small functions to control the code flow and memory. +Some of them could be written from scratch, some of them could be adapted. +Look at /FreeRTOS/FreeRTOS-Kernel/portable FreeRTOS source code folder. There are a plenty of templates are provided for most toolchains and architectures. But not all of them are fully and tested or even completed. +To make FreeRTOS port for newer hardware, the software engineer should deeply know an architecture of new system, it's assemble language and CPU features. +Most important for pre-emptive OS implementation is exception and/or interruption mechanism. Some notes about porting the OS are collected here. ### An importance of serialized interrupt calling and interrupt masking sequence - From db57f9826c54d856b27f6f2e35eae70ac97d3345 Mon Sep 17 00:00:00 2001 From: Nikolay Pokhilchenko Date: Thu, 3 Sep 2026 21:15:10 +0300 Subject: [PATCH 5/9] Update 05-FeeRTOS-Porting-Notes.md The content for "An importance of robust interrupt calling and interrupt masking sequence serialization" note is written. It is my own original text. --- .../05-FeeRTOS-Porting-Notes.md | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md b/content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md index f7628d25..dbdcf207 100644 --- a/content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md +++ b/content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md @@ -21,8 +21,39 @@ relatedLinks: Every new architecture of computing platform will require their own kernel stubs - a number of definitions, assemble inserts or small functions to control the code flow and memory. Some of them could be written from scratch, some of them could be adapted. -Look at /FreeRTOS/FreeRTOS-Kernel/portable FreeRTOS source code folder. There are a plenty of templates are provided for most toolchains and architectures. But not all of them are fully and tested or even completed. +Look at /FreeRTOS/FreeRTOS-Kernel/portable FreeRTOS source code folder. There are a plenty of templates provided for most toolchains and architectures. But not all of them are fully and tested or even completed. To make FreeRTOS port for newer hardware, the software engineer should deeply know an architecture of new system, it's assemble language and CPU features. Most important for pre-emptive OS implementation is exception and/or interruption mechanism. Some notes about porting the OS are collected here. -### An importance of serialized interrupt calling and interrupt masking sequence +### An importance of robust interrupt calling and interrupt masking sequence serialization + +Hard to notice, hard to debug could be a race condition between context switch interrupt request and interrupt masking in code after. In several places of FreeRTOS sources, particularly in blocking sections there are combinations like these: +For correct task blocking and resuming, the yielding functions should ensure that the interrupt or exception used for context switching will be not blocked by entering critical section even being placed back-to-back in the code: + + { + ... + { + taskYIELD_WITHIN_API(); + } + ... + } + taskENTER_CRITICAL(); + +This arrangement is usually placed at the boundary between task blocking (yielding) and running which starts from entering critical part. Actually, taskYIELD command is the point where the task is blocked. And next instructions after it are executed when the task is switched-in by the scheduler back to run. +In task yield macro, an interrupt or exception is triggered to switch an execution from task being blocking to the scheduler function. Triggering an interrupt is normal way to execute the scheduler in any case: when an API function like taskYIELD_WITHIN_API() is called or when system tick interval is ended. +From another side, the entering into critical section should block scheduler interrupt to prevent scheduler interrupt during the time the task control block is updated. +In short: + + - taskYIELD calls an interrupt to block the task. Until an interrupt is executed (the scheduler is executed) the task is not blocked and will continue. + - taskENTER_CRITICAL, in contrast, blocks an interrupt calling to prevent scheduler execution during processing critical part of task control on switching-in running state. + +So these control functions should be executed in the order they are arranged. The scheduler should be executed first, the critical section should be executed only when the task should be unblocked (switched-in). Exact behavior depends on hardware a lot. + + - In case of an exception usage for calling the scheduler, the exception is synchronous interrupt for a CPU. Being triggered by an instruction it acts immediately. + - In case of hardware interrupt usage, an interrupt is asynchronous for the CPU and has a latency. + +An exception mechanism is usually intrinsic for a CPU. In that case the order of an execution of yield and enter critical parts is ensured by immediate propagation of an exception signal. +In contrast, an interrupt controller is external block for a CPU even being placed on the same silicon. After an instruction to trigger scheduler interrupt is executed, an interrupt signal takes several CPU cycles to propagate through an interrupt controller to the CPU back. This latency between yield command and actual scheduler interrupt start opens a window for the race: the code after yield instruction continues it's execution for several CPU cycles before being interrupted by the scheduler. +In some cases, particularly at higher compiler optimization levels, an instruction which masks an interrupts globally is executed before scheduler interrupt signal reaching internal CPU interrupt line! We have a BUG! The scheduler interrupt is missed. This way the task skips the blocking state and, after critical section interrupt masking, continues to run like it is already unblocked. In critical part the state of the task is switched to running completely and upon critical part exiting and unmasking scheduler interrupt, the scheduler interrupt takes it's place. But it is too late - the task is already unblocked and blocking state is completely missed. + +Conclusion for this note: When porting the FreeRTOS, while implementing or reviewing the YIELD stub, do know which way the scheduler execution is called and how much CPU cycles it could take? Knowing that, ensure the interrupt masking for critical section (typically, global interrupt disable assemble instruction) will not be executed before entering the scheduler interrupt. This sequence should be ensured in any cases for every possible compiler optimizations. From e125930e3608bc0710de665be54a2c6bf9f127d1 Mon Sep 17 00:00:00 2001 From: Nikolay Pokhilchenko Date: Thu, 3 Sep 2026 21:17:23 +0300 Subject: [PATCH 6/9] Update 05-FeeRTOS-Porting-Notes.md Minor text editing --- .../02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md b/content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md index dbdcf207..73cf01b0 100644 --- a/content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md +++ b/content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md @@ -27,8 +27,7 @@ Most important for pre-emptive OS implementation is exception and/or interruptio ### An importance of robust interrupt calling and interrupt masking sequence serialization -Hard to notice, hard to debug could be a race condition between context switch interrupt request and interrupt masking in code after. In several places of FreeRTOS sources, particularly in blocking sections there are combinations like these: -For correct task blocking and resuming, the yielding functions should ensure that the interrupt or exception used for context switching will be not blocked by entering critical section even being placed back-to-back in the code: +Hard to notice, hard to debug could be the race condition between context switch interrupt request and interrupt masking in code after. In several places of FreeRTOS sources, particularly in blocking sections there are combinations like these, for correct task blocking and resuming, the yielding functions should ensure that the interrupt or exception used for context switching will be not blocked by entering critical section even being placed back-to-back in the code: { ... From 98506616b19cabd1bf611cb926003e7b0c817bd7 Mon Sep 17 00:00:00 2001 From: Nikolay Pokhilchenko Date: Thu, 3 Sep 2026 21:33:45 +0300 Subject: [PATCH 7/9] Update 05-FeeRTOS-Porting-Notes.md Some edit without of new content --- .../03-Supported-devices/05-FeeRTOS-Porting-Notes.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md b/content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md index 73cf01b0..711e6057 100644 --- a/content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md +++ b/content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md @@ -27,7 +27,7 @@ Most important for pre-emptive OS implementation is exception and/or interruptio ### An importance of robust interrupt calling and interrupt masking sequence serialization -Hard to notice, hard to debug could be the race condition between context switch interrupt request and interrupt masking in code after. In several places of FreeRTOS sources, particularly in blocking sections there are combinations like these, for correct task blocking and resuming, the yielding functions should ensure that the interrupt or exception used for context switching will be not blocked by entering critical section even being placed back-to-back in the code: +Hard to notice, hard to debug could be the race condition between context switch interrupt request and interrupt masking in code after. In several places of FreeRTOS sources, particularly in blocking sections there are combinations like these: { ... @@ -38,7 +38,8 @@ Hard to notice, hard to debug could be the race condition between context switch } taskENTER_CRITICAL(); -This arrangement is usually placed at the boundary between task blocking (yielding) and running which starts from entering critical part. Actually, taskYIELD command is the point where the task is blocked. And next instructions after it are executed when the task is switched-in by the scheduler back to run. +For correct task blocking and resuming, the yielding function should ensure that the interrupt or exception used for context switching will be not blocked by entering critical section even being placed back-to-back in the code. +Code arrangement above is usually placed at the boundary between task blocking (yielding) and running which starts from entering critical part. Actually, taskYIELD command is the point where the task is blocked. And next instructions after it are executed when the task is switched-in by the scheduler back to run. In task yield macro, an interrupt or exception is triggered to switch an execution from task being blocking to the scheduler function. Triggering an interrupt is normal way to execute the scheduler in any case: when an API function like taskYIELD_WITHIN_API() is called or when system tick interval is ended. From another side, the entering into critical section should block scheduler interrupt to prevent scheduler interrupt during the time the task control block is updated. In short: From 1e9dfd8e38c8f8adb63e0e530ff7907236167aa5 Mon Sep 17 00:00:00 2001 From: Nikolay Pokhilchenko Date: Thu, 3 Sep 2026 21:38:44 +0300 Subject: [PATCH 8/9] Update 05-FeeRTOS-Porting-Notes.md Minor addendum --- .../02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md b/content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md index 711e6057..233d2dfe 100644 --- a/content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md +++ b/content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md @@ -54,6 +54,6 @@ So these control functions should be executed in the order they are arranged. Th An exception mechanism is usually intrinsic for a CPU. In that case the order of an execution of yield and enter critical parts is ensured by immediate propagation of an exception signal. In contrast, an interrupt controller is external block for a CPU even being placed on the same silicon. After an instruction to trigger scheduler interrupt is executed, an interrupt signal takes several CPU cycles to propagate through an interrupt controller to the CPU back. This latency between yield command and actual scheduler interrupt start opens a window for the race: the code after yield instruction continues it's execution for several CPU cycles before being interrupted by the scheduler. -In some cases, particularly at higher compiler optimization levels, an instruction which masks an interrupts globally is executed before scheduler interrupt signal reaching internal CPU interrupt line! We have a BUG! The scheduler interrupt is missed. This way the task skips the blocking state and, after critical section interrupt masking, continues to run like it is already unblocked. In critical part the state of the task is switched to running completely and upon critical part exiting and unmasking scheduler interrupt, the scheduler interrupt takes it's place. But it is too late - the task is already unblocked and blocking state is completely missed. +In some cases, particularly at higher compiler optimization levels, an instruction which masks an interrupts globally is executed before scheduler interrupt signal reaching internal CPU interrupt line! We have a BUG! The scheduler interrupt is missed. This way the task skips the blocking state and, after critical section interrupt masking, continues to run like it is already unblocked. In critical part the state of the task is switched to running completely and upon critical part exiting and unmasking scheduler interrupt, the erroneously delayed scheduler interrupt takes it's place. But it is too late - the task is already unblocked and blocking state is completely missed. Conclusion for this note: When porting the FreeRTOS, while implementing or reviewing the YIELD stub, do know which way the scheduler execution is called and how much CPU cycles it could take? Knowing that, ensure the interrupt masking for critical section (typically, global interrupt disable assemble instruction) will not be executed before entering the scheduler interrupt. This sequence should be ensured in any cases for every possible compiler optimizations. From 2f3ddc1d1aaed3c6568be034362f8dd159c36734 Mon Sep 17 00:00:00 2001 From: Nikolay Pokhilchenko Date: Thu, 3 Sep 2026 21:52:41 +0300 Subject: [PATCH 9/9] Update 05-FeeRTOS-Porting-Notes.md An example is added from my own practice. --- .../03-Supported-devices/05-FeeRTOS-Porting-Notes.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md b/content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md index 233d2dfe..4735e59b 100644 --- a/content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md +++ b/content/en-us/Documentation/02-Kernel/03-Supported-devices/05-FeeRTOS-Porting-Notes.md @@ -57,3 +57,14 @@ In contrast, an interrupt controller is external block for a CPU even being plac In some cases, particularly at higher compiler optimization levels, an instruction which masks an interrupts globally is executed before scheduler interrupt signal reaching internal CPU interrupt line! We have a BUG! The scheduler interrupt is missed. This way the task skips the blocking state and, after critical section interrupt masking, continues to run like it is already unblocked. In critical part the state of the task is switched to running completely and upon critical part exiting and unmasking scheduler interrupt, the erroneously delayed scheduler interrupt takes it's place. But it is too late - the task is already unblocked and blocking state is completely missed. Conclusion for this note: When porting the FreeRTOS, while implementing or reviewing the YIELD stub, do know which way the scheduler execution is called and how much CPU cycles it could take? Knowing that, ensure the interrupt masking for critical section (typically, global interrupt disable assemble instruction) will not be executed before entering the scheduler interrupt. This sequence should be ensured in any cases for every possible compiler optimizations. + +Here is an example of adapting portYIELD code for one of RISC-V microcontroller. The macro before the modification: +``` +#define portYIELD() NVIC_SetPendingIRQ(Software_IRQn) +``` +The macro after the modification: +``` +#define portYIELD() do{NVIC_SetPendingIRQ(Software_IRQn); \ + __asm volatile("fence.i");}while(0) +``` +In the example above, original code had triggering scheduler interrupt but failed to prevent critical section against too early interrupt blocking. The addition of single assemble instruction was enough to let software interrupt signal to propagate. The tests were done while interrupt masking instruction were placed right after portYIELD macro and the serialization of execution of these functions after the modification was confirmed.