Unverified Commit bda630e4 authored by Earle F. Philhower, III's avatar Earle F. Philhower, III Committed by GitHub

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).
parent 9afdc48d
......@@ -20,7 +20,7 @@ jobs:
- name: Run codespell
uses: codespell-project/actions-codespell@master
with:
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
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
ignore_words_list: ser,DOUT
# Consistent style
......
......@@ -25,3 +25,6 @@
[submodule "libraries/Adafruit_TinyUSB_Arduino"]
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
url = https://github.com/earlephilhower/FreeRTOS-Kernel.git
......@@ -173,6 +173,7 @@ If you want to contribute or have bugfixes, drop me a note at <earlephilhower@ya
* [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).
* [UF2CONV.PY](https://github.com/microsoft/uf2) is by Microsoft Corporation and licensed under the MIT license.
* Some filesystem code taken from the [ESP8266 Arduino Core](https://github.com/esp8266/Arduino) and licensed under the LGPL.
* [FreeRTOS](https://freertos.org) is Copyright Amazon.com, Inc. or its affiliates, and distributed under the MIT license.
-Earle F. Philhower, III
earlephilhower@yahoo.com
......@@ -79,6 +79,9 @@ void analogWriteFreq(uint32_t freq);
void analogWriteRange(uint32_t range);
void analogWriteResolution(int res);
// FreeRTOS potential calls
extern bool __isFreeRTOS;
#ifdef __cplusplus
} // extern "C"
#endif
......
......@@ -25,7 +25,11 @@
#include <hardware/structs/systick.h>
#include <pico/multicore.h>
#include <pico/util/queue.h>
#include <CoreMutex.h>
#include "CoreMutex.h"
#include "ccount.pio.h"
extern "C" volatile bool __otherCoreIdled;
class _MFIFO {
public:
......@@ -45,9 +49,12 @@ public:
}
void registerCore() {
multicore_fifo_clear_irq();
irq_set_exclusive_handler(SIO_IRQ_PROC0 + get_core_num(), _irq);
irq_set_enabled(SIO_IRQ_PROC0 + get_core_num(), true);
if (!__isFreeRTOS) {
multicore_fifo_clear_irq();
irq_set_exclusive_handler(SIO_IRQ_PROC0 + get_core_num(), _irq);
irq_set_enabled(SIO_IRQ_PROC0 + get_core_num(), true);
}
// FreeRTOS port.c will handle the IRQ hooking
}
void push(uint32_t val) {
......@@ -79,9 +86,9 @@ public:
return;
}
mutex_enter_blocking(&_idleMutex);
_otherIdled = false;
__otherCoreIdled = false;
multicore_fifo_push_blocking(_GOTOSLEEP);
while (!_otherIdled) { /* noop */ }
while (!__otherCoreIdled) { /* noop */ }
}
void resumeOtherCore() {
......@@ -89,9 +96,9 @@ public:
return;
}
mutex_exit(&_idleMutex);
_otherIdled = false;
__otherCoreIdled = false;
// Other core will exit busy-loop and return to operation
// once otherIdled == false.
// once __otherCoreIdled == false.
}
void clear() {
......@@ -108,98 +115,31 @@ public:
private:
static void __no_inline_not_in_flash_func(_irq)() {
multicore_fifo_clear_irq();
noInterrupts(); // We need total control, can't run anything
while (multicore_fifo_rvalid()) {
if (_GOTOSLEEP == multicore_fifo_pop_blocking()) {
_otherIdled = true;
while (_otherIdled) { /* noop */ }
break;
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;
}
}
interrupts();
}
interrupts();
}
bool _multicore = false;
bool _multicore = false;
mutex_t _idleMutex;
static volatile bool _otherIdled;
queue_t _queue[2];
static constexpr int _GOTOSLEEP = 0x66666666;
static constexpr uint32_t _GOTOSLEEP = 0xC0DED02E;
};
class RP2040;
extern RP2040 rp2040;
extern "C" void main1();
class RP2040 {
public:
RP2040() {
_epoch = 0;
// Enable SYSTICK exception
exception_set_exclusive_handler(SYSTICK_EXCEPTION, _SystickHandler);
systick_hw->csr = 0x7;
systick_hw->rvr = 0x00FFFFFF;
}
~RP2040() { /* noop */ }
// Convert from microseconds to PIO clock cycles
static int usToPIOCycles(int us) {
// Parenthesis needed to guarantee order of operations to avoid 32bit overflow
return (us * (clock_get_hz(clk_sys) / 1000000));
}
// Get current clock frequency
static int f_cpu() {
return clock_get_hz(clk_sys);
}
// Get CPU cycle count. Needs to do magic to extens 24b HW to something longer
volatile uint64_t _epoch = 0;
inline uint32_t getCycleCount() {
uint32_t epoch;
uint32_t ctr;
do {
epoch = (uint32_t)_epoch;
ctr = systick_hw->cvr;
} while (epoch != (uint32_t)_epoch);
return epoch + (1 << 24) - ctr; /* CTR counts down from 1<<24-1 */
}
inline uint64_t getCycleCount64() {
uint64_t epoch;
uint64_t ctr;
do {
epoch = _epoch;
ctr = systick_hw->cvr;
} while (epoch != _epoch);
return epoch + (1LL << 24) - ctr;
}
void idleOtherCore() {
fifo.idleOtherCore();
}
void resumeOtherCore() {
fifo.resumeOtherCore();
}
void restartCore1() {
multicore_reset_core1();
fifo.clear();
multicore_launch_core1(main1);
}
// Multicore comms FIFO
_MFIFO fifo;
private:
static void _SystickHandler() {
rp2040._epoch += 1LL << 24;
}
};
class PIOProgram;
// Wrapper class for PIO programs, abstracting common operations out
// TODO - Add unload/destructor
......@@ -255,3 +195,90 @@ private:
const pio_program_t *_pgm;
};
class RP2040 {
public:
RP2040() { /* noop */ }
~RP2040() { /* noop */ }
void begin() {
_epoch = 0;
if (!__isFreeRTOS) {
// Enable SYSTICK exception
exception_set_exclusive_handler(SYSTICK_EXCEPTION, _SystickHandler);
systick_hw->csr = 0x7;
systick_hw->rvr = 0x00FFFFFF;
} else {
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);
}
}
// Convert from microseconds to PIO clock cycles
static int usToPIOCycles(int us) {
// Parenthesis needed to guarantee order of operations to avoid 32bit overflow
return (us * (clock_get_hz(clk_sys) / 1000000));
}
// Get current clock frequency
static int f_cpu() {
return clock_get_hz(clk_sys);
}
// Get CPU cycle count. Needs to do magic to extens 24b HW to something longer
volatile uint64_t _epoch = 0;
inline uint32_t getCycleCount() {
if (!__isFreeRTOS) {
uint32_t epoch;
uint32_t ctr;
do {
epoch = (uint32_t)_epoch;
ctr = systick_hw->cvr;
} while (epoch != (uint32_t)_epoch);
return epoch + (1 << 24) - ctr; /* CTR counts down from 1<<24-1 */
} else {
return ccount_read(_pio, _sm);
}
}
inline uint64_t getCycleCount64() {
if (!__isFreeRTOS) {
uint64_t epoch;
uint64_t ctr;
do {
epoch = _epoch;
ctr = systick_hw->cvr;
} while (epoch != _epoch);
return epoch + (1LL << 24) - ctr;
} else {
return ccount_read(_pio, _sm);
}
}
void idleOtherCore() {
fifo.idleOtherCore();
}
void resumeOtherCore() {
fifo.resumeOtherCore();
}
void restartCore1() {
multicore_reset_core1();
fifo.clear();
multicore_launch_core1(main1);
}
// Multicore comms FIFO
_MFIFO fifo;
private:
static void _SystickHandler() {
rp2040._epoch += 1LL << 24;
}
PIO _pio;
int _sm;
PIOProgram *_ccountPgm;
};
......@@ -287,6 +287,8 @@ static int64_t timer_task(__unused alarm_id_t id, __unused void *user_data) {
return USB_TASK_INTERVAL;
}
void __USBStart() __attribute__((weak));
void __USBStart() {
if (tusb_inited()) {
// Already called
......
; Cycle Count for the Raspberry Pi Pico RP2040
;
; Copyright (c) 2022 Earle F. Philhower, III <earlephilhower@yahoo.com>
;
; This library is free software; you can redistribute it and/or
; modify it under the terms of the GNU Lesser General Public
; License as published by the Free Software Foundation; either
; version 2.1 of the License, or (at your option) any later version.
;
; This library is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
; Lesser General Public License for more details.
;
; You should have received a copy of the GNU Lesser General Public
; License along with this library; if not, write to the Free Software
; Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
; Cycle count is stored in {-y, -x}
.program ccount
cnt:
jmp x-- cnt
epoch:
jmp y-- cnt
% c-sdk {
static inline void ccount_program_init(PIO pio, uint sm, uint offset) {
pio_sm_config c = ccount_program_get_default_config(offset);
pio_sm_init(pio, sm, offset, &c);
pio_sm_exec(pio, sm, pio_encode_set(pio_x, 0));
pio_sm_exec(pio, sm, pio_encode_set(pio_y, 0));
}
static inline uint64_t ccount_read(PIO pio, uint sm) {
static uint64_t extra = 0;
// Guard against having the epoch rollover while we're reading the time.
// If epoch2 != epoch1, we looped in middle and get new LSW
pio_sm_exec(pio, sm, pio_encode_mov(pio_isr, pio_y));
pio_sm_exec(pio, sm, pio_encode_push(false, false));
pio_sm_exec(pio, sm, pio_encode_mov(pio_isr, pio_x));
pio_sm_exec(pio, sm, pio_encode_push(false, false));
pio_sm_exec(pio, sm, pio_encode_mov(pio_isr, pio_y));
pio_sm_exec(pio, sm, pio_encode_push(false, false));
pio_sm_exec(pio, sm, pio_encode_mov(pio_isr, pio_x));
pio_sm_exec(pio, sm, pio_encode_push(false, false));
extra += 8;
uint32_t y1 = -((int)pio_sm_get_blocking(pio, sm));
uint32_t x1 = -((int)pio_sm_get_blocking(pio, sm));
uint32_t y2 = -((int)pio_sm_get_blocking(pio, sm));
uint32_t x2 = -((int)pio_sm_get_blocking(pio, sm));
uint64_t val;
if (y2 != y1) {
val = ((((uint64_t)y2) << 32LL) | x2) + y2 /* adjust for missed cycle every epoch increment */;
} else {
val = ((((uint64_t)y1) << 32LL) | x1) + y1 /* adjust for missed cycle every epoch increment */;
}
return val + extra;
}
%}
// -------------------------------------------------- //
// This file is autogenerated by pioasm; do not edit! //
// -------------------------------------------------- //
#pragma once
#if !PICO_NO_HARDWARE
#include "hardware/pio.h"
#endif
// ------ //
// ccount //
// ------ //
#define ccount_wrap_target 0
#define ccount_wrap 1
static const uint16_t ccount_program_instructions[] = {
// .wrap_target
0x0040, // 0: jmp x--, 0
0x0080, // 1: jmp y--, 0
// .wrap
};
#if !PICO_NO_HARDWARE
static const struct pio_program ccount_program = {
.instructions = ccount_program_instructions,
.length = 2,
.origin = -1,
};
static inline pio_sm_config ccount_program_get_default_config(uint offset) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + ccount_wrap_target, offset + ccount_wrap);
return c;
}
static inline void ccount_program_init(PIO pio, uint sm, uint offset) {
pio_sm_config c = ccount_program_get_default_config(offset);
pio_sm_init(pio, sm, offset, &c);
pio_sm_exec(pio, sm, pio_encode_set(pio_x, 0));
pio_sm_exec(pio, sm, pio_encode_set(pio_y, 0));
}
static inline uint64_t ccount_read(PIO pio, uint sm) {
static uint64_t extra = 0;
// Guard against having the epoch rollover while we're reading the time.
// If epoch2 != epoch1, we looped in middle and get new LSW
pio_sm_exec(pio, sm, pio_encode_mov(pio_isr, pio_y));
pio_sm_exec(pio, sm, pio_encode_push(false, false));
pio_sm_exec(pio, sm, pio_encode_mov(pio_isr, pio_x));
pio_sm_exec(pio, sm, pio_encode_push(false, false));
pio_sm_exec(pio, sm, pio_encode_mov(pio_isr, pio_y));
pio_sm_exec(pio, sm, pio_encode_push(false, false));
pio_sm_exec(pio, sm, pio_encode_mov(pio_isr, pio_x));
pio_sm_exec(pio, sm, pio_encode_push(false, false));
extra += 8;
uint32_t y1 = -((int)pio_sm_get_blocking(pio, sm));
uint32_t x1 = -((int)pio_sm_get_blocking(pio, sm));
uint32_t y2 = -((int)pio_sm_get_blocking(pio, sm));
uint32_t x2 = -((int)pio_sm_get_blocking(pio, sm));
uint64_t val;
if (y2 != y1) {
val = ((((uint64_t)y2) << 32LL) | x2) + y2 /* adjust for missed cycle every epoch increment */;
} else {
val = ((((uint64_t)y1) << 32LL) | x1) + y1 /* adjust for missed cycle every epoch increment */;
}
return val + extra;
}
#endif
......@@ -25,6 +25,9 @@
#include "Adafruit_TinyUSB_API.h"
#endif
extern "C" void delay(unsigned long ms) __attribute__((weak));
extern "C" void yield() __attribute__((weak));
extern "C"
{
......
......@@ -24,20 +24,24 @@
#include <pico/multicore.h>
RP2040 rp2040;
extern "C" {
volatile bool __otherCoreIdled = false;
};
volatile bool _MFIFO::_otherIdled = false;
mutex_t _pioMutex;
extern void setup();
extern void loop();
// FreeRTOS potential includes
extern void initFreeRTOS() __attribute__((weak));
extern void startFreeRTOS() __attribute__((weak));
bool __isFreeRTOS;
// Weak empty variant initialization. May be redefined by variant files.
void initVariant() __attribute__((weak));
void initVariant() { }
// Optional 2nd core setup and loop
extern void setup1() __attribute__((weak));
extern void loop1() __attribute__((weak));
......@@ -53,14 +57,40 @@ extern "C" void main1() {
}
}
extern void __loop() {
#ifdef USE_TINYUSB
yield();
#endif
if (arduino::serialEventRun) {
arduino::serialEventRun();
}
if (arduino::serialEvent1Run) {
arduino::serialEvent1Run();
}
if (arduino::serialEvent2Run) {
arduino::serialEvent2Run();
}
}
extern "C" int main() {
#if F_CPU != 125000000
set_sys_clock_khz(F_CPU / 1000, true);
#endif
// Let rest of core know if we're using FreeRTOS
__isFreeRTOS = initFreeRTOS ? true : false;
mutex_init(&_pioMutex);
rp2040.begin();
initVariant();
if (__isFreeRTOS) {
initFreeRTOS();
}
#ifndef NO_USB
#ifdef USE_TINYUSB
TinyUSB_Device_Init(0);
......@@ -69,43 +99,46 @@ extern "C" int main() {
__USBStart();
#ifndef DISABLE_USB_SERIAL
// Enable serial port for reset/upload always
Serial.begin(115200);
if (!__isFreeRTOS) {
// Enable serial port for reset/upload always
Serial.begin(115200);
}
#endif
#endif
#endif
#if defined DEBUG_RP2040_PORT
DEBUG_RP2040_PORT.begin(115200);
if (!__isFreeRTOS) {
DEBUG_RP2040_PORT.begin(115200);
}
#endif
#ifndef NO_USB
if (setup1 || loop1) {
rp2040.fifo.begin(2);
multicore_launch_core1(main1);
} else {
rp2040.fifo.begin(1);
if (!__isFreeRTOS) {
if (setup1 || loop1) {
rp2040.fifo.begin(2);
multicore_launch_core1(main1);
} else {
rp2040.fifo.begin(1);
}
rp2040.fifo.registerCore();
}
rp2040.fifo.registerCore();
#endif
setup();
while (true) {
loop();
#ifdef USE_TINYUSB
yield();
#endif
if (arduino::serialEventRun) {
arduino::serialEventRun();
}
if (arduino::serialEvent1Run) {
arduino::serialEvent1Run();
}
if (arduino::serialEvent2Run) {
arduino::serialEvent2Run();
if (!__isFreeRTOS) {
setup();
while (true) {
loop();
__loop();
}
} else {
rp2040.fifo.begin(2);
startFreeRTOS();
}
return 0;
}
extern "C" unsigned long ulMainGetRunTimeCounterValue() {
return rp2040.getCycleCount64();
}
FreeRTOS
========
The SMP port of FreeRTOS is included with the core. This allows complex task operations
and real preemptive multithreading in your sketches. To enable FreeRTOS, simply add
.. code:: c++
#include <FreeRTOS.h>
to your sketch and it will be included and enabled automatically.
FreeRTOS is configured with 8 priority levels (0 through 7) and a process for
``setup()/loop()``, ``setup1()/loop1()``, and the USB port will be created. The task
quantum is 1 millisecond (i.e. 1,000 switches per second).
``setup()`` and ``loop()`` are assigned to only run on core 0, while ``setup1()`` and ``loop1()``
only run in core 1 in this mode, the same as the default multithreading mode.
You can launch and manage additional processes using the standard FreeRTOS routines.
``delay()`` and ``yield()`` free the CPU for other tasks, while ``delayMicroseconds()`` does not.
For full FreeRTOS documentation look at `FreeRTOS.org <https://freertos.org/index.html>`__
and `FreeRTOS SMP support <https://freertos.org/symmetric-multiprocessing-introduction.html>`__.
......@@ -37,6 +37,8 @@ For the latest version, always check https://github.com/earlephilhower/arduino-p
USB (Arduino and Adafruit_TinyUSB) <usb>
Multicore Processing <multicore>
FreeRTOS <freertos>
Ported/Optimized Libraries <libraries>
Using Pico-SDK <sdk>
......
// Demonstrates a simple use of the setup1()/loop1() functions
// for a multiprocessor run.
// Will output something like, where C0 is running on core 0 and
// C1 is on core 1, in parallel.
// 11:23:07.507 -> C0: Blue leader standing by...
// 11:23:07.507 -> C1: Red leader standing by...
// 11:23:07.507 -> C1: Stay on target...
// 11:23:08.008 -> C1: Stay on target...
// 11:23:08.505 -> C0: Blue leader standing by...
// 11:23:08.505 -> C1: Stay on target...
// 11:23:09.007 -> C1: Stay on target...
// 11:23:09.511 -> C0: Blue leader standing by...
// 11:23:09.511 -> C1: Stay on target...
// 11:23:10.015 -> C1: Stay on target...
// Released to the public domain
#include <FreeRTOS.h>
#include <task.h>
#include <map>
#include <EEPROM.h>
std::map<eTaskState, const char *> eTaskStateName { {eReady, "Ready"}, { eRunning, "Running" }, {eBlocked, "Blocked"}, {eSuspended, "Suspended"}, {eDeleted, "Deleted"} };
void ps() {
int tasks = uxTaskGetNumberOfTasks();
TaskStatus_t *pxTaskStatusArray = new TaskStatus_t[tasks];
unsigned long runtime;
tasks = uxTaskGetSystemState( pxTaskStatusArray, tasks, &runtime );
Serial.printf("# Tasks: %d\n", tasks);
Serial.println("ID, NAME, STATE, PRIO, CYCLES");
for (int i=0; i < tasks; i++) {
Serial.printf("%d: %-16s %-10s %d %lu\n", i, pxTaskStatusArray[i].pcTaskName, eTaskStateName[pxTaskStatusArray[i].eCurrentState], pxTaskStatusArray[i].uxCurrentPriority, pxTaskStatusArray[i].ulRunTimeCounter);
}
delete[] pxTaskStatusArray;
}
void blink(void *param) {
(void) param;
pinMode(LED_BUILTIN, OUTPUT);
while (true) {
digitalWrite(LED_BUILTIN, LOW);
delay(750);
digitalWrite(LED_BUILTIN, HIGH);
delay(250);
}
}
void setup() {
Serial.begin(115200);
xTaskCreate(blink, "BLINK", 128, nullptr, 1, nullptr);
delay(5000);
}
volatile int val= 0;
void loop() {
Serial.printf("C0: Blue leader standing by...\n");
ps();
Serial.printf("val: %d\n", val);
delay(1000);
}
// Running on core1
void setup1() {
delay(5000);
Serial.printf("C1: Red leader standing by...\n");
}
void loop1() {
static int x = 0;
Serial.printf("C1: Stay on target...\n");
val++;
if (++x < 10) {
EEPROM.begin(512);
EEPROM.write(0,x);
EEPROM.commit();
}
delay(1000);
}
# Syntax Coloring Map For FreeRTOS
# https://arduino.github.io/arduino-cli/library-specification/#keywords
# Formatted by a single true tab (not spaces)
# Datatypes (KEYWORD1)
StackType_t KEYWORD1
BaseType_t KEYWORD1
UBaseType_t KEYWORD1
TickType_t KEYWORD1
TaskHandle_t KEYWORD1
QueueHandle_t KEYWORD1
TimerHandle_t KEYWORD1
SemaphoreHandle_t KEYWORD1
StreamBufferHandle_t KEYWORD1
MessageBufferHandle_t KEYWORD1
EventGroupHandle_t KEYWORD1
# Methods and Functions (KEYWORD2)
xSemaphoreCreateMutex KEYWORD2
xSemaphoreCreateBinary KEYWORD2
xSemaphoreTake KEYWORD2
xSemaphoreTakeFromISR KEYWORD2
xSemaphoreGive KEYWORD2
xSemaphoreGiveFromISR KEYWORD2
xTaskCreate KEYWORD2
vTaskDelete KEYWORD2
vTaskDelay KEYWORD2
xTaskDelayUntil KEYWORD2
xQueueCreate KEYWORD2
xQueueSend KEYWORD2
xQueueReceive KEYWORD2
pcTaskGetName KEYWORD2
ulTaskNotifyTake KEYWORD2
vTaskNotifyGiveFromISR KEYWORD2
taskYIELD KEYWORD2
vTaskSuspend KEYWORD2
vTaskResume KEYWORD2
xTaskResumeFromISR KEYWORD2
xTaskGetTickCount KEYWORD2
xTaskGetTickCountFromISR KEYWORD2
uxTaskGetNumberOfTasks KEYWORD2
uxTaskGetStackHighWaterMark KEYWORD2
# Instances (KEYWORD2)
# Structures (KEYWORD3)
TaskParameters_t KEYWORD3
TaskStatus_t KEYWORD3
ListItem_t KEYWORD3
MiniListItem_t KEYWORD3
HeapStats_t KEYWORD3
# Constants (LITERAL1)
portUSE_WDTO LITERAL1
portTICK_PERIOD_MS LITERAL1
configTICK_RATE_HZ LITERAL1
configCPU_CLOCK_HZ LITERAL1
configMAX_PRIORITIES LITERAL1
configMINIMAL_STACK_SIZE LITERAL1
Subproject commit f9c21016ab3793b4dc8e6530007a68c9ee774675
name=FreeRTOS
version=1.0.0
author=Graham Sanderson <info@freertos.org>
maintainer=Graham Sanderson <info@freertos.org>
sentence=<h3>FreeRTOS Real Time Operating System implemented for RP2040.</h3>
paragraph=Taken from the official FreeRTOS SMP branch.
category=Timing
url=https://github.com/FreeRTOS/FreeRTOS-Kernel
architectures=rp2040
license=MIT
**ATTENTION**
Please be aware that this library was copied from the original Arduino AVR FreeRTOS library and may still contain files from that library that have no meaning in the context of this package, i.e. the licensing and code of conduct file! Each file retains the license and copyright from where it was taken (FreeRTOS repository or AVR FreeRTOS library, respectively.)
______
This is a copy of the RP2040 port of the FreeRTOS SMP branch, packaged as an Arduino library.
It has been created to provide access to FreeRTOS capabilities, with full compatibility to the Arduino environment.
It does this by keeping hands off almost everything, and only touching the minimum of hardware to be successful.
## General
FreeRTOS has a multitude of configuration options, which can be specified from within the FreeRTOSConfig.h file.
To keep commonality with all of the Arduino hardware options, some sensible defaults have been selected.
System ticks are 1ms, which means that Tasks can only be scheduled to run up to 1000 times per second.
Stack for the `loop()` function has been set at 256 bytes. This can be configured by adjusting the `configMINIMAL_STACK_SIZE` parameter. If you have stack overflow issues, just increase it.
Users should prefer to allocate larger structures, arrays, or buffers using `pvPortMalloc()`, rather than defining them locally on the stack.
Memory for the heap is allocated by the normal `malloc()` function, wrapped by `pvPortMalloc()`.
This option has been selected because it is automatically adjusted to use the capabilities of each device.
Other heap allocation schemes are supported by FreeRTOS, and they can used with additional configuration.
## Errors
* Stack Overflow: If any stack (for the `loop()` or) for any Task overflows, there will be a slow LED blink, with 4 second cycle.
* Heap Overflow: If any Task tries to allocate memory and that allocation fails, there will be a fast LED blink, with 100 millisecond cycle.
## Files & Configuration
* `RP2040_FreeRTOS.h` : Must always be `#include` first. It references other configuration files, and sets defaults where necessary.
* `FreeRTOSConfig.h` : Contains a multitude of API and environment configurations.
* `variantHooks.cpp` : Contains the RP2040 specific configurations for this port of FreeRTOS.
* `heap_3.c` : Contains the heap allocation scheme based on `malloc()`. Other schemes are available, but depend on user configuration for specific MCU choice.
## Sources / Credits ✨
This library is built on the efforts of the authors of the FreeRTOS SMP port for the RP2040, using the original Arduino FreeRTOS library as a template for the library package and the Arduino specific behavior.
#include "../lib/FreeRTOS-Kernel/include/FreeRTOS.h"
/* Cores */
#define configNUM_CORES 2
#define configUSE_CORE_AFFINITY 1
#define configRUN_MULTIPLE_PRIORITIES 1
#define configUSE_PREEMPTION 1
#define configUSE_IDLE_HOOK 1
#define configUSE_MINIMAL_IDLE_HOOK 1
#define configUSE_TICK_HOOK 1
#define configCPU_CLOCK_HZ ( ( unsigned long ) F_CPU )
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
#define configMAX_PRIORITIES ( 8 )
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 256 )
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 164 * 1024 ) )
#define configMAX_TASK_NAME_LEN ( 10 )
#define configUSE_TRACE_FACILITY 1
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
#define configUSE_MUTEXES 1
#define configQUEUE_REGISTRY_SIZE 8
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_MALLOC_FAILED_HOOK 1
#define configUSE_APPLICATION_TASK_TAG 0
#define configUSE_COUNTING_SEMAPHORES 1
#define configUSE_QUEUE_SETS 1
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configSUPPORT_STATIC_ALLOCATION 0
/* Run time stats related definitions. */
void vMainConfigureTimerForRunTimeStats( void );
unsigned long ulMainGetRunTimeCounterValue( void );
#define configGENERATE_RUN_TIME_STATS 1
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() //vMainConfigureTimerForRunTimeStats()
#define portGET_RUN_TIME_COUNTER_VALUE() ulMainGetRunTimeCounterValue()
/* Co-routine definitions. */
#define configUSE_CO_ROUTINES 1
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
/* Software timer definitions. */
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY ( 2 )
#define configTIMER_QUEUE_LENGTH 5
#define configTIMER_TASK_STACK_DEPTH ( 80 )
/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
#define INCLUDE_xTaskGetCurrentTaskHandle 1
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskCleanUpResources 1
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_eTaskGetState 1
/* This demo makes use of one or more example stats formatting functions. These
format the raw data provided by the uxTaskGetSystemState() function in to human
readable ASCII form. See the notes in the implementation of vTaskList() within
FreeRTOS/Source/tasks.c for limitations. */
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
#define configUSE_MUTEXES 1
#define INCLUDE_uxTaskGetStackHighWaterMark 1
#define INCLUDE_xTaskGetIdleTaskHandle 1
#define configUSE_MALLOC_FAILED_HOOK 1
#define configCHECK_FOR_STACK_OVERFLOW 2
/* Normal assert() semantics without relying on the provision of an assert.h
header file. */
/* Cortex-M specific definitions. */
#undef __NVIC_PRIO_BITS
#ifdef __NVIC_PRIO_BITS
/* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
#define configPRIO_BITS __NVIC_PRIO_BITS
#else
#define configPRIO_BITS 3 /* 8 priority levels */
#endif
/* The lowest interrupt priority that can be used in a call to a "set priority"
function. */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0x7
/* The highest interrupt priority that can be used by any interrupt service
routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL
INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
/* Interrupt priorities used by the kernel port layer itself. These are generic
to all Cortex-M ports, and do not rely on any particular library functions. */
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
extern void rtosFatalError(void);
#define configASSERT( x ) \
if( ( x ) == 0 ) { portDISABLE_INTERRUPTS(); rtosFatalError(); }
/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
standard names - or at least those used in the unmodified vector table. */
//#define xPortPendSVHandler PendSV_Handler
//#define xPortSysTickHandler SysTick_Handler
//#define vPortSVCHandler SVC_Handler
/* The size of the global output buffer that is available for use when there
are multiple command interpreters running at once (for example, one on a UART
and one on TCP/IP). This is done to prevent an output buffer being defined by
each implementation - which would waste RAM. In this case, there is only one
command interpreter running. */
#define configCOMMAND_INT_MAX_OUTPUT_SIZE 2048
#define configUSE_DYNAMIC_EXCEPTION_HANDLERS 1
#define configSUPPORT_PICO_SYNC_INTEROP 1
#define configSUPPORT_PICO_TIME_INTEROP 1
#include "rp2040_config.h"
//#include "task.h"
#include "../lib/FreeRTOS-Kernel/include/StackMacros.h"
#include "../lib/FreeRTOS-Kernel/include/atomic.h"
#include "../lib/FreeRTOS-Kernel/croutine.c"
#include "../lib/FreeRTOS-Kernel/include/croutine.h"
#include "../lib/FreeRTOS-Kernel/include/deprecated_definitions.h"
#include "../lib/FreeRTOS-Kernel/event_groups.c"
#include "../lib/FreeRTOS-Kernel/include/event_groups.h"
#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2040/include/freertos_sdk_config.h"
#include "../lib/FreeRTOS-Kernel/portable/MemMang/heap_3.c"
#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2040/idle_task_static_memory.c"
#include "../lib/FreeRTOS-Kernel/list.c"
#include "../lib/FreeRTOS-Kernel/include/list.h"
#include "../lib/FreeRTOS-Kernel/include/message_buffer.h"
#include "../lib/FreeRTOS-Kernel/include/mpu_prototypes.h"
#include "../lib/FreeRTOS-Kernel/include/mpu_wrappers.h"
#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2040/port.c"
#include "../lib/FreeRTOS-Kernel/include/portable.h"
#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2040/include/portmacro.h"
#include "../lib/FreeRTOS-Kernel/include/projdefs.h"
#include "../lib/FreeRTOS-Kernel/queue.c"
#include "../lib/FreeRTOS-Kernel/include/queue.h"
#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2040/include/rp2040_config.h"
#include "../lib/FreeRTOS-Kernel/include/semphr.h"
#include "../lib/FreeRTOS-Kernel/include/stack_macros.h"
#include "../lib/FreeRTOS-Kernel/stream_buffer.c"
#include "../lib/FreeRTOS-Kernel/include/stream_buffer.h"
#include "../lib/FreeRTOS-Kernel/include/task.h"
#include "../lib/FreeRTOS-Kernel/tasks.c"
#include "../lib/FreeRTOS-Kernel/timers.c"
#include "../lib/FreeRTOS-Kernel/include/timers.h"
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment