Skip to content

Commit ae908c8

Browse files
Use real FreeRTOS tasks to idle core during flash (earlephilhower#1444)
Fixes earlephilhower#1439 Use a real FreeRTOS task, at the highest priority, to idle the other core while doing flash accesses. The USB stack seems to have some timing dependent bits which get broken if FreeRTOS switches out the current task when it's running. Avoid any issue by disabling preemption on the core for all tud_task calls. The PendSV handler disable flag can live completely inside the FreeRTOS variant port, so remove any reference to it in the main core. Tested using Multicode-FreeRTOS, earlephilhower#1402 and earlephilhower#1441 The USB FIFO interrupts were still being serviced even when the core was frozen, leading to crashes. Explicitly shut off IRQs on both the victim and the initiator core when freezing. Removed the need for hack __holdUpPendSV flag
1 parent 723c814 commit ae908c8

File tree

5 files changed

+102
-64
lines changed

5 files changed

+102
-64
lines changed

cores/rp2040/RP2040Support.h

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -91,15 +91,14 @@ class _MFIFO {
9191
if (!_multicore) {
9292
return;
9393
}
94-
__holdUpPendSV = 1;
9594
if (__isFreeRTOS) {
96-
vTaskPreemptionDisable(nullptr);
97-
vTaskSuspendAll();
95+
__freertos_idle_other_core();
96+
} else {
97+
mutex_enter_blocking(&_idleMutex);
98+
__otherCoreIdled = false;
99+
multicore_fifo_push_blocking(_GOTOSLEEP);
100+
while (!__otherCoreIdled) { /* noop */ }
98101
}
99-
mutex_enter_blocking(&_idleMutex);
100-
__otherCoreIdled = false;
101-
multicore_fifo_push_blocking(_GOTOSLEEP);
102-
while (!__otherCoreIdled) { /* noop */ }
103102
}
104103

105104
void resumeOtherCore() {
@@ -109,10 +108,8 @@ class _MFIFO {
109108
mutex_exit(&_idleMutex);
110109
__otherCoreIdled = false;
111110
if (__isFreeRTOS) {
112-
xTaskResumeAll();
113-
vTaskPreemptionEnable(nullptr);
111+
__freertos_resume_other_core();
114112
}
115-
__holdUpPendSV = 0;
116113

117114
// Other core will exit busy-loop and return to operation
118115
// once __otherCoreIdled == false.

cores/rp2040/SerialUSB.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,10 @@ static bool _rts = false;
177177
static int _bps = 115200;
178178
static bool _rebooting = false;
179179
static void CheckSerialReset() {
180-
__holdUpPendSV = 1; // Ensure we don't get swapped out by FreeRTOS
181180
if (!_rebooting && (_bps == 1200) && (!_dtr)) {
181+
if (__isFreeRTOS) {
182+
vTaskPreemptionDisable(nullptr);
183+
}
182184
_rebooting = true;
183185
// Disable NVIC IRQ, so that we don't get bothered anymore
184186
irq_set_enabled(USBCTRL_IRQ, false);
@@ -190,7 +192,6 @@ static void CheckSerialReset() {
190192
reset_usb_boot(0, 0);
191193
while (1); // WDT will fire here
192194
}
193-
__holdUpPendSV = 0;
194195
}
195196

196197
extern "C" void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) {

cores/rp2040/_freertos.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,7 @@ extern "C" {
5959
extern void vTaskPreemptionEnable(TaskHandle_t p) __attribute__((weak));
6060
#endif
6161

62+
extern void __freertos_idle_other_core() __attribute__((weak));
63+
extern void __freertos_resume_other_core() __attribute__((weak));
6264
}
6365
extern SemaphoreHandle_t __get_freertos_mutex_for_ptr(mutex_t *m, bool recursive = false);
64-
65-
// Halt the FreeRTOS PendSV task switching magic
66-
extern "C" int __holdUpPendSV;

cores/rp2040/main.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
RP2040 rp2040;
2828
extern "C" {
2929
volatile bool __otherCoreIdled = false;
30-
int __holdUpPendSV = 0;
3130
};
3231

3332
mutex_t _pioMutex;

libraries/FreeRTOS/src/variantHooks.cpp

Lines changed: 90 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,54 @@
4040
#include <pico.h>
4141
#include <pico/time.h>
4242

43-
#include "_freertos.h"
43+
#include <_freertos.h>
44+
45+
// Interfaces for the main core to use FreeRTOS mutexes
46+
extern "C" {
47+
extern volatile bool __otherCoreIdled;
48+
int __holdUpPendSV = 0; // TOTO - remove from FreeRTOS lib
49+
50+
SemaphoreHandle_t __freertos_mutex_create() {
51+
return xSemaphoreCreateMutex();
52+
}
53+
54+
SemaphoreHandle_t _freertos_recursive_mutex_create() {
55+
return xSemaphoreCreateRecursiveMutex();
56+
}
57+
58+
void __freertos_mutex_take(SemaphoreHandle_t mtx) {
59+
xSemaphoreTake(mtx, portMAX_DELAY);
60+
}
61+
62+
void __freertos_mutex_take_from_isr(SemaphoreHandle_t mtx) {
63+
xSemaphoreTakeFromISR(mtx, NULL);
64+
}
65+
66+
int __freertos_mutex_try_take(SemaphoreHandle_t mtx) {
67+
return xSemaphoreTake(mtx, 0);
68+
}
69+
70+
void __freertos_mutex_give(SemaphoreHandle_t mtx) {
71+
xSemaphoreGive(mtx);
72+
}
73+
74+
void __freertos_mutex_give_from_isr(SemaphoreHandle_t mtx) {
75+
xSemaphoreGiveFromISR(mtx, NULL);
76+
}
77+
78+
void __freertos_recursive_mutex_take(SemaphoreHandle_t mtx) {
79+
xSemaphoreTakeRecursive(mtx, portMAX_DELAY);
80+
}
81+
82+
int __freertos_recursive_mutex_try_take(SemaphoreHandle_t mtx) {
83+
return xSemaphoreTakeRecursive(mtx, 0);
84+
}
85+
86+
void __freertos_recursive_mutex_give(SemaphoreHandle_t mtx) {
87+
xSemaphoreGiveRecursive(mtx);
88+
}
89+
}
90+
4491

4592
/*-----------------------------------------------------------*/
4693

@@ -108,6 +155,40 @@ extern "C" void yield() {
108155
taskYIELD();
109156
}
110157

158+
static TaskHandle_t __idleCoreTask[2];
159+
static void __no_inline_not_in_flash_func(IdleThisCore)(void *param) {
160+
(void) param;
161+
while (true) {
162+
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
163+
vTaskPreemptionDisable(nullptr);
164+
portDISABLE_INTERRUPTS();
165+
__otherCoreIdled = true;
166+
while (__otherCoreIdled) {
167+
/* noop */
168+
}
169+
portENABLE_INTERRUPTS();
170+
vTaskPreemptionEnable(nullptr);
171+
}
172+
}
173+
174+
extern "C" void __no_inline_not_in_flash_func(__freertos_idle_other_core)() {
175+
vTaskPreemptionDisable(nullptr);
176+
xTaskNotifyGive(__idleCoreTask[ 1 ^ sio_hw->cpuid ]);
177+
while (!__otherCoreIdled) {
178+
/* noop */
179+
}
180+
portDISABLE_INTERRUPTS();
181+
vTaskSuspendAll();
182+
}
183+
184+
extern "C" void __no_inline_not_in_flash_func(__freertos_resume_other_core)() {
185+
__otherCoreIdled = false;
186+
portENABLE_INTERRUPTS();
187+
xTaskResumeAll();
188+
vTaskPreemptionEnable(nullptr);
189+
}
190+
191+
111192
extern mutex_t __usb_mutex;
112193
static TaskHandle_t __usbTask;
113194
static void __usb(void *param);
@@ -124,6 +205,12 @@ void startFreeRTOS(void) {
124205
vTaskCoreAffinitySet(c1, 1 << 1);
125206
}
126207

208+
// Create the idle-other-core tasks (for when flash is being written)
209+
xTaskCreate(IdleThisCore, "IdleCore0", 128, 0, configMAX_PRIORITIES - 1, __idleCoreTask + 0);
210+
vTaskCoreAffinitySet(__idleCoreTask[0], 1 << 0);
211+
xTaskCreate(IdleThisCore, "IdleCore1", 128, 0, configMAX_PRIORITIES - 1, __idleCoreTask + 1);
212+
vTaskCoreAffinitySet(__idleCoreTask[1], 1 << 1);
213+
127214
// Initialise and run the freeRTOS scheduler. Execution should never return here.
128215
__freeRTOSinitted = true;
129216
vTaskStartScheduler();
@@ -398,54 +485,9 @@ void __USBStart() {
398485
__SetupDescHIDReport();
399486
__SetupUSBDescriptor();
400487

401-
// Make highest prio and locked to core 0
402-
xTaskCreate(__usb, "USB", 256, 0, configMAX_PRIORITIES - 1, &__usbTask);
488+
// Make high prio and locked to core 0
489+
xTaskCreate(__usb, "USB", 256, 0, configMAX_PRIORITIES - 2, &__usbTask);
403490
vTaskCoreAffinitySet(__usbTask, 1 << 0);
404491
}
405492

406493

407-
// Interfaces for the main core to use FreeRTOS mutexes
408-
extern "C" {
409-
410-
SemaphoreHandle_t __freertos_mutex_create() {
411-
return xSemaphoreCreateMutex();
412-
}
413-
414-
SemaphoreHandle_t _freertos_recursive_mutex_create() {
415-
return xSemaphoreCreateRecursiveMutex();
416-
}
417-
418-
void __freertos_mutex_take(SemaphoreHandle_t mtx) {
419-
xSemaphoreTake(mtx, portMAX_DELAY);
420-
}
421-
422-
void __freertos_mutex_take_from_isr(SemaphoreHandle_t mtx) {
423-
xSemaphoreTakeFromISR(mtx, NULL);
424-
}
425-
426-
int __freertos_mutex_try_take(SemaphoreHandle_t mtx) {
427-
return xSemaphoreTake(mtx, 0);
428-
}
429-
430-
void __freertos_mutex_give(SemaphoreHandle_t mtx) {
431-
xSemaphoreGive(mtx);
432-
}
433-
434-
void __freertos_mutex_give_from_isr(SemaphoreHandle_t mtx) {
435-
xSemaphoreGiveFromISR(mtx, NULL);
436-
}
437-
438-
void __freertos_recursive_mutex_take(SemaphoreHandle_t mtx) {
439-
xSemaphoreTakeRecursive(mtx, portMAX_DELAY);
440-
}
441-
442-
int __freertos_recursive_mutex_try_take(SemaphoreHandle_t mtx) {
443-
return xSemaphoreTakeRecursive(mtx, 0);
444-
}
445-
446-
void __freertos_recursive_mutex_give(SemaphoreHandle_t mtx) {
447-
xSemaphoreGiveRecursive(mtx);
448-
}
449-
450-
}
451-

0 commit comments

Comments
 (0)