Compare commits
@@ -14,21 +14,21 @@ jobs:
|
||||
name: Check spelling
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
- 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
|
||||
ignore_words_list: ser,DOUT
|
||||
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
|
||||
ignore_words_list: ser,dout
|
||||
|
||||
# Consistent style
|
||||
astyle:
|
||||
name: Style, Boards, Package
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: false
|
||||
- name: Check package references
|
||||
@@ -46,10 +46,10 @@ jobs:
|
||||
./tests/restyle.sh
|
||||
# If anything changed, GIT should return an error and fail the test
|
||||
git diff --exit-code
|
||||
- name: Check Arduino API copy is clean
|
||||
run: |
|
||||
git submodule update --init ./ArduinoCore-API
|
||||
diff -r ./cores/rp2040/api ./ArduinoCore-API/api
|
||||
# - name: Check Arduino API copy is clean
|
||||
# run: |
|
||||
# git submodule update --init ./ArduinoCore-API
|
||||
# diff -r ./cores/rp2040/api ./ArduinoCore-API/api
|
||||
|
||||
# Build all examples on linux (core and Arduino IDE)
|
||||
build-linux:
|
||||
@@ -59,7 +59,7 @@ jobs:
|
||||
matrix:
|
||||
chunk: [0, 1, 2, 3]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
- uses: actions/setup-python@v2
|
||||
@@ -81,8 +81,6 @@ jobs:
|
||||
run: |
|
||||
cd pico-sdk
|
||||
git submodule update --init
|
||||
cd ../pico-extras
|
||||
git submodule update --init
|
||||
cd ..
|
||||
bash ./tests/build.sh
|
||||
|
||||
@@ -91,7 +89,7 @@ jobs:
|
||||
name: Build TinyUSB Examples
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
- uses: actions/setup-python@v2
|
||||
@@ -111,8 +109,6 @@ jobs:
|
||||
run: |
|
||||
cd pico-sdk
|
||||
git submodule update --init
|
||||
cd ../pico-extras
|
||||
git submodule update --init
|
||||
cd ..
|
||||
bash ./tests/build-tinyusb.sh
|
||||
|
||||
@@ -121,7 +117,7 @@ jobs:
|
||||
name: Windows
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
- uses: actions/setup-python@v2
|
||||
@@ -147,8 +143,6 @@ jobs:
|
||||
try { Get-Command python3 } catch { copy (get-command python).source (get-command python).source.Replace("python.exe", "python3.exe") }
|
||||
cd pico-sdk
|
||||
git submodule update --init
|
||||
cd ../pico-extras
|
||||
git submodule update --init
|
||||
cd ..
|
||||
bash ./tests/build.sh
|
||||
|
||||
@@ -158,7 +152,7 @@ jobs:
|
||||
name: Mac
|
||||
runs-on: macOS-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
- uses: actions/setup-python@v2
|
||||
@@ -181,8 +175,40 @@ jobs:
|
||||
run: |
|
||||
cd pico-sdk
|
||||
git submodule update --init
|
||||
cd ../pico-extras
|
||||
git submodule update --init
|
||||
cd ..
|
||||
bash ./tests/build.sh
|
||||
|
||||
# Build a few examples with PlatformIO to test if integration works
|
||||
build-platformio:
|
||||
name: Build PlatformIO Examples
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
- name: Cache PlatformIO
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
- name: Install PlatformIO
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install --upgrade platformio
|
||||
pio pkg install --global --platform https://github.com/maxgerhardt/platform-raspberrypi.git
|
||||
pio pkg install --global --tool symlink://.
|
||||
- name: Build Multicore Example
|
||||
run: pio ci --board=rpipico --board=adafruit_feather -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/rp2040/examples/Multicore/Multicore.ino
|
||||
- name: Build Fade Example
|
||||
run: pio ci --board=rpipico --board=adafruit_feather -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/rp2040/examples/Fade/Fade.ino
|
||||
- name: Build TinyUSB Example
|
||||
run: pio ci --board=rpipico --board=adafruit_feather -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" -O "build_flags=-DUSE_TINYUSB" libraries/Adafruit_TinyUSB_Arduino/examples/CDC/cdc_multi/cdc_multi.ino
|
||||
@@ -12,16 +12,36 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
- name: Cache PlatformIO
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install PlatformIO
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install --upgrade platformio
|
||||
- name: Deploy updated JSON
|
||||
env:
|
||||
TRAVIS_BUILD_DIR: ${{ github.workspace }}
|
||||
BUILD_TYPE: package
|
||||
CI_GITHUB_API_KEY: ${{ secrets.GITHUB_TOKEN }}
|
||||
PLATFORMIO_AUTH_TOKEN: ${{ secrets.PLATFORMIO_AUTH_TOKEN }}
|
||||
run: |
|
||||
pip3 install PyGithub
|
||||
TAG=$(git describe --exact-match --tags)
|
||||
curl -L -o package_rp2040_index.json "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/releases/download/$TAG/package_rp2040_index.json"
|
||||
./package/update_release.py --token ${CI_GITHUB_API_KEY} --repo "$GITHUB_REPOSITORY" --tag global package_rp2040_index.json
|
||||
# Upload to Platform.IO
|
||||
curl -LO $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/releases/download/$TAG/rp2040-$TAG.zip
|
||||
pio package publish rp2040-$TAG.zip --non-interactive
|
||||
|
||||
@@ -29,7 +29,6 @@ jobs:
|
||||
CI_GITHUB_API_KEY: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
(cd pico-sdk && git submodule update --init)
|
||||
(cd pico-extras && git submodule update --init)
|
||||
(cd ./package && bash ./build_boards_manager_package.sh)
|
||||
pip3 install PyGithub
|
||||
# Create a draft release and upload the ZIP and JSON files.
|
||||
|
||||
+3
-3
@@ -13,9 +13,6 @@
|
||||
[submodule "libraries/SdFat"]
|
||||
path = libraries/ESP8266SdFat
|
||||
url = https://github.com/earlephilhower/ESP8266SdFat.git
|
||||
[submodule "pico-extras"]
|
||||
path = pico-extras
|
||||
url = https://github.com/raspberrypi/pico-extras.git
|
||||
[submodule "libraries/Keyboard"]
|
||||
path = libraries/Keyboard
|
||||
url = https://github.com/earlephilhower/Keyboard
|
||||
@@ -25,3 +22,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
|
||||
|
||||
@@ -18,21 +18,26 @@ See https://arduino-pico.readthedocs.io/en/latest/ along with the examples for m
|
||||
* Adafruit QTPy RP2040
|
||||
* Adafruit STEMMA Friend RP2040
|
||||
* Adafruit Trinkey RP2040 QT
|
||||
* Arduino Nano RP2040 Connect (preliminary)
|
||||
* Arduino Nano RP2040 Connect
|
||||
* Cytron Maker Pi RP2040
|
||||
* Cytron Maker Nano RP2040
|
||||
* DeRuiLab FlyBoard2040 Core
|
||||
* DFRobot Beetle RP2040
|
||||
* Invector Labs Challenger RP2040 WiFi
|
||||
* Invector Labs Challenger RP2040 WiFi/BLE
|
||||
* Invector Labs Challenger NB RP2040 WiFi
|
||||
* Invector Labs Challenger RP2040 LTE
|
||||
* Invector Labs Challenger RP2040 LoRa
|
||||
* Invector Labs RPICO32
|
||||
* Melopero Shake RP2040
|
||||
* Seeed XIAO RP2040
|
||||
* Solder Party RP2040 Stamp
|
||||
* SparkFun ProMicro RP2040
|
||||
* SparkFun Thing Plus RP2040
|
||||
* uPesy RP2040 DevKit
|
||||
* WIZnet W5100S-EVB-Pico
|
||||
* WIZnet W5500-EVB-Pico
|
||||
* WIZnet WizFi360-EVB-Pico
|
||||
* Generic (configurable flash, I/O pins)
|
||||
|
||||
# Installing via Arduino Boards Manager
|
||||
@@ -68,8 +73,6 @@ cd ~/Arduino/hardware/pico/rp2040
|
||||
git submodule update --init
|
||||
cd pico-sdk
|
||||
git submodule update --init
|
||||
cd ../pico-extras
|
||||
git submodule update --init
|
||||
cd ../tools
|
||||
python3 ./get.py
|
||||
`````
|
||||
@@ -141,14 +144,16 @@ The installed tools include a version of OpenOCD (in the pqt-openocd directory)
|
||||
* Generic Arduino USB Serial, Keyboard, and Mouse emulation
|
||||
* Filesystems (LittleFS and SD/SDFS)
|
||||
* Multicore support (setup1() and loop1())
|
||||
* FreeRTOS SMP support
|
||||
* Overclocking and underclocking from the menus
|
||||
* digitalWrite/Read, shiftIn/Out, tone, analogWrite(PWM)/Read, temperature
|
||||
* Peripherals: SPI master, Wire(I2C) master/slave, dual UART, emulated EEPROM, I2S audio output, Servo
|
||||
* Peripherals: SPI master, Wire(I2C) master/slave, dual UART, emulated EEPROM, I2S audio input, I2S audio output, Servo
|
||||
* printf (i.e. debug) output over USB serial
|
||||
|
||||
The RP2040 PIO state machines (SMs) are used to generate jitter-free:
|
||||
* Servos
|
||||
* Tones
|
||||
* I2S Input
|
||||
* I2S Output
|
||||
* Software UARTs (Serial ports)
|
||||
|
||||
@@ -166,11 +171,12 @@ If you want to contribute or have bugfixes, drop me a note at <earlephilhower@ya
|
||||
# Licensing and Credits
|
||||
* The [Arduino IDE and ArduinoCore-API](https://arduino.cc) are developed and maintained by the Arduino team. The IDE is licensed under GPL.
|
||||
* The [RP2040 GCC-based toolchain](https://github.com/earlephilhower/pico-quick-toolchain) is licensed under under the GPL.
|
||||
* The [Pico-SDK](https://github.com/raspberrypi/pico-sdk) and [Pico-Extras](https://github.com/raspberrypi/pico-extras) are by Raspberry Pi (Trading) Ltd and licensed under the BSD 3-Clause license.
|
||||
* The [Pico-SDK](https://github.com/raspberrypi/pico-sdk) is by Raspberry Pi (Trading) Ltd and licensed under the BSD 3-Clause license.
|
||||
* [Arduino-Pico](https://github.com/earlephilhower/arduino-pico) core files are licensed under the LGPL.
|
||||
* [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
|
||||
|
||||
+3770
-295
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -47,8 +47,8 @@ static bool __no_inline_not_in_flash_func(get_bootsel_button)() {
|
||||
GPIO_OVERRIDE_NORMAL << IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_LSB,
|
||||
IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS);
|
||||
|
||||
interrupts();
|
||||
rp2040.resumeOtherCore();
|
||||
interrupts();
|
||||
|
||||
return button_state;
|
||||
}
|
||||
|
||||
@@ -188,15 +188,6 @@ public:
|
||||
bool _autoFormat;
|
||||
};
|
||||
|
||||
class SPIFFSConfig : public FSConfig {
|
||||
public:
|
||||
static constexpr uint32_t FSId = 0x53504946;
|
||||
SPIFFSConfig(bool autoFormat = true) : FSConfig(FSId, autoFormat) { }
|
||||
|
||||
// Inherit _type and _autoFormat
|
||||
// nothing yet, enableTime TBD when SPIFFS has metadate
|
||||
};
|
||||
|
||||
class FS {
|
||||
public:
|
||||
FS(FSImplPtr impl) : _impl(impl) {
|
||||
@@ -272,11 +263,6 @@ using fs::SeekCur;
|
||||
using fs::SeekEnd;
|
||||
using fs::FSInfo;
|
||||
using fs::FSConfig;
|
||||
using fs::SPIFFSConfig;
|
||||
#endif //FS_NO_GLOBALS
|
||||
|
||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SPIFFS)
|
||||
extern fs::FS SPIFFS __attribute__((deprecated("SPIFFS has been deprecated. Please consider moving to LittleFS or other filesystems.")));
|
||||
#endif
|
||||
|
||||
#endif //FS_H
|
||||
|
||||
+116
-89
@@ -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;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
+33
-27
@@ -120,49 +120,49 @@ int __USBGetMouseReportID() {
|
||||
return __USBInstallKeyboard ? 2 : 1;
|
||||
}
|
||||
|
||||
static int __hid_report_len = 0;
|
||||
static uint8_t *__hid_report = nullptr;
|
||||
|
||||
static uint8_t *GetDescHIDReport(int *len) {
|
||||
static uint8_t *report = nullptr;
|
||||
int report_len = 0;
|
||||
|
||||
if (report) {
|
||||
free(report);
|
||||
report = nullptr;
|
||||
if (len) {
|
||||
*len = __hid_report_len;
|
||||
}
|
||||
return __hid_report;
|
||||
}
|
||||
|
||||
void __SetupDescHIDReport() {
|
||||
if (__USBInstallKeyboard && __USBInstallMouse) {
|
||||
uint8_t desc_hid_report[] = {
|
||||
TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(1)),
|
||||
TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(2))
|
||||
};
|
||||
report_len = sizeof(desc_hid_report);
|
||||
report = (uint8_t *)malloc(report_len);
|
||||
if (report) {
|
||||
memcpy(report, desc_hid_report, report_len);
|
||||
__hid_report = (uint8_t *)malloc(sizeof(desc_hid_report));
|
||||
if (__hid_report) {
|
||||
__hid_report_len = sizeof(desc_hid_report);
|
||||
memcpy(__hid_report, desc_hid_report, __hid_report_len);
|
||||
}
|
||||
} else if (__USBInstallKeyboard && ! __USBInstallMouse) {
|
||||
uint8_t desc_hid_report[] = {
|
||||
TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(1))
|
||||
};
|
||||
report_len = sizeof(desc_hid_report);
|
||||
report = (uint8_t *)malloc(report_len);
|
||||
if (report) {
|
||||
memcpy(report, desc_hid_report, report_len);
|
||||
__hid_report = (uint8_t *)malloc(sizeof(desc_hid_report));
|
||||
if (__hid_report) {
|
||||
__hid_report_len = sizeof(desc_hid_report);
|
||||
memcpy(__hid_report, desc_hid_report, __hid_report_len);
|
||||
}
|
||||
} else { // if (!__USBInstallKeyboard && __USBInstallMouse) {
|
||||
} else if (! __USBInstallKeyboard && __USBInstallMouse) {
|
||||
uint8_t desc_hid_report[] = {
|
||||
TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(1))
|
||||
};
|
||||
report_len = sizeof(desc_hid_report);
|
||||
report = (uint8_t *)malloc(report_len);
|
||||
if (report) {
|
||||
memcpy(report, desc_hid_report, report_len);
|
||||
__hid_report = (uint8_t *)malloc(sizeof(desc_hid_report));
|
||||
if (__hid_report) {
|
||||
__hid_report_len = sizeof(desc_hid_report);
|
||||
memcpy(__hid_report, desc_hid_report, __hid_report_len);
|
||||
}
|
||||
} else {
|
||||
__hid_report = nullptr;
|
||||
__hid_report_len = 0;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
*len = report_len;
|
||||
}
|
||||
return report;
|
||||
}
|
||||
|
||||
// Invoked when received GET HID REPORT DESCRIPTOR
|
||||
@@ -173,11 +173,13 @@ uint8_t const * tud_hid_descriptor_report_cb(uint8_t instance) {
|
||||
return GetDescHIDReport(nullptr);
|
||||
}
|
||||
|
||||
|
||||
static uint8_t *usbd_desc_cfg = nullptr;
|
||||
const uint8_t *tud_descriptor_configuration_cb(uint8_t index) {
|
||||
(void)index;
|
||||
static uint8_t *usbd_desc_cfg = nullptr;
|
||||
return usbd_desc_cfg;
|
||||
}
|
||||
|
||||
void __SetupUSBDescriptor() {
|
||||
if (!usbd_desc_cfg) {
|
||||
bool hasHID = __USBInstallKeyboard || __USBInstallMouse;
|
||||
|
||||
@@ -229,7 +231,6 @@ const uint8_t *tud_descriptor_configuration_cb(uint8_t index) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return usbd_desc_cfg;
|
||||
}
|
||||
|
||||
const uint16_t *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
|
||||
@@ -287,12 +288,17 @@ 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
|
||||
return;
|
||||
}
|
||||
|
||||
__SetupDescHIDReport();
|
||||
__SetupUSBDescriptor();
|
||||
|
||||
mutex_init(&__usb_mutex);
|
||||
|
||||
tusb_init();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#define ARDUINO_PICO_MAJOR 1
|
||||
#define ARDUINO_PICO_MINOR 13
|
||||
#define ARDUINO_PICO_REVISION 0
|
||||
#define ARDUINO_PICO_VERSION_STR "1.13.0"
|
||||
#define ARDUINO_PICO_MAJOR 2
|
||||
#define ARDUINO_PICO_MINOR 2
|
||||
#define ARDUINO_PICO_REVISION 1
|
||||
#define ARDUINO_PICO_VERSION_STR "2.2.1"
|
||||
|
||||
@@ -97,7 +97,7 @@ void __not_in_flash_func(SerialPIO::_handleIRQ)() {
|
||||
}
|
||||
while (!pio_sm_is_rx_fifo_empty(_rxPIO, _rxSM)) {
|
||||
uint32_t decode = _rxPIO->rxf[_rxSM];
|
||||
decode >>= 32 - _rxBits;
|
||||
decode >>= 33 - _rxBits;
|
||||
uint32_t val = 0;
|
||||
for (int b = 0; b < _bits + 1; b++) {
|
||||
val |= (decode & (1 << (b * 2))) ? 1 << b : 0;
|
||||
@@ -127,7 +127,7 @@ void __not_in_flash_func(SerialPIO::_handleIRQ)() {
|
||||
asm volatile("" ::: "memory"); // Ensure the queue is written before the written count advances
|
||||
_writer = next_writer;
|
||||
} else {
|
||||
// TODO: Overflow
|
||||
_overflow = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -146,6 +146,7 @@ SerialPIO::~SerialPIO() {
|
||||
}
|
||||
|
||||
void SerialPIO::begin(unsigned long baud, uint16_t config) {
|
||||
_overflow = false;
|
||||
_baud = baud;
|
||||
switch (config & SERIAL_PARITY_MASK) {
|
||||
case SERIAL_PARITY_EVEN:
|
||||
@@ -229,7 +230,7 @@ void SerialPIO::begin(unsigned long baud, uint16_t config) {
|
||||
pio_sm_clear_fifos(_rxPIO, _rxSM); // Remove any existing data
|
||||
|
||||
// Put phase divider into OSR w/o using add'l program memory
|
||||
pio_sm_put_blocking(_rxPIO, _rxSM, clock_get_hz(clk_sys) / (_baud * 2) - 2);
|
||||
pio_sm_put_blocking(_rxPIO, _rxSM, clock_get_hz(clk_sys) / (_baud * 2) - 5 /* insns in PIO halfbit loop */);
|
||||
pio_sm_exec(_rxPIO, _rxSM, pio_encode_pull(false, false));
|
||||
|
||||
// Join the TX FIFO to the RX one now that we don't need it
|
||||
@@ -256,8 +257,23 @@ void SerialPIO::end() {
|
||||
if (!_running) {
|
||||
return;
|
||||
}
|
||||
// TODO: Deallocate PIO resources, stop them
|
||||
_pioSP[pio_get_index(_rxPIO)][_rxSM] = nullptr;
|
||||
if (_tx != NOPIN) {
|
||||
pio_sm_set_enabled(_txPIO, _txSM, false);
|
||||
}
|
||||
if (_rx != NOPIN) {
|
||||
pio_sm_set_enabled(_rxPIO, _rxSM, false);
|
||||
_pioSP[pio_get_index(_rxPIO)][_rxSM] = nullptr;
|
||||
// If no more active, disable the IRQ
|
||||
auto pioNum = pio_get_index(_rxPIO);
|
||||
bool used = false;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
used = used || !!_pioSP[pioNum][i];
|
||||
}
|
||||
if (!used) {
|
||||
auto irqno = pioNum == 0 ? PIO0_IRQ_0 : PIO1_IRQ_0;
|
||||
irq_set_enabled(irqno, false);
|
||||
}
|
||||
}
|
||||
_running = false;
|
||||
}
|
||||
|
||||
@@ -289,6 +305,17 @@ int SerialPIO::read() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool SerialPIO::overflow() {
|
||||
CoreMutex m(&_mutex);
|
||||
if (!_running || !m || (_rx == NOPIN)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hold = _overflow;
|
||||
_overflow = false;
|
||||
return hold;
|
||||
}
|
||||
|
||||
int SerialPIO::available() {
|
||||
CoreMutex m(&_mutex);
|
||||
if (!_running || !m || (_rx == NOPIN)) {
|
||||
|
||||
@@ -47,19 +47,21 @@ public:
|
||||
virtual int availableForWrite() override;
|
||||
virtual void flush() override;
|
||||
virtual size_t write(uint8_t c) override;
|
||||
bool overflow();
|
||||
using Print::write;
|
||||
operator bool() override;
|
||||
|
||||
// Not to be called by users, only from the IRQ handler. In public so that the C-language IQR callback can access it
|
||||
void _handleIRQ();
|
||||
|
||||
private:
|
||||
protected:
|
||||
bool _running = false;
|
||||
pin_size_t _tx, _rx;
|
||||
int _baud;
|
||||
int _bits;
|
||||
uart_parity_t _parity;
|
||||
int _stop;
|
||||
bool _overflow;
|
||||
mutex_t _mutex;
|
||||
|
||||
PIOProgram *_txPgm;
|
||||
|
||||
+95
-18
@@ -114,19 +114,24 @@ bool SerialUART::setFIFOSize(size_t size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
SerialUART::SerialUART(uart_inst_t *uart, pin_size_t tx, pin_size_t rx) {
|
||||
SerialUART::SerialUART(uart_inst_t *uart, pin_size_t tx, pin_size_t rx, pin_size_t rts, pin_size_t cts) {
|
||||
_uart = uart;
|
||||
_tx = tx;
|
||||
_rx = rx;
|
||||
_rts = UART_PIN_NOT_DEFINED;
|
||||
_cts = UART_PIN_NOT_DEFINED;
|
||||
_rts = rts;
|
||||
_cts = cts;
|
||||
mutex_init(&_mutex);
|
||||
mutex_init(&_fifoMutex);
|
||||
}
|
||||
|
||||
static void _uart0IRQ();
|
||||
static void _uart1IRQ();
|
||||
|
||||
void SerialUART::begin(unsigned long baud, uint16_t config) {
|
||||
if (_running) {
|
||||
end();
|
||||
}
|
||||
_overflow = false;
|
||||
_queue = new uint8_t[_fifoSize];
|
||||
_baud = baud;
|
||||
uart_init(_uart, baud);
|
||||
@@ -198,6 +203,7 @@ void SerialUART::end() {
|
||||
if (!_running) {
|
||||
return;
|
||||
}
|
||||
_running = false;
|
||||
if (!_polling) {
|
||||
if (_uart == uart0) {
|
||||
irq_set_enabled(UART0_IRQ, false);
|
||||
@@ -205,9 +211,28 @@ void SerialUART::end() {
|
||||
irq_set_enabled(UART1_IRQ, false);
|
||||
}
|
||||
}
|
||||
// Paranoia - ensure nobody else is using anything here at the same time
|
||||
mutex_enter_blocking(&_mutex);
|
||||
mutex_enter_blocking(&_fifoMutex);
|
||||
uart_deinit(_uart);
|
||||
delete[] _queue;
|
||||
_running = false;
|
||||
// Reset the mutexes once all is off/cleaned up
|
||||
mutex_exit(&_fifoMutex);
|
||||
mutex_exit(&_mutex);
|
||||
}
|
||||
|
||||
void SerialUART::_pumpFIFO() {
|
||||
// Use the _fifoMutex to guard against the other core potentially
|
||||
// running the IRQ (since we can't disable their IRQ handler).
|
||||
// We guard against this core by disabling the IRQ handler and
|
||||
// re-enabling if it was previously enabled at the end.
|
||||
auto irqno = (_uart == uart0) ? UART0_IRQ : UART1_IRQ;
|
||||
bool enabled = irq_is_enabled(irqno);
|
||||
irq_set_enabled(irqno, false);
|
||||
mutex_enter_blocking(&_fifoMutex);
|
||||
_handleIRQ(false);
|
||||
mutex_exit(&_fifoMutex);
|
||||
irq_set_enabled(irqno, enabled);
|
||||
}
|
||||
|
||||
int SerialUART::peek() {
|
||||
@@ -216,7 +241,9 @@ int SerialUART::peek() {
|
||||
return -1;
|
||||
}
|
||||
if (_polling) {
|
||||
_handleIRQ();
|
||||
_handleIRQ(false);
|
||||
} else {
|
||||
_pumpFIFO();
|
||||
}
|
||||
if (_writer != _reader) {
|
||||
return _queue[_reader];
|
||||
@@ -230,7 +257,9 @@ int SerialUART::read() {
|
||||
return -1;
|
||||
}
|
||||
if (_polling) {
|
||||
_handleIRQ();
|
||||
_handleIRQ(false);
|
||||
} else {
|
||||
_pumpFIFO();
|
||||
}
|
||||
if (_writer != _reader) {
|
||||
auto ret = _queue[_reader];
|
||||
@@ -243,13 +272,25 @@ int SerialUART::read() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool SerialUART::overflow() {
|
||||
CoreMutex m(&_mutex);
|
||||
if (!_running || !m) {
|
||||
return false;
|
||||
}
|
||||
bool hold = _overflow;
|
||||
_overflow = false;
|
||||
return hold;
|
||||
}
|
||||
|
||||
int SerialUART::available() {
|
||||
CoreMutex m(&_mutex);
|
||||
if (!_running || !m) {
|
||||
return 0;
|
||||
}
|
||||
if (_polling) {
|
||||
_handleIRQ();
|
||||
_handleIRQ(false);
|
||||
} else {
|
||||
_pumpFIFO();
|
||||
}
|
||||
return (_writer - _reader) % _fifoSize;
|
||||
}
|
||||
@@ -260,7 +301,7 @@ int SerialUART::availableForWrite() {
|
||||
return 0;
|
||||
}
|
||||
if (_polling) {
|
||||
_handleIRQ();
|
||||
_handleIRQ(false);
|
||||
}
|
||||
return (uart_is_writable(_uart)) ? 1 : 0;
|
||||
}
|
||||
@@ -271,7 +312,7 @@ void SerialUART::flush() {
|
||||
return;
|
||||
}
|
||||
if (_polling) {
|
||||
_handleIRQ();
|
||||
_handleIRQ(false);
|
||||
}
|
||||
uart_tx_wait_blocking(_uart);
|
||||
}
|
||||
@@ -282,7 +323,7 @@ size_t SerialUART::write(uint8_t c) {
|
||||
return 0;
|
||||
}
|
||||
if (_polling) {
|
||||
_handleIRQ();
|
||||
_handleIRQ(false);
|
||||
}
|
||||
uart_putc_raw(_uart, c);
|
||||
return 1;
|
||||
@@ -294,7 +335,7 @@ size_t SerialUART::write(const uint8_t *p, size_t len) {
|
||||
return 0;
|
||||
}
|
||||
if (_polling) {
|
||||
_handleIRQ();
|
||||
_handleIRQ(false);
|
||||
}
|
||||
size_t cnt = len;
|
||||
while (cnt) {
|
||||
@@ -309,9 +350,6 @@ SerialUART::operator bool() {
|
||||
return _running;
|
||||
}
|
||||
|
||||
SerialUART Serial1(uart0, PIN_SERIAL1_TX, PIN_SERIAL1_RX);
|
||||
SerialUART Serial2(uart1, PIN_SERIAL2_TX, PIN_SERIAL2_RX);
|
||||
|
||||
void arduino::serialEvent1Run(void) {
|
||||
if (serialEvent1 && Serial1.available()) {
|
||||
serialEvent1();
|
||||
@@ -325,7 +363,15 @@ void arduino::serialEvent2Run(void) {
|
||||
}
|
||||
|
||||
// IRQ handler, called when FIFO > 1/8 full or when it had held unread data for >32 bit times
|
||||
void __not_in_flash_func(SerialUART::_handleIRQ)() {
|
||||
void __not_in_flash_func(SerialUART::_handleIRQ)(bool inIRQ) {
|
||||
if (inIRQ) {
|
||||
uint32_t owner;
|
||||
if (!mutex_try_enter(&_fifoMutex, &owner)) {
|
||||
// Main app on the other core has the mutex so it is
|
||||
// in the process of pulling data out of the HW FIFO
|
||||
return;
|
||||
}
|
||||
}
|
||||
// ICR is write-to-clear
|
||||
uart_get_hw(_uart)->icr = UART_UARTICR_RTIC_BITS | UART_UARTICR_RXIC_BITS;
|
||||
while (uart_is_readable(_uart)) {
|
||||
@@ -340,15 +386,46 @@ void __not_in_flash_func(SerialUART::_handleIRQ)() {
|
||||
// Avoid using division or mod because the HW divider could be in use
|
||||
_writer = next_writer;
|
||||
} else {
|
||||
// TODO: Overflow
|
||||
_overflow = true;
|
||||
}
|
||||
}
|
||||
if (inIRQ) {
|
||||
mutex_exit(&_fifoMutex);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef __SERIAL1_DEVICE
|
||||
#define __SERIAL1_DEVICE uart0
|
||||
#endif
|
||||
#ifndef __SERIAL2_DEVICE
|
||||
#define __SERIAL2_DEVICE uart1
|
||||
#endif
|
||||
|
||||
#if defined(PIN_SERIAL1_RTS)
|
||||
SerialUART Serial1(__SERIAL1_DEVICE, PIN_SERIAL1_TX, PIN_SERIAL1_RX, PIN_SERIAL1_RTS, PIN_SERIAL1_CTS);
|
||||
#else
|
||||
SerialUART Serial1(__SERIAL1_DEVICE, PIN_SERIAL1_TX, PIN_SERIAL1_RX);
|
||||
#endif
|
||||
|
||||
#if defined(PIN_SERIAL2_RTS)
|
||||
SerialUART Serial2(__SERIAL2_DEVICE, PIN_SERIAL2_TX, PIN_SERIAL2_RX, PIN_SERIAL2_RTS, PIN_SERIAL2_CTS);
|
||||
#else
|
||||
SerialUART Serial2(__SERIAL2_DEVICE, PIN_SERIAL2_TX, PIN_SERIAL2_RX);
|
||||
#endif
|
||||
|
||||
|
||||
static void __not_in_flash_func(_uart0IRQ)() {
|
||||
Serial1._handleIRQ();
|
||||
if (__SERIAL1_DEVICE == uart0) {
|
||||
Serial1._handleIRQ();
|
||||
} else {
|
||||
Serial2._handleIRQ();
|
||||
}
|
||||
}
|
||||
|
||||
static void __not_in_flash_func(_uart1IRQ)() {
|
||||
Serial2._handleIRQ();
|
||||
if (__SERIAL2_DEVICE == uart1) {
|
||||
Serial2._handleIRQ();
|
||||
} else {
|
||||
Serial1._handleIRQ();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ extern "C" typedef struct uart_inst uart_inst_t;
|
||||
#define UART_PIN_NOT_DEFINED (255u)
|
||||
class SerialUART : public HardwareSerial {
|
||||
public:
|
||||
SerialUART(uart_inst_t *uart, pin_size_t tx, pin_size_t rx);
|
||||
SerialUART(uart_inst_t *uart, pin_size_t tx, pin_size_t rx, pin_size_t rts = UART_PIN_NOT_DEFINED, pin_size_t cts = UART_PIN_NOT_DEFINED);
|
||||
|
||||
// Select the pinout. Call before .begin()
|
||||
bool setRX(pin_size_t pin);
|
||||
@@ -60,10 +60,11 @@ public:
|
||||
virtual size_t write(uint8_t c) override;
|
||||
virtual size_t write(const uint8_t *p, size_t len) override;
|
||||
using Print::write;
|
||||
bool overflow();
|
||||
operator bool() override;
|
||||
|
||||
// Not to be called by users, only from the IRQ handler. In public so that the C-language IQR callback can access it
|
||||
void _handleIRQ();
|
||||
void _handleIRQ(bool inIRQ = true);
|
||||
|
||||
private:
|
||||
bool _running = false;
|
||||
@@ -73,12 +74,15 @@ private:
|
||||
int _baud;
|
||||
mutex_t _mutex;
|
||||
bool _polling = false;
|
||||
bool _overflow;
|
||||
|
||||
// Lockless, IRQ-handled circular queue
|
||||
uint32_t _writer;
|
||||
uint32_t _reader;
|
||||
size_t _fifoSize = 32;
|
||||
uint8_t *_queue;
|
||||
uint8_t *_queue;
|
||||
mutex_t _fifoMutex; // Only needed when non-IRQ updates _writer
|
||||
void _pumpFIFO(); // User space FIFO transfer
|
||||
};
|
||||
|
||||
extern SerialUART Serial1; // HW UART 0
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
SoftwareSerial wrapper for SerialPIO
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SerialPIO.h"
|
||||
|
||||
class SoftwareSerial : public SerialPIO {
|
||||
public:
|
||||
// Note the rx/tx pins are swapped in PIO vs SWSerial
|
||||
SoftwareSerial(pin_size_t rx, pin_size_t tx, bool invert = false) : SerialPIO(tx, rx) {
|
||||
_invert = invert;
|
||||
}
|
||||
|
||||
~SoftwareSerial() {
|
||||
if (_invert) {
|
||||
gpio_set_outover(_tx, 0);
|
||||
gpio_set_outover(_rx, 0);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void begin(unsigned long baud = 115200) override {
|
||||
begin(baud, SERIAL_8N1);
|
||||
};
|
||||
|
||||
void begin(unsigned long baud, uint16_t config) override {
|
||||
SerialPIO::begin(baud, config);
|
||||
if (_invert) {
|
||||
gpio_set_outover(_tx, GPIO_OVERRIDE_INVERT);
|
||||
gpio_set_inover(_rx, GPIO_OVERRIDE_INVERT);
|
||||
}
|
||||
}
|
||||
|
||||
void listen() { /* noop */ }
|
||||
|
||||
bool isListening() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool _invert;
|
||||
};
|
||||
@@ -20,6 +20,10 @@ typedef enum {
|
||||
OUTPUT = 0x1,
|
||||
INPUT_PULLUP = 0x2,
|
||||
INPUT_PULLDOWN = 0x3,
|
||||
OUTPUT_2MA = 0x4,
|
||||
OUTPUT_4MA = 0x5,
|
||||
OUTPUT_8MA = 0x6,
|
||||
OUTPUT_12MA = 0x7,
|
||||
} PinMode;
|
||||
|
||||
typedef enum {
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
; 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;
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
// -------------------------------------------------- //
|
||||
// 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"
|
||||
{
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
Newlib retargetable lock class using RP2040 SDK
|
||||
|
||||
Overrides weak functions in Newlib for locking to safely support
|
||||
multi-core operation. Does not need any --wrap for memory allocators.
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
|
||||
#include <pico/mutex.h>
|
||||
#include <sys/lock.h>
|
||||
|
||||
// HACK ALERT
|
||||
// Pico-SDK defines mutex which can be at global scope, but when the auto_init_
|
||||
// macros are used they are defined as static. Newlib needs global access to
|
||||
// these mutextes, so instead of hacking pico-sdk just make "static" a no-op.
|
||||
|
||||
#define static
|
||||
auto_init_recursive_mutex(__lock___sinit_recursive_mutex);
|
||||
auto_init_recursive_mutex(__lock___sfp_recursive_mutex);
|
||||
auto_init_recursive_mutex(__lock___atexit_recursive_mutex);
|
||||
auto_init_mutex(__lock___at_quick_exit_mutex);
|
||||
auto_init_recursive_mutex(__lock___malloc_recursive_mutex);
|
||||
auto_init_recursive_mutex(__lock___env_recursive_mutex);
|
||||
auto_init_mutex(__lock___tz_mutex);
|
||||
auto_init_mutex(__lock___dd_hash_mutex);
|
||||
auto_init_mutex(__lock___arc4random_mutex);
|
||||
#undef static
|
||||
|
||||
void __retarget_lock_init(_LOCK_T *lock) {
|
||||
mutex_init((mutex_t*) lock);
|
||||
}
|
||||
|
||||
void __retarget_lock_init_recursive(_LOCK_T *lock) {
|
||||
recursive_mutex_init((recursive_mutex_t*) lock);
|
||||
}
|
||||
|
||||
void __retarget_lock_close(_LOCK_T lock) {
|
||||
(void) lock;
|
||||
}
|
||||
|
||||
void __retarget_lock_close_recursive(_LOCK_T lock) {
|
||||
(void) lock;
|
||||
}
|
||||
|
||||
void __retarget_lock_acquire(_LOCK_T lock) {
|
||||
mutex_enter_blocking((mutex_t*)lock);
|
||||
}
|
||||
|
||||
void __retarget_lock_acquire_recursive(_LOCK_T lock) {
|
||||
recursive_mutex_enter_blocking((recursive_mutex_t*)lock);
|
||||
}
|
||||
|
||||
int __retarget_lock_try_acquire(_LOCK_T lock) {
|
||||
return mutex_try_enter((mutex_t *)lock, NULL);
|
||||
}
|
||||
|
||||
int __retarget_lock_try_acquire_recursive(_LOCK_T lock) {
|
||||
return recursive_mutex_try_enter((recursive_mutex_t*)lock, NULL);
|
||||
}
|
||||
|
||||
void __retarget_lock_release(_LOCK_T lock) {
|
||||
mutex_exit((mutex_t*)lock);
|
||||
}
|
||||
|
||||
void __retarget_lock_release_recursive(_LOCK_T lock) {
|
||||
recursive_mutex_exit((recursive_mutex_t*)lock);
|
||||
}
|
||||
+87
-28
@@ -22,22 +22,27 @@
|
||||
#include "RP2040USB.h"
|
||||
#include <pico/stdlib.h>
|
||||
#include <pico/multicore.h>
|
||||
#include <reent.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 +58,47 @@ 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();
|
||||
}
|
||||
}
|
||||
static struct _reent *_impure_ptr1 = nullptr;
|
||||
|
||||
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;
|
||||
|
||||
// Allocate impure_ptr (newlib temps) if there is a 2nd core running
|
||||
if (!__isFreeRTOS && (setup1 || loop1)) {
|
||||
_impure_ptr1 = (struct _reent*)calloc(sizeof(struct _reent), 1);
|
||||
_REENT_INIT_PTR(_impure_ptr1);
|
||||
}
|
||||
|
||||
mutex_init(&_pioMutex);
|
||||
|
||||
rp2040.begin();
|
||||
|
||||
initVariant();
|
||||
|
||||
if (__isFreeRTOS) {
|
||||
initFreeRTOS();
|
||||
}
|
||||
|
||||
#ifndef NO_USB
|
||||
#ifdef USE_TINYUSB
|
||||
TinyUSB_Device_Init(0);
|
||||
@@ -69,43 +107,64 @@ 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();
|
||||
}
|
||||
|
||||
extern "C" void __register_impure_ptr(struct _reent *p) {
|
||||
if (get_core_num() == 0) {
|
||||
_impure_ptr = p;
|
||||
} else {
|
||||
_impure_ptr1 = p;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO: FreeRTOS should implement this based on thread ID (and each thread should have its own struct _reent
|
||||
extern "C" struct _reent *__wrap___getreent() {
|
||||
if (get_core_num() == 0) {
|
||||
return _impure_ptr;
|
||||
} else {
|
||||
return _impure_ptr1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include <hardware/adc.h>
|
||||
|
||||
static uint32_t analogScale = 255;
|
||||
static uint16_t analogFreq = 1000;
|
||||
static uint32_t analogFreq = 1000;
|
||||
static bool pwmInitted = false;
|
||||
static bool adcInitted = false;
|
||||
static uint16_t analogWritePseudoScale = 1;
|
||||
@@ -42,9 +42,9 @@ extern "C" void analogWriteFreq(uint32_t freq) {
|
||||
if (freq < 100) {
|
||||
DEBUGCORE("ERROR: analogWriteFreq too low (%d)\n", freq);
|
||||
analogFreq = 100;
|
||||
} else if (freq > 60000) {
|
||||
} else if (freq > 1000000) {
|
||||
DEBUGCORE("ERROR: analogWriteFreq too high (%d)\n", freq);
|
||||
analogFreq = 60000;
|
||||
analogFreq = 1000000;
|
||||
} else {
|
||||
analogFreq = freq;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,24 @@ extern "C" void pinMode(pin_size_t ulPin, PinMode ulMode) {
|
||||
gpio_put(ulPin, 1);
|
||||
break;
|
||||
case OUTPUT:
|
||||
case OUTPUT_4MA:
|
||||
gpio_init(ulPin);
|
||||
gpio_set_drive_strength(ulPin, GPIO_DRIVE_STRENGTH_4MA);
|
||||
gpio_set_dir(ulPin, true);
|
||||
break;
|
||||
case OUTPUT_2MA:
|
||||
gpio_init(ulPin);
|
||||
gpio_set_drive_strength(ulPin, GPIO_DRIVE_STRENGTH_2MA);
|
||||
gpio_set_dir(ulPin, true);
|
||||
break;
|
||||
case OUTPUT_8MA:
|
||||
gpio_init(ulPin);
|
||||
gpio_set_drive_strength(ulPin, GPIO_DRIVE_STRENGTH_8MA);
|
||||
gpio_set_dir(ulPin, true);
|
||||
break;
|
||||
case OUTPUT_12MA:
|
||||
gpio_init(ulPin);
|
||||
gpio_set_drive_strength(ulPin, GPIO_DRIVE_STRENGTH_12MA);
|
||||
gpio_set_dir(ulPin, true);
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -45,26 +45,40 @@ extern "C" void noInterrupts() {
|
||||
// Only 1 GPIO IRQ callback for all pins, so we need to look at the pin it's for and
|
||||
// dispatch to the real callback manually
|
||||
auto_init_mutex(_irqMutex);
|
||||
static std::map<pin_size_t, voidFuncPtr> _map;
|
||||
class CBInfo {
|
||||
public:
|
||||
CBInfo(voidFuncPtr cb) : _cb(cb), _useParam(false), _param(nullptr) { };
|
||||
CBInfo(voidFuncPtrParam cbParam, void *param) : _cbParam(cbParam), _useParam(true), _param(param) { };
|
||||
void callback() {
|
||||
if (_useParam && _cbParam) {
|
||||
_cbParam(_param);
|
||||
} else if (_cb) {
|
||||
_cb();
|
||||
}
|
||||
}
|
||||
private:
|
||||
union {
|
||||
voidFuncPtr _cb;
|
||||
voidFuncPtrParam _cbParam;
|
||||
};
|
||||
bool _useParam;
|
||||
void *_param;
|
||||
};
|
||||
|
||||
|
||||
static std::map<pin_size_t, CBInfo> _map;
|
||||
|
||||
void _gpioInterruptDispatcher(uint gpio, uint32_t events) {
|
||||
(void) events;
|
||||
// Only need to lock around the std::map check, not the whole IRQ callback
|
||||
voidFuncPtr cb = nullptr;
|
||||
{
|
||||
CoreMutex m(&_irqMutex);
|
||||
if (m) {
|
||||
auto irq = _map.find(gpio);
|
||||
if (irq != _map.end()) {
|
||||
cb = irq->second;
|
||||
}
|
||||
CoreMutex m(&_irqMutex);
|
||||
if (m) {
|
||||
auto irq = _map.find(gpio);
|
||||
if (irq != _map.end()) {
|
||||
auto cb = irq->second;
|
||||
cb.callback();
|
||||
}
|
||||
}
|
||||
if (cb) {
|
||||
cb(); // Do the callback
|
||||
} else {
|
||||
// ERROR, but we're in an IRQ so do nothing
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void attachInterrupt(pin_size_t pin, voidFuncPtr callback, PinStatus mode) {
|
||||
@@ -84,7 +98,31 @@ extern "C" void attachInterrupt(pin_size_t pin, voidFuncPtr callback, PinStatus
|
||||
}
|
||||
noInterrupts();
|
||||
detachInterrupt(pin);
|
||||
_map.insert({pin, callback});
|
||||
CBInfo cb(callback);
|
||||
_map.insert({pin, cb});
|
||||
gpio_set_irq_enabled_with_callback(pin, events, true, _gpioInterruptDispatcher);
|
||||
interrupts();
|
||||
}
|
||||
|
||||
void attachInterruptParam(pin_size_t pin, voidFuncPtrParam callback, PinStatus mode, void *param) {
|
||||
CoreMutex m(&_irqMutex);
|
||||
if (!m) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t events;
|
||||
switch (mode) {
|
||||
case LOW: events = 1; break;
|
||||
case HIGH: events = 2; break;
|
||||
case FALLING: events = 4; break;
|
||||
case RISING: events = 8; break;
|
||||
case CHANGE: events = 4 | 8; break;
|
||||
default: return; // ERROR
|
||||
}
|
||||
noInterrupts();
|
||||
detachInterrupt(pin);
|
||||
CBInfo cb(callback, param);
|
||||
_map.insert({pin, cb});
|
||||
gpio_set_irq_enabled_with_callback(pin, events, true, _gpioInterruptDispatcher);
|
||||
interrupts();
|
||||
}
|
||||
|
||||
+17
-1
@@ -13,6 +13,11 @@ int analogRead(pin_size_t pin = A0..A3)
|
||||
Returns a value from 0...4095 correspionding to the ADC reading
|
||||
of the specific pin.
|
||||
|
||||
void analogReadResolution(int bits)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Determines the resolution (in bits) of the value returned by the analogRead() function.
|
||||
Default resolution is 10bit.
|
||||
|
||||
float analogReadTemp()
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
Returns the temperature, in Celsius, of the onboard thermal sensor.
|
||||
@@ -30,10 +35,21 @@ While up to 16 PWM channels can be generated, they are not independent
|
||||
and there are significant restrictions as to allowed pins in parallel.
|
||||
See the `RP2040 datasheet <https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf>`_ for full details.
|
||||
|
||||
Analog Output Restrictions
|
||||
--------------------------
|
||||
|
||||
The PWM generator source clock restricts the legal combinations of
|
||||
frequency and ranges. For example, at 1MHz only about 6 bits of range
|
||||
are possible. When you define an ``analogWriteFreq`` and ``analogWriteRange``
|
||||
that can't be fulfilled by the hardware, the frequency will be preserved
|
||||
but the accuracy (range) will be reduced automatically. Your code will
|
||||
still send in the range you specify, but the core itself will transparently
|
||||
map it into the allowable PWN range.
|
||||
|
||||
void analogWriteFreq(uint32_t freq)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Sets the master PWM frequency used (i.e. how often the PWM output cycles).
|
||||
From 100Hz to 60KHz are supported.
|
||||
From 100Hz to 1MHz are supported.
|
||||
|
||||
void analogWriteRange(uint32_t range) and analogWriteResolution(int res)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
+4
-4
@@ -19,7 +19,7 @@
|
||||
# import os
|
||||
# import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
import sphinx_rtd_theme
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = []
|
||||
extensions = ['sphinx_rtd_theme']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
@@ -46,7 +46,7 @@ master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'Arduino-Pico'
|
||||
copyright = u'2021, Earle F. Philhower, III'
|
||||
copyright = u'2022, Earle F. Philhower, III'
|
||||
author = u'Earle F. Philhower, III'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
@@ -82,7 +82,7 @@ todo_include_todos = False
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = 'alabaster'
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
FreeRTOS SMP
|
||||
============
|
||||
|
||||
The SMP (multicore) port of FreeRTOS is included with the core. This allows complex
|
||||
task operations and real preemptive multithreading in your sketches. While the
|
||||
``setup1`` and ``loop1`` way of multitasking is simplest for most folks, FreeRTOS
|
||||
is much more powerful.
|
||||
|
||||
Enabling FreeRTOS
|
||||
-----------------
|
||||
|
||||
To enable FreeRTOS, simply add
|
||||
|
||||
.. code:: c++
|
||||
|
||||
#include <FreeRTOS.h>
|
||||
|
||||
to your sketch and it will be included and enabled automatically.
|
||||
|
||||
Configuration and Predefined Tasks
|
||||
----------------------------------
|
||||
|
||||
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.
|
||||
|
||||
Caveats
|
||||
-------
|
||||
|
||||
While the core now supports FreeRTOS, most (probably all) Arduino libraries were not written
|
||||
to support preemptive multithreading. This means that all calls to a particular library should
|
||||
be made from a single task.
|
||||
|
||||
In particular, the ``LittleFS`` and ``SDFS`` libraries can not be called from different
|
||||
threads. Do all ``File`` operations from a single thread or else undefined behavior
|
||||
(aka strange crashes or data corruption) can occur.
|
||||
|
||||
More Information
|
||||
----------------
|
||||
|
||||
For full FreeRTOS documentation look at `FreeRTOS.org <https://freertos.org/index.html>`__
|
||||
and `FreeRTOS SMP support <https://freertos.org/symmetric-multiprocessing-introduction.html>`__.
|
||||
+144
-52
@@ -1,89 +1,181 @@
|
||||
I2S (Digital Audio) Output Library
|
||||
==================================
|
||||
I2S (Digital Audio) Audio Library
|
||||
=================================
|
||||
|
||||
While the RP2040 chip on the Raspberry Pi Pico does not include a hardware
|
||||
I2S device, it is possible to use the PIO (Programmable I/O) state machines
|
||||
to implement one dynamically.
|
||||
|
||||
This I2S library uses the ``pico-extras`` I2S audio library and wraps it in
|
||||
an Arduino I2S library. It supports 16 bits/sample and frequencies of up
|
||||
to 48kHZ, with configurable BCLK, LRCLK(always pin "BCLK + 1"), and DOUT pins.
|
||||
Digital audio input and output are supported at 8, 16, 24, and 32 bits per
|
||||
sample.
|
||||
|
||||
Theoretically up to 6 I2S ports may be created, but in practice there
|
||||
may not be enough resources (DMA, PIO SM) to actually create and use so
|
||||
many.
|
||||
|
||||
Create an I2S port by instantiating a variable of the I2S class
|
||||
specifying the direction. Configure it using API calls below before
|
||||
using it.
|
||||
|
||||
**Note:** This I2S device takes over the entire PIO1 (second) unit and adjusts
|
||||
its clock frequency to meet the I2S needs. That means when only 4 Tones
|
||||
or only 4 Servos may be used when the I2S device is used.
|
||||
|
||||
I2S Class API
|
||||
-------------
|
||||
|
||||
I2S(OUTPUT)
|
||||
~~~~~~~~~~~
|
||||
Creates an I2S output port. Needs to be connected up to the
|
||||
desired pins (see below) and started before any output can happen.
|
||||
|
||||
I2S(INPUT)
|
||||
~~~~~~~~~~
|
||||
Creates an I2S input port. Needs to be connected up to the
|
||||
desired pins (see below) and started before any input can happen.
|
||||
|
||||
bool setBCLK(pin_size_t pin)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Sets the BCLK pin of the I2S device. The LRCLK/word clock will be ``pin + 1``
|
||||
due to limitations of the PIO state machines. Call this before ``I2S.begin()``
|
||||
Default BCLK = 26, LRCLK = 27
|
||||
due to limitations of the PIO state machines. Call this before ``I2S::begin()``
|
||||
|
||||
bool setDOUT(pin_size_t pin)
|
||||
bool setDATA(pin_size_t pin)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Sets the DOUT pin of the I2S device. Any pin may be used. Default DOUT = 28
|
||||
Call before ``I2S.begin()``
|
||||
Sets the DOUT or DIN pin of the I2S device. Any pin may be used.
|
||||
Call before ``I2S::begin()``
|
||||
|
||||
bool begin(long sampleRate)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Start the I2S device up with the given sample rate. The pins selected above
|
||||
will be turned to output and the I2S will begin to drive silence frames (all
|
||||
zero) out.
|
||||
bool setBitsPerSample(int bits)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Specify how many bits per audio sample to read or write. Note that
|
||||
for 24-bit samples, audio samples must be left-aligned (i.e. bits 31...8).
|
||||
Call before ``I2S::begin()``
|
||||
|
||||
bool setBuffers(size_t buffers, size_t bufferWords, int32_t silenceSample = 0)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Set the number of DMA buffers and their size in 32-bit words as well as
|
||||
the word to fill when no data is available to send to the I2S hardware.
|
||||
Call before ``I2S::begin()``.
|
||||
|
||||
bool setFrequency(long sampleRate)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Sets the word clock frequency, but does not start the I2S device if not
|
||||
already running. May be called after ``I2S::begin()`` to change the
|
||||
sample rate on-the-fly.
|
||||
|
||||
bool begin()/begin(long sampleRate)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Start the I2S device up with the given sample rate, or with the value set
|
||||
using the prior ``setFrequency`` call.
|
||||
|
||||
void end()
|
||||
~~~~~~~~~~
|
||||
Stops the I2S device. **Note, at present the memory allocated for I2S buffers
|
||||
is not freed leading to a memory leak when ``end()`` is called. This is due
|
||||
to the state of the ``pico-extras`` release which this code uses.**
|
||||
Stops the I2S device.
|
||||
|
||||
void flush()
|
||||
~~~~~~~~~~~~
|
||||
Sends any partial frames in memory to the I2S output device. They may NOT play
|
||||
immediately. Potential use case for this call would be when the frequency of
|
||||
the output will be changing.
|
||||
Waits until all the I2S buffers have been output.
|
||||
|
||||
size_t write(uint8_t)
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
Provided for compatibility, but not very useful. Writes a sample from 0...255
|
||||
to the I2S buffer. See ``write(int16_t)`` for a better one
|
||||
size_t write(uint8_t/int8_t/int16_t/int32_t)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Writes a single sample of ``bitsPerSample`` to the buffer. It is up to the
|
||||
user to keep track of left/right channels. Note this writes data equivalent
|
||||
to one channel's data, not the size of the passed in variable (i.e. if you have
|
||||
a 16-bit sample size and ``write((int8_t)-5); write((int8_t)5);`` you will have
|
||||
written **2 samples** to the I2S buffer of whatever the I2S size, not a single
|
||||
16-bit sample.
|
||||
|
||||
This call will block (wait) until space is available to actually write
|
||||
the data.
|
||||
|
||||
size_t write(int32_t val, bool sync)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Writes 32 bits of data to the I2S buffer (regardless of the configured I2S
|
||||
bit size). When ``sync`` is true, it will not return until the data has
|
||||
been writte. When ``sync`` is false, it will return ``0`` immediately if
|
||||
there is no space present in the I2S buffer.
|
||||
|
||||
size_t write(const uint8_t \*buffer, size_t size)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Transfers number of bytes from an application buffer to the I2S output buffer.
|
||||
Be aware that ``size`` is in *bytes** and not samples. Size must be a multiple
|
||||
of **4 bytes** (i.e. one left/right sample). Will not block, so check
|
||||
the return value to find out how many bytes were actually written.
|
||||
of **4 bytes**. Will not block, so check the return value to find out how
|
||||
many bytes were actually written.
|
||||
|
||||
int availableForWrite()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Returns the number of **32-bit L/R samples** that can be written without
|
||||
Returns the number of L/R samples that can be written without
|
||||
potentially blocking.
|
||||
|
||||
bool setFrequency(int newFreq)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Adjusts the I2S output frequency. When changing frequency while I2S output
|
||||
is underway, be sure to use ``I2S.flush()`` before changing the frequency to
|
||||
ensure the older data is played at the right frequency.
|
||||
int read()
|
||||
~~~~~~~~~~
|
||||
Reads a single sample of I2S data, whatever the I2S sample size is configured.
|
||||
Will not return until data is available.
|
||||
|
||||
size_t write(int16_t)
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
Writes a single 16-bit left or right sample to the I2S output buffer. The
|
||||
user is required to ensure that an even number of samples is written (i.e.
|
||||
left and right) over the application lifetime. The application also needs
|
||||
to track which sample is next to be written (right/left). For this reason,
|
||||
the ``write(void *b, size_t lrsamples)`` call may be easier and faster to use.
|
||||
int peek()
|
||||
~~~~~~~~~~
|
||||
Returns the next sample to be read from the I2S buffer (without actually
|
||||
removing it).
|
||||
|
||||
size_t write(const void \*buffer, size_t lrsamples)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Writes up to size left+right packed samples to the I2S device. Non-blocking,
|
||||
will writefrom 0...size samples and return that count. Be sure your app
|
||||
handles partial writes (i.e. by ``yield()`` ing and then retrying to write the
|
||||
remaining data.)
|
||||
void onTransmit(void (\*fn)(void))
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Sets a callback to be called when an I2S DMA buffer is fully transmitted.
|
||||
Will be in an interrupt context so the specified function must operate
|
||||
quickly and not use blocking calls like delay() or write to the I2S.
|
||||
|
||||
The ``onTransmit`` callback is not supported.
|
||||
void onReceive(void (\*fn)(void))
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Sets a callback to be called when an I2S DMA buffer is fully read in.
|
||||
Will be in an interrupt context so the specified function must operate
|
||||
quickly and not use blocking calls like delay() or read from the I2S.
|
||||
|
||||
See the `ESP8266Audio <https://github.com/earlephilhower/ESP8266Audio>`_ library
|
||||
for a working example, or look at the included sample tone generator.
|
||||
Sample Writing/Reading API
|
||||
--------------------------
|
||||
Because I2S streams consist of a natural left and right sample, it is often
|
||||
convenient to write or read both with a single call. The following calls
|
||||
allow applications to read or write both samples at the same time, and
|
||||
explicitly indicate the bit widths required (to avoid potential issues with
|
||||
type conversion on calls).
|
||||
|
||||
size_t write8(int8_t l, int8_t r)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Writes a left and right 8-bit sample to the I2S buffers. Blocks until space
|
||||
is available.
|
||||
|
||||
size_t write16(int16_t l, int16_t r)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Writes a left and right 16-bit sample to the I2S buffers. Blocks until space
|
||||
is available.
|
||||
|
||||
size_t write24(int32_t l, int32_t r)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Writes a left and right 24-bit sample to the I2S buffers. See note below
|
||||
about 24-bit mode. Blocks until space is available.
|
||||
|
||||
size_t write32(int32_t l, int32_t r)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Writes a left and right 32-bit sample to the I2S buffers. Blocks until space
|
||||
is available.
|
||||
|
||||
bool read8(int8_t \*l, int8_t \*r)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Reads a left and right 8-bit sample and returns ``true`` on success. Will block
|
||||
until data is available.
|
||||
|
||||
bool read16(int16_t \*l, int16_t \*r)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Reads a left and right 16-bit sample and returns ``true`` on success. Will block
|
||||
until data is available.
|
||||
|
||||
bool read24(int32_t \*l, int32_t \*r)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Reads a left and right 24-bit sample and returns ``true`` on success. See note below
|
||||
about 24-bit mode. Will block until data is available.
|
||||
|
||||
bool read32(int32_t \*l, int32_t \*r)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Reads a left and right 32-bit sample and returns ``true`` on success. Will block
|
||||
until data is available.
|
||||
|
||||
|
||||
Note About 24-bit Samples
|
||||
-------------------------
|
||||
24-bit samples are stored as left-aligned 32-bit values with bits 7..0
|
||||
ignored. Only the upper 24 bits 31...8 will be transmitted or
|
||||
received. The actual I2S protocol will only transmit or receive 24 bits
|
||||
in this mode, even though the data is 32-bit packed.
|
||||
|
||||
@@ -34,3 +34,40 @@ Debug messages from `printf` and the Core can be printed to a Serial port
|
||||
to allow for easier debugging. Select the desired port and verbosity.
|
||||
Selecting a port for debug output does not stop a sketch from using it
|
||||
for normal operations.
|
||||
|
||||
Generic RP2040 Support
|
||||
----------------------
|
||||
If your RP2040 board isn't in the menus you can still use it with the
|
||||
IDE bu using the `Board->Generic RP2040` menu option. You will need to
|
||||
then set the flash size (see above) and tell the IDE how to communicate
|
||||
with the flash chip using the `Tools->Boot Stage 2` menu.
|
||||
|
||||
Boot Stage 2 Options for Generic RP2040
|
||||
---------------------------------------
|
||||
The Arduino Pico needs to set up its internal flash interface to talk to
|
||||
whatever flash chip is in the system. While all flash chips support a
|
||||
basic (and slow) 1-bit operation using common timings, each different
|
||||
brand (and sometimes model) of flash chip require custom timings to work
|
||||
in QSPI (4-bit) mode. The `Boot Stage 2` menu lets you select from
|
||||
the supported timings.
|
||||
|
||||
The options with `/2` in them divide the system clock by 2 to drive the
|
||||
bus. Options with `/4` divide the clock by 4 and so are slower but more
|
||||
compatible.
|
||||
|
||||
If you can't match a chip name in the menu to your flash chip, a simple
|
||||
test can be run to determine which is correct. Simpily load the `Blink`
|
||||
example, select the first option in the `Boot Stage 2` menu, and upload.
|
||||
If that works, note it and continue. Iterate through the options and
|
||||
note which ones work. If an option doesn't work, unplug the chip and
|
||||
hold the BOOTSEL button down while re-inserting it to enter the ROM
|
||||
uploader mode. (The CPU and flash will not be harmed if the test fails.)
|
||||
|
||||
If one of the custom bootloaders (not `Generic SPI /2 or /4`) worked, use
|
||||
that option to get best performance. If none worked other than the
|
||||
`Generic SPI /2 or /4` then use that. The `/2` options of all models
|
||||
is preferred as it is faster, but some boards do require `/4` on the
|
||||
custom chip interfaces.
|
||||
|
||||
When in doubt, `Generic SPI /4` should work with any flash chip but is
|
||||
slow.
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 119 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
@@ -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 SMP (multicore) <freertos>
|
||||
|
||||
Ported/Optimized Libraries <libraries>
|
||||
Using Pico-SDK <sdk>
|
||||
|
||||
|
||||
@@ -40,8 +40,6 @@ To install via GIT (for latest and greatest versions):
|
||||
git submodule update --init
|
||||
cd pico-sdk
|
||||
git submodule update --init
|
||||
cd pico-extras
|
||||
git submodule update --init
|
||||
cd ../tools
|
||||
python3 ./get.py
|
||||
|
||||
|
||||
@@ -60,3 +60,8 @@ it use a non-default pinout with a simple call
|
||||
SPI.setCS(5);
|
||||
SD.begin(5);
|
||||
}
|
||||
|
||||
Pad Strength
|
||||
============
|
||||
|
||||
The Raspberry Pi Pico has the ability to set the current that a pin (actually the pad associated with it) is capable of supplying. The current can be set to values of 2mA, 4mA, 8mA and 12mA. By default, on a reset, the setting is 4mA. A `pinMode(x, OUTPUT)`, where `x` is the pin number, is also the default setting. 4 settings have been added for use with `pinMode`: `OUTPUT_2MA`, `OUTPUT_4MA`, which has the same behavior as `OUTPUT`, `OUTPUT_8MA` and `OUTPUT_12MA`.
|
||||
|
||||
+15
-2
@@ -3,8 +3,8 @@
|
||||
|
||||
Equivalent to the Arduino SoftwareSerial library, an emulated UART using
|
||||
one or two PIO state machines is included in the Arduino-Pico core. This
|
||||
allows for up to 8 additional serial ports to be run from the RP2040 without
|
||||
requiring additional CPU resources.
|
||||
allows for up to 4 bidirectional or up to 8 unidirectional serial ports to
|
||||
be run from the RP2040 without requiring additional CPU resources.
|
||||
|
||||
Instantiate a ``SerialPIO(txpin, rxpin, fifosize)`` object in your sketch and then
|
||||
use it the same as any other serial port. Even, odd, and no parity modes
|
||||
@@ -21,3 +21,16 @@ For example, to make a transmit-only port on GP16
|
||||
|
||||
For detailed information about the Serial ports, see the
|
||||
Arduino `Serial Reference <https://www.arduino.cc/reference/en/language/functions/communication/serial/>`_ .
|
||||
|
||||
|
||||
SoftwareSerial Emulation
|
||||
========================
|
||||
A ``SoftwareSerial`` wrapper is included to provide plug-and-play compatibility
|
||||
with the Arduino `Software Serial <https://docs.arduino.cc/learn/built-in-libraries/software-serial>`_
|
||||
library. Use the normal ``#include <SoftwareSerial.h>`` to include it. The following
|
||||
differences from the Arduino standard are present:
|
||||
|
||||
* Inverted mode is not supported
|
||||
* All ports are always listening
|
||||
* ``listen`` call is a no-op
|
||||
* ``isListening()`` always returns ``true``
|
||||
|
||||
+100
-14
@@ -19,14 +19,14 @@ The PlatformIO experience:
|
||||
|
||||
Refer to the general documentation at https://docs.platformio.org/.
|
||||
|
||||
Especially useful is the `Getting started with VSCode + PlatformIO <https://docs.platformio.org/en/latest/integration/ide/vscode.html#installation), [CLI reference](https://docs.platformio.org/en/latest/core/index.html) and [platformio.ini options](https://docs.platformio.org/en/latest/projectconf/index.html)>`__ page.
|
||||
Especially useful is the `Getting started with VSCode + PlatformIO <https://docs.platformio.org/en/latest/integration/ide/vscode.html#installation>`_, `CLI reference <https://docs.platformio.org/en/latest/core/index.html>`_ and the `platformio.ini options <https://docs.platformio.org/en/latest/projectconf/index.html>`_ page.
|
||||
|
||||
Hereafter it is assumed that you have a basic understanding of PlatformIO in regards to project creation, project file structure and building and uploading PlatformIO projects, through reading the above pages.
|
||||
|
||||
Current state of development
|
||||
----------------------------
|
||||
|
||||
At the time of writing, PlatformIO integration for this core is a work-in-progress and not yet merged into mainline PlatformIO. This is subject to change soon.
|
||||
At the time of writing, PlatformIO integration for this core is a work-in-progress and not yet merged into mainline PlatformIO. This is subject to change once `this pull request <https://github.com/platformio/platform-raspberrypi/pull/36>`_ is merged.
|
||||
|
||||
If you want to use the PlatformIO integration right now, make sure you first create a standard Raspberry Pi Pico + Arduino project within PlatformIO.
|
||||
This will give you a project with the ``platformio.ini``
|
||||
@@ -38,8 +38,7 @@ This will give you a project with the ``platformio.ini``
|
||||
board = pico
|
||||
framework = arduino
|
||||
|
||||
Here, you need to change the `platform` to take advantage of the features described hereunder.
|
||||
You *also* need to inject two PlatformIO packages, one for the compiler toolchain and one for the Arduino core package.
|
||||
Here, you need to change the `platform` to take advantage of the features described hereunder and switch to the new core.
|
||||
|
||||
.. code:: ini
|
||||
|
||||
@@ -47,12 +46,32 @@ You *also* need to inject two PlatformIO packages, one for the compiler toolchai
|
||||
platform = https://github.com/maxgerhardt/platform-raspberrypi.git
|
||||
board = pico
|
||||
framework = arduino
|
||||
board_build.core = earlephilhower
|
||||
|
||||
When the support for this core has been merged into mainline PlatformIO, this notice will be removed and a standard `platformio.ini` as shown above will work as a base.
|
||||
|
||||
Deprecation warnings
|
||||
---------------------
|
||||
|
||||
Previous versions of this documentation told users to inject the framework and toolchain package into the project by using
|
||||
|
||||
.. code:: ini
|
||||
|
||||
; note that download link for toolchain is specific for OS. see https://github.com/earlephilhower/pico-quick-toolchain/releases.
|
||||
platform_packages =
|
||||
maxgerhardt/framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git
|
||||
maxgerhardt/toolchain-pico@https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.1-a/x86_64-w64-mingw32.arm-none-eabi-7855b0c.210706.zip
|
||||
|
||||
When the support for this core has been merged into mainline PlatformIO, this notice will be removed and a standard `platformio.ini` as shown above will work as a base.
|
||||
|
||||
This is now **deprecated** and should not be done anymore. Users should delete these ``platform_packages`` lines and update the platform integration by issuing the command
|
||||
|
||||
.. code:: bash
|
||||
|
||||
pio pkg update -g -p https://github.com/maxgerhardt/platform-raspberrypi.git
|
||||
|
||||
in the `PlatformIO CLI <https://docs.platformio.org/en/latest/integration/ide/vscode.html#platformio-core-cli>`_. The same can be achieved by using the VSCode PIO Home -> Platforms -> Updates GUI.
|
||||
|
||||
The toolchain, which was also renamed to ``toolchain-rp2040-earlephilhower`` is downloaded automatically from the registry. The same goes for the ``framework-arduinopico`` toolchain package, which points directly to the Arduino-Pico Github repository.
|
||||
However, users can still select a custom fork or branch of the core if desired so, as detailed in a chapter below.
|
||||
|
||||
Selecting the new core
|
||||
----------------------
|
||||
@@ -61,8 +80,8 @@ Prerequisite for using this core is to tell PlatformIO to switch to it.
|
||||
There will be board definition files where the Earle-Philhower core will
|
||||
be the default since it's a board that only exists in this core (and not
|
||||
the other https://github.com/arduino/ArduinoCore-mbed). To switch boards
|
||||
for which this is not the default core (e.g. the standard
|
||||
``board = pico``), the directive
|
||||
for which this is not the default core (which are only
|
||||
``board = pico`` and ``board = nanorp2040connect``), the directive
|
||||
|
||||
.. code:: ini
|
||||
|
||||
@@ -72,6 +91,8 @@ must be added to the ``platformio.ini``. This controls the `core
|
||||
switching
|
||||
logic <https://github.com/maxgerhardt/platform-raspberrypi/blob/77e0d3a29d1dbf00fd3ec3271104e3bf4820869c/builder/frameworks/arduino/arduino.py#L27-L32>`__.
|
||||
|
||||
When using Arduino-Pico-only boards like ``board = rpipico`` or ``board = adafruit_feather``, this is not needed.
|
||||
|
||||
Flash size
|
||||
----------
|
||||
|
||||
@@ -154,6 +175,37 @@ either a sing line or a newline-separated expression.
|
||||
-DDEBUG_RP2040_CORE
|
||||
-DDEBUG_RP2040_PORT=Serial2
|
||||
|
||||
C++ Exceptions
|
||||
--------------
|
||||
|
||||
Exceptions are disabled by default. To enable them, use
|
||||
|
||||
.. code:: ini
|
||||
|
||||
; Enable Exceptions
|
||||
build_flags = -DPIO_FRAMEWORK_ARDUINO_ENABLE_EXCEPTIONS
|
||||
|
||||
Stack Protector
|
||||
---------------
|
||||
|
||||
To enable GCC's stack protection feature, use
|
||||
|
||||
.. code:: ini
|
||||
|
||||
; Enable Stack Protector
|
||||
build_flags = -fstack-protector
|
||||
|
||||
|
||||
RTTI
|
||||
----
|
||||
|
||||
RTTI (run-time type information) is disabled by default. To enable it, use
|
||||
|
||||
.. code:: ini
|
||||
|
||||
; Enable RTTI
|
||||
build_flags = -DPIO_FRAMEWORK_ARDUINO_ENABLE_RTTI
|
||||
|
||||
USB Stack
|
||||
---------
|
||||
|
||||
@@ -188,8 +240,8 @@ directive to do so. Simply specify that the framework package
|
||||
Whereas the ``#master`` can also be replaced by a ``#branchname`` or a
|
||||
``#commithash``. If left out, it will pull the default branch, which is ``master``.
|
||||
|
||||
The ``file://`` pseudo-protocol can also be used instead of ``https://`` to point to a
|
||||
local copy of the core (with e.g. some modifications) on disk.
|
||||
The ``file://`` and ``symlink://`` pseudo-protocols can also be used instead of ``https://`` to point to a
|
||||
local copy of the core (with e.g. some modifications) on disk (`see documentation <https://docs.platformio.org/en/latest/core/userguide/pkg/cmd_install.html?#local-folder>`_).
|
||||
|
||||
Note that this can only be done for versions that have the PlatformIO
|
||||
builder script it in, so versions before 1.9.2 are not supported.
|
||||
@@ -206,14 +258,48 @@ and 0.5MByte filesystem.
|
||||
platform = https://github.com/maxgerhardt/platform-raspberrypi.git
|
||||
board = pico
|
||||
framework = arduino
|
||||
; board can use both Arduino cores -- we select Arduino-Pico here
|
||||
board_build.core = earlephilhower
|
||||
board_build.filesystem_size = 0.5m
|
||||
; note that download link for toolchain is specific for OS. see https://github.com/earlephilhower/pico-quick-toolchain/releases.
|
||||
platform_packages =
|
||||
maxgerhardt/framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git
|
||||
maxgerhardt/toolchain-pico@https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.1-a/x86_64-w64-mingw32.arm-none-eabi-7855b0c.210706.zip
|
||||
|
||||
|
||||
The initial project structure should be generated just creating a new
|
||||
project for the Pico and the Arduino framework, after which the
|
||||
auto-generated ``platformio.ini`` can be adapted per above.
|
||||
|
||||
Debugging
|
||||
---------
|
||||
|
||||
With recent updates to the toolchain and OpenOCD, debugging firmwares is also possible.
|
||||
|
||||
To specify the debugging adapter, use ``debug_tool`` (`documentation <https://docs.platformio.org/en/latest/projectconf/section_env_debug.html#debug-tool>`_). Supported values are:
|
||||
|
||||
* ``picoprobe``
|
||||
* ``cmsis-dap``
|
||||
* ``jlink``
|
||||
* ``raspberrypi-swd``
|
||||
|
||||
These values can also be used in ``upload_protocol`` if you want PlatformIO to upload the regular firmware through this method, which you likely want.
|
||||
|
||||
Especially the PicoProbe method is convenient when you have two Raspberry Pi Pico boards. One of them can be flashed with the PicoProbe firmware (`documentation <https://www.raspberrypi.com/documentation/microcontrollers/raspberry-pi-pico.html#debugging-using-another-raspberry-pi-pico>`_) and is then connected to the target Raspberry Pi Pico board (see `documentation <https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf>`_ chapter "Picoprobe Wiring"). Remember that on Windows, you have to use `Zadig <https://zadig.akeo.ie/>`_ to also load "WinUSB" drivers for the "Picoprobe (Interface 2)" device so that OpenOCD can speak to it.
|
||||
|
||||
With that set up, debugging can be started via the left debugging sidebar and works nicely: Setup breakpoints, inspect the value of variables in the code, step through the code line by line. When a breakpoint is hit or execution is halted, you can even see the execution state both Cortex-M0+ cores of the RP2040.
|
||||
|
||||
.. image:: images/pio_debugging.png
|
||||
|
||||
For further information on customizing debug options, like the initial breakpoint or debugging / SWD speed, consult `the documentation <https://docs.platformio.org/en/latest/projectconf/section_env_debug.html>`_.
|
||||
|
||||
Filesystem Uploading
|
||||
--------------------
|
||||
|
||||
For the Arduino IDE, `a plugin <https://github.com/earlephilhower/arduino-pico#uploading-filesystem-images>`_ is available that enables a data folder to be packed as a LittleFS filesystem binary and uploaded to the Pico.
|
||||
|
||||
This functionality is also built-in in the PlatformIO integration. Open the `project tasks <https://docs.platformio.org/en/latest/integration/ide/vscode.html#project-tasks>`_ and expand the "Platform" tasks:
|
||||
|
||||
.. image:: images/pio_fs_upload.png
|
||||
|
||||
The files you want to upload should be placed in a folder called ``data`` inside the project. This can be customized `if needed <https://docs.platformio.org/en/latest/projectconf/section_platformio.html#data-dir>`_.
|
||||
|
||||
The task "Build Filesystem Image" will take all files in the data directory and create a ``littlefs.bin`` file from it using the ``mklittlefs`` tool.
|
||||
|
||||
The task "Upload Filesystem Image" will upload the filesystem image to the Pico via the specified ``upload_protocol``.
|
||||
|
||||
+3
-4
@@ -32,15 +32,14 @@ using the ``setFIFOSize`` call prior to calling ``begin()``
|
||||
Serial1.begin(baud);
|
||||
|
||||
The FIFO is normally handled via an interrupt, which reduced CPU load and
|
||||
makes it less likely to lose characters. However, the FIFO introduces up
|
||||
to 32 bit-times of delay before serial data is available to the application.
|
||||
makes it less likely to lose characters.
|
||||
|
||||
For applications where this is an issue (i.e. very low baud), use
|
||||
For applications where an IRQ driven serial port is not appropriate, use
|
||||
``setPollingMode(true)`` before calling ``begin()``
|
||||
|
||||
.. code:: cpp
|
||||
Serial1.setPollingMode(true);
|
||||
Serial1.begin(110)
|
||||
Serial1.begin(300)
|
||||
|
||||
For detailed information about the Serial ports, see the
|
||||
Arduino `Serial Reference <https://www.arduino.cc/reference/en/language/functions/communication/serial/>`_ .
|
||||
|
||||
+6
-1
@@ -11,7 +11,7 @@
|
||||
#######################################
|
||||
|
||||
setup1 KEYWORD2
|
||||
loop2 KEYWORD2
|
||||
loop1 KEYWORD2
|
||||
|
||||
analogWriteFreq KEYWORD2
|
||||
analogWriteRange KEYWORD2
|
||||
@@ -36,3 +36,8 @@ prepare KEYWORD2
|
||||
SerialPIO KEYWORD2
|
||||
setFIFOSize KEYWORD2
|
||||
setPollingMode KEYWORD2
|
||||
|
||||
OUTPUT_2MA LITERAL1
|
||||
OUTPUT_4MA LITERAL1
|
||||
OUTPUT_8MA LITERAL1
|
||||
OUTPUT_12MA LITERAL1
|
||||
|
||||
Binary file not shown.
@@ -13,7 +13,7 @@
|
||||
|
||||
#define PICO_SDK_VERSION_MAJOR 1
|
||||
#define PICO_SDK_VERSION_MINOR 3
|
||||
#define PICO_SDK_VERSION_REVISION 0
|
||||
#define PICO_SDK_VERSION_STRING "1.3.0"
|
||||
#define PICO_SDK_VERSION_REVISION 2
|
||||
#define PICO_SDK_VERSION_STRING "1.3.2-develop"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
-iwithprefixbefore/cores/rp2040/api/deprecated-avr-comp/
|
||||
-iwithprefixbefore/lib/pico_base/
|
||||
-iwithprefixbefore/pico-extras/src/common/pico_audio/include
|
||||
-iwithprefixbefore/pico-extras/src/common/pico_util_buffer/include
|
||||
-iwithprefixbefore/pico-extras/src/rp2_common/pico_audio_i2s/include
|
||||
-iwithprefixbefore/pico-sdk/lib/tinyusb/src/
|
||||
-iwithprefixbefore/pico-sdk/src/boards/include
|
||||
-iwithprefixbefore/pico-sdk/src/common/pico_base/include
|
||||
|
||||
@@ -71,7 +71,6 @@
|
||||
-Wl,--wrap=atanf
|
||||
-Wl,--wrap=atanh
|
||||
-Wl,--wrap=atanhf
|
||||
-Wl,--wrap=calloc
|
||||
-Wl,--wrap=cbrt
|
||||
-Wl,--wrap=cbrtf
|
||||
-Wl,--wrap=ceil
|
||||
@@ -105,7 +104,6 @@
|
||||
-Wl,--wrap=fmaf
|
||||
-Wl,--wrap=fmod
|
||||
-Wl,--wrap=fmodf
|
||||
-Wl,--wrap=free
|
||||
-Wl,--wrap=hypot
|
||||
-Wl,--wrap=hypotf
|
||||
-Wl,--wrap=ldexp
|
||||
@@ -118,7 +116,6 @@
|
||||
-Wl,--wrap=log2
|
||||
-Wl,--wrap=log2f
|
||||
-Wl,--wrap=logf
|
||||
-Wl,--wrap=malloc
|
||||
-Wl,--wrap=memcpy
|
||||
-Wl,--wrap=memset
|
||||
-Wl,--wrap=__popcountdi2
|
||||
@@ -147,3 +144,4 @@
|
||||
-Wl,--wrap=tanhf
|
||||
-Wl,--wrap=trunc
|
||||
-Wl,--wrap=truncf
|
||||
-Wl,--wrap=__getreent
|
||||
|
||||
Submodule libraries/Adafruit_TinyUSB_Arduino updated: 4f2c0ab42a...7264c1492a
@@ -0,0 +1,81 @@
|
||||
// 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);
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
# 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
|
||||
Submodule
+1
Submodule libraries/FreeRTOS/lib/FreeRTOS-Kernel added at f5fe79dacd
@@ -0,0 +1,10 @@
|
||||
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
|
||||
@@ -0,0 +1,39 @@
|
||||
**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.
|
||||
@@ -0,0 +1 @@
|
||||
#include "../lib/FreeRTOS-Kernel/include/FreeRTOS.h"
|
||||
@@ -0,0 +1,129 @@
|
||||
/* 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
|
||||
#define configSTACK_DEPTH_TYPE uint32_t
|
||||
|
||||
#define configUSE_NEWLIB_REENTRANT 1
|
||||
#define configNEWLIB_REENTRANT_IS_DYNAMIC 0 /* Note that we have a different config option, portSET_IMPURE_PTR */
|
||||
#include <reent.h>
|
||||
extern void __register_impure_ptr(struct _reent *p);
|
||||
#define portSET_IMPURE_PTR(x) __register_impure_ptr(x)
|
||||
|
||||
/* 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 0
|
||||
#define configSUPPORT_PICO_SYNC_INTEROP 1
|
||||
#define configSUPPORT_PICO_TIME_INTEROP 1
|
||||
|
||||
|
||||
#include "rp2040_config.h"
|
||||
//#include "task.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../lib/FreeRTOS-Kernel/include/StackMacros.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../lib/FreeRTOS-Kernel/include/atomic.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../lib/FreeRTOS-Kernel/croutine.c"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../lib/FreeRTOS-Kernel/include/croutine.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../lib/FreeRTOS-Kernel/include/deprecated_definitions.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../lib/FreeRTOS-Kernel/event_groups.c"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../lib/FreeRTOS-Kernel/include/event_groups.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2040/include/freertos_sdk_config.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../lib/FreeRTOS-Kernel/portable/MemMang/heap_3.c"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2040/idle_task_static_memory.c"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../lib/FreeRTOS-Kernel/list.c"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../lib/FreeRTOS-Kernel/include/list.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../lib/FreeRTOS-Kernel/include/message_buffer.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../lib/FreeRTOS-Kernel/include/mpu_prototypes.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../lib/FreeRTOS-Kernel/include/mpu_wrappers.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2040/port.c"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../lib/FreeRTOS-Kernel/include/portable.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2040/include/portmacro.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../lib/FreeRTOS-Kernel/include/projdefs.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../lib/FreeRTOS-Kernel/queue.c"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../lib/FreeRTOS-Kernel/include/queue.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../lib/FreeRTOS-Kernel/portable/ThirdParty/GCC/RP2040/include/rp2040_config.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../lib/FreeRTOS-Kernel/include/semphr.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../lib/FreeRTOS-Kernel/include/stack_macros.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../lib/FreeRTOS-Kernel/stream_buffer.c"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../lib/FreeRTOS-Kernel/include/stream_buffer.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../lib/FreeRTOS-Kernel/include/task.h"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../lib/FreeRTOS-Kernel/tasks.c"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../lib/FreeRTOS-Kernel/timers.c"
|
||||
@@ -0,0 +1 @@
|
||||
#include "../lib/FreeRTOS-Kernel/include/timers.h"
|
||||
@@ -0,0 +1,425 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Phillip Stevens All Rights Reserved.
|
||||
* Modifications by Earle F. Philhower, III, for Arduino-Pico
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*
|
||||
* This file is NOT part of the FreeRTOS distribution.
|
||||
*
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Arduino Core includes */
|
||||
#include <Arduino.h>
|
||||
#include <RP2040USB.h>
|
||||
#include "tusb.h"
|
||||
#define USB_TASK_IRQ 31
|
||||
|
||||
|
||||
/* Raspberry PI Pico includes */
|
||||
#include <pico.h>
|
||||
#include <pico/time.h>
|
||||
|
||||
/* FreeRTOS includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "timers.h"
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void initFreeRTOS(void)
|
||||
{
|
||||
}
|
||||
|
||||
extern void setup() __attribute__((weak));
|
||||
extern void loop() __attribute__((weak));
|
||||
extern void setup1() __attribute__((weak));
|
||||
extern void loop1() __attribute__((weak));
|
||||
// Idle functions (USB, events, ...) from the core
|
||||
extern void __loop();
|
||||
volatile bool __usbInitted = false;
|
||||
|
||||
static void __core0(void *params)
|
||||
{
|
||||
(void) params;
|
||||
#ifndef NO_USB
|
||||
while (!__usbInitted) {
|
||||
delay(1);
|
||||
}
|
||||
#endif
|
||||
if (setup) {
|
||||
setup();
|
||||
}
|
||||
if (loop) {
|
||||
while (1) {
|
||||
loop();
|
||||
__loop();
|
||||
}
|
||||
} else {
|
||||
while (1) {
|
||||
__loop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void __core1(void *params)
|
||||
{
|
||||
(void) params;
|
||||
#ifndef NO_USB
|
||||
while (!__usbInitted) {
|
||||
delay(1);
|
||||
}
|
||||
#endif
|
||||
if (setup1) {
|
||||
setup1();
|
||||
}
|
||||
if (loop1) {
|
||||
while (1) {
|
||||
loop1();
|
||||
}
|
||||
} else {
|
||||
while (1) {
|
||||
vTaskDelay(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void delay(unsigned long ms) {
|
||||
vTaskDelay(ms / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
extern "C" void yield() {
|
||||
taskYIELD();
|
||||
}
|
||||
|
||||
extern mutex_t __usb_mutex;
|
||||
static TaskHandle_t __usbTask;
|
||||
static void __usb(void *param);
|
||||
|
||||
void startFreeRTOS(void)
|
||||
{
|
||||
|
||||
TaskHandle_t c0;
|
||||
xTaskCreate(__core0, "CORE0", 1024, 0, configMAX_PRIORITIES / 2, &c0);
|
||||
vTaskCoreAffinitySet( c0, 1 << 0 );
|
||||
|
||||
if (setup1 || loop1) {
|
||||
TaskHandle_t c1;
|
||||
xTaskCreate(__core1, "CORE1", 1024, 0, configMAX_PRIORITIES / 2, &c1);
|
||||
vTaskCoreAffinitySet( c1, 1 << 1 );
|
||||
}
|
||||
|
||||
// Initialise and run the freeRTOS scheduler. Execution should never return here.
|
||||
vTaskStartScheduler();
|
||||
|
||||
while (true) {
|
||||
/* noop */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void prvDisableInterrupts()
|
||||
{
|
||||
portDISABLE_INTERRUPTS();
|
||||
}
|
||||
|
||||
void prvEnableInterrupts()
|
||||
{
|
||||
portENABLE_INTERRUPTS();
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
#if ( configUSE_IDLE_HOOK == 1 )
|
||||
/*
|
||||
* Call the user defined loop() function from within the idle task.
|
||||
* This allows the application designer to add background functionality
|
||||
* without the overhead of a separate task.
|
||||
*
|
||||
* NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES, CALL A FUNCTION THAT MIGHT BLOCK.
|
||||
*
|
||||
*/
|
||||
|
||||
extern "C"
|
||||
void vApplicationIdleHook( void ) __attribute__((weak));
|
||||
|
||||
|
||||
void vApplicationIdleHook( void )
|
||||
{
|
||||
__wfe(); // Low power idle if nothing to do...
|
||||
}
|
||||
|
||||
#endif /* configUSE_IDLE_HOOK == 1 */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( configUSE_MINIMAL_IDLE_HOOK == 1 )
|
||||
/*
|
||||
* Call the user defined minimalIdle() function from within the idle task.
|
||||
* This allows the application designer to add background functionality
|
||||
* without the overhead of a separate task.
|
||||
*
|
||||
* NOTE: vApplicationMinimalIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES, CALL A FUNCTION THAT MIGHT BLOCK.
|
||||
*
|
||||
*/
|
||||
void minimalIdle( void ) __attribute__((weak));
|
||||
void minimalIdle() {} //Empty minimalIdle function
|
||||
|
||||
extern "C"
|
||||
void vApplicationMinimalIdleHook( void ) __attribute__((weak));
|
||||
|
||||
void vApplicationMinimalIdleHook( void )
|
||||
{
|
||||
minimalIdle();
|
||||
}
|
||||
|
||||
#endif /* configUSE_MINIMAL_IDLE_HOOK == 1 */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( configUSE_TICK_HOOK == 1 )
|
||||
/*
|
||||
* Call the user defined minimalIdle() function from within the idle task.
|
||||
* This allows the application designer to add background functionality
|
||||
* without the overhead of a separate task.
|
||||
*
|
||||
* NOTE: vApplicationMinimalIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES, CALL A FUNCTION THAT MIGHT BLOCK.
|
||||
*
|
||||
*/
|
||||
void tick( void ) __attribute__((weak));
|
||||
void tick() {} //Empty minimalIdle function
|
||||
|
||||
extern "C"
|
||||
void vApplicationTickHook( void ) __attribute__((weak));
|
||||
|
||||
void vApplicationTickHook( void )
|
||||
{
|
||||
tick();
|
||||
}
|
||||
|
||||
#endif /* configUSE_TICK_HOOK == 1 */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( configUSE_MALLOC_FAILED_HOOK == 1 || configCHECK_FOR_STACK_OVERFLOW >= 1 || configDEFAULT_ASSERT == 1 )
|
||||
|
||||
/**
|
||||
* Private function to enable board led to use it in application hooks
|
||||
*/
|
||||
void prvSetMainLedOn( void )
|
||||
{
|
||||
gpio_init(LED_BUILTIN);
|
||||
gpio_set_dir(LED_BUILTIN, true);
|
||||
gpio_put(LED_BUILTIN, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private function to blink board led to use it in application hooks
|
||||
*/
|
||||
void prvBlinkMainLed( void )
|
||||
{
|
||||
gpio_put(LED_BUILTIN, !gpio_get(LED_BUILTIN));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
Usage:
|
||||
called on fatal error (interrupts disabled already)
|
||||
\*---------------------------------------------------------------------------*/
|
||||
extern "C"
|
||||
void rtosFatalError(void)
|
||||
{
|
||||
prvSetMainLedOn(); // Main LED on.
|
||||
|
||||
for(;;)
|
||||
{
|
||||
// Main LED slow flash
|
||||
sleep_ms(100);
|
||||
prvBlinkMainLed();
|
||||
sleep_ms(2000);
|
||||
prvBlinkMainLed();
|
||||
}
|
||||
}
|
||||
|
||||
#if ( configUSE_MALLOC_FAILED_HOOK == 1 )
|
||||
/*---------------------------------------------------------------------------*\
|
||||
Usage:
|
||||
called by task system when a malloc failure is noticed
|
||||
Description:
|
||||
Malloc failure handler -- Shut down all interrupts, send serious complaint
|
||||
to command port. FAST Blink on main LED.
|
||||
Arguments:
|
||||
pxTask - pointer to task handle
|
||||
pcTaskName - pointer to task name
|
||||
Results:
|
||||
<none>
|
||||
Notes:
|
||||
This routine will never return.
|
||||
This routine is referenced in the task.c file of FreeRTOS as an extern.
|
||||
\*---------------------------------------------------------------------------*/
|
||||
extern "C"
|
||||
void vApplicationMallocFailedHook( void ) __attribute__((weak));
|
||||
|
||||
void vApplicationMallocFailedHook( void )
|
||||
{
|
||||
prvSetMainLedOn(); // Main LED on.
|
||||
|
||||
for(;;)
|
||||
{
|
||||
sleep_ms(50);
|
||||
prvBlinkMainLed(); // Main LED fast blink.
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* configUSE_MALLOC_FAILED_HOOK == 1 */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
|
||||
#if ( configCHECK_FOR_STACK_OVERFLOW >= 1 )
|
||||
|
||||
extern "C"
|
||||
void vApplicationStackOverflowHook( TaskHandle_t xTask,
|
||||
char * pcTaskName ) __attribute__((weak));
|
||||
|
||||
void vApplicationStackOverflowHook( TaskHandle_t xTask __attribute__((unused)),
|
||||
char * pcTaskName __attribute__((unused)) )
|
||||
{
|
||||
prvSetMainLedOn(); // Main LED on.
|
||||
|
||||
for(;;)
|
||||
{
|
||||
sleep_ms(2000);
|
||||
prvBlinkMainLed(); // Main LED slow blink.
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* configCHECK_FOR_STACK_OVERFLOW >= 1 */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( configSUPPORT_STATIC_ALLOCATION >= 1 )
|
||||
|
||||
extern "C"
|
||||
void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
|
||||
StackType_t ** ppxIdleTaskStackBuffer,
|
||||
configSTACK_DEPTH_TYPE * pulIdleTaskStackSize ) __attribute__((weak));
|
||||
|
||||
void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
|
||||
StackType_t ** ppxIdleTaskStackBuffer,
|
||||
configSTACK_DEPTH_TYPE * pulIdleTaskStackSize )
|
||||
{
|
||||
static StaticTask_t xIdleTaskTCB;
|
||||
static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ];
|
||||
|
||||
*ppxIdleTaskTCBBuffer = &xIdleTaskTCB;
|
||||
*ppxIdleTaskStackBuffer = uxIdleTaskStack;
|
||||
*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
|
||||
}
|
||||
|
||||
#if ( configUSE_TIMERS >= 1 )
|
||||
|
||||
extern "C"
|
||||
void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer,
|
||||
StackType_t ** ppxTimerTaskStackBuffer,
|
||||
configSTACK_DEPTH_TYPE * pulTimerTaskStackSize ) __attribute__((weak));
|
||||
|
||||
void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer,
|
||||
StackType_t ** ppxTimerTaskStackBuffer,
|
||||
configSTACK_DEPTH_TYPE * pulTimerTaskStackSize )
|
||||
{
|
||||
static StaticTask_t xTimerTaskTCB;
|
||||
static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ];
|
||||
|
||||
*ppxTimerTaskTCBBuffer = &xTimerTaskTCB;
|
||||
*ppxTimerTaskStackBuffer = uxTimerTaskStack;
|
||||
*pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
|
||||
}
|
||||
|
||||
#endif /* configUSE_TIMERS >= 1 */
|
||||
|
||||
#endif /* configSUPPORT_STATIC_ALLOCATION >= 1 */
|
||||
|
||||
/**
|
||||
* configASSERT default implementation
|
||||
*/
|
||||
#if configDEFAULT_ASSERT == 1
|
||||
|
||||
extern "C"
|
||||
void vApplicationAssertHook() {
|
||||
|
||||
taskDISABLE_INTERRUPTS(); // Disable task interrupts
|
||||
|
||||
prvSetMainLedOn(); // Main LED on.
|
||||
for(;;)
|
||||
{
|
||||
sleep_ms(100);
|
||||
prvBlinkMainLed(); // Led off.
|
||||
|
||||
sleep_ms(2000);
|
||||
prvBlinkMainLed(); // Led on.
|
||||
|
||||
sleep_ms(100);
|
||||
prvBlinkMainLed(); // Led off
|
||||
|
||||
sleep_ms(100);
|
||||
prvBlinkMainLed(); // Led on.
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void __usb_irq() {
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
vTaskNotifyGiveFromISR( __usbTask, &xHigherPriorityTaskWoken );
|
||||
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
||||
}
|
||||
|
||||
static void __usb(void *param)
|
||||
{
|
||||
(void) param;
|
||||
|
||||
tusb_init();
|
||||
irq_set_exclusive_handler(USB_TASK_IRQ, __usb_irq);
|
||||
irq_set_enabled(USB_TASK_IRQ, true);
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
__usbInitted = true;
|
||||
|
||||
while (true) {
|
||||
if (mutex_try_enter(&__usb_mutex, NULL)) {
|
||||
tud_task();
|
||||
mutex_exit(&__usb_mutex);
|
||||
}
|
||||
vTaskDelay(1 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
extern void __SetupDescHIDReport();
|
||||
extern void __SetupUSBDescriptor();
|
||||
|
||||
void __USBStart()
|
||||
{
|
||||
mutex_init(&__usb_mutex);
|
||||
|
||||
__SetupDescHIDReport();
|
||||
__SetupUSBDescriptor();
|
||||
|
||||
// Make highest prio and locked to core 0
|
||||
xTaskCreate(__usb, "USB", 256, 0, configMAX_PRIORITIES - 1, &__usbTask);
|
||||
vTaskCoreAffinitySet( __usbTask, 1 << 0 );
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
I2S stereo microphone (input) example
|
||||
Run using the Arduino Serial Plotter to see waveform.
|
||||
Released to the Public Domain by Earle F. Philhower, III
|
||||
|
||||
For the Google AIY Voice Hat Microphone daughterboard, part
|
||||
of the Raspberry Pi AIY cardboard box, the I2S stereo pinout
|
||||
looking at the board top with the RPI logo on the left hand
|
||||
side:
|
||||
+-- ------------------------------------ --+
|
||||
left RPI | (1) GND (2) DIN (3) BCLK (4) LRCLK (5) 3.3V | AIY right
|
||||
logo +---------------------------------------------+ logo
|
||||
*/
|
||||
|
||||
#include <I2S.h>
|
||||
|
||||
I2S i2s(INPUT);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
i2s.setDATA(0);
|
||||
i2s.setBCLK(1); // LRCLK = GP2
|
||||
i2s.setBitsPerSample(16);
|
||||
i2s.setFrequency(22050);
|
||||
i2s.begin();
|
||||
|
||||
while (1) {
|
||||
int16_t l, r;
|
||||
i2s.read16(&l, &r);
|
||||
Serial.printf("%d %d\n", l, r);
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
/* Nothing here */
|
||||
}
|
||||
@@ -5,29 +5,54 @@
|
||||
|
||||
created 17 November 2016
|
||||
by Sandeep Mistry
|
||||
modified for ESP8266 by Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
modified for RP2040 by Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
|
||||
|
||||
bool setBCLK(pin_size_t pin);
|
||||
- This assigns two adjacent pins - the pin after this one (one greater)
|
||||
is the WS (word select) signal, which toggles before the sample for
|
||||
each channel is sent
|
||||
|
||||
bool setDATA(pin_size_t pin);
|
||||
- Sets the DOUT pin, can be any valid GPIO pin
|
||||
*/
|
||||
|
||||
#include <I2S.h>
|
||||
|
||||
// Create the I2S port using a PIO state machine
|
||||
I2S i2s(OUTPUT);
|
||||
|
||||
// GPIO pin numbers
|
||||
#define pBCLK 20
|
||||
#define pWS (pBCLK+1)
|
||||
#define pDOUT 22
|
||||
|
||||
const int frequency = 440; // frequency of square wave in Hz
|
||||
const int amplitude = 500; // amplitude of square wave
|
||||
const int sampleRate = 8000; // sample rate in Hz
|
||||
const int sampleRate = 16000; // minimum for UDA1334A
|
||||
|
||||
const int halfWavelength = (sampleRate / frequency); // half wavelength of square wave
|
||||
|
||||
short sample = amplitude; // current sample value
|
||||
int16_t sample = amplitude; // current sample value
|
||||
int count = 0;
|
||||
|
||||
void setup() {
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
digitalWrite(LED_BUILTIN, 1);
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println("I2S simple tone");
|
||||
|
||||
i2s.setBCLK(pBCLK);
|
||||
i2s.setDATA(pDOUT);
|
||||
i2s.setBitsPerSample(16);
|
||||
|
||||
// start I2S at the sample rate with 16-bits per sample
|
||||
if (!I2S.begin(sampleRate)) {
|
||||
if (!i2s.begin(sampleRate)) {
|
||||
Serial.println("Failed to initialize I2S!");
|
||||
while (1); // do nothing
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
@@ -37,10 +62,9 @@ void loop() {
|
||||
}
|
||||
|
||||
// write the same sample twice, once for left and once for the right channel
|
||||
I2S.write(sample);
|
||||
I2S.write(sample);
|
||||
i2s.write(sample);
|
||||
i2s.write(sample);
|
||||
|
||||
// increment the counter for the next sample
|
||||
count++;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,10 +14,24 @@ I2S KEYWORD1
|
||||
begin KEYWORD2
|
||||
end KEYWORD2
|
||||
|
||||
setBCLK KEYWORD2
|
||||
setDATA KEYWORD2
|
||||
setBitsPerSample KEYWORD2
|
||||
setFrequency KEYWORD2
|
||||
|
||||
read8 KEYWORD2
|
||||
read16 KEYWORD2
|
||||
read24 KEYWORD2
|
||||
read32 KEYWORD2
|
||||
|
||||
write8 KEYWORD2
|
||||
write16 KEYWORD2
|
||||
write24 KEYWORD2
|
||||
write32 KEYWORD2
|
||||
|
||||
onReceive KEYWORD2
|
||||
onTransmit KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
I2S_PHILIPS_MODE LITERAL1
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
name=I2S
|
||||
version=1.0
|
||||
version=2.0
|
||||
author=Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
maintainer=Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
sentence=Enables the communication with devices that use the Inter-IC Sound (I2S) Bus. Specific implementation for RP2040, based off of pico-extras samples.
|
||||
sentence=Enables the communication with devices that use the Inter-IC Sound (I2S) Bus.
|
||||
paragraph=
|
||||
category=Communication
|
||||
url=http://www.arduino.cc/en/Reference/I2S
|
||||
architectures=rp2040
|
||||
|
||||
|
||||
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
AudioRingBuffer for Raspnerry Pi Pico RP2040
|
||||
Implements a ring buffer for PIO DMA for I2S read or write
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <vector>
|
||||
#include "hardware/dma.h"
|
||||
#include "hardware/irq.h"
|
||||
#include "hardware/pio.h"
|
||||
#include "pio_i2s.pio.h"
|
||||
#include "AudioRingBuffer.h"
|
||||
|
||||
static int __channelCount = 0; // # of channels left. When we hit 0, then remove our handler
|
||||
static AudioRingBuffer* __channelMap[12]; // Lets the IRQ handler figure out where to dispatch to
|
||||
|
||||
AudioRingBuffer::AudioRingBuffer(size_t bufferCount, size_t bufferWords, int32_t silenceSample, PinMode direction) {
|
||||
_running = false;
|
||||
_silenceSample = silenceSample;
|
||||
_bufferCount = bufferCount;
|
||||
_wordsPerBuffer = bufferWords;
|
||||
_isOutput = direction == OUTPUT;
|
||||
_overunderflow = false;
|
||||
_callback = nullptr;
|
||||
_userBuffer = -1;
|
||||
_userOff = 0;
|
||||
for (size_t i = 0; i < bufferCount; i++) {
|
||||
auto ab = new AudioBuffer;
|
||||
ab->buff = new uint32_t[_wordsPerBuffer];
|
||||
ab->empty = true;
|
||||
_buffers.push_back(ab);
|
||||
}
|
||||
}
|
||||
|
||||
AudioRingBuffer::~AudioRingBuffer() {
|
||||
if (_running) {
|
||||
for (auto i = 0; i < 2; i++) {
|
||||
dma_channel_set_irq0_enabled(_channelDMA[i], false);
|
||||
dma_channel_unclaim(_channelDMA[i]);
|
||||
__channelMap[_channelDMA[i]] = nullptr;
|
||||
}
|
||||
while (_buffers.size()) {
|
||||
auto ab = _buffers.back();
|
||||
_buffers.pop_back();
|
||||
delete[] ab->buff;
|
||||
delete ab;
|
||||
}
|
||||
__channelCount--;
|
||||
if (!__channelCount) {
|
||||
irq_set_enabled(DMA_IRQ_0, false);
|
||||
// TODO - how can we know if there are no other parts of the core using DMA0 IRQ??
|
||||
irq_remove_handler(DMA_IRQ_0, _irq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioRingBuffer::setCallback(void (*fn)()) {
|
||||
_callback = fn;
|
||||
}
|
||||
|
||||
bool AudioRingBuffer::begin(int dreq, volatile void *pioFIFOAddr) {
|
||||
_running = true;
|
||||
// Set all buffers to silence, empty
|
||||
for (auto buff : _buffers) {
|
||||
buff->empty = true;
|
||||
if (_isOutput) {
|
||||
for (uint32_t x = 0; x < _wordsPerBuffer; x++) {
|
||||
buff->buff[x] = _silenceSample;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Get ping and pong DMA channels
|
||||
for (auto i = 0; i < 2; i++) {
|
||||
_channelDMA[i] = dma_claim_unused_channel(true);
|
||||
if (_channelDMA[i] == -1) {
|
||||
if (i == 1) {
|
||||
dma_channel_unclaim(_channelDMA[0]);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool needSetIRQ = __channelCount == 0;
|
||||
// Need to know both channels to set up ping-pong, so do in 2 stages
|
||||
for (auto i = 0; i < 2; i++) {
|
||||
dma_channel_config c = dma_channel_get_default_config(_channelDMA[i]);
|
||||
channel_config_set_transfer_data_size(&c, DMA_SIZE_32); // 32b transfers into PIO FIFO
|
||||
if (_isOutput) {
|
||||
channel_config_set_read_increment(&c, true); // Reading incrementing addresses
|
||||
channel_config_set_write_increment(&c, false); // Writing to the same FIFO address
|
||||
} else {
|
||||
channel_config_set_read_increment(&c, false); // Reading same FIFO address
|
||||
channel_config_set_write_increment(&c, true); // Writing to incrememting buffers
|
||||
}
|
||||
channel_config_set_dreq(&c, dreq); // Wait for the PIO TX FIFO specified
|
||||
channel_config_set_chain_to(&c, _channelDMA[i ^ 1]); // Start other channel when done
|
||||
channel_config_set_irq_quiet(&c, false); // Need IRQs
|
||||
|
||||
if (_isOutput) {
|
||||
dma_channel_configure(_channelDMA[i], &c, pioFIFOAddr, _buffers[i]->buff, _wordsPerBuffer, false);
|
||||
} else {
|
||||
dma_channel_configure(_channelDMA[i], &c, _buffers[i]->buff, pioFIFOAddr, _wordsPerBuffer, false);
|
||||
}
|
||||
dma_channel_set_irq0_enabled(_channelDMA[i], true);
|
||||
__channelMap[_channelDMA[i]] = this;
|
||||
__channelCount++;
|
||||
}
|
||||
if (needSetIRQ) {
|
||||
irq_add_shared_handler(DMA_IRQ_0, _irq, PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY);
|
||||
irq_set_enabled(DMA_IRQ_0, true);
|
||||
}
|
||||
_curBuffer = 0;
|
||||
_nextBuffer = 2 % _bufferCount;
|
||||
dma_channel_start(_channelDMA[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AudioRingBuffer::write(uint32_t v, bool sync) {
|
||||
if (!_running || !_isOutput) {
|
||||
return false;
|
||||
}
|
||||
if (_userBuffer == -1) {
|
||||
// First write or overflow, pick spot 2 buffers out
|
||||
_userBuffer = (_nextBuffer + 2) % _bufferCount;
|
||||
_userOff = 0;
|
||||
}
|
||||
if (!_buffers[_userBuffer]->empty) {
|
||||
if (!sync) {
|
||||
return false;
|
||||
} else {
|
||||
while (!_buffers[_userBuffer]->empty) {
|
||||
/* noop busy wait */
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_userBuffer == _curBuffer) {
|
||||
if (!sync) {
|
||||
return false;
|
||||
} else {
|
||||
while (_userBuffer == _curBuffer) {
|
||||
/* noop busy wait */
|
||||
}
|
||||
}
|
||||
}
|
||||
_buffers[_userBuffer]->buff[_userOff++] = v;
|
||||
if (_userOff == _wordsPerBuffer) {
|
||||
_buffers[_userBuffer]->empty = false;
|
||||
_userBuffer = (_userBuffer + 1) % _bufferCount;
|
||||
_userOff = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AudioRingBuffer::read(uint32_t *v, bool sync) {
|
||||
if (!_running || _isOutput) {
|
||||
return false;
|
||||
}
|
||||
if (_userBuffer == -1) {
|
||||
// First write or overflow, pick last filled buffer
|
||||
_userBuffer = (_curBuffer - 1 + _bufferCount) % _bufferCount;
|
||||
_userOff = 0;
|
||||
}
|
||||
if (_buffers[_userBuffer]->empty) {
|
||||
if (!sync) {
|
||||
return false;
|
||||
} else {
|
||||
while (_buffers[_userBuffer]->empty) {
|
||||
/* noop busy wait */
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_userBuffer == _curBuffer) {
|
||||
if (!sync) {
|
||||
return false;
|
||||
} else {
|
||||
while (_userBuffer == _curBuffer) {
|
||||
/* noop busy wait */
|
||||
}
|
||||
}
|
||||
}
|
||||
auto ret = _buffers[_userBuffer]->buff[_userOff++];
|
||||
if (_userOff == _wordsPerBuffer) {
|
||||
_buffers[_userBuffer]->empty = true;
|
||||
_userBuffer = (_userBuffer + 1) % _bufferCount;
|
||||
_userOff = 0;
|
||||
}
|
||||
*v = ret;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AudioRingBuffer::getOverUnderflow() {
|
||||
bool hold = _overunderflow;
|
||||
_overunderflow = false;
|
||||
return hold;
|
||||
}
|
||||
|
||||
int AudioRingBuffer::available() {
|
||||
if (!_running) {
|
||||
return 0;
|
||||
}
|
||||
int avail;
|
||||
avail = _wordsPerBuffer - _userOff;
|
||||
avail += ((_bufferCount + _curBuffer - _userBuffer) % _bufferCount) * _wordsPerBuffer;
|
||||
return avail;
|
||||
}
|
||||
|
||||
void AudioRingBuffer::flush() {
|
||||
while (_curBuffer != _userBuffer) {
|
||||
// busy wait
|
||||
}
|
||||
}
|
||||
|
||||
void __not_in_flash_func(AudioRingBuffer::_dmaIRQ)(int channel) {
|
||||
if (_isOutput) {
|
||||
for (uint32_t x = 0; x < _wordsPerBuffer; x++) {
|
||||
_buffers[_curBuffer]->buff[x] = _silenceSample;
|
||||
}
|
||||
_buffers[_curBuffer]-> empty = true;
|
||||
_overunderflow = _overunderflow | _buffers[_nextBuffer]->empty;
|
||||
dma_channel_set_read_addr(channel, _buffers[_nextBuffer]->buff, false);
|
||||
} else {
|
||||
_buffers[_curBuffer]-> empty = false;
|
||||
_overunderflow = _overunderflow | !_buffers[_nextBuffer]->empty;
|
||||
dma_channel_set_write_addr(channel, _buffers[_nextBuffer]->buff, false);
|
||||
}
|
||||
dma_channel_set_trans_count(channel, _wordsPerBuffer, false);
|
||||
_curBuffer = (_curBuffer + 1) % _bufferCount;
|
||||
_nextBuffer = (_nextBuffer + 1) % _bufferCount;
|
||||
dma_channel_acknowledge_irq0(channel);
|
||||
if (_callback) {
|
||||
_callback();
|
||||
}
|
||||
}
|
||||
|
||||
void __not_in_flash_func(AudioRingBuffer::_irq)() {
|
||||
for (size_t i = 0; i < sizeof(__channelMap); i++) {
|
||||
if (dma_channel_get_irq0_status(i) && __channelMap[i]) {
|
||||
__channelMap[i]->_dmaIRQ(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
AudioRingBuffer for Rasperry Pi Pico
|
||||
Implements a ring buffer for PIO DMA for I2S read or write
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <Arduino.h>
|
||||
#include <vector>
|
||||
|
||||
class AudioRingBuffer {
|
||||
public:
|
||||
AudioRingBuffer(size_t bufferCount, size_t bufferWords, int32_t silenceSample, PinMode direction = OUTPUT);
|
||||
~AudioRingBuffer();
|
||||
|
||||
void setCallback(void (*fn)());
|
||||
|
||||
bool begin(int dreq, volatile void *pioFIFOAddr);
|
||||
|
||||
bool write(uint32_t v, bool sync = true);
|
||||
bool read(uint32_t *v, bool sync = true);
|
||||
void flush();
|
||||
|
||||
bool getOverUnderflow();
|
||||
int available();
|
||||
|
||||
private:
|
||||
void _dmaIRQ(int channel);
|
||||
static void _irq();
|
||||
|
||||
typedef struct {
|
||||
uint32_t *buff;
|
||||
volatile bool empty;
|
||||
} AudioBuffer;
|
||||
|
||||
bool _running = false;
|
||||
std::vector<AudioBuffer*> _buffers;
|
||||
volatile int _curBuffer;
|
||||
volatile int _nextBuffer;
|
||||
size_t _chunkSampleCount;
|
||||
int _bitsPerSample;
|
||||
size_t _wordsPerBuffer;
|
||||
size_t _bufferCount;
|
||||
bool _isOutput;
|
||||
int32_t _silenceSample;
|
||||
int _channelDMA[2];
|
||||
void (*_callback)();
|
||||
|
||||
bool _overunderflow;
|
||||
|
||||
// User buffer pointer
|
||||
int _userBuffer = -1;
|
||||
size_t _userOff = 0;
|
||||
};
|
||||
+280
-156
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
I2S Master library for the Raspberry Pi Pico RP2040
|
||||
I2SIn and I2SOut for Raspberry Pi Pico
|
||||
Implements one or more I2S interfaces using DMA
|
||||
|
||||
Copyright (c) 2021 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
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
|
||||
@@ -17,30 +18,30 @@
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "I2S.h"
|
||||
#include "pio_i2s.pio.h"
|
||||
|
||||
#ifdef USE_TINYUSB
|
||||
// For Serial when selecting TinyUSB. Can't include in the core because Arduino IDE
|
||||
// will not link in libraries called from the core. Instead, add the header to all
|
||||
// the standard libraries in the hope it will still catch some user cases where they
|
||||
// use these libraries.
|
||||
// See https://github.com/earlephilhower/arduino-pico/issues/167#issuecomment-848622174
|
||||
#include <Adafruit_TinyUSB.h>
|
||||
#endif
|
||||
|
||||
I2SClass::I2SClass() {
|
||||
I2S::I2S(PinMode direction) {
|
||||
_running = false;
|
||||
_pool = nullptr;
|
||||
_curBuff = nullptr;
|
||||
_bps = 0;
|
||||
_bps = 16;
|
||||
_writtenHalf = false;
|
||||
_pinBCLK = 26;
|
||||
_pinDOUT = 28;
|
||||
_freq = 48000;
|
||||
_arb = nullptr;
|
||||
_isOutput = direction == OUTPUT;
|
||||
_cb = nullptr;
|
||||
_buffers = 8;
|
||||
_bufferWords = 16;
|
||||
_silenceSample = 0;
|
||||
}
|
||||
|
||||
bool I2SClass::setBCLK(pin_size_t pin) {
|
||||
I2S::~I2S() {
|
||||
}
|
||||
|
||||
bool I2S::setBCLK(pin_size_t pin) {
|
||||
if (_running || (pin > 28)) {
|
||||
return false;
|
||||
}
|
||||
@@ -48,7 +49,7 @@ bool I2SClass::setBCLK(pin_size_t pin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool I2SClass::setDOUT(pin_size_t pin) {
|
||||
bool I2S::setDATA(pin_size_t pin) {
|
||||
if (_running || (pin > 29)) {
|
||||
return false;
|
||||
}
|
||||
@@ -56,173 +57,296 @@ bool I2SClass::setDOUT(pin_size_t pin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool I2SClass::begin(long sampleRate) {
|
||||
bool I2S::setBitsPerSample(int bps) {
|
||||
if (_running || ((bps != 8) && (bps != 16) && (bps != 24) && (bps != 32))) {
|
||||
return false;
|
||||
}
|
||||
_bps = bps;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool I2S::setBuffers(size_t buffers, size_t bufferWords, int32_t silenceSample) {
|
||||
if (_running || (buffers < 3) || (bufferWords < 8)) {
|
||||
return false;
|
||||
}
|
||||
_buffers = buffers;
|
||||
_bufferWords = bufferWords;
|
||||
_silenceSample = silenceSample;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool I2S::setFrequency(int newFreq) {
|
||||
_freq = newFreq;
|
||||
if (_running) {
|
||||
return false;
|
||||
float bitClk = _freq * _bps * 2.0;
|
||||
pio_sm_set_clkdiv(_pio, _sm, (float)clock_get_hz(clk_sys) / bitClk);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bzero(&_audio_format, sizeof(_audio_format));
|
||||
_audio_format.sample_freq = (uint32_t)sampleRate;
|
||||
_audio_format.format = AUDIO_BUFFER_FORMAT_PCM_S16;
|
||||
_audio_format.channel_count = 2;
|
||||
|
||||
bzero(&_producer_format, sizeof(_producer_format));
|
||||
_producer_format.format = &_audio_format;
|
||||
_producer_format.sample_stride = 4;
|
||||
|
||||
if (!_pool) {
|
||||
_pool = audio_new_producer_pool(&_producer_format, 3, 256);
|
||||
void I2S::onTransmit(void(*fn)(void)) {
|
||||
if (_isOutput) {
|
||||
_cb = fn;
|
||||
if (_running) {
|
||||
_arb->setCallback(_cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bzero(&_config, sizeof(_config));
|
||||
_config.data_pin = _pinDOUT;
|
||||
_config.clock_pin_base = _pinBCLK;
|
||||
_config.dma_channel = 0;
|
||||
_config.pio_sm = 1;
|
||||
|
||||
if (!audio_i2s_setup(&_audio_format, &_config)) {
|
||||
return false;
|
||||
void I2S::onReceive(void(*fn)(void)) {
|
||||
if (!_isOutput) {
|
||||
_cb = fn;
|
||||
if (_running) {
|
||||
_arb->setCallback(_cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!audio_i2s_connect(_pool)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
audio_i2s_set_enabled(true);
|
||||
|
||||
_curBuff = take_audio_buffer(_pool, true);
|
||||
_curBuff->sample_count = 0;
|
||||
|
||||
_bps = 16;
|
||||
_freq = sampleRate;
|
||||
bool I2S::begin() {
|
||||
_running = true;
|
||||
_hasPeeked = false;
|
||||
int off = 0;
|
||||
_i2s = new PIOProgram(_isOutput ? &pio_i2s_out_program : &pio_i2s_in_program);
|
||||
_i2s->prepare(&_pio, &_sm, &off);
|
||||
if (_isOutput) {
|
||||
pio_i2s_out_program_init(_pio, _sm, off, _pinDOUT, _pinBCLK, _bps);
|
||||
} else {
|
||||
pio_i2s_in_program_init(_pio, _sm, off, _pinDOUT, _pinBCLK, _bps);
|
||||
}
|
||||
setFrequency(_freq);
|
||||
if (_bps == 8) {
|
||||
uint8_t a = _silenceSample & 0xff;
|
||||
_silenceSample = (a << 24) | (a << 16) | (a << 8) | a;
|
||||
} else if (_bps == 16) {
|
||||
uint16_t a = _silenceSample & 0xffff;
|
||||
_silenceSample = (a << 16) | a;
|
||||
}
|
||||
_arb = new AudioRingBuffer(_buffers, _bufferWords, _silenceSample, _isOutput ? OUTPUT : INPUT);
|
||||
_arb->begin(pio_get_dreq(_pio, _sm, _isOutput), _isOutput ? &_pio->txf[_sm] : (volatile void*)&_pio->rxf[_sm]);
|
||||
_arb->setCallback(_cb);
|
||||
pio_sm_set_enabled(_pio, _sm, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void I2SClass::end() {
|
||||
if (_running) {
|
||||
audio_i2s_set_enabled(false);
|
||||
if (_curBuff) {
|
||||
release_audio_buffer(_pool, _curBuff);
|
||||
_curBuff = nullptr;
|
||||
}
|
||||
}
|
||||
void I2S::end() {
|
||||
_running = false;
|
||||
_bps = 0;
|
||||
_freq = 0;
|
||||
_writtenHalf = false;
|
||||
delete _arb;
|
||||
_arb = nullptr;
|
||||
delete _i2s;
|
||||
_i2s = nullptr;
|
||||
}
|
||||
|
||||
int I2SClass::availableForWrite() {
|
||||
if (!_running) {
|
||||
int I2S::available() {
|
||||
if (!_running || _isOutput) {
|
||||
return 0;
|
||||
}
|
||||
// Can we get a whole new buffer to work with?
|
||||
if (!_curBuff) {
|
||||
_curBuff = take_audio_buffer(_pool, false);
|
||||
_curBuff->sample_count = 0;
|
||||
}
|
||||
if (!_curBuff) {
|
||||
return false;
|
||||
}
|
||||
return _curBuff->max_sample_count - _curBuff->sample_count;
|
||||
return _arb->available();
|
||||
}
|
||||
|
||||
void I2SClass::flush() {
|
||||
if (!_curBuff || !_curBuff->sample_count) {
|
||||
return;
|
||||
}
|
||||
_audio_format.sample_freq = _freq;
|
||||
give_audio_buffer(_pool, _curBuff);
|
||||
_curBuff = nullptr;
|
||||
}
|
||||
|
||||
bool I2SClass::setFrequency(int newFreq) {
|
||||
if (newFreq != _freq) {
|
||||
flush();
|
||||
_freq = newFreq;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t I2SClass::write(uint8_t s) {
|
||||
return write((int16_t)s);
|
||||
}
|
||||
|
||||
size_t I2SClass::write(const uint8_t *buffer, size_t size) {
|
||||
return write((const void *)buffer, size);
|
||||
}
|
||||
|
||||
size_t I2SClass::write(int16_t s) {
|
||||
if (!_running) {
|
||||
int I2S::read() {
|
||||
if (!_running || _isOutput) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Because our HW really wants 32b writes, store any 16b writes until another
|
||||
// 16b write comes in and then send the combined write down.
|
||||
if (_bps == 16) {
|
||||
if (_writtenHalf) {
|
||||
_writtenData <<= 16;
|
||||
_writtenData |= 0xffff & s;
|
||||
_writtenHalf = false;
|
||||
if (!_curBuff) {
|
||||
_curBuff = take_audio_buffer(_pool, true);
|
||||
_curBuff->sample_count = 0;
|
||||
}
|
||||
int32_t *samples = (int32_t *)_curBuff->buffer->bytes;
|
||||
samples[_curBuff->sample_count++] = _writtenData;
|
||||
if (_curBuff->sample_count == _curBuff->max_sample_count) {
|
||||
_audio_format.sample_freq = _freq;
|
||||
give_audio_buffer(_pool, _curBuff);
|
||||
_curBuff = nullptr;
|
||||
}
|
||||
if (_hasPeeked) {
|
||||
_hasPeeked = false;
|
||||
return _peekSaved;
|
||||
}
|
||||
|
||||
if (_wasHolding <= 0) {
|
||||
read(&_holdWord, true);
|
||||
_wasHolding = 32;
|
||||
}
|
||||
|
||||
int ret;
|
||||
switch (_bps) {
|
||||
case 8:
|
||||
ret = _holdWord >> 24;
|
||||
_holdWord <<= 8;
|
||||
_wasHolding -= 8;
|
||||
return ret;
|
||||
case 16:
|
||||
ret = _holdWord >> 16;
|
||||
_holdWord <<= 16;
|
||||
_wasHolding -= 32;
|
||||
return ret;
|
||||
case 24:
|
||||
case 32:
|
||||
default:
|
||||
ret = _holdWord;
|
||||
_wasHolding = 0;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
int I2S::peek() {
|
||||
if (!_running || _isOutput) {
|
||||
return 0;
|
||||
}
|
||||
if (!_hasPeeked) {
|
||||
_peekSaved = read();
|
||||
_hasPeeked = true;
|
||||
}
|
||||
return _peekSaved;
|
||||
}
|
||||
|
||||
void I2S::flush() {
|
||||
if (_running) {
|
||||
_arb->flush();
|
||||
}
|
||||
}
|
||||
|
||||
size_t I2S::_writeNatural(int32_t s) {
|
||||
if (!_running || !_isOutput) {
|
||||
return 0;
|
||||
}
|
||||
switch (_bps) {
|
||||
case 8:
|
||||
_holdWord |= s & 0xff;
|
||||
if (_wasHolding >= 24) {
|
||||
auto ret = write(_holdWord, true);
|
||||
_holdWord = 0;
|
||||
_wasHolding = 0;
|
||||
return ret;
|
||||
} else {
|
||||
_writtenHalf = true;
|
||||
_writtenData = s & 0xffff;
|
||||
_holdWord <<= 8;
|
||||
_wasHolding += 8;
|
||||
return 1;
|
||||
}
|
||||
case 16:
|
||||
_holdWord |= s & 0xffff;
|
||||
if (_wasHolding) {
|
||||
auto ret = write(_holdWord, true);
|
||||
_holdWord = 0;
|
||||
_wasHolding = 0;
|
||||
return ret;
|
||||
} else {
|
||||
_holdWord <<= 16;
|
||||
_wasHolding = 16;
|
||||
return 1;
|
||||
}
|
||||
case 24:
|
||||
case 32:
|
||||
default:
|
||||
return write(s, true);
|
||||
}
|
||||
}
|
||||
|
||||
size_t I2S::write(int32_t val, bool sync) {
|
||||
if (!_running || !_isOutput) {
|
||||
return 0;
|
||||
}
|
||||
return _arb->write(val, sync);
|
||||
}
|
||||
|
||||
size_t I2S::write8(int8_t l, int8_t r) {
|
||||
if (!_running || !_isOutput) {
|
||||
return 0;
|
||||
}
|
||||
int16_t o = (l << 8) | (r & 0xff);
|
||||
return write((int16_t) o);
|
||||
}
|
||||
|
||||
size_t I2S::write16(int16_t l, int16_t r) {
|
||||
if (!_running || !_isOutput) {
|
||||
return 0;
|
||||
}
|
||||
int32_t o = (l << 16) | (r & 0xffff);
|
||||
return write((int32_t)o, true);
|
||||
}
|
||||
|
||||
size_t I2S::write24(int32_t l, int32_t r) {
|
||||
return write32(l, r);
|
||||
}
|
||||
|
||||
size_t I2S::write32(int32_t l, int32_t r) {
|
||||
if (!_running || !_isOutput) {
|
||||
return 0;
|
||||
}
|
||||
write((int32_t)l);
|
||||
write((int32_t)r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Mostly non-blocking
|
||||
size_t I2SClass::write(const void *buffer, size_t size) {
|
||||
if (!_running) {
|
||||
size_t I2S::read(int32_t *val, bool sync) {
|
||||
if (!_running || _isOutput) {
|
||||
return 0;
|
||||
}
|
||||
// We have no choice here because we need to write at least 1 byte...
|
||||
if (!_curBuff) {
|
||||
_curBuff = take_audio_buffer(_pool, true);
|
||||
_curBuff->sample_count = 0;
|
||||
}
|
||||
|
||||
int32_t *inSamples = (int32_t *)buffer;
|
||||
int written = 0;
|
||||
int wantToWrite = size / 4;
|
||||
while (wantToWrite) {
|
||||
if (!_curBuff) {
|
||||
_curBuff = take_audio_buffer(_pool, false);
|
||||
if (_curBuff) {
|
||||
_curBuff->sample_count = 0;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int avail = _curBuff->max_sample_count - _curBuff->sample_count;
|
||||
int writeSize = (avail > wantToWrite) ? wantToWrite : avail;
|
||||
int32_t *samples = (int32_t *)_curBuff->buffer->bytes;
|
||||
memcpy(samples + _curBuff->sample_count, inSamples, writeSize * 4);
|
||||
_curBuff->sample_count += writeSize;
|
||||
inSamples += writeSize;
|
||||
written += writeSize;
|
||||
wantToWrite -= writeSize;
|
||||
if (_curBuff->sample_count == _curBuff->max_sample_count) {
|
||||
_audio_format.sample_freq = _freq;
|
||||
give_audio_buffer(_pool, _curBuff);
|
||||
_curBuff = nullptr;
|
||||
}
|
||||
}
|
||||
return written;
|
||||
return _arb->read((uint32_t *)val, sync);
|
||||
}
|
||||
|
||||
I2SClass I2S;
|
||||
bool I2S::read8(int8_t *l, int8_t *r) {
|
||||
if (!_running || _isOutput) {
|
||||
return false;
|
||||
}
|
||||
if (_wasHolding) {
|
||||
*l = (_holdWord >> 8) & 0xff;
|
||||
*r = (_holdWord >> 0) & 0xff;
|
||||
_wasHolding = 0;
|
||||
} else {
|
||||
read(&_holdWord, true);
|
||||
_wasHolding = 16;
|
||||
*l = (_holdWord >> 24) & 0xff;
|
||||
*r = (_holdWord >> 16) & 0xff;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool I2S::read16(int16_t *l, int16_t *r) {
|
||||
if (!_running || _isOutput) {
|
||||
return false;
|
||||
}
|
||||
int32_t o;
|
||||
read(&o, true);
|
||||
*l = (o >> 16) & 0xffff;
|
||||
*r = (o >> 0) & 0xffff;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool I2S::read24(int32_t *l, int32_t *r) {
|
||||
if (!_running || _isOutput) {
|
||||
return false;
|
||||
}
|
||||
read32(l, r);
|
||||
// 24-bit samples are read right-aligned, so left-align them to keep the binary point between 33.32
|
||||
*l <<= 8;
|
||||
*r <<= 8;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool I2S::read32(int32_t *l, int32_t *r) {
|
||||
if (!_running || _isOutput) {
|
||||
return false;
|
||||
}
|
||||
read(l, true);
|
||||
read(r, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t I2S::write(const uint8_t *buffer, size_t size) {
|
||||
// We can only write 32-bit chunks here
|
||||
if (size & 0x3) {
|
||||
return 0;
|
||||
}
|
||||
size_t writtenSize = 0;
|
||||
int32_t *p = (int32_t *)buffer;
|
||||
while (size) {
|
||||
if (!write((int32_t)*p)) {
|
||||
// Blocked, stop write here
|
||||
return writtenSize;
|
||||
} else {
|
||||
p++;
|
||||
size -= 4;
|
||||
writtenSize += 4;
|
||||
}
|
||||
}
|
||||
return writtenSize;
|
||||
}
|
||||
|
||||
int I2S::availableForWrite() {
|
||||
if (!_running || !_isOutput) {
|
||||
return 0;
|
||||
}
|
||||
return _arb->available();
|
||||
}
|
||||
|
||||
+80
-42
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
I2S Master library for the Raspberry Pi Pico RP2040
|
||||
I2SIn and I2SOut for Raspberry Pi Pico
|
||||
Implements one or more I2S interfaces using DMA
|
||||
|
||||
Copyright (c) 2021 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
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
|
||||
@@ -19,72 +20,109 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "pico/audio_i2s.h"
|
||||
#include <vector>
|
||||
#include "AudioRingBuffer.h"
|
||||
|
||||
class I2SClass : public Stream {
|
||||
class I2S : public Stream {
|
||||
public:
|
||||
I2SClass();
|
||||
I2S(PinMode direction = OUTPUT);
|
||||
virtual ~I2S();
|
||||
|
||||
// Only 16 bitsPerSample are allowed by the PIO code. Only write, no read.
|
||||
bool setBCLK(pin_size_t pin);
|
||||
bool setDOUT(pin_size_t pin);
|
||||
bool begin(long sampleRate);
|
||||
bool setDATA(pin_size_t pin);
|
||||
bool setBitsPerSample(int bps);
|
||||
bool setBuffers(size_t buffers, size_t bufferWords, int32_t silenceSample = 0);
|
||||
bool setFrequency(int newFreq);
|
||||
|
||||
bool begin(long sampleRate) {
|
||||
setFrequency(sampleRate);
|
||||
return begin();
|
||||
}
|
||||
|
||||
bool begin();
|
||||
void end();
|
||||
|
||||
// from Stream
|
||||
virtual int available() override {
|
||||
return -1;
|
||||
}
|
||||
virtual int read() override {
|
||||
return -1;
|
||||
}
|
||||
virtual int peek() override {
|
||||
return -1;
|
||||
}
|
||||
virtual int available() override;
|
||||
virtual int read() override;
|
||||
virtual int peek() override;
|
||||
virtual void flush() override;
|
||||
|
||||
// from Print (see notes on write() methods below)
|
||||
virtual size_t write(uint8_t) override;
|
||||
virtual size_t write(const uint8_t *buffer, size_t size) override;
|
||||
virtual int availableForWrite() override;
|
||||
|
||||
bool setFrequency(int newFreq);
|
||||
// Try and make I2S::write() do what makes sense, namely write
|
||||
// one sample (L or R) at the I2S configured bit width
|
||||
virtual size_t write(uint8_t s) override {
|
||||
return _writeNatural(s & 0xff);
|
||||
}
|
||||
size_t write(int8_t s) {
|
||||
return write((uint8_t)s);
|
||||
}
|
||||
size_t write(uint16_t s) {
|
||||
return _writeNatural(s & 0xffff);
|
||||
}
|
||||
size_t write(int16_t s) {
|
||||
return write((uint16_t)s);
|
||||
}
|
||||
size_t write(uint32_t s) {
|
||||
return _writeNatural(s);
|
||||
}
|
||||
size_t write(int32_t s) {
|
||||
return write((uint32_t)s);
|
||||
}
|
||||
|
||||
// Write a single L:R sample to the I2S device. Blocking until write succeeds
|
||||
size_t write(int16_t);
|
||||
// Write up to size samples to the I2S device. Non-blocking, will write
|
||||
// from 0...size samples and return that count. Be sure your app handles
|
||||
// partial writes (i.e. by yield()ing and then retrying to write the
|
||||
// remaining data.
|
||||
size_t write(const void *buffer, size_t lrsamples);
|
||||
// Write 32 bit value to port, user responsbile for packing/alignment, etc.
|
||||
size_t write(int32_t val, bool sync);
|
||||
|
||||
// Write sample to I2S port, will block until completed
|
||||
size_t write8(int8_t l, int8_t r);
|
||||
size_t write16(int16_t l, int16_t r);
|
||||
size_t write24(int32_t l, int32_t r); // Note that 24b must have values left-aligned (i.e. 0xABCDEF00)
|
||||
size_t write32(int32_t l, int32_t r);
|
||||
|
||||
// Read 32 bit value to port, user responsbile for packing/alignment, etc.
|
||||
size_t read(int32_t *val, bool sync);
|
||||
|
||||
// Read samples from I2S port, will block until data available
|
||||
bool read8(int8_t *l, int8_t *r);
|
||||
bool read16(int16_t *l, int16_t *r);
|
||||
bool read24(int32_t *l, int32_t *r); // Note that 24b reads will be left-aligned (see above)
|
||||
bool read32(int32_t *l, int32_t *r);
|
||||
|
||||
// Note that these callback are called from **INTERRUPT CONTEXT** and hence
|
||||
// must be both stored in IRAM and not perform anything that's not legal in
|
||||
// an interrupt
|
||||
//void onTransmit(void(*)(void)); -- Not yet implemented, need to edit pico-extra to get callback
|
||||
//void onReceive(void(*)(void)); -- no I2S input yet
|
||||
// should be in RAM, not FLASH, and should be quick to execute.
|
||||
void onTransmit(void(*)(void));
|
||||
void onReceive(void(*)(void));
|
||||
|
||||
private:
|
||||
pin_size_t _pinBCLK;
|
||||
pin_size_t _pinDOUT;
|
||||
int _bps;
|
||||
int _freq;
|
||||
size_t _buffers;
|
||||
size_t _bufferWords;
|
||||
int32_t _silenceSample;
|
||||
bool _isOutput;
|
||||
|
||||
bool _running;
|
||||
|
||||
// Audio format/pool config
|
||||
audio_format_t _audio_format;
|
||||
audio_buffer_format_t _producer_format;
|
||||
audio_i2s_config_t _config;
|
||||
bool _hasPeeked;
|
||||
int32_t _peekSaved;
|
||||
|
||||
// We manage our own buffer pool here...
|
||||
audio_buffer_pool_t *_pool;
|
||||
audio_buffer_t *_curBuff;
|
||||
|
||||
// Support for ::write(x) on 16b quantities
|
||||
size_t _writeNatural(int32_t s);
|
||||
uint32_t _writtenData;
|
||||
bool _writtenHalf;
|
||||
};
|
||||
|
||||
extern I2SClass I2S;
|
||||
int32_t _holdWord = 0;
|
||||
int _wasHolding = 0;
|
||||
|
||||
void (*_cb)();
|
||||
|
||||
AudioRingBuffer *_arb;
|
||||
PIOProgram *_i2s;
|
||||
PIO _pio;
|
||||
int _sm;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
; pio_i2s for the Raspberry Pi Pico RP2040
|
||||
;
|
||||
; Based loosely off of the MicroPython I2S code in
|
||||
; https://github.com/micropython/micropython/blob/master/ports/rp2/machine_i2s.c
|
||||
;
|
||||
; 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
|
||||
|
||||
|
||||
.program pio_i2s_out
|
||||
.side_set 2 ; 0 = bclk, 1=wclk
|
||||
|
||||
; The C code should place (number of bits/sample - 2) in Y and
|
||||
; also update the SHIFTCTRL to be 24 or 32 as appropriate
|
||||
|
||||
; +----- WCLK
|
||||
; |+---- BCLK
|
||||
mov x, y side 0b01
|
||||
left:
|
||||
out pins, 1 side 0b00
|
||||
jmp x--, left side 0b01
|
||||
out pins, 1 side 0b10 ; Last bit of left has WCLK change per I2S spec
|
||||
|
||||
mov x, y side 0b11
|
||||
right:
|
||||
out pins, 1 side 0b10
|
||||
jmp x--, right side 0b11
|
||||
out pins, 1 side 0b00 ; Last bit of right also has WCLK change
|
||||
; Loop back to beginning...
|
||||
|
||||
|
||||
.program pio_i2s_in ; Note this is the same as _out, just "in" and not "out"
|
||||
.side_set 2 ; 0 = bclk, 1=wclk
|
||||
|
||||
; The C code should place (number of bits/sample - 2) in Y and
|
||||
; also update the SHIFTCTRL to be 24 or 32 as appropriate
|
||||
|
||||
; +----- WCLK
|
||||
; |+---- BCLK
|
||||
mov x, y side 0b00
|
||||
left:
|
||||
in pins, 1 side 0b01
|
||||
jmp x--, left side 0b00
|
||||
in pins, 1 side 0b11 ; Last bit of left has WCLK change per I2S spec
|
||||
|
||||
mov x, y side 0b10
|
||||
right:
|
||||
in pins, 1 side 0b11
|
||||
jmp x--, right side 0b10
|
||||
in pins, 1 side 0b01 ; Last bit of right also has WCLK change
|
||||
; Loop back to beginning...
|
||||
|
||||
|
||||
|
||||
% c-sdk {
|
||||
|
||||
static inline void pio_i2s_out_program_init(PIO pio, uint sm, uint offset, uint data_pin, uint clock_pin_base, uint bits) {
|
||||
pio_gpio_init(pio, data_pin);
|
||||
pio_gpio_init(pio, clock_pin_base);
|
||||
pio_gpio_init(pio, clock_pin_base + 1);
|
||||
|
||||
pio_sm_config sm_config = pio_i2s_out_program_get_default_config(offset);
|
||||
|
||||
sm_config_set_out_pins(&sm_config, data_pin, 1);
|
||||
sm_config_set_sideset_pins(&sm_config, clock_pin_base);
|
||||
sm_config_set_out_shift(&sm_config, false, true, (bits <= 16) ? 2 * bits : bits);
|
||||
sm_config_set_fifo_join(&sm_config, PIO_FIFO_JOIN_TX);
|
||||
|
||||
pio_sm_init(pio, sm, offset, &sm_config);
|
||||
|
||||
uint pin_mask = (1u << data_pin) | (3u << clock_pin_base);
|
||||
pio_sm_set_pindirs_with_mask(pio, sm, pin_mask, pin_mask);
|
||||
pio_sm_set_pins(pio, sm, 0); // clear pins
|
||||
|
||||
pio_sm_exec(pio, sm, pio_encode_set(pio_y, bits - 2));
|
||||
}
|
||||
|
||||
static inline void pio_i2s_in_program_init(PIO pio, uint sm, uint offset, uint data_pin, uint clock_pin_base, uint bits) {
|
||||
pio_gpio_init(pio, data_pin);
|
||||
pio_gpio_init(pio, clock_pin_base);
|
||||
pio_gpio_init(pio, clock_pin_base + 1);
|
||||
|
||||
pio_sm_config sm_config = pio_i2s_in_program_get_default_config(offset);
|
||||
|
||||
sm_config_set_in_pins(&sm_config, data_pin);
|
||||
sm_config_set_sideset_pins(&sm_config, clock_pin_base);
|
||||
sm_config_set_in_shift(&sm_config, false, true, (bits <= 16) ? 2 * bits : bits);
|
||||
sm_config_set_fifo_join(&sm_config, PIO_FIFO_JOIN_RX);
|
||||
|
||||
pio_sm_init(pio, sm, offset, &sm_config);
|
||||
|
||||
uint pin_mask = 3u << clock_pin_base;
|
||||
pio_sm_set_pindirs_with_mask(pio, sm, pin_mask, pin_mask);
|
||||
pio_sm_set_pins(pio, sm, 0); // clear pins
|
||||
|
||||
pio_sm_exec(pio, sm, pio_encode_set(pio_y, bits - 2));
|
||||
}
|
||||
|
||||
%}
|
||||
@@ -0,0 +1,112 @@
|
||||
// -------------------------------------------------- //
|
||||
// This file is autogenerated by pioasm; do not edit! //
|
||||
// -------------------------------------------------- //
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !PICO_NO_HARDWARE
|
||||
#include "hardware/pio.h"
|
||||
#endif
|
||||
|
||||
// ----------- //
|
||||
// pio_i2s_out //
|
||||
// ----------- //
|
||||
|
||||
#define pio_i2s_out_wrap_target 0
|
||||
#define pio_i2s_out_wrap 7
|
||||
|
||||
static const uint16_t pio_i2s_out_program_instructions[] = {
|
||||
// .wrap_target
|
||||
0xa822, // 0: mov x, y side 1
|
||||
0x6001, // 1: out pins, 1 side 0
|
||||
0x0841, // 2: jmp x--, 1 side 1
|
||||
0x7001, // 3: out pins, 1 side 2
|
||||
0xb822, // 4: mov x, y side 3
|
||||
0x7001, // 5: out pins, 1 side 2
|
||||
0x1845, // 6: jmp x--, 5 side 3
|
||||
0x6001, // 7: out pins, 1 side 0
|
||||
// .wrap
|
||||
};
|
||||
|
||||
#if !PICO_NO_HARDWARE
|
||||
static const struct pio_program pio_i2s_out_program = {
|
||||
.instructions = pio_i2s_out_program_instructions,
|
||||
.length = 8,
|
||||
.origin = -1,
|
||||
};
|
||||
|
||||
static inline pio_sm_config pio_i2s_out_program_get_default_config(uint offset) {
|
||||
pio_sm_config c = pio_get_default_sm_config();
|
||||
sm_config_set_wrap(&c, offset + pio_i2s_out_wrap_target, offset + pio_i2s_out_wrap);
|
||||
sm_config_set_sideset(&c, 2, false, false);
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
|
||||
// ---------- //
|
||||
// pio_i2s_in //
|
||||
// ---------- //
|
||||
|
||||
#define pio_i2s_in_wrap_target 0
|
||||
#define pio_i2s_in_wrap 7
|
||||
|
||||
static const uint16_t pio_i2s_in_program_instructions[] = {
|
||||
// .wrap_target
|
||||
0xa022, // 0: mov x, y side 0
|
||||
0x4801, // 1: in pins, 1 side 1
|
||||
0x0041, // 2: jmp x--, 1 side 0
|
||||
0x5801, // 3: in pins, 1 side 3
|
||||
0xb022, // 4: mov x, y side 2
|
||||
0x5801, // 5: in pins, 1 side 3
|
||||
0x1045, // 6: jmp x--, 5 side 2
|
||||
0x4801, // 7: in pins, 1 side 1
|
||||
// .wrap
|
||||
};
|
||||
|
||||
#if !PICO_NO_HARDWARE
|
||||
static const struct pio_program pio_i2s_in_program = {
|
||||
.instructions = pio_i2s_in_program_instructions,
|
||||
.length = 8,
|
||||
.origin = -1,
|
||||
};
|
||||
|
||||
static inline pio_sm_config pio_i2s_in_program_get_default_config(uint offset) {
|
||||
pio_sm_config c = pio_get_default_sm_config();
|
||||
sm_config_set_wrap(&c, offset + pio_i2s_in_wrap_target, offset + pio_i2s_in_wrap);
|
||||
sm_config_set_sideset(&c, 2, false, false);
|
||||
return c;
|
||||
}
|
||||
|
||||
static inline void pio_i2s_out_program_init(PIO pio, uint sm, uint offset, uint data_pin, uint clock_pin_base, uint bits) {
|
||||
pio_gpio_init(pio, data_pin);
|
||||
pio_gpio_init(pio, clock_pin_base);
|
||||
pio_gpio_init(pio, clock_pin_base + 1);
|
||||
pio_sm_config sm_config = pio_i2s_out_program_get_default_config(offset);
|
||||
sm_config_set_out_pins(&sm_config, data_pin, 1);
|
||||
sm_config_set_sideset_pins(&sm_config, clock_pin_base);
|
||||
sm_config_set_out_shift(&sm_config, false, true, (bits <= 16) ? 2 * bits : bits);
|
||||
sm_config_set_fifo_join(&sm_config, PIO_FIFO_JOIN_TX);
|
||||
pio_sm_init(pio, sm, offset, &sm_config);
|
||||
uint pin_mask = (1u << data_pin) | (3u << clock_pin_base);
|
||||
pio_sm_set_pindirs_with_mask(pio, sm, pin_mask, pin_mask);
|
||||
pio_sm_set_pins(pio, sm, 0); // clear pins
|
||||
pio_sm_exec(pio, sm, pio_encode_set(pio_y, bits - 2));
|
||||
}
|
||||
static inline void pio_i2s_in_program_init(PIO pio, uint sm, uint offset, uint data_pin, uint clock_pin_base, uint bits) {
|
||||
pio_gpio_init(pio, data_pin);
|
||||
pio_gpio_init(pio, clock_pin_base);
|
||||
pio_gpio_init(pio, clock_pin_base + 1);
|
||||
pio_sm_config sm_config = pio_i2s_in_program_get_default_config(offset);
|
||||
sm_config_set_in_pins(&sm_config, data_pin);
|
||||
sm_config_set_sideset_pins(&sm_config, clock_pin_base);
|
||||
sm_config_set_in_shift(&sm_config, false, true, (bits <= 16) ? 2 * bits : bits);
|
||||
sm_config_set_fifo_join(&sm_config, PIO_FIFO_JOIN_RX);
|
||||
pio_sm_init(pio, sm, offset, &sm_config);
|
||||
uint pin_mask = 3u << clock_pin_base;
|
||||
pio_sm_set_pindirs_with_mask(pio, sm, pin_mask, pin_mask);
|
||||
pio_sm_set_pins(pio, sm, 0); // clear pins
|
||||
pio_sm_exec(pio, sm, pio_encode_set(pio_y, bits - 2));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Submodule libraries/LittleFS/lib/littlefs updated: ead50807f1...40dba4a556
@@ -307,5 +307,12 @@ void SPIClassRP2040::setClockDivider(uint8_t uc_div) {
|
||||
(void) uc_div; // no-op
|
||||
}
|
||||
|
||||
SPIClassRP2040 SPI(spi0, PIN_SPI0_MISO, PIN_SPI0_SS, PIN_SPI0_SCK, PIN_SPI0_MOSI);
|
||||
SPIClassRP2040 SPI1(spi1, PIN_SPI1_MISO, PIN_SPI1_SS, PIN_SPI1_SCK, PIN_SPI1_MOSI);
|
||||
#ifndef __SPI0_DEVICE
|
||||
#define __SPI0_DEVICE spi0
|
||||
#endif
|
||||
#ifndef __SPI1_DEVICE
|
||||
#define __SPI1_DEVICE spi1
|
||||
#endif
|
||||
|
||||
SPIClassRP2040 SPI(__SPI0_DEVICE, PIN_SPI0_MISO, PIN_SPI0_SS, PIN_SPI0_SCK, PIN_SPI0_MOSI);
|
||||
SPIClassRP2040 SPI1(__SPI1_DEVICE, PIN_SPI1_MISO, PIN_SPI1_SS, PIN_SPI1_SCK, PIN_SPI1_MOSI);
|
||||
@@ -126,13 +126,12 @@ void TwoWire::begin(uint8_t addr) {
|
||||
i2c_set_slave_mode(_i2c, true, addr);
|
||||
|
||||
// Our callback IRQ
|
||||
_i2c->hw->intr_mask = (1 << 10) | (1 << 9) | (1 << 6) | (1 << 5) | (1 << 2);
|
||||
_i2c->hw->intr_mask = (1 << 12) | (1 << 10) | (1 << 9) | (1 << 6) | (1 << 5) | (1 << 2);
|
||||
|
||||
int irqNo = I2C0_IRQ + i2c_hw_index(_i2c);
|
||||
irq_set_exclusive_handler(irqNo, i2c_hw_index(_i2c) == 0 ? _handler0 : _handler1);
|
||||
irq_set_enabled(irqNo, true);
|
||||
|
||||
|
||||
gpio_set_function(_sda, GPIO_FUNC_I2C);
|
||||
gpio_pull_up(_sda);
|
||||
gpio_set_function(_scl, GPIO_FUNC_I2C);
|
||||
@@ -142,6 +141,15 @@ void TwoWire::begin(uint8_t addr) {
|
||||
}
|
||||
|
||||
void TwoWire::onIRQ() {
|
||||
if (_i2c->hw->intr_stat & (1 << 12)) {
|
||||
if (_onReceiveCallback && _buffLen) {
|
||||
_onReceiveCallback(_buffLen);
|
||||
}
|
||||
_buffLen = 0;
|
||||
_buffOff = 0;
|
||||
_slaveStartDet = false;
|
||||
_i2c->hw->clr_restart_det;
|
||||
}
|
||||
if (_i2c->hw->intr_stat & (1 << 10)) {
|
||||
_buffLen = 0;
|
||||
_buffOff = 0;
|
||||
@@ -183,7 +191,15 @@ void TwoWire::end() {
|
||||
// ERROR
|
||||
return;
|
||||
}
|
||||
|
||||
if (_slave) {
|
||||
int irqNo = I2C0_IRQ + i2c_hw_index(_i2c);
|
||||
irq_remove_handler(irqNo, i2c_hw_index(_i2c) == 0 ? _handler0 : _handler1);
|
||||
irq_set_enabled(irqNo, false);
|
||||
}
|
||||
|
||||
i2c_deinit(_i2c);
|
||||
|
||||
pinMode(_sda, INPUT);
|
||||
pinMode(_scl, INPUT);
|
||||
_running = false;
|
||||
@@ -207,7 +223,7 @@ size_t TwoWire::requestFrom(uint8_t address, size_t quantity, bool stopBit) {
|
||||
}
|
||||
|
||||
_buffLen = i2c_read_blocking_until(_i2c, address, _buff, quantity, !stopBit, make_timeout_time_ms(_timeout));
|
||||
if (_buffLen == PICO_ERROR_GENERIC) {
|
||||
if ((_buffLen == PICO_ERROR_GENERIC) || (_buffLen == PICO_ERROR_TIMEOUT)) {
|
||||
_buffLen = 0;
|
||||
}
|
||||
_buffOff = 0;
|
||||
@@ -368,5 +384,12 @@ void TwoWire::onRequest(void(*function)(void)) {
|
||||
_onRequestCallback = function;
|
||||
}
|
||||
|
||||
TwoWire Wire(i2c0, PIN_WIRE0_SDA, PIN_WIRE0_SCL);
|
||||
TwoWire Wire1(i2c1, PIN_WIRE1_SDA, PIN_WIRE1_SCL);
|
||||
#ifndef __WIRE0_DEVICE
|
||||
#define __WIRE0_DEVICE i2c0
|
||||
#endif
|
||||
#ifndef __WIRE1_DEVICE
|
||||
#define __WIRE1_DEVICE i2c1
|
||||
#endif
|
||||
|
||||
TwoWire Wire(__WIRE0_DEVICE, PIN_WIRE0_SDA, PIN_WIRE0_SCL);
|
||||
TwoWire Wire1(__WIRE1_DEVICE, PIN_WIRE1_SDA, PIN_WIRE1_SCL);
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "framework-arduinopico",
|
||||
"version": "1.11300.0",
|
||||
"version": "1.20201.0",
|
||||
"description": "Arduino Wiring-based Framework (RPi Pico RP2040)",
|
||||
"keywords": [
|
||||
"framework",
|
||||
|
||||
@@ -110,20 +110,12 @@ sed 's/^tools.uf2conv.cmd=.*//g' | \
|
||||
sed 's/^#tools.uf2conv.cmd=/tools.uf2conv.cmd=/g' | \
|
||||
sed 's/^tools.picoprobe.cmd=.*//g' | \
|
||||
sed 's/^#tools.picoprobe.cmd=/tools.picoprobe.cmd=/g' | \
|
||||
sed 's/^tools.picodebug.cmd=.*//g' | \
|
||||
sed 's/^#tools.picodebug.cmd=/tools.picodebug.cmd=/g' | \
|
||||
sed "s/version=.*/version=$ver/g" |\
|
||||
sed -E "s/name=([a-zA-Z0-9\ -]+).*/name=\1($ver)/g"\
|
||||
> $outdir/platform.txt
|
||||
|
||||
# Put core version and short hash of git version into core_version.h
|
||||
ver_define=`echo $plain_ver | tr "[:lower:].\055" "[:upper:]_"`
|
||||
echo Ver define: $ver_define
|
||||
echo \#define ARDUINO_RP2040_GIT_VER 0x`git rev-parse --short=8 HEAD 2>/dev/null` >$outdir/cores/rp2040/core_version.h
|
||||
echo \#define ARDUINO_RP2040_GIT_DESC `git describe --tags 2>/dev/null` >>$outdir/cores/rp2040/core_version.h
|
||||
echo \#define ARDUINO_RP2040_RELEASE_$ver_define >>$outdir/cores/rp2040/core_version.h
|
||||
echo \#define ARDUINO_RP2040_RELEASE \"$ver_define\" >>$outdir/cores/rp2040/core_version.h
|
||||
|
||||
sed -i 's/"version": .*/"version": "'$visible_ver'"/' $outdir/package.json
|
||||
|
||||
# Zip the package
|
||||
pushd package/versions/$visible_ver
|
||||
echo "Making $package_name.zip"
|
||||
|
||||
@@ -59,6 +59,9 @@
|
||||
{
|
||||
"name": "Invector Labs Challenger RP2040 WiFi"
|
||||
},
|
||||
{
|
||||
"name": "Invector Labs Challenger RP2040 WiFi/BLE"
|
||||
},
|
||||
{
|
||||
"name": "Invector Labs Challenger NB RP2040 WiFi"
|
||||
},
|
||||
@@ -71,12 +74,18 @@
|
||||
{
|
||||
"name": "Invector Labs RPICO32"
|
||||
},
|
||||
{
|
||||
"name": "Seeed XIAO RP2040"
|
||||
},
|
||||
{
|
||||
"name": "Solder Party RP2040 Stamp"
|
||||
},
|
||||
{
|
||||
"name": "SparkFun ProMicro RP2040"
|
||||
},
|
||||
{
|
||||
"name": "SparkFun Thing Plus RP2040"
|
||||
},
|
||||
{
|
||||
"name": "Melopero Shake RP2040"
|
||||
},
|
||||
@@ -86,6 +95,12 @@
|
||||
{
|
||||
"name": "WIZnet W5100S-EVB-Pico"
|
||||
},
|
||||
{
|
||||
"name": "WIZnet 5500-EVB-Pico"
|
||||
},
|
||||
{
|
||||
"name": "WIZnet WizFi360-EVB-Pico"
|
||||
},
|
||||
{
|
||||
"name": "Generic RP2040 Module"
|
||||
}
|
||||
@@ -93,22 +108,22 @@
|
||||
"toolsDependencies": [
|
||||
{
|
||||
"packager": "rp2040",
|
||||
"version": "1.3.3-a-ed6d983",
|
||||
"version": "1.4.0-b-cb31b54",
|
||||
"name": "pqt-gcc"
|
||||
},
|
||||
{
|
||||
"packager": "rp2040",
|
||||
"version": "1.3.3-a-ed6d983",
|
||||
"version": "1.4.0-b-cb31b54",
|
||||
"name": "pqt-mklittlefs"
|
||||
},
|
||||
{
|
||||
"packager": "rp2040",
|
||||
"version": "1.3.3-a-ed6d983",
|
||||
"version": "1.4.0-b-cb31b54",
|
||||
"name": "pqt-elf2uf2"
|
||||
},
|
||||
{
|
||||
"packager": "rp2040",
|
||||
"version": "1.3.3-a-ed6d983",
|
||||
"version": "1.4.0-b-cb31b54",
|
||||
"name": "pqt-pioasm"
|
||||
},
|
||||
{
|
||||
@@ -118,7 +133,7 @@
|
||||
},
|
||||
{
|
||||
"packager": "rp2040",
|
||||
"version": "1.3.3-a-ed6d983",
|
||||
"version": "1.4.0-b-cb31b54",
|
||||
"name": "pqt-openocd"
|
||||
}
|
||||
],
|
||||
@@ -129,57 +144,57 @@
|
||||
],
|
||||
"tools": [
|
||||
{
|
||||
"version": "1.3.3-a-ed6d983",
|
||||
"version": "1.4.0-b-cb31b54",
|
||||
"name": "pqt-openocd",
|
||||
"systems": [
|
||||
{
|
||||
"host": "aarch64-linux-gnu",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/aarch64-linux-gnu.openocd-e3428fadb.220212.tar.gz",
|
||||
"archiveFileName": "aarch64-linux-gnu.openocd-e3428fadb.220212.tar.gz",
|
||||
"checksum": "SHA-256:d1d95978101c69c3bc777e61ba70077bf9dc4b3245aa7dd93171acaec4d29fb1",
|
||||
"size": "5607214"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/aarch64-linux-gnu.openocd-e3428fadb.220619.tar.gz",
|
||||
"archiveFileName": "aarch64-linux-gnu.openocd-e3428fadb.220619.tar.gz",
|
||||
"checksum": "SHA-256:8cdddf73090b6d7f5ef7fdb1b60e9f755166ce494d774b91004e6655a80abfa1",
|
||||
"size": "5607149"
|
||||
},
|
||||
{
|
||||
"host": "arm-linux-gnueabihf",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/arm-linux-gnueabihf.openocd-e3428fadb.220212.tar.gz",
|
||||
"archiveFileName": "arm-linux-gnueabihf.openocd-e3428fadb.220212.tar.gz",
|
||||
"checksum": "SHA-256:81373c1e12a88e382a587688343c2e2f2f1f999d38334b7b6ded174929cc9b88",
|
||||
"size": "5344032"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/arm-linux-gnueabihf.openocd-e3428fadb.220619.tar.gz",
|
||||
"archiveFileName": "arm-linux-gnueabihf.openocd-e3428fadb.220619.tar.gz",
|
||||
"checksum": "SHA-256:07d4e170396f57d5180569168d9bc24b258207900fbc8c87b38056ac1b2fed1e",
|
||||
"size": "5344134"
|
||||
},
|
||||
{
|
||||
"host": "i686-pc-linux-gnu",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/i686-linux-gnu.openocd-e3428fadb.220212.tar.gz",
|
||||
"archiveFileName": "i686-linux-gnu.openocd-e3428fadb.220212.tar.gz",
|
||||
"checksum": "SHA-256:6a4dd98422a187c7725fc349b045b55e4742166c65461847d1bd59537242b0be",
|
||||
"size": "5168258"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/i686-linux-gnu.openocd-e3428fadb.220619.tar.gz",
|
||||
"archiveFileName": "i686-linux-gnu.openocd-e3428fadb.220619.tar.gz",
|
||||
"checksum": "SHA-256:9e3f18ccfb47ee4051bb93c8b9b177e3135eedbbfb3fd9207524b649efe09aed",
|
||||
"size": "5168404"
|
||||
},
|
||||
{
|
||||
"host": "i686-mingw32",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/x86_64-w64-mingw32.openocd-e3428fadb.220212.zip",
|
||||
"archiveFileName": "x86_64-w64-mingw32.openocd-e3428fadb.220212.zip",
|
||||
"checksum": "SHA-256:0643903fcd887a8423cb4ba5329565b499c206921f77ad2e59ae32c472a26dd7",
|
||||
"size": "2156820"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/i686-w64-mingw32.openocd-e3428fadb.220619.zip",
|
||||
"archiveFileName": "i686-w64-mingw32.openocd-e3428fadb.220619.zip",
|
||||
"checksum": "SHA-256:c38bf855c099d933c09d92d57fd1473853eee205957fe22b618e3514d638fe4f",
|
||||
"size": "2156831"
|
||||
},
|
||||
{
|
||||
"host": "x86_64-apple-darwin",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/x86_64-apple-darwin14.openocd-e3428fadb.220212.tar.gz",
|
||||
"archiveFileName": "x86_64-apple-darwin14.openocd-e3428fadb.220212.tar.gz",
|
||||
"checksum": "SHA-256:913b65baeeef1b60caf202e69cde4cd5a3ba0ed2f75f2600adfb3dcf4b3899ef",
|
||||
"size": "2002482"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/x86_64-apple-darwin14.openocd-e3428fadb.220619.tar.gz",
|
||||
"archiveFileName": "x86_64-apple-darwin14.openocd-e3428fadb.220619.tar.gz",
|
||||
"checksum": "SHA-256:c36483c5cecfdeba8466b6e112552736c99a2409e6f8e80287b80a3f8d8fdb16",
|
||||
"size": "2002506"
|
||||
},
|
||||
{
|
||||
"host": "x86_64-pc-linux-gnu",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/x86_64-linux-gnu.openocd-e3428fadb.220212.tar.gz",
|
||||
"archiveFileName": "x86_64-linux-gnu.openocd-e3428fadb.220212.tar.gz",
|
||||
"checksum": "SHA-256:63b2be48c1438d2a09f4ed65d89e555176f18753886555cf48f861e9288d7dc1",
|
||||
"size": "5540524"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/x86_64-linux-gnu.openocd-e3428fadb.220619.tar.gz",
|
||||
"archiveFileName": "x86_64-linux-gnu.openocd-e3428fadb.220619.tar.gz",
|
||||
"checksum": "SHA-256:57083723758814567f6b54e4f81713ce1ce070c6878362a97636da73362f00c9",
|
||||
"size": "5540547"
|
||||
},
|
||||
{
|
||||
"host": "x86_64-mingw32",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/x86_64-w64-mingw32.openocd-e3428fadb.220212.zip",
|
||||
"archiveFileName": "x86_64-w64-mingw32.openocd-e3428fadb.220212.zip",
|
||||
"checksum": "SHA-256:0643903fcd887a8423cb4ba5329565b499c206921f77ad2e59ae32c472a26dd7",
|
||||
"size": "2156820"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/x86_64-w64-mingw32.openocd-e3428fadb.220619.zip",
|
||||
"archiveFileName": "x86_64-w64-mingw32.openocd-e3428fadb.220619.zip",
|
||||
"checksum": "SHA-256:b05d1dbf32d277e214664ae44dd86be96bae61f615c0bac6c1c1c281d6b52b71",
|
||||
"size": "2156832"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -246,226 +261,226 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.3.3-a-ed6d983",
|
||||
"version": "1.4.0-b-cb31b54",
|
||||
"name": "pqt-gcc",
|
||||
"systems": [
|
||||
{
|
||||
"host": "aarch64-linux-gnu",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/aarch64-linux-gnu.arm-none-eabi-ed6d983.220212.tar.gz",
|
||||
"archiveFileName": "aarch64-linux-gnu.arm-none-eabi-ed6d983.220212.tar.gz",
|
||||
"checksum": "SHA-256:7773b43b9c0bf5b7cdb2299e9d1b151df97e0a2ded4428809ec68264ac9818a9",
|
||||
"size": "102741416"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/aarch64-linux-gnu.arm-none-eabi-cb31b54.220619.tar.gz",
|
||||
"archiveFileName": "aarch64-linux-gnu.arm-none-eabi-cb31b54.220619.tar.gz",
|
||||
"checksum": "SHA-256:27dd4a1fe0b6010588928acc9b61937d149ebcd7a4aa47ce944506d71827c460",
|
||||
"size": "77881122"
|
||||
},
|
||||
{
|
||||
"host": "arm-linux-gnueabihf",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/arm-linux-gnueabihf.arm-none-eabi-ed6d983.220212.tar.gz",
|
||||
"archiveFileName": "arm-linux-gnueabihf.arm-none-eabi-ed6d983.220212.tar.gz",
|
||||
"checksum": "SHA-256:c422910ef0e29528939e037ea3c518a532726111604b85b27f3f245820680ccb",
|
||||
"size": "95383443"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/arm-linux-gnueabihf.arm-none-eabi-cb31b54.220619.tar.gz",
|
||||
"archiveFileName": "arm-linux-gnueabihf.arm-none-eabi-cb31b54.220619.tar.gz",
|
||||
"checksum": "SHA-256:3e3547998b6c2382d7c6e91b43f0a7a3190e2955160bb471de4cc204b599a757",
|
||||
"size": "73345531"
|
||||
},
|
||||
{
|
||||
"host": "i686-pc-linux-gnu",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/i686-linux-gnu.arm-none-eabi-ed6d983.220212.tar.gz",
|
||||
"archiveFileName": "i686-linux-gnu.arm-none-eabi-ed6d983.220212.tar.gz",
|
||||
"checksum": "SHA-256:6306791b43de955c4a4d0a1b8972e0f696206591a810eefc16b906b157322bd3",
|
||||
"size": "105350371"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/i686-linux-gnu.arm-none-eabi-cb31b54.220619.tar.gz",
|
||||
"archiveFileName": "i686-linux-gnu.arm-none-eabi-cb31b54.220619.tar.gz",
|
||||
"checksum": "SHA-256:fca37e1e49a6e25dd507a24e2e9a6947fd0eec7d0a8a30f4bdcac524c9bd18a1",
|
||||
"size": "79497966"
|
||||
},
|
||||
{
|
||||
"host": "i686-mingw32",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/i686-w64-mingw32.arm-none-eabi-ed6d983.220212.zip",
|
||||
"archiveFileName": "i686-w64-mingw32.arm-none-eabi-ed6d983.220212.zip",
|
||||
"checksum": "SHA-256:b00aa3594d1911bea07c1dbf31b9a63430f4dcb91c7b3b1341f8551d361d405f",
|
||||
"size": "105568357"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/i686-w64-mingw32.arm-none-eabi-cb31b54.220619.zip",
|
||||
"archiveFileName": "i686-w64-mingw32.arm-none-eabi-cb31b54.220619.zip",
|
||||
"checksum": "SHA-256:61f31ae875a67e8334e031c188fbe30d98c5f1bceb33305acf49d985d9ca71ce",
|
||||
"size": "82625221"
|
||||
},
|
||||
{
|
||||
"host": "x86_64-apple-darwin",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/x86_64-apple-darwin14.arm-none-eabi-ed6d983.220212.tar.gz",
|
||||
"archiveFileName": "x86_64-apple-darwin14.arm-none-eabi-ed6d983.220212.tar.gz",
|
||||
"checksum": "SHA-256:e93b967d1fb6ed0fc7cf6a5161e22a597dd05080c1353ac74e2a42ddf8dfe98d",
|
||||
"size": "107429038"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/x86_64-apple-darwin14.arm-none-eabi-cb31b54.220619.tar.gz",
|
||||
"archiveFileName": "x86_64-apple-darwin14.arm-none-eabi-cb31b54.220619.tar.gz",
|
||||
"checksum": "SHA-256:d32c7797be2c31d20dc4b5182a0dd77be67324c3c6a52737bfb4e63e1d622f80",
|
||||
"size": "82123114"
|
||||
},
|
||||
{
|
||||
"host": "x86_64-pc-linux-gnu",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/x86_64-linux-gnu.arm-none-eabi-ed6d983.220212.tar.gz",
|
||||
"archiveFileName": "x86_64-linux-gnu.arm-none-eabi-ed6d983.220212.tar.gz",
|
||||
"checksum": "SHA-256:047c4d482cf77e09bd8069fc9d5b28b1e0c76440ad81583a0fc3a8e809959bb8",
|
||||
"size": "106740897"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/x86_64-linux-gnu.arm-none-eabi-cb31b54.220619.tar.gz",
|
||||
"archiveFileName": "x86_64-linux-gnu.arm-none-eabi-cb31b54.220619.tar.gz",
|
||||
"checksum": "SHA-256:470cbe690b2553d3b780ece36cda9fc26c7b53db47362ced3a937d701e696e9e",
|
||||
"size": "80361816"
|
||||
},
|
||||
{
|
||||
"host": "x86_64-mingw32",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/x86_64-w64-mingw32.arm-none-eabi-ed6d983.220212.zip",
|
||||
"archiveFileName": "x86_64-w64-mingw32.arm-none-eabi-ed6d983.220212.zip",
|
||||
"checksum": "SHA-256:5c15725628a3dbd47a8fa8f9a9aab7a2221815ec9bf85dc2080ce19166316ae6",
|
||||
"size": "110420777"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/x86_64-w64-mingw32.arm-none-eabi-cb31b54.220619.zip",
|
||||
"archiveFileName": "x86_64-w64-mingw32.arm-none-eabi-cb31b54.220619.zip",
|
||||
"checksum": "SHA-256:7b50d3f34cd602a28d8cf1580c65dd22e683088ce5b954be5bfb67ba50094134",
|
||||
"size": "86068608"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.3.3-a-ed6d983",
|
||||
"version": "1.4.0-b-cb31b54",
|
||||
"name": "pqt-elf2uf2",
|
||||
"systems": [
|
||||
{
|
||||
"host": "aarch64-linux-gnu",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/aarch64-linux-gnu.elf2uf2-2062372.220212.tar.gz",
|
||||
"archiveFileName": "aarch64-linux-gnu.elf2uf2-2062372.220212.tar.gz",
|
||||
"checksum": "SHA-256:8cb7ce703b0fa6f2fce6b124ae6f34ad0b866aa4a58096f22b66b1251c1b11c0",
|
||||
"size": "79853"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/aarch64-linux-gnu.elf2uf2-2062372.220619.tar.gz",
|
||||
"archiveFileName": "aarch64-linux-gnu.elf2uf2-2062372.220619.tar.gz",
|
||||
"checksum": "SHA-256:74dd8cf38160bd9f972ea22e02bd6fa6b11bc510aa7738b603c7fbd016fe4b50",
|
||||
"size": "79874"
|
||||
},
|
||||
{
|
||||
"host": "arm-linux-gnueabihf",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/arm-linux-gnueabihf.elf2uf2-2062372.220212.tar.gz",
|
||||
"archiveFileName": "arm-linux-gnueabihf.elf2uf2-2062372.220212.tar.gz",
|
||||
"checksum": "SHA-256:790d46b411c16a4a210a91436eb4bdc81fb34f0119148a8f9c4b09489489a54d",
|
||||
"size": "54244"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/arm-linux-gnueabihf.elf2uf2-2062372.220619.tar.gz",
|
||||
"archiveFileName": "arm-linux-gnueabihf.elf2uf2-2062372.220619.tar.gz",
|
||||
"checksum": "SHA-256:efa24ac288a5eacad7b535ce4d9ac66a25686d993f80daf86248858310b3fc63",
|
||||
"size": "54265"
|
||||
},
|
||||
{
|
||||
"host": "i686-pc-linux-gnu",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/i686-linux-gnu.elf2uf2-2062372.220212.tar.gz",
|
||||
"archiveFileName": "i686-linux-gnu.elf2uf2-2062372.220212.tar.gz",
|
||||
"checksum": "SHA-256:7c05c70f761bb6caa986d24ac1065367fe906ff7f0434cf4b0112ace331f74bc",
|
||||
"size": "87891"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/i686-linux-gnu.elf2uf2-2062372.220619.tar.gz",
|
||||
"archiveFileName": "i686-linux-gnu.elf2uf2-2062372.220619.tar.gz",
|
||||
"checksum": "SHA-256:c0816a703fe5821a1d1bf60dcb584d98185b83e926d532fd37c69e8801e211ff",
|
||||
"size": "87908"
|
||||
},
|
||||
{
|
||||
"host": "i686-mingw32",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/i686-w64-mingw32.elf2uf2-2062372.220212.zip",
|
||||
"archiveFileName": "i686-w64-mingw32.elf2uf2-2062372.220212.zip",
|
||||
"checksum": "SHA-256:e6f0578ea781b160390994d3e95bedfec01e212d47243b1adb84f910a06bcba4",
|
||||
"size": "70405"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/i686-w64-mingw32.elf2uf2-2062372.220619.zip",
|
||||
"archiveFileName": "i686-w64-mingw32.elf2uf2-2062372.220619.zip",
|
||||
"checksum": "SHA-256:7a2f86735220fef0946856f418a136ff4ed3ad4cf0cacc17d8016f6cbd1ca735",
|
||||
"size": "70416"
|
||||
},
|
||||
{
|
||||
"host": "x86_64-apple-darwin",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/x86_64-apple-darwin14.elf2uf2-2062372.220212.tar.gz",
|
||||
"archiveFileName": "x86_64-apple-darwin14.elf2uf2-2062372.220212.tar.gz",
|
||||
"checksum": "SHA-256:d65de7218eaf01c9bf58fa22bd9e1e7c10c054213948b4b62f648a058d09b4de",
|
||||
"size": "81981"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/x86_64-apple-darwin14.elf2uf2-2062372.220619.tar.gz",
|
||||
"archiveFileName": "x86_64-apple-darwin14.elf2uf2-2062372.220619.tar.gz",
|
||||
"checksum": "SHA-256:2ae3ffd477eaabb891e68e1b4525e3d4d4b2fee3c6f70e6ae68c45746c03fb54",
|
||||
"size": "81995"
|
||||
},
|
||||
{
|
||||
"host": "x86_64-pc-linux-gnu",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/x86_64-linux-gnu.elf2uf2-2062372.220212.tar.gz",
|
||||
"archiveFileName": "x86_64-linux-gnu.elf2uf2-2062372.220212.tar.gz",
|
||||
"checksum": "SHA-256:ba7795ed49c54f3f52caee675b0fd078f6fb8498a47bf7e5d7457065271df338",
|
||||
"size": "79585"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/x86_64-linux-gnu.elf2uf2-2062372.220619.tar.gz",
|
||||
"archiveFileName": "x86_64-linux-gnu.elf2uf2-2062372.220619.tar.gz",
|
||||
"checksum": "SHA-256:2be1052db1e676418c59a4331ef688f686b4a31053330c90348219ab1ecd6bcf",
|
||||
"size": "79610"
|
||||
},
|
||||
{
|
||||
"host": "x86_64-mingw32",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/x86_64-w64-mingw32.elf2uf2-2062372.220212.zip",
|
||||
"archiveFileName": "x86_64-w64-mingw32.elf2uf2-2062372.220212.zip",
|
||||
"checksum": "SHA-256:02c7684ed1aea4e18216ec6bbbcedeb482c5f23ad7d5eb9dcb942b8ae6cad5ae",
|
||||
"size": "78279"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/x86_64-w64-mingw32.elf2uf2-2062372.220619.zip",
|
||||
"archiveFileName": "x86_64-w64-mingw32.elf2uf2-2062372.220619.zip",
|
||||
"checksum": "SHA-256:2a39f7f20e42c5b981286dfdf50bc3d7201cbe63d191caf38a0ffa306422ed08",
|
||||
"size": "78291"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.3.3-a-ed6d983",
|
||||
"version": "1.4.0-b-cb31b54",
|
||||
"name": "pqt-pioasm",
|
||||
"systems": [
|
||||
{
|
||||
"host": "aarch64-linux-gnu",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/aarch64-linux-gnu.pioasm-2062372.220212.tar.gz",
|
||||
"archiveFileName": "aarch64-linux-gnu.pioasm-2062372.220212.tar.gz",
|
||||
"checksum": "SHA-256:9ea17ecf0e492bc6a971f6a78780c3b3c6ee644d52e056cba08a708ac225add2",
|
||||
"size": "453558"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/aarch64-linux-gnu.pioasm-2062372.220619.tar.gz",
|
||||
"archiveFileName": "aarch64-linux-gnu.pioasm-2062372.220619.tar.gz",
|
||||
"checksum": "SHA-256:71887999ad64e64f75658a1883029b337cb9738d87e04944b1dbc0321d3c7a67",
|
||||
"size": "453580"
|
||||
},
|
||||
{
|
||||
"host": "arm-linux-gnueabihf",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/arm-linux-gnueabihf.pioasm-2062372.220212.tar.gz",
|
||||
"archiveFileName": "arm-linux-gnueabihf.pioasm-2062372.220212.tar.gz",
|
||||
"checksum": "SHA-256:c7af69227a3b3c54ccf87122b18842460a263bd711abf93336794ce5f905c284",
|
||||
"size": "360559"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/arm-linux-gnueabihf.pioasm-2062372.220619.tar.gz",
|
||||
"archiveFileName": "arm-linux-gnueabihf.pioasm-2062372.220619.tar.gz",
|
||||
"checksum": "SHA-256:5b2e863e5764b0c4d53f536b5ea217e2a27f02f04b74da799e19b1fa6c8b39a8",
|
||||
"size": "360581"
|
||||
},
|
||||
{
|
||||
"host": "i686-pc-linux-gnu",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/i686-linux-gnu.pioasm-2062372.220212.tar.gz",
|
||||
"archiveFileName": "i686-linux-gnu.pioasm-2062372.220212.tar.gz",
|
||||
"checksum": "SHA-256:f66b9bde3d6859d43049b019fb639dd0bfafcd43f1389ffc499d18949bcf1808",
|
||||
"size": "511397"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/i686-linux-gnu.pioasm-2062372.220619.tar.gz",
|
||||
"archiveFileName": "i686-linux-gnu.pioasm-2062372.220619.tar.gz",
|
||||
"checksum": "SHA-256:fd5ec8b1940e51db6ec2e2beea73d7be7f1e9cf09f6e66d739e3ed1be177a7a6",
|
||||
"size": "511417"
|
||||
},
|
||||
{
|
||||
"host": "i686-mingw32",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/i686-w64-mingw32.pioasm-2062372.220212.zip",
|
||||
"archiveFileName": "i686-w64-mingw32.pioasm-2062372.220212.zip",
|
||||
"checksum": "SHA-256:89cfa44101dade30000cfaa5985de7f0e7aba93d03dc45ba962f97226ae4e41f",
|
||||
"size": "385748"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/i686-w64-mingw32.pioasm-2062372.220619.zip",
|
||||
"archiveFileName": "i686-w64-mingw32.pioasm-2062372.220619.zip",
|
||||
"checksum": "SHA-256:6a4a5f4f3c0b7a3bc08b2b3bd8111d33a5619633de9b04e03bf0bca6f17d1337",
|
||||
"size": "385759"
|
||||
},
|
||||
{
|
||||
"host": "x86_64-apple-darwin",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/x86_64-apple-darwin14.pioasm-2062372.220212.tar.gz",
|
||||
"archiveFileName": "x86_64-apple-darwin14.pioasm-2062372.220212.tar.gz",
|
||||
"checksum": "SHA-256:d531c911e6eba0333379af04dd807917659bd4d34be9f4bd6792aeff55ab15a9",
|
||||
"size": "480495"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/x86_64-apple-darwin14.pioasm-2062372.220619.tar.gz",
|
||||
"archiveFileName": "x86_64-apple-darwin14.pioasm-2062372.220619.tar.gz",
|
||||
"checksum": "SHA-256:9d9d7a3addaaca00712fdf5516a21fdae94926210f12f7ae16dc8ebf7beacfe8",
|
||||
"size": "480510"
|
||||
},
|
||||
{
|
||||
"host": "x86_64-pc-linux-gnu",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/x86_64-linux-gnu.pioasm-2062372.220212.tar.gz",
|
||||
"archiveFileName": "x86_64-linux-gnu.pioasm-2062372.220212.tar.gz",
|
||||
"checksum": "SHA-256:2cd4aa8af98558461cb7b85b21830ea854a430a3e57668d618c5f1cd5e389809",
|
||||
"size": "458730"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/x86_64-linux-gnu.pioasm-2062372.220619.tar.gz",
|
||||
"archiveFileName": "x86_64-linux-gnu.pioasm-2062372.220619.tar.gz",
|
||||
"checksum": "SHA-256:be77c350eb7777de01c93312919c370e4ef3e5e281f122f46a2348a21693c480",
|
||||
"size": "458738"
|
||||
},
|
||||
{
|
||||
"host": "x86_64-mingw32",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/x86_64-w64-mingw32.pioasm-2062372.220212.zip",
|
||||
"archiveFileName": "x86_64-w64-mingw32.pioasm-2062372.220212.zip",
|
||||
"checksum": "SHA-256:ba586e67f4b309690a51fca70fdd26f38b68951b0fee4dc8333183ef6429833a",
|
||||
"size": "408649"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/x86_64-w64-mingw32.pioasm-2062372.220619.zip",
|
||||
"archiveFileName": "x86_64-w64-mingw32.pioasm-2062372.220619.zip",
|
||||
"checksum": "SHA-256:451ad335a5cebcee3b6acda73d887a488f98c4a8839b8e98d557425f8d7f47ea",
|
||||
"size": "408660"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.3.3-a-ed6d983",
|
||||
"version": "1.4.0-b-cb31b54",
|
||||
"name": "pqt-mklittlefs",
|
||||
"systems": [
|
||||
{
|
||||
"host": "aarch64-linux-gnu",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/aarch64-linux-gnu.mklittlefs-affa497.220212.tar.gz",
|
||||
"archiveFileName": "aarch64-linux-gnu.mklittlefs-affa497.220212.tar.gz",
|
||||
"checksum": "SHA-256:2455f5ca6cb1f7b73ed1cb55d4d2261d249c1b24915bd4e66e28f037a0a13116",
|
||||
"size": "47271"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/aarch64-linux-gnu.mklittlefs-affa497.220619.tar.gz",
|
||||
"archiveFileName": "aarch64-linux-gnu.mklittlefs-affa497.220619.tar.gz",
|
||||
"checksum": "SHA-256:1752294e6cc6ce3edd8b417e773c8703a1dc4e616f158ed6c928b62bec7289b5",
|
||||
"size": "47286"
|
||||
},
|
||||
{
|
||||
"host": "arm-linux-gnueabihf",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/arm-linux-gnueabihf.mklittlefs-affa497.220212.tar.gz",
|
||||
"archiveFileName": "arm-linux-gnueabihf.mklittlefs-affa497.220212.tar.gz",
|
||||
"checksum": "SHA-256:f4b71138f1469e4b9ce82b3b21252aca265a88d56a5d48513dbb5c6d58b19841",
|
||||
"size": "40807"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/arm-linux-gnueabihf.mklittlefs-affa497.220619.tar.gz",
|
||||
"archiveFileName": "arm-linux-gnueabihf.mklittlefs-affa497.220619.tar.gz",
|
||||
"checksum": "SHA-256:07e182ca15cf60d0f266030ff796ffc566c78e5e1fd148948a6ec3cbab444103",
|
||||
"size": "40823"
|
||||
},
|
||||
{
|
||||
"host": "i686-pc-linux-gnu",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/i686-linux-gnu.mklittlefs-affa497.220212.tar.gz",
|
||||
"archiveFileName": "i686-linux-gnu.mklittlefs-affa497.220212.tar.gz",
|
||||
"checksum": "SHA-256:ed1011230c75447dad3d912b7b5607ddcc59e093ee7ebd653fb05274bc876f4c",
|
||||
"size": "50909"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/i686-linux-gnu.mklittlefs-affa497.220619.tar.gz",
|
||||
"archiveFileName": "i686-linux-gnu.mklittlefs-affa497.220619.tar.gz",
|
||||
"checksum": "SHA-256:774657fbfaca1793acd8461e90399de1be0e99715b9135af0b935adc40211c72",
|
||||
"size": "50926"
|
||||
},
|
||||
{
|
||||
"host": "i686-mingw32",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/i686-w64-mingw32.mklittlefs-affa497.220212.zip",
|
||||
"archiveFileName": "i686-w64-mingw32.mklittlefs-affa497.220212.zip",
|
||||
"checksum": "SHA-256:1289f51c674ebdc568843b82c88db21eb4c295f3b15c26398d31266b9da63b4c",
|
||||
"size": "334050"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/i686-w64-mingw32.mklittlefs-affa497.220619.zip",
|
||||
"archiveFileName": "i686-w64-mingw32.mklittlefs-affa497.220619.zip",
|
||||
"checksum": "SHA-256:473ba014d011737d97e703059cf2819d9ee2328f2af2f93f52c43eba53e34f55",
|
||||
"size": "334062"
|
||||
},
|
||||
{
|
||||
"host": "x86_64-apple-darwin",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/x86_64-apple-darwin14.mklittlefs-affa497.220212.tar.gz",
|
||||
"archiveFileName": "x86_64-apple-darwin14.mklittlefs-affa497.220212.tar.gz",
|
||||
"checksum": "SHA-256:0c0d7d8c80739ed79bc5a41e831d0229b6378e87f4c58f148d884814f1ad46d2",
|
||||
"size": "365757"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/x86_64-apple-darwin14.mklittlefs-affa497.220619.tar.gz",
|
||||
"archiveFileName": "x86_64-apple-darwin14.mklittlefs-affa497.220619.tar.gz",
|
||||
"checksum": "SHA-256:ffc1fef60f4c359978f6476a8cc33995638d826e4820ca96fc17f3cf47250bec",
|
||||
"size": "365767"
|
||||
},
|
||||
{
|
||||
"host": "x86_64-pc-linux-gnu",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/x86_64-linux-gnu.mklittlefs-affa497.220212.tar.gz",
|
||||
"archiveFileName": "x86_64-linux-gnu.mklittlefs-affa497.220212.tar.gz",
|
||||
"checksum": "SHA-256:c504429c24cfea9bf841cbf0caa29bbe0115e72c94c18f949451ffa540d6cacc",
|
||||
"size": "49766"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/x86_64-linux-gnu.mklittlefs-affa497.220619.tar.gz",
|
||||
"archiveFileName": "x86_64-linux-gnu.mklittlefs-affa497.220619.tar.gz",
|
||||
"checksum": "SHA-256:0a05281f13ae48a1ce4894107525e7027258746c1cac3a568b51b8082f99e93f",
|
||||
"size": "49786"
|
||||
},
|
||||
{
|
||||
"host": "x86_64-mingw32",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.3.3-a/x86_64-w64-mingw32.mklittlefs-affa497.220212.zip",
|
||||
"archiveFileName": "x86_64-w64-mingw32.mklittlefs-affa497.220212.zip",
|
||||
"checksum": "SHA-256:4ada867888513596fa51bf78c98d9e970de9b8f1eec4f88d85e6e7621704fb91",
|
||||
"size": "347602"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-b/x86_64-w64-mingw32.mklittlefs-affa497.220619.zip",
|
||||
"archiveFileName": "x86_64-w64-mingw32.mklittlefs-affa497.220619.zip",
|
||||
"checksum": "SHA-256:039981ec41f38a9c89de3466d9fd8c9e7c0723ab53798223ceb4d122fdcac914",
|
||||
"size": "347613"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user