Skip to content

WIP - Make FreeRTOS a first-class citizen #3063

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 26 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
3109f1d
WIP - Make FreeRTOS a first-class citizen
earlephilhower Aug 8, 2025
15a1cb5
Merge branch 'master' into freesanity
earlephilhower Aug 8, 2025
b5193a4
Move FreeRTOS to main core, refactor async_context, move to LWIP task
earlephilhower Aug 14, 2025
e2f324e
Clean up and fill in RAW, UDP, and TCP wrappers
earlephilhower Aug 14, 2025
31177da
More debug, identified deadlock conditions
earlephilhower Aug 14, 2025
f412d28
Update FreeRTOS submnodule
earlephilhower Aug 14, 2025
b94aa52
Wrap ethernet_output
earlephilhower Aug 16, 2025
5fd15b9
Debug
earlephilhower Aug 16, 2025
ac8c05f
HW semaphore`
earlephilhower Aug 16, 2025
452abcb
Use callback from LWIP thread to process Ethernet
earlephilhower Aug 16, 2025
623c2df
lwip_callback can take a cbData
earlephilhower Aug 16, 2025
0b14547
Add IRQ support
earlephilhower Aug 17, 2025
946f973
Fix polling and IRQ memory corruption
earlephilhower Aug 18, 2025
ef0ce09
Use driver local storage for IRQ request area
earlephilhower Aug 18, 2025
9e92724
Fix race condition in WiFiServer
earlephilhower Aug 18, 2025
224ddd1
Merge branch 'master' into freesanity
earlephilhower Aug 18, 2025
b0e272e
LWIP task calls lwip_init and sys_check_timeouts
earlephilhower Aug 18, 2025
361a366
Merge branch 'freesanity' of https://github.com/earlephilhower/arduin…
earlephilhower Aug 18, 2025
6cdf3f3
Re-add FreeRTOS examples, update spellcheck
earlephilhower Aug 18, 2025
00a99e4
Astyle
earlephilhower Aug 18, 2025
c447d4f
WiFiClient/WiFiUDP list needs mutex protection
earlephilhower Aug 18, 2025
c54ec2b
Restore bare-metal compilation
earlephilhower Aug 18, 2025
354ed53
Add LWIP_DEBUG menu item
earlephilhower Aug 18, 2025
b84db3d
Unbreak FreeRTOS, clean up unused async_ctx method
earlephilhower Aug 18, 2025
50b1583
Forgot to add lwip_wrap.h, d'oh!
earlephilhower Aug 18, 2025
504de82
Use __FREERTOS for example CI builds
earlephilhower Aug 19, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ jobs:
- name: Run codespell
uses: codespell-project/actions-codespell@v2
with:
skip: ./ArduinoCore-API,./libraries/ESP8266SdFat,./libraries/Adafruit_TinyUSB_Arduino,./libraries/LittleFS/lib,./tools/pyserial,./pico-sdk,./.github,./docs/i2s.rst,./cores/rp2040/api,./libraries/FreeRTOS,./tools/libbearssl/bearssl,./include,./libraries/WiFi/examples/BearSSL_Server,./ota/uzlib,./libraries/http-parser/lib,./libraries/WebServer/examples/HelloServerBearSSL/HelloServerBearSSL.ino,./libraries/HTTPUpdateServer/examples/SecureBearSSLUpdater/SecureBearSSLUpdater.ino,./.git,./libraries/FatFS/lib/fatfs,./libraries/FatFS/src/diskio.h,./libraries/FatFS/src/ff.cpp,./libraries/FatFS/src/ffconf.h,./libraries/FatFS/src/ffsystem.cpp,./libraries/FatFS/src/ff.h,./libraries/lwIP_WINC1500/src/driver,./libraries/lwIP_WINC1500/src/common,./libraries/lwIP_WINC1500/src/bus_wrapper,./libraries/lwIP_WINC1500/src/spi_flash,./libraries/WiFi/examples/BearSSL_Validation/certs.h
ignore_words_list: ser,dout,shiftIn,acount,froms
skip: ./ArduinoCore-API,./libraries/ESP8266SdFat,./libraries/Adafruit_TinyUSB_Arduino,./libraries/LittleFS/lib,./tools/pyserial,./pico-sdk,./.github,./docs/i2s.rst,./cores/rp2040/api,./FreeRTOS,./tools/libbearssl/bearssl,./include,./libraries/WiFi/examples/BearSSL_Server,./ota/uzlib,./libraries/http-parser/lib,./libraries/WebServer/examples/HelloServerBearSSL/HelloServerBearSSL.ino,./libraries/HTTPUpdateServer/examples/SecureBearSSLUpdater/SecureBearSSLUpdater.ino,./.git,./libraries/FatFS/lib/fatfs,./libraries/FatFS/src/diskio.h,./libraries/FatFS/src/ff.cpp,./libraries/FatFS/src/ffconf.h,./libraries/FatFS/src/ffsystem.cpp,./libraries/FatFS/src/ff.h,./libraries/lwIP_WINC1500/src/driver,./libraries/lwIP_WINC1500/src/common,./libraries/lwIP_WINC1500/src/bus_wrapper,./libraries/lwIP_WINC1500/src/spi_flash,./libraries/WiFi/examples/BearSSL_Validation/certs.h
ignore_words_list: ser,dout,shiftIn,acount,froms,ThirdParty
- name: Check boards.txt was not edited after makeboards.py
run: |
./tools/makeboards.py
Expand Down
5 changes: 4 additions & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
path = libraries/Adafruit_TinyUSB_Arduino
url = https://github.com/adafruit/Adafruit_TinyUSB_Arduino.git
[submodule "libraries/FreeRTOS/lib/FreeRTOS-Kernel"]
path = libraries/FreeRTOS/lib/FreeRTOS-Kernel
path = FreeRTOS-Kernel
url = https://github.com/earlephilhower/FreeRTOS-Kernel.git
[submodule "tools/libbearssl/bearssl"]
path = tools/libbearssl/bearssl
Expand All @@ -49,3 +49,6 @@
[submodule "libraries/SdFat"]
path = libraries/SdFat
url = https://github.com/greiman/SdFat.git
[submodule "FreeRTOS-Kernel"]
path = FreeRTOS-Kernel
url = https://github.com/earlephilhower/FreeRTOS-Kernel.git
1,065 changes: 932 additions & 133 deletions boards.txt

Large diffs are not rendered by default.

3 changes: 0 additions & 3 deletions cores/rp2040/Arduino.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,6 @@ void analogWriteResolution(int res);
} // extern "C"
#endif

// FreeRTOS potential calls
extern bool __isFreeRTOS;

// Ancient AVR defines
#define HAVE_HWSERIAL0
#define HAVE_HWSERIAL1
Expand Down
12 changes: 6 additions & 6 deletions cores/rp2040/Bootsel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ static bool __no_inline_not_in_flash_func(get_bootsel_button)() {

// Must disable interrupts, as interrupt handlers may be in flash, and we
// are about to temporarily disable flash access!
if (!__isFreeRTOS) {
noInterrupts();
}
#ifndef __FREERTOS
noInterrupts();
#endif
rp2040.idleOtherCore();

// Set chip select to Hi-Z
Expand All @@ -55,9 +55,9 @@ static bool __no_inline_not_in_flash_func(get_bootsel_button)() {
IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS);

rp2040.resumeOtherCore();
if (!__isFreeRTOS) {
interrupts();
}
#ifndef __FREERTOS
interrupts();
#endif

return button_state;
}
Expand Down
52 changes: 26 additions & 26 deletions cores/rp2040/CoreMutex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,45 +28,45 @@ CoreMutex::CoreMutex(mutex_t *mutex, uint8_t option) {
_mutex = mutex;
_acquired = false;
_option = option;
#ifdef __FREERTOS
_pxHigherPriorityTaskWoken = 0; // pdFALSE
if (__isFreeRTOS) {
auto m = __get_freertos_mutex_for_ptr(mutex);
auto m = __get_freertos_mutex_for_ptr(mutex);

if (__freertos_check_if_in_isr()) {
if (!__freertos_mutex_take_from_isr(m, &_pxHigherPriorityTaskWoken)) {
return;
}
// At this point we have the mutex in ISR
} else {
// Grab the mutex normally, possibly waking other tasks to get it
__freertos_mutex_take(m);
if (__freertos_check_if_in_isr()) {
if (!__freertos_mutex_take_from_isr(m, &_pxHigherPriorityTaskWoken)) {
return;
}
// At this point we have the mutex in ISR
} else {
uint32_t owner;
if (!mutex_try_enter(_mutex, &owner)) {
if (owner == get_core_num()) { // Deadlock!
if (_option & DebugEnable) {
DEBUGCORE("CoreMutex - Deadlock detected!\n");
}
return;
// Grab the mutex normally, possibly waking other tasks to get it
__freertos_mutex_take(m);
}
#else
uint32_t owner;
if (!mutex_try_enter(_mutex, &owner)) {
if (owner == get_core_num()) { // Deadlock!
if (_option & DebugEnable) {
DEBUGCORE("CoreMutex - Deadlock detected!\n");
}
mutex_enter_blocking(_mutex);
return;
}
mutex_enter_blocking(_mutex);
}
#endif
_acquired = true;
}

CoreMutex::~CoreMutex() {
if (_acquired) {
if (__isFreeRTOS) {
auto m = __get_freertos_mutex_for_ptr(_mutex);
if (__freertos_check_if_in_isr()) {
__freertos_mutex_give_from_isr(m, &_pxHigherPriorityTaskWoken);
} else {
__freertos_mutex_give(m);
}
#ifdef __FREERTOS
auto m = __get_freertos_mutex_for_ptr(_mutex);
if (__freertos_check_if_in_isr()) {
__freertos_mutex_give_from_isr(m, &_pxHigherPriorityTaskWoken);
} else {
mutex_exit(_mutex);
__freertos_mutex_give(m);
}
#else
mutex_exit(_mutex);
#endif
}
}
2 changes: 2 additions & 0 deletions cores/rp2040/CoreMutex.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,7 @@ class CoreMutex {
mutex_t *_mutex;
bool _acquired;
uint8_t _option;
#ifdef __FREERTOS
BaseType_t _pxHigherPriorityTaskWoken;
#endif
};
135 changes: 62 additions & 73 deletions cores/rp2040/RP2040Support.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,18 @@ class _MFIFO {
}

void registerCore() {
if (!__isFreeRTOS) {
multicore_fifo_clear_irq();
#ifndef __FREERTOS
multicore_fifo_clear_irq();
#ifdef PICO_RP2350
irq_set_exclusive_handler(SIO_IRQ_FIFO, _irq);
irq_set_enabled(SIO_IRQ_FIFO, true);
irq_set_exclusive_handler(SIO_IRQ_FIFO, _irq);
irq_set_enabled(SIO_IRQ_FIFO, true);
#else
irq_set_exclusive_handler(SIO_IRQ_PROC0 + get_core_num(), _irq);
irq_set_enabled(SIO_IRQ_PROC0 + get_core_num(), true);
irq_set_exclusive_handler(SIO_IRQ_PROC0 + get_core_num(), _irq);
irq_set_enabled(SIO_IRQ_PROC0 + get_core_num(), true);
#endif
}
#else
// FreeRTOS port.c will handle the IRQ hooking
#endif
}

void push(uint32_t val) {
Expand Down Expand Up @@ -113,14 +114,14 @@ class _MFIFO {
if (!_multicore) {
return;
}
if (__isFreeRTOS) {
__freertos_idle_other_core();
} else {
mutex_enter_blocking(&_idleMutex);
__otherCoreIdled = false;
multicore_fifo_push_blocking(_GOTOSLEEP);
while (!__otherCoreIdled) { /* noop */ }
}
#ifdef __FREERTOS
__freertos_idle_other_core();
#else
mutex_enter_blocking(&_idleMutex);
__otherCoreIdled = false;
multicore_fifo_push_blocking(_GOTOSLEEP);
while (!__otherCoreIdled) { /* noop */ }
#endif
}

void resumeOtherCore() {
Expand All @@ -129,9 +130,9 @@ class _MFIFO {
}
mutex_exit(&_idleMutex);
__otherCoreIdled = false;
if (__isFreeRTOS) {
__freertos_resume_other_core();
}
#ifdef __FREERTOS
__freertos_resume_other_core();
#endif

// Other core will exit busy-loop and return to operation
// once __otherCoreIdled == false.
Expand All @@ -151,18 +152,18 @@ class _MFIFO {

private:
static void __no_inline_not_in_flash_func(_irq)() {
if (!__isFreeRTOS) {
multicore_fifo_clear_irq();
noInterrupts(); // We need total control, can't run anything
while (multicore_fifo_rvalid()) {
if (_GOTOSLEEP == multicore_fifo_pop_blocking()) {
__otherCoreIdled = true;
while (__otherCoreIdled) { /* noop */ }
break;
}
#ifndef __FREERTOS
multicore_fifo_clear_irq();
noInterrupts(); // We need total control, can't run anything
while (multicore_fifo_rvalid()) {
if (_GOTOSLEEP == multicore_fifo_pop_blocking()) {
__otherCoreIdled = true;
while (__otherCoreIdled) { /* noop */ }
break;
}
interrupts();
}
interrupts();
#endif
}

bool _multicore = false;
Expand Down Expand Up @@ -192,23 +193,19 @@ class RP2040 {

void begin(int cpuid) {
_epoch[cpuid] = 0;
#if !defined(__riscv) && !defined(__PROFILE)
if (!__isFreeRTOS) {
// Enable SYSTICK exception
exception_set_exclusive_handler(SYSTICK_EXCEPTION, _SystickHandler);
systick_hw->csr = 0x7;
systick_hw->rvr = 0x00FFFFFF;
} else {
#endif
// Only start 1 instance of the PIO SM
if (cpuid == 0) {
int off = 0;
_ccountPgm = new PIOProgram(&ccount_program);
_ccountPgm->prepare(&_pio, &_sm, &off);
ccount_program_init(_pio, _sm, off);
pio_sm_set_enabled(_pio, _sm, true);
}
#if !defined(__riscv) && !defined(__PROFILE)
#if !defined(__riscv) && !defined(__PROFILE) && !defined(__FREERTOS)
// Enable SYSTICK exception
exception_set_exclusive_handler(SYSTICK_EXCEPTION, _SystickHandler);
systick_hw->csr = 0x7;
systick_hw->rvr = 0x00FFFFFF;
#else
// Only start 1 instance of the PIO SM
if (cpuid == 0) {
int off = 0;
_ccountPgm = new PIOProgram(&ccount_program);
_ccountPgm->prepare(&_pio, &_sm, &off);
ccount_program_init(_pio, _sm, off);
pio_sm_set_enabled(_pio, _sm, true);
}
#endif
}
Expand Down Expand Up @@ -255,21 +252,17 @@ class RP2040 {
@returns CPU clock cycles since power up
*/
inline uint32_t getCycleCount() {
#if !defined(__riscv) && !defined(__PROFILE)
#if !defined(__riscv) && !defined(__PROFILE) && !defined(__FREERTOS)
// Get CPU cycle count. Needs to do magic to extend 24b HW to something longer
if (!__isFreeRTOS) {
uint32_t epoch;
uint32_t ctr;
do {
epoch = (uint32_t)_epoch[sio_hw->cpuid];
ctr = systick_hw->cvr;
} while (epoch != (uint32_t)_epoch[sio_hw->cpuid]);
return epoch + (1 << 24) - ctr; /* CTR counts down from 1<<24-1 */
} else {
#endif
return ccount_read(_pio, _sm);
#if !defined(__riscv) && !defined(__PROFILE)
}
uint32_t epoch;
uint32_t ctr;
do {
epoch = (uint32_t)_epoch[sio_hw->cpuid];
ctr = systick_hw->cvr;
} while (epoch != (uint32_t)_epoch[sio_hw->cpuid]);
return epoch + (1 << 24) - ctr; /* CTR counts down from 1<<24-1 */
#else
return ccount_read(_pio, _sm);
#endif
}
/**
Expand All @@ -278,20 +271,16 @@ class RP2040 {
@returns CPU clock cycles since power up
*/
inline uint64_t getCycleCount64() {
#if !defined(__riscv) && !defined(__PROFILE)
if (!__isFreeRTOS) {
uint64_t epoch;
uint64_t ctr;
do {
epoch = _epoch[sio_hw->cpuid];
ctr = systick_hw->cvr;
} while (epoch != _epoch[sio_hw->cpuid]);
return epoch + (1LL << 24) - ctr;
} else {
#endif
return ccount_read(_pio, _sm);
#if !defined(__riscv) && !defined(__PROFILE)
}
#if !defined(__riscv) && !defined(__PROFILE) && !defined(__FREERTOS)
uint64_t epoch;
uint64_t ctr;
do {
epoch = _epoch[sio_hw->cpuid];
ctr = systick_hw->cvr;
} while (epoch != _epoch[sio_hw->cpuid]);
return epoch + (1LL << 24) - ctr;
#else
return ccount_read(_pio, _sm);
#endif
}

Expand Down
6 changes: 3 additions & 3 deletions cores/rp2040/SerialUSB.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,9 @@ static int _bps = 115200;
static bool _rebooting = false;
static void CheckSerialReset() {
if (!_rebooting && (_bps == 1200) && (!_dtr)) {
if (__isFreeRTOS) {
__freertos_idle_other_core();
}
#ifdef __FREERTOS
__freertos_idle_other_core();
#endif
_rebooting = true;
// Disable NVIC IRQ, so that we don't get bothered anymore
irq_set_enabled(USBCTRL_IRQ, false);
Expand Down
4 changes: 4 additions & 0 deletions cores/rp2040/_freertos.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#ifdef __FREERTOS

#include "_freertos.h"
#include <pico/mutex.h>
#include <stdlib.h>
Expand Down Expand Up @@ -60,3 +62,5 @@ SemaphoreHandle_t __get_freertos_mutex_for_ptr(mutex_t *m, bool recursive) {
}
return nullptr; // Need to make space for more mutex maps!
}

#endif
6 changes: 4 additions & 2 deletions cores/rp2040/_freertos.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#ifdef __FREERTOS

#pragma once
#include <pico/mutex.h>

// Cannot include refs to FreeRTOS's actual semaphore calls because they
// are implemented as macros, so we have a wrapper in our variant hook
// to handle it.

extern bool __isFreeRTOS;

// FreeRTOS has been set up
extern volatile bool __freeRTOSinitted;

Expand Down Expand Up @@ -63,3 +63,5 @@ extern void __freertos_task_enter_critical() __attribute__((weak));
}
extern SemaphoreHandle_t __get_freertos_mutex_for_ptr(mutex_t *m, bool recursive = false);
#endif // __cplusplus

#endif // __FREERTOS
5 changes: 5 additions & 0 deletions cores/rp2040/freertos/FreeRTOS.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#ifdef __FREERTOS
#include "../../../FreeRTOS-Kernel/include/FreeRTOS.h"
#else
#error "#define __FREERTOS 1 to use FreeRTOS in your application"
#endif
Loading
Loading