Skip to content

Commit bda630e

Browse files
Add FreeRTOS support thanks to @hfellner (#533)
Using all the work from @hfellner and others, add FreeRTOS SMP support. Allow idling cores through the FreeRTOS FIFO queue to allow for file system and EEPROM support. Make delay a weak function so FreeRTOS can override. Add cycle count support under FreeRTOS using a PIO SM. Use a task-based approach for handling the USB periodic work instead of the IRQ-based one in the main core. Set 8 prio levels so it fits in 3 bits nicely (0..7).
1 parent 9afdc48 commit bda630e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+1114
-118
lines changed

.github/workflows/pull-request.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
- name: Run codespell
2121
uses: codespell-project/actions-codespell@master
2222
with:
23-
skip: ./pico-extras,./ArduinoCore-API,./libraries/ESP8266SdFat,./libraries/Adafruit_TinyUSB_Arduino,./libraries/LittleFS/lib,./tools/pyserial,./pico-sdk,./.github,./docs/i2s.rst,./cores/rp2040/api
23+
skip: ./pico-extras,./ArduinoCore-API,./libraries/ESP8266SdFat,./libraries/Adafruit_TinyUSB_Arduino,./libraries/LittleFS/lib,./tools/pyserial,./pico-sdk,./.github,./docs/i2s.rst,./cores/rp2040/api,./libraries/FreeRTOS
2424
ignore_words_list: ser,DOUT
2525

2626
# Consistent style

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,6 @@
2525
[submodule "libraries/Adafruit_TinyUSB_Arduino"]
2626
path = libraries/Adafruit_TinyUSB_Arduino
2727
url = https://github.com/adafruit/Adafruit_TinyUSB_Arduino.git
28+
[submodule "libraries/FreeRTOS/lib/FreeRTOS-Kernel"]
29+
path = libraries/FreeRTOS/lib/FreeRTOS-Kernel
30+
url = https://github.com/earlephilhower/FreeRTOS-Kernel.git

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ If you want to contribute or have bugfixes, drop me a note at <earlephilhower@ya
173173
* [LittleFS](https://github.com/ARMmbed/littlefs) library written by ARM Limited and released under the [BSD 3-clause license](https://github.com/ARMmbed/littlefs/blob/master/LICENSE.md).
174174
* [UF2CONV.PY](https://github.com/microsoft/uf2) is by Microsoft Corporation and licensed under the MIT license.
175175
* Some filesystem code taken from the [ESP8266 Arduino Core](https://github.com/esp8266/Arduino) and licensed under the LGPL.
176+
* [FreeRTOS](https://freertos.org) is Copyright Amazon.com, Inc. or its affiliates, and distributed under the MIT license.
176177
177178
-Earle F. Philhower, III
178179

cores/rp2040/Arduino.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ void analogWriteFreq(uint32_t freq);
7979
void analogWriteRange(uint32_t range);
8080
void analogWriteResolution(int res);
8181

82+
// FreeRTOS potential calls
83+
extern bool __isFreeRTOS;
84+
8285
#ifdef __cplusplus
8386
} // extern "C"
8487
#endif

cores/rp2040/RP2040Support.h

Lines changed: 116 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@
2525
#include <hardware/structs/systick.h>
2626
#include <pico/multicore.h>
2727
#include <pico/util/queue.h>
28-
#include <CoreMutex.h>
28+
#include "CoreMutex.h"
29+
#include "ccount.pio.h"
30+
31+
32+
extern "C" volatile bool __otherCoreIdled;
2933

3034
class _MFIFO {
3135
public:
@@ -45,9 +49,12 @@ class _MFIFO {
4549
}
4650

4751
void registerCore() {
48-
multicore_fifo_clear_irq();
49-
irq_set_exclusive_handler(SIO_IRQ_PROC0 + get_core_num(), _irq);
50-
irq_set_enabled(SIO_IRQ_PROC0 + get_core_num(), true);
52+
if (!__isFreeRTOS) {
53+
multicore_fifo_clear_irq();
54+
irq_set_exclusive_handler(SIO_IRQ_PROC0 + get_core_num(), _irq);
55+
irq_set_enabled(SIO_IRQ_PROC0 + get_core_num(), true);
56+
}
57+
// FreeRTOS port.c will handle the IRQ hooking
5158
}
5259

5360
void push(uint32_t val) {
@@ -79,19 +86,19 @@ class _MFIFO {
7986
return;
8087
}
8188
mutex_enter_blocking(&_idleMutex);
82-
_otherIdled = false;
89+
__otherCoreIdled = false;
8390
multicore_fifo_push_blocking(_GOTOSLEEP);
84-
while (!_otherIdled) { /* noop */ }
91+
while (!__otherCoreIdled) { /* noop */ }
8592
}
8693

8794
void resumeOtherCore() {
8895
if (!_multicore) {
8996
return;
9097
}
9198
mutex_exit(&_idleMutex);
92-
_otherIdled = false;
99+
__otherCoreIdled = false;
93100
// Other core will exit busy-loop and return to operation
94-
// once otherIdled == false.
101+
// once __otherCoreIdled == false.
95102
}
96103

97104
void clear() {
@@ -108,98 +115,31 @@ class _MFIFO {
108115

109116
private:
110117
static void __no_inline_not_in_flash_func(_irq)() {
111-
multicore_fifo_clear_irq();
112-
noInterrupts(); // We need total control, can't run anything
113-
while (multicore_fifo_rvalid()) {
114-
if (_GOTOSLEEP == multicore_fifo_pop_blocking()) {
115-
_otherIdled = true;
116-
while (_otherIdled) { /* noop */ }
117-
break;
118+
if (!__isFreeRTOS) {
119+
multicore_fifo_clear_irq();
120+
noInterrupts(); // We need total control, can't run anything
121+
while (multicore_fifo_rvalid()) {
122+
if (_GOTOSLEEP == multicore_fifo_pop_blocking()) {
123+
__otherCoreIdled = true;
124+
while (__otherCoreIdled) { /* noop */ }
125+
break;
126+
}
118127
}
128+
interrupts();
119129
}
120-
interrupts();
121130
}
122-
bool _multicore = false;
123131

132+
bool _multicore = false;
124133
mutex_t _idleMutex;
125-
static volatile bool _otherIdled;
126134
queue_t _queue[2];
127-
128-
static constexpr int _GOTOSLEEP = 0x66666666;
135+
static constexpr uint32_t _GOTOSLEEP = 0xC0DED02E;
129136
};
130137

138+
131139
class RP2040;
132140
extern RP2040 rp2040;
133141
extern "C" void main1();
134-
135-
class RP2040 {
136-
public:
137-
RP2040() {
138-
_epoch = 0;
139-
// Enable SYSTICK exception
140-
exception_set_exclusive_handler(SYSTICK_EXCEPTION, _SystickHandler);
141-
systick_hw->csr = 0x7;
142-
systick_hw->rvr = 0x00FFFFFF;
143-
}
144-
145-
~RP2040() { /* noop */ }
146-
147-
148-
// Convert from microseconds to PIO clock cycles
149-
static int usToPIOCycles(int us) {
150-
// Parenthesis needed to guarantee order of operations to avoid 32bit overflow
151-
return (us * (clock_get_hz(clk_sys) / 1000000));
152-
}
153-
154-
// Get current clock frequency
155-
static int f_cpu() {
156-
return clock_get_hz(clk_sys);
157-
}
158-
159-
// Get CPU cycle count. Needs to do magic to extens 24b HW to something longer
160-
volatile uint64_t _epoch = 0;
161-
inline uint32_t getCycleCount() {
162-
uint32_t epoch;
163-
uint32_t ctr;
164-
do {
165-
epoch = (uint32_t)_epoch;
166-
ctr = systick_hw->cvr;
167-
} while (epoch != (uint32_t)_epoch);
168-
return epoch + (1 << 24) - ctr; /* CTR counts down from 1<<24-1 */
169-
}
170-
171-
inline uint64_t getCycleCount64() {
172-
uint64_t epoch;
173-
uint64_t ctr;
174-
do {
175-
epoch = _epoch;
176-
ctr = systick_hw->cvr;
177-
} while (epoch != _epoch);
178-
return epoch + (1LL << 24) - ctr;
179-
}
180-
181-
void idleOtherCore() {
182-
fifo.idleOtherCore();
183-
}
184-
185-
void resumeOtherCore() {
186-
fifo.resumeOtherCore();
187-
}
188-
189-
void restartCore1() {
190-
multicore_reset_core1();
191-
fifo.clear();
192-
multicore_launch_core1(main1);
193-
}
194-
195-
// Multicore comms FIFO
196-
_MFIFO fifo;
197-
198-
private:
199-
static void _SystickHandler() {
200-
rp2040._epoch += 1LL << 24;
201-
}
202-
};
142+
class PIOProgram;
203143

204144
// Wrapper class for PIO programs, abstracting common operations out
205145
// TODO - Add unload/destructor
@@ -255,3 +195,90 @@ class PIOProgram {
255195
const pio_program_t *_pgm;
256196
};
257197

198+
class RP2040 {
199+
public:
200+
RP2040() { /* noop */ }
201+
~RP2040() { /* noop */ }
202+
203+
void begin() {
204+
_epoch = 0;
205+
if (!__isFreeRTOS) {
206+
// Enable SYSTICK exception
207+
exception_set_exclusive_handler(SYSTICK_EXCEPTION, _SystickHandler);
208+
systick_hw->csr = 0x7;
209+
systick_hw->rvr = 0x00FFFFFF;
210+
} else {
211+
int off = 0;
212+
_ccountPgm = new PIOProgram(&ccount_program);
213+
_ccountPgm->prepare(&_pio, &_sm, &off);
214+
ccount_program_init(_pio, _sm, off);
215+
pio_sm_set_enabled(_pio, _sm, true);
216+
}
217+
}
218+
219+
// Convert from microseconds to PIO clock cycles
220+
static int usToPIOCycles(int us) {
221+
// Parenthesis needed to guarantee order of operations to avoid 32bit overflow
222+
return (us * (clock_get_hz(clk_sys) / 1000000));
223+
}
224+
225+
// Get current clock frequency
226+
static int f_cpu() {
227+
return clock_get_hz(clk_sys);
228+
}
229+
230+
// Get CPU cycle count. Needs to do magic to extens 24b HW to something longer
231+
volatile uint64_t _epoch = 0;
232+
inline uint32_t getCycleCount() {
233+
if (!__isFreeRTOS) {
234+
uint32_t epoch;
235+
uint32_t ctr;
236+
do {
237+
epoch = (uint32_t)_epoch;
238+
ctr = systick_hw->cvr;
239+
} while (epoch != (uint32_t)_epoch);
240+
return epoch + (1 << 24) - ctr; /* CTR counts down from 1<<24-1 */
241+
} else {
242+
return ccount_read(_pio, _sm);
243+
}
244+
}
245+
246+
inline uint64_t getCycleCount64() {
247+
if (!__isFreeRTOS) {
248+
uint64_t epoch;
249+
uint64_t ctr;
250+
do {
251+
epoch = _epoch;
252+
ctr = systick_hw->cvr;
253+
} while (epoch != _epoch);
254+
return epoch + (1LL << 24) - ctr;
255+
} else {
256+
return ccount_read(_pio, _sm);
257+
}
258+
}
259+
260+
void idleOtherCore() {
261+
fifo.idleOtherCore();
262+
}
263+
264+
void resumeOtherCore() {
265+
fifo.resumeOtherCore();
266+
}
267+
268+
void restartCore1() {
269+
multicore_reset_core1();
270+
fifo.clear();
271+
multicore_launch_core1(main1);
272+
}
273+
274+
// Multicore comms FIFO
275+
_MFIFO fifo;
276+
277+
private:
278+
static void _SystickHandler() {
279+
rp2040._epoch += 1LL << 24;
280+
}
281+
PIO _pio;
282+
int _sm;
283+
PIOProgram *_ccountPgm;
284+
};

cores/rp2040/RP2040USB.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,8 @@ static int64_t timer_task(__unused alarm_id_t id, __unused void *user_data) {
287287
return USB_TASK_INTERVAL;
288288
}
289289

290+
void __USBStart() __attribute__((weak));
291+
290292
void __USBStart() {
291293
if (tusb_inited()) {
292294
// Already called

cores/rp2040/ccount.pio

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
; Cycle Count for the Raspberry Pi Pico RP2040
2+
;
3+
; Copyright (c) 2022 Earle F. Philhower, III <[email protected]>
4+
;
5+
; This library is free software; you can redistribute it and/or
6+
; modify it under the terms of the GNU Lesser General Public
7+
; License as published by the Free Software Foundation; either
8+
; version 2.1 of the License, or (at your option) any later version.
9+
;
10+
; This library is distributed in the hope that it will be useful,
11+
; but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
; Lesser General Public License for more details.
14+
;
15+
; You should have received a copy of the GNU Lesser General Public
16+
; License along with this library; if not, write to the Free Software
17+
; Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18+
19+
; Cycle count is stored in {-y, -x}
20+
21+
.program ccount
22+
cnt:
23+
jmp x-- cnt
24+
epoch:
25+
jmp y-- cnt
26+
27+
% c-sdk {
28+
static inline void ccount_program_init(PIO pio, uint sm, uint offset) {
29+
pio_sm_config c = ccount_program_get_default_config(offset);
30+
pio_sm_init(pio, sm, offset, &c);
31+
pio_sm_exec(pio, sm, pio_encode_set(pio_x, 0));
32+
pio_sm_exec(pio, sm, pio_encode_set(pio_y, 0));
33+
}
34+
35+
static inline uint64_t ccount_read(PIO pio, uint sm) {
36+
static uint64_t extra = 0;
37+
// Guard against having the epoch rollover while we're reading the time.
38+
// If epoch2 != epoch1, we looped in middle and get new LSW
39+
pio_sm_exec(pio, sm, pio_encode_mov(pio_isr, pio_y));
40+
pio_sm_exec(pio, sm, pio_encode_push(false, false));
41+
pio_sm_exec(pio, sm, pio_encode_mov(pio_isr, pio_x));
42+
pio_sm_exec(pio, sm, pio_encode_push(false, false));
43+
pio_sm_exec(pio, sm, pio_encode_mov(pio_isr, pio_y));
44+
pio_sm_exec(pio, sm, pio_encode_push(false, false));
45+
pio_sm_exec(pio, sm, pio_encode_mov(pio_isr, pio_x));
46+
pio_sm_exec(pio, sm, pio_encode_push(false, false));
47+
extra += 8;
48+
uint32_t y1 = -((int)pio_sm_get_blocking(pio, sm));
49+
uint32_t x1 = -((int)pio_sm_get_blocking(pio, sm));
50+
uint32_t y2 = -((int)pio_sm_get_blocking(pio, sm));
51+
uint32_t x2 = -((int)pio_sm_get_blocking(pio, sm));
52+
uint64_t val;
53+
if (y2 != y1) {
54+
val = ((((uint64_t)y2) << 32LL) | x2) + y2 /* adjust for missed cycle every epoch increment */;
55+
} else {
56+
val = ((((uint64_t)y1) << 32LL) | x1) + y1 /* adjust for missed cycle every epoch increment */;
57+
}
58+
return val + extra;
59+
}
60+
61+
%}
62+

0 commit comments

Comments
 (0)