Compare commits
@@ -6,6 +6,10 @@ name: Arduino-Pico CI
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
TRAVIS_BUILD_DIR: ${{ github.workspace }}
|
||||
TRAVIS_TAG: ${{ github.ref }}
|
||||
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -20,7 +24,7 @@ jobs:
|
||||
- name: Run codespell
|
||||
uses: codespell-project/actions-codespell@master
|
||||
with:
|
||||
skip: ./ArduinoCore-API,./libraries/ESP8266SdFat,./libraries/Adafruit_TinyUSB_Arduino,./libraries/LittleFS/lib,./tools/pyserial,./pico-sdk,./.github,./docs/i2s.rst,./cores/rp2040/api,./libraries/FreeRTOS,./tools/libbearssl/bearssl,./include,./libraries/WiFi/examples/BearSSL_Server,./ota/uzlib,./libraries/http-parser/lib,./libraries/WebServer/examples/HelloServerBearSSL/HelloServerBearSSL.ino,./libraries/HTTPUpdateServer/examples/SecureBearSSLUpdater/SecureBearSSLUpdater.ino
|
||||
skip: ./ArduinoCore-API,./libraries/ESP8266SdFat,./libraries/Adafruit_TinyUSB_Arduino,./libraries/LittleFS/lib,./tools/pyserial,./pico-sdk,./.github,./docs/i2s.rst,./cores/rp2040/api,./libraries/FreeRTOS,./tools/libbearssl/bearssl,./include,./libraries/WiFi/examples/BearSSL_Server,./ota/uzlib,./libraries/http-parser/lib,./libraries/WebServer/examples/HelloServerBearSSL/HelloServerBearSSL.ino,./libraries/HTTPUpdateServer/examples/SecureBearSSLUpdater/SecureBearSSLUpdater.ino,./.git
|
||||
ignore_words_list: ser,dout
|
||||
|
||||
# Consistent style
|
||||
@@ -46,10 +50,6 @@ 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
|
||||
|
||||
# Build all examples on linux (core and Arduino IDE)
|
||||
build-linux:
|
||||
@@ -62,19 +62,17 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Cache Linux toolchain
|
||||
id: cache-linux
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ./tools/dist
|
||||
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
|
||||
- name: Build Sketches
|
||||
env:
|
||||
TRAVIS_BUILD_DIR: ${{ github.workspace }}
|
||||
TRAVIS_TAG: ${{ github.ref }}
|
||||
BUILD_PARITY: custom
|
||||
mod: 6
|
||||
rem: ${{ matrix.chunk }}
|
||||
@@ -92,19 +90,17 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Cache Linux toolchain
|
||||
id: cache-linux
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ./tools/dist
|
||||
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
|
||||
- name: Build Sketches
|
||||
env:
|
||||
TRAVIS_BUILD_DIR: ${{ github.workspace }}
|
||||
TRAVIS_TAG: ${{ github.ref }}
|
||||
BUILD_PARITY: custom
|
||||
run: |
|
||||
cd pico-sdk
|
||||
@@ -120,19 +116,17 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Cache Windows toolchain
|
||||
id: cache-windows
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ./tools/dist
|
||||
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
|
||||
- name: Build Sketch
|
||||
env:
|
||||
TRAVIS_BUILD_DIR: ${{ github.workspace }}
|
||||
TRAVIS_TAG: ${{ github.ref }}
|
||||
WINDOWS: 1
|
||||
BUILD_PARITY: custom
|
||||
mod: 500
|
||||
@@ -150,24 +144,22 @@ jobs:
|
||||
# Single build under macOS to ensure the Mac toolchain is good.
|
||||
build-mac:
|
||||
name: Mac
|
||||
runs-on: macOS-latest
|
||||
runs-on: macOS-12
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Cache Mac toolchain
|
||||
id: cache-mac
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ./tools/dist
|
||||
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
|
||||
- name: Build Sketch
|
||||
env:
|
||||
TRAVIS_BUILD_DIR: ${{ github.workspace }}
|
||||
TRAVIS_TAG: ${{ github.ref }}
|
||||
MACOSX: 1
|
||||
BUILD_PARITY: custom
|
||||
mod: 500
|
||||
@@ -194,19 +186,21 @@ jobs:
|
||||
git submodule update --init
|
||||
cd ../..
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
- name: Cache PlatformIO
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install PlatformIO
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
|
||||
@@ -9,22 +9,22 @@ jobs:
|
||||
name: Update master JSON file
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
- name: Cache PlatformIO
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install PlatformIO
|
||||
|
||||
@@ -15,11 +15,11 @@ jobs:
|
||||
name: Package
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Build package JSON
|
||||
|
||||
@@ -13,6 +13,7 @@ See https://arduino-pico.readthedocs.io/en/latest/ along with the examples for m
|
||||
* Raspberry Pi Pico
|
||||
* Raspberry Pi Pico W
|
||||
* Adafruit Feather RP2040
|
||||
* Adafruit Feather RP2040 SCORPIO
|
||||
* Adafruit ItsyBitsy RP2040
|
||||
* Adafruit KB2040
|
||||
* Adafruit Macropad RP2040
|
||||
@@ -20,8 +21,10 @@ See https://arduino-pico.readthedocs.io/en/latest/ along with the examples for m
|
||||
* Adafruit STEMMA Friend RP2040
|
||||
* Adafruit Trinkey RP2040 QT
|
||||
* Arduino Nano RP2040 Connect
|
||||
* BridgeTek IDM2040-7A
|
||||
* Cytron Maker Pi RP2040
|
||||
* Cytron Maker Nano RP2040
|
||||
* DatanoiseTV PicoADK+
|
||||
* DeRuiLab FlyBoard2040 Core
|
||||
* DFRobot Beetle RP2040
|
||||
* ElectronicCats Hunter Cat NFC
|
||||
@@ -34,12 +37,21 @@ See https://arduino-pico.readthedocs.io/en/latest/ along with the examples for m
|
||||
* Invector Labs Challenger RP2040 SubGHz
|
||||
* Invector Labs Challenger RP2040 SD/RTC
|
||||
* Invector Labs RPICO32
|
||||
* Melopero Cookie RP2040
|
||||
* Melopero Shake RP2040
|
||||
* nullbits Bit-C PRO
|
||||
* Pimoroni PGA2040
|
||||
* Seeed XIAO RP2040
|
||||
* Solder Party RP2040 Stamp
|
||||
* SparkFun ProMicro RP2040
|
||||
* SparkFun Thing Plus RP2040
|
||||
* uPesy RP2040 DevKit
|
||||
* Viyalab Mizu RP2040
|
||||
* Waveshare RP2040 Zero
|
||||
* Waveshare RP2040 One
|
||||
* Waveshare RP2040 Plus
|
||||
* Waveshare RP2040 LCD 0.96
|
||||
* Waveshare RP2040 LCD 1.28
|
||||
* WIZnet W5100S-EVB-Pico
|
||||
* WIZnet W5500-EVB-Pico
|
||||
* WIZnet WizFi360-EVB-Pico
|
||||
|
||||
+8491
-490
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,23 @@
|
||||
// Padded and checksummed version of: generated\Winbond\W25Q16JVxQ\boot2.bin
|
||||
|
||||
.cpu cortex-m0plus
|
||||
.thumb
|
||||
|
||||
.section .boot2, "ax"
|
||||
|
||||
.byte 0xf7, 0xb5, 0x73, 0x46, 0x21, 0x22, 0x02, 0x26, 0x01, 0x93, 0x29, 0x4b, 0xc0, 0x24, 0x5a, 0x60
|
||||
.byte 0x9a, 0x68, 0x00, 0x27, 0xb2, 0x43, 0xda, 0x60, 0x9a, 0x60, 0x1a, 0x61, 0x5a, 0x61, 0x04, 0x23
|
||||
.byte 0x01, 0x25, 0x64, 0x05, 0xa7, 0x60, 0x63, 0x61, 0x22, 0x4b, 0x30, 0x00, 0x1d, 0x60, 0xe0, 0x23
|
||||
.byte 0xdb, 0x02, 0x23, 0x60, 0x35, 0x23, 0xa5, 0x60, 0x23, 0x66, 0x23, 0x66, 0x00, 0xf0, 0x4a, 0xf8
|
||||
.byte 0xc0, 0xb2, 0xb0, 0x42, 0x12, 0xd0, 0x06, 0x23, 0x28, 0x00, 0x23, 0x66, 0x00, 0xf0, 0x42, 0xf8
|
||||
.byte 0x25, 0x66, 0x03, 0x20, 0x27, 0x66, 0x26, 0x66, 0x00, 0xf0, 0x3c, 0xf8, 0x03, 0x36, 0x26, 0x66
|
||||
.byte 0x02, 0x20, 0x26, 0x66, 0x00, 0xf0, 0x36, 0xf8, 0x28, 0x42, 0xf8, 0xd1, 0x00, 0x25, 0x12, 0x4b
|
||||
.byte 0xa5, 0x60, 0x12, 0x4f, 0x23, 0x60, 0x12, 0x4b, 0x65, 0x60, 0x01, 0x26, 0x3b, 0x60, 0xeb, 0x23
|
||||
.byte 0xa6, 0x60, 0x23, 0x66, 0x4b, 0x3b, 0x23, 0x66, 0x02, 0x20, 0x00, 0xf0, 0x23, 0xf8, 0x0d, 0x4b
|
||||
.byte 0xa5, 0x60, 0x3b, 0x60, 0xa6, 0x60, 0x01, 0x9b, 0xab, 0x42, 0x08, 0xd1, 0x0a, 0x4b, 0x0b, 0x4a
|
||||
.byte 0x13, 0x60, 0x1b, 0x68, 0x83, 0xf3, 0x08, 0x88, 0x09, 0x4b, 0x1b, 0x68, 0x18, 0x47, 0xf7, 0xbd
|
||||
.byte 0x00, 0x00, 0x02, 0x40, 0xf0, 0x00, 0x00, 0x18, 0x00, 0x03, 0x5f, 0x00, 0xf4, 0x00, 0x00, 0x18
|
||||
.byte 0x21, 0x22, 0x00, 0x00, 0x22, 0x20, 0x00, 0xa0, 0x00, 0x01, 0x00, 0x10, 0x08, 0xed, 0x00, 0xe0
|
||||
.byte 0x04, 0x01, 0x00, 0x10, 0xc0, 0x22, 0x03, 0x00, 0x04, 0x21, 0x52, 0x05, 0x90, 0x6a, 0x08, 0x42
|
||||
.byte 0xfc, 0xd0, 0x01, 0x21, 0x90, 0x6a, 0x08, 0x42, 0xfc, 0xd1, 0x01, 0x3b, 0xdb, 0xb2, 0x10, 0x6e
|
||||
.byte 0x00, 0x2b, 0xfa, 0xd1, 0x70, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xa0, 0xf0, 0x2f
|
||||
@@ -0,0 +1,23 @@
|
||||
// Padded and checksummed version of: boot2_w25q64jv.4.bin
|
||||
|
||||
.cpu cortex-m0plus
|
||||
.thumb
|
||||
|
||||
.section .boot2, "ax"
|
||||
|
||||
.byte 0xf7, 0xb5, 0x73, 0x46, 0x21, 0x22, 0x02, 0x25, 0x01, 0x93, 0x29, 0x4b, 0xc0, 0x24, 0x5a, 0x60
|
||||
.byte 0x9a, 0x68, 0x01, 0x26, 0xaa, 0x43, 0xda, 0x60, 0x9a, 0x60, 0x1a, 0x61, 0x5a, 0x61, 0x00, 0x23
|
||||
.byte 0x64, 0x05, 0xa3, 0x60, 0x04, 0x33, 0x63, 0x61, 0x22, 0x4b, 0x28, 0x00, 0x1e, 0x60, 0xe0, 0x23
|
||||
.byte 0xdb, 0x02, 0x23, 0x60, 0x35, 0x23, 0xa6, 0x60, 0x23, 0x66, 0x23, 0x66, 0x00, 0xf0, 0x4a, 0xf8
|
||||
.byte 0xc0, 0xb2, 0xa8, 0x42, 0x12, 0xd0, 0x06, 0x23, 0x30, 0x00, 0x23, 0x66, 0x00, 0xf0, 0x42, 0xf8
|
||||
.byte 0x31, 0x23, 0x28, 0x00, 0x23, 0x66, 0x25, 0x66, 0x00, 0xf0, 0x3c, 0xf8, 0x03, 0x35, 0x25, 0x66
|
||||
.byte 0x02, 0x20, 0x25, 0x66, 0x00, 0xf0, 0x36, 0xf8, 0x30, 0x42, 0xf8, 0xd1, 0x00, 0x25, 0x12, 0x4b
|
||||
.byte 0xa5, 0x60, 0x12, 0x4f, 0x23, 0x60, 0x12, 0x4b, 0x65, 0x60, 0x01, 0x26, 0x3b, 0x60, 0xeb, 0x23
|
||||
.byte 0xa6, 0x60, 0x23, 0x66, 0x4b, 0x3b, 0x23, 0x66, 0x02, 0x20, 0x00, 0xf0, 0x23, 0xf8, 0x0d, 0x4b
|
||||
.byte 0xa5, 0x60, 0x3b, 0x60, 0xa6, 0x60, 0x01, 0x9b, 0xab, 0x42, 0x08, 0xd1, 0x0a, 0x4b, 0x0b, 0x4a
|
||||
.byte 0x13, 0x60, 0x1b, 0x68, 0x83, 0xf3, 0x08, 0x88, 0x09, 0x4b, 0x1b, 0x68, 0x18, 0x47, 0xf7, 0xbd
|
||||
.byte 0x00, 0x00, 0x02, 0x40, 0xf0, 0x00, 0x00, 0x18, 0x00, 0x03, 0x5f, 0x00, 0xf4, 0x00, 0x00, 0x18
|
||||
.byte 0x21, 0x22, 0x00, 0x00, 0x22, 0x20, 0x00, 0xa0, 0x00, 0x01, 0x00, 0x10, 0x08, 0xed, 0x00, 0xe0
|
||||
.byte 0x04, 0x01, 0x00, 0x10, 0xc0, 0x23, 0x02, 0x00, 0x04, 0x21, 0x5b, 0x05, 0x98, 0x6a, 0x08, 0x42
|
||||
.byte 0xfc, 0xd0, 0x01, 0x21, 0x98, 0x6a, 0x08, 0x42, 0xfc, 0xd1, 0x18, 0x6e, 0x01, 0x2a, 0x00, 0xd0
|
||||
.byte 0x18, 0x6e, 0x70, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x2d, 0x68, 0xca
|
||||
@@ -68,10 +68,12 @@ void noInterrupts();
|
||||
#define portOutputRegister(port) ((volatile uint32_t*) sio_hw->gpio_out)
|
||||
#define portInputRegister(port) ((volatile uint32_t*) sio_hw->gpio_in)
|
||||
#define portModeRegister(port) ((volatile uint32_t*) sio_hw->gpio_oe)
|
||||
#define digitalWriteFast(pin, val) (val ? sio_hw->gpio_set = (1 << pin) : sio_hw->gpio_clr = (1 << pin))
|
||||
#define digitalReadFast(pin) ((1 << pin) & sio_hw->gpio_in)
|
||||
|
||||
// ADC RP2040-specific calls
|
||||
void analogReadResolution(int bits);
|
||||
float analogReadTemp(); // Returns core temp in Centigrade
|
||||
float analogReadTemp(float vref = 3.3); // Returns core temp in Centigrade
|
||||
|
||||
// PWM RP2040-specific calls
|
||||
void analogWriteFreq(uint32_t freq);
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
CoreMutex for the Raspberry Pi Pico RP2040
|
||||
|
||||
Implements a deadlock-safe multicore mutex for sharing things like the
|
||||
USB or UARTs.
|
||||
|
||||
Copyright (c) 2021 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 "CoreMutex.h"
|
||||
|
||||
CoreMutex::CoreMutex(mutex_t *mutex, uint8_t option) {
|
||||
_mutex = mutex;
|
||||
_acquired = false;
|
||||
_option = option;
|
||||
if (__isFreeRTOS) {
|
||||
auto m = __get_freertos_mutex_for_ptr(mutex);
|
||||
if (_option & FromISR) {
|
||||
__freertos_mutex_take_from_isr(m);
|
||||
} else {
|
||||
__freertos_mutex_take(m);
|
||||
}
|
||||
} else {
|
||||
uint32_t owner;
|
||||
if (!mutex_try_enter(_mutex, &owner)) {
|
||||
if (owner == get_core_num()) { // Deadlock!
|
||||
if (_option & DebugEnable) {
|
||||
DEBUGCORE("CoreMutex - Deadlock detected!\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
mutex_enter_blocking(_mutex);
|
||||
}
|
||||
}
|
||||
_acquired = true;
|
||||
}
|
||||
|
||||
CoreMutex::~CoreMutex() {
|
||||
if (_acquired) {
|
||||
if (__isFreeRTOS) {
|
||||
auto m = __get_freertos_mutex_for_ptr(_mutex);
|
||||
if (_option & FromISR) {
|
||||
__freertos_mutex_give_from_isr(m);
|
||||
} else {
|
||||
__freertos_mutex_give(m);
|
||||
}
|
||||
} else {
|
||||
mutex_exit(_mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,39 +26,15 @@
|
||||
#include "pico/mutex.h"
|
||||
#include "_freertos.h"
|
||||
|
||||
enum {
|
||||
DebugEnable = 1,
|
||||
FromISR = 1 << 1,
|
||||
};
|
||||
|
||||
class CoreMutex {
|
||||
public:
|
||||
CoreMutex(mutex_t *mutex, bool debugEnable = true) {
|
||||
_mutex = mutex;
|
||||
_acquired = false;
|
||||
if (__isFreeRTOS) {
|
||||
auto m = __get_freertos_mutex_for_ptr(mutex);
|
||||
__freertos_mutex_take(m);
|
||||
} else {
|
||||
uint32_t owner;
|
||||
if (!mutex_try_enter(_mutex, &owner)) {
|
||||
if (owner == get_core_num()) { // Deadlock!
|
||||
if (debugEnable) {
|
||||
DEBUGCORE("CoreMutex - Deadlock detected!\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
mutex_enter_blocking(_mutex);
|
||||
}
|
||||
}
|
||||
_acquired = true;
|
||||
}
|
||||
|
||||
~CoreMutex() {
|
||||
if (_acquired) {
|
||||
if (__isFreeRTOS) {
|
||||
auto m = __get_freertos_mutex_for_ptr(_mutex);
|
||||
__freertos_mutex_give(m);
|
||||
} else {
|
||||
mutex_exit(_mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
CoreMutex(mutex_t *mutex, uint8_t option = DebugEnable);
|
||||
~CoreMutex();
|
||||
|
||||
operator bool() {
|
||||
return _acquired;
|
||||
@@ -67,4 +43,5 @@ public:
|
||||
private:
|
||||
mutex_t *_mutex;
|
||||
bool _acquired;
|
||||
u_int8_t _option;
|
||||
};
|
||||
|
||||
+6
-7
@@ -192,13 +192,12 @@ File File::openNextFile() {
|
||||
String File::readString() {
|
||||
String ret;
|
||||
ret.reserve(size() - position());
|
||||
char temp[256 + 1];
|
||||
int countRead = readBytes(temp, sizeof(temp) - 1);
|
||||
while (countRead > 0) {
|
||||
temp[countRead] = 0;
|
||||
ret += temp;
|
||||
countRead = readBytes(temp, sizeof(temp) - 1);
|
||||
}
|
||||
uint8_t temp[256];
|
||||
int countRead;
|
||||
do {
|
||||
countRead = read(temp, sizeof(temp));
|
||||
ret.concat(temp, countRead);
|
||||
} while (countRead > 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
/*
|
||||
WiFiMutex.h - Ensure the timer-driven sys_check_timeouts doesn't
|
||||
get executed while we're in the user-level TCP stack.
|
||||
Copyright (c) 2022 Earle F. Philhower, III. All rights reserved.
|
||||
RP2040 utility class
|
||||
|
||||
Implements the API defined by the Arduino WiFiNINA library,
|
||||
copyright (c) 2018 Arduino SA. All rights reserved.
|
||||
Copyright (c) 2021 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
|
||||
@@ -21,21 +18,16 @@
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <Arduino.h>
|
||||
#include <hardware/structs/psm.h>
|
||||
|
||||
extern "C" volatile bool __inLWIP;
|
||||
extern "C" void boot_double_tap_check();
|
||||
|
||||
class LWIPMutex {
|
||||
public:
|
||||
LWIPMutex() {
|
||||
__inLWIP = true;
|
||||
_ref++;
|
||||
// The following check will never actually execute, but it will cause the boot reset
|
||||
// checker to be linked in as part of the constructors.
|
||||
|
||||
void RP2040::enableDoubleResetBootloader() {
|
||||
if (psm_hw->done == 0) {
|
||||
boot_double_tap_check();
|
||||
}
|
||||
~LWIPMutex() {
|
||||
if (0 == --_ref) {
|
||||
__inLWIP = false;
|
||||
}
|
||||
}
|
||||
private:
|
||||
static int _ref;
|
||||
};
|
||||
}
|
||||
@@ -314,6 +314,8 @@ public:
|
||||
reboot();
|
||||
}
|
||||
|
||||
static void enableDoubleResetBootloader();
|
||||
|
||||
void wdt_begin(uint32_t delay_ms) {
|
||||
watchdog_enable(delay_ms, 1);
|
||||
}
|
||||
@@ -323,7 +325,7 @@ public:
|
||||
}
|
||||
|
||||
const char *getChipID() {
|
||||
static char id[PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1] = { 0 };
|
||||
static char id[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1] = { 0 };
|
||||
if (!id[0]) {
|
||||
pico_get_unique_board_id_string(id, sizeof(id));
|
||||
}
|
||||
|
||||
@@ -68,9 +68,11 @@ static int __usb_task_irq;
|
||||
#define USBD_STR_SERIAL (0x03)
|
||||
#define USBD_STR_CDC (0x04)
|
||||
|
||||
|
||||
#define EPNUM_HID 0x83
|
||||
|
||||
#define USBD_MSC_EPOUT 0x03
|
||||
#define USBD_MSC_EPIN 0x84
|
||||
#define USBD_MSC_EPSIZE 64
|
||||
|
||||
const uint8_t *tud_descriptor_device_cb(void) {
|
||||
static tusb_desc_device_t usbd_desc_device = {
|
||||
@@ -89,7 +91,7 @@ const uint8_t *tud_descriptor_device_cb(void) {
|
||||
.iSerialNumber = USBD_STR_SERIAL,
|
||||
.bNumConfigurations = 1
|
||||
};
|
||||
if (__USBInstallSerial && !__USBInstallKeyboard && !__USBInstallMouse && !__USBInstallJoystick) {
|
||||
if (__USBInstallSerial && !__USBInstallKeyboard && !__USBInstallMouse && !__USBInstallJoystick && !__USBInstallMassStorage) {
|
||||
// Can use as-is, this is the default USB case
|
||||
return (const uint8_t *)&usbd_desc_device;
|
||||
}
|
||||
@@ -103,6 +105,9 @@ const uint8_t *tud_descriptor_device_cb(void) {
|
||||
if (__USBInstallJoystick) {
|
||||
usbd_desc_device.idProduct |= 0x0100;
|
||||
}
|
||||
if (__USBInstallMassStorage) {
|
||||
usbd_desc_device.idProduct ^= 0x2000;
|
||||
}
|
||||
// Set the device class to 0 to indicate multiple device classes
|
||||
usbd_desc_device.bDeviceClass = 0;
|
||||
usbd_desc_device.bDeviceSubClass = 0;
|
||||
@@ -223,7 +228,7 @@ void __SetupUSBDescriptor() {
|
||||
if (!usbd_desc_cfg) {
|
||||
bool hasHID = __USBInstallKeyboard || __USBInstallMouse || __USBInstallJoystick;
|
||||
|
||||
uint8_t interface_count = (__USBInstallSerial ? 2 : 0) + (hasHID ? 1 : 0);
|
||||
uint8_t interface_count = (__USBInstallSerial ? 2 : 0) + (hasHID ? 1 : 0) + (__USBInstallMassStorage ? 1 : 0);
|
||||
|
||||
uint8_t cdc_desc[TUD_CDC_DESC_LEN] = {
|
||||
// Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval
|
||||
@@ -238,7 +243,12 @@ void __SetupUSBDescriptor() {
|
||||
TUD_HID_DESCRIPTOR(hid_itf, 0, HID_ITF_PROTOCOL_NONE, hid_report_len, EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 10)
|
||||
};
|
||||
|
||||
int usbd_desc_len = TUD_CONFIG_DESC_LEN + (__USBInstallSerial ? sizeof(cdc_desc) : 0) + (hasHID ? sizeof(hid_desc) : 0);
|
||||
uint8_t msd_itf = interface_count - 1;
|
||||
uint8_t msd_desc[TUD_MSC_DESC_LEN] = {
|
||||
TUD_MSC_DESCRIPTOR(msd_itf, 0, USBD_MSC_EPOUT, USBD_MSC_EPIN, USBD_MSC_EPSIZE)
|
||||
};
|
||||
|
||||
int usbd_desc_len = TUD_CONFIG_DESC_LEN + (__USBInstallSerial ? sizeof(cdc_desc) : 0) + (hasHID ? sizeof(hid_desc) : 0) + (__USBInstallMassStorage ? sizeof(msd_desc) : 0);
|
||||
|
||||
uint8_t tud_cfg_desc[TUD_CONFIG_DESC_LEN] = {
|
||||
// Config number, interface count, string index, total length, attribute, power in mA
|
||||
@@ -260,6 +270,10 @@ void __SetupUSBDescriptor() {
|
||||
memcpy(ptr, hid_desc, sizeof(hid_desc));
|
||||
ptr += sizeof(hid_desc);
|
||||
}
|
||||
if (__USBInstallMassStorage) {
|
||||
memcpy(ptr, msd_desc, sizeof(msd_desc));
|
||||
ptr += sizeof(msd_desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -367,4 +381,55 @@ extern "C" void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_r
|
||||
(void) bufsize;
|
||||
}
|
||||
|
||||
extern "C" int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) __attribute__((weak));
|
||||
extern "C" int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) {
|
||||
(void) lun;
|
||||
(void) lba;
|
||||
(void) offset;
|
||||
(void) buffer;
|
||||
(void) bufsize;
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" bool tud_msc_test_unit_ready_cb(uint8_t lun) __attribute__((weak));
|
||||
extern "C" bool tud_msc_test_unit_ready_cb(uint8_t lun) {
|
||||
(void) lun;
|
||||
return false;
|
||||
}
|
||||
|
||||
extern "C" int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) __attribute__((weak));
|
||||
extern "C" int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) {
|
||||
(void) lun;
|
||||
(void) lba;
|
||||
(void) offset;
|
||||
(void) buffer;
|
||||
(void) bufsize;
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) __attribute__((weak));
|
||||
extern "C" int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) {
|
||||
(void) lun;
|
||||
(void) scsi_cmd;
|
||||
(void) buffer;
|
||||
(void) bufsize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) __attribute__((weak));
|
||||
extern "C" void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) {
|
||||
(void) lun;
|
||||
*block_count = 0;
|
||||
*block_size = 0;
|
||||
}
|
||||
|
||||
extern "C" void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) __attribute__((weak));
|
||||
extern "C" void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) {
|
||||
(void) lun;
|
||||
vendor_id[0] = 0;
|
||||
product_id[0] = 0;
|
||||
product_rev[0] = 0;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -26,6 +26,7 @@ extern void __USBInstallSerial() __attribute__((weak));
|
||||
extern void __USBInstallKeyboard() __attribute__((weak));
|
||||
extern void __USBInstallJoystick() __attribute__((weak));
|
||||
extern void __USBInstallMouse() __attribute__((weak));
|
||||
extern void __USBInstallMassStorage() __attribute__((weak));
|
||||
|
||||
// Big, global USB mutex, shared with all USB devices to make sure we don't
|
||||
// have multiple cores updating the TUSB state in parallel
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#define ARDUINO_PICO_MAJOR 2
|
||||
#define ARDUINO_PICO_MINOR 5
|
||||
#define ARDUINO_PICO_REVISION 3
|
||||
#define ARDUINO_PICO_VERSION_STR "2.5.3"
|
||||
#define ARDUINO_PICO_MINOR 7
|
||||
#define ARDUINO_PICO_REVISION 0
|
||||
#define ARDUINO_PICO_VERSION_STR "2.7.0"
|
||||
|
||||
@@ -230,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) - 5 /* insns in PIO halfbit loop */);
|
||||
pio_sm_put_blocking(_rxPIO, _rxSM, clock_get_hz(clk_sys) / (_baud * 2) - 7 /* 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
|
||||
@@ -259,9 +259,11 @@ void SerialPIO::end() {
|
||||
}
|
||||
if (_tx != NOPIN) {
|
||||
pio_sm_set_enabled(_txPIO, _txSM, false);
|
||||
pio_sm_unclaim(_txPIO, _txSM);
|
||||
}
|
||||
if (_rx != NOPIN) {
|
||||
pio_sm_set_enabled(_rxPIO, _rxSM, false);
|
||||
pio_sm_unclaim(_rxPIO, _rxSM);
|
||||
_pioSP[pio_get_index(_rxPIO)][_rxSM] = nullptr;
|
||||
// If no more active, disable the IRQ
|
||||
auto pioNum = pio_get_index(_rxPIO);
|
||||
|
||||
@@ -69,7 +69,7 @@ bool SerialUART::setRTS(pin_size_t pin) {
|
||||
constexpr uint32_t valid[2] = { __bitset({3, 15, 19}) /* UART0 */,
|
||||
__bitset({7, 11, 23, 27}) /* UART1 */
|
||||
};
|
||||
if ((!_running) && ((1 << pin) & valid[uart_get_index(_uart)])) {
|
||||
if ((!_running) && ((pin == UART_PIN_NOT_DEFINED) || ((1 << pin) & valid[uart_get_index(_uart)]))) {
|
||||
_rts = pin;
|
||||
return true;
|
||||
}
|
||||
@@ -86,7 +86,7 @@ bool SerialUART::setCTS(pin_size_t pin) {
|
||||
constexpr uint32_t valid[2] = { __bitset({2, 14, 18}) /* UART0 */,
|
||||
__bitset({6, 10, 22, 26}) /* UART1 */
|
||||
};
|
||||
if ((!_running) && ((1 << pin) & valid[uart_get_index(_uart)])) {
|
||||
if ((!_running) && ((pin == UART_PIN_NOT_DEFINED) || ((1 << pin) & valid[uart_get_index(_uart)]))) {
|
||||
_cts = pin;
|
||||
return true;
|
||||
}
|
||||
@@ -390,7 +390,12 @@ void __not_in_flash_func(SerialUART::_handleIRQ)(bool inIRQ) {
|
||||
// ICR is write-to-clear
|
||||
uart_get_hw(_uart)->icr = UART_UARTICR_RTIC_BITS | UART_UARTICR_RXIC_BITS;
|
||||
while (uart_is_readable(_uart)) {
|
||||
auto val = uart_getc(_uart);
|
||||
uint32_t raw = uart_get_hw(_uart)->dr;
|
||||
if (raw & 0x700) {
|
||||
// Framing, Parity, or Break. Ignore this bad char
|
||||
continue;
|
||||
}
|
||||
uint8_t val = raw & 0xff;
|
||||
auto next_writer = _writer + 1;
|
||||
if (next_writer == _fifoSize) {
|
||||
next_writer = 0;
|
||||
|
||||
+13
-3
@@ -28,6 +28,7 @@ typedef struct {
|
||||
pin_size_t pin;
|
||||
PIO pio;
|
||||
int sm;
|
||||
int off;
|
||||
alarm_id_t alarm;
|
||||
} Tone;
|
||||
|
||||
@@ -38,10 +39,18 @@ auto_init_mutex(_toneMutex);
|
||||
static PIOProgram _tone2Pgm(&tone2_program);
|
||||
static std::map<pin_size_t, Tone *> _toneMap;
|
||||
|
||||
static inline bool pio_sm_get_enabled(PIO pio, uint sm) {
|
||||
check_pio_param(pio);
|
||||
check_sm_param(sm);
|
||||
return (pio->ctrl & ~(1u << sm)) & (1 << sm);
|
||||
}
|
||||
|
||||
int64_t _stopTonePIO(alarm_id_t id, void *user_data) {
|
||||
(void) id;
|
||||
Tone *tone = (Tone *)user_data;
|
||||
tone->alarm = 0;
|
||||
digitalWrite(tone->pin, LOW);
|
||||
pinMode(tone->pin, OUTPUT);
|
||||
pio_sm_set_enabled(tone->pio, tone->sm, false);
|
||||
return 0;
|
||||
}
|
||||
@@ -72,14 +81,12 @@ void tone(uint8_t pin, unsigned int frequency, unsigned long duration) {
|
||||
newTone = new Tone();
|
||||
newTone->pin = pin;
|
||||
pinMode(pin, OUTPUT);
|
||||
int off;
|
||||
if (!_tone2Pgm.prepare(&newTone->pio, &newTone->sm, &off)) {
|
||||
if (!_tone2Pgm.prepare(&newTone->pio, &newTone->sm, &newTone->off)) {
|
||||
DEBUGCORE("ERROR: tone unable to start, out of PIO resources\n");
|
||||
// ERROR, no free slots
|
||||
delete newTone;
|
||||
return;
|
||||
}
|
||||
tone2_program_init(newTone->pio, newTone->sm, off, pin);
|
||||
newTone->alarm = 0;
|
||||
} else {
|
||||
newTone = entry->second;
|
||||
@@ -88,6 +95,9 @@ void tone(uint8_t pin, unsigned int frequency, unsigned long duration) {
|
||||
newTone->alarm = 0;
|
||||
}
|
||||
}
|
||||
if (!pio_sm_get_enabled(newTone->pio, newTone->sm)) {
|
||||
tone2_program_init(newTone->pio, newTone->sm, newTone->off, pin);
|
||||
}
|
||||
pio_sm_clear_fifos(newTone->pio, newTone->sm); // Remove any old updates that haven't yet taken effect
|
||||
pio_sm_put_blocking(newTone->pio, newTone->sm, RP2040::usToPIOCycles(us));
|
||||
pio_sm_set_enabled(newTone->pio, newTone->sm, true);
|
||||
|
||||
@@ -38,10 +38,15 @@ extern "C" SemaphoreHandle_t __get_freertos_mutex_for_ptr(mutex_t *m) {
|
||||
return _map[i].dst;
|
||||
}
|
||||
}
|
||||
// Make a new mutex
|
||||
auto fm = __freertos_mutex_create();
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (_map[i].src == nullptr) {
|
||||
// Make a new mutex
|
||||
SemaphoreHandle_t fm = __freertos_mutex_create();
|
||||
if (fm == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
_map[i].src = m;
|
||||
_map[i].dst = fm;
|
||||
return fm;
|
||||
|
||||
@@ -41,8 +41,10 @@ extern "C" {
|
||||
extern SemaphoreHandle_t _freertos_recursive_mutex_create() __attribute__((weak));
|
||||
|
||||
extern void __freertos_mutex_take(SemaphoreHandle_t mtx) __attribute__((weak));
|
||||
extern void __freertos_mutex_take_from_isr(SemaphoreHandle_t mtx) __attribute__((weak));
|
||||
extern int __freertos_mutex_try_take(SemaphoreHandle_t mtx) __attribute__((weak));
|
||||
extern void __freertos_mutex_give(SemaphoreHandle_t mtx) __attribute__((weak));
|
||||
extern void __freertos_mutex_give_from_isr(SemaphoreHandle_t mtx) __attribute__((weak));
|
||||
|
||||
extern void __freertos_recursive_mutex_take(SemaphoreHandle_t mtx) __attribute__((weak));
|
||||
extern int __freertos_recursive_mutex_try_take(SemaphoreHandle_t mtx) __attribute__((weak));
|
||||
|
||||
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
LWIP wrappers to protect against timer-based re-entrancy
|
||||
|
||||
Copyright (c) 202s 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 "lwip/pbuf.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/tcp.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "lwip/raw.h"
|
||||
#include "lwip/timeouts.h"
|
||||
|
||||
// Global indicator that we're inside an LWIP block
|
||||
extern "C" {
|
||||
volatile bool __inLWIP = false;
|
||||
}
|
||||
|
||||
auto_init_recursive_mutex(__mtxLWIP);
|
||||
|
||||
class LWIPMutex {
|
||||
public:
|
||||
LWIPMutex() {
|
||||
noInterrupts();
|
||||
recursive_mutex_enter_blocking(&__mtxLWIP);
|
||||
__inLWIP = true;
|
||||
_ref++;
|
||||
interrupts();
|
||||
}
|
||||
|
||||
~LWIPMutex() {
|
||||
noInterrupts();
|
||||
if (0 == --_ref) {
|
||||
__inLWIP = false;
|
||||
}
|
||||
recursive_mutex_exit(&__mtxLWIP);
|
||||
interrupts();
|
||||
}
|
||||
|
||||
private:
|
||||
static int _ref;
|
||||
};
|
||||
int LWIPMutex::_ref = 0;
|
||||
|
||||
|
||||
extern "C" {
|
||||
|
||||
extern u8_t __real_pbuf_header(struct pbuf *p, s16_t header_size);
|
||||
u8_t __wrap_pbuf_header(struct pbuf *p, s16_t header_size) {
|
||||
LWIPMutex m;
|
||||
return __real_pbuf_header(p, header_size);
|
||||
}
|
||||
|
||||
extern u8_t __real_pbuf_free(struct pbuf *p);
|
||||
u8_t __wrap_pbuf_free(struct pbuf *p) {
|
||||
LWIPMutex m;
|
||||
return __real_pbuf_free(p);
|
||||
}
|
||||
|
||||
extern struct pbuf *__real_pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type);
|
||||
struct pbuf *__wrap_pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type) {
|
||||
LWIPMutex m;
|
||||
return __real_pbuf_alloc(l, length, type);
|
||||
}
|
||||
|
||||
extern err_t __real_pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len);
|
||||
err_t __wrap_pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len) {
|
||||
LWIPMutex m;
|
||||
return __real_pbuf_take(buf, dataptr, len);
|
||||
}
|
||||
|
||||
extern u16_t __real_pbuf_copy_partial(const struct pbuf *p, void *dataptr, u16_t len, u16_t offset);
|
||||
u16_t __wrap_pbuf_copy_partial(const struct pbuf *p, void *dataptr, u16_t len, u16_t offset) {
|
||||
LWIPMutex m;
|
||||
return __real_pbuf_copy_partial(p, dataptr, len, offset);
|
||||
}
|
||||
|
||||
extern void __real_pbuf_ref(struct pbuf *p);
|
||||
void __wrap_pbuf_ref(struct pbuf *p) {
|
||||
LWIPMutex m;
|
||||
__real_pbuf_ref(p);
|
||||
}
|
||||
|
||||
extern u8_t __real_pbuf_get_at(const struct pbuf* p, u16_t offset);
|
||||
u8_t __wrap_pbuf_get_at(const struct pbuf* p, u16_t offset) {
|
||||
LWIPMutex m;
|
||||
return __real_pbuf_get_at(p, offset);
|
||||
}
|
||||
|
||||
extern void *__real_pbuf_get_contiguous(const struct pbuf *p, void *buffer, size_t bufsize, u16_t len, u16_t offset);
|
||||
void *__wrap_pbuf_get_contiguous(const struct pbuf *p, void *buffer, size_t bufsize, u16_t len, u16_t offset) {
|
||||
LWIPMutex m;
|
||||
return __real_pbuf_get_contiguous(p, buffer, bufsize, len, offset);
|
||||
}
|
||||
|
||||
extern void __real_pbuf_cat(struct pbuf *head, struct pbuf *tail);
|
||||
void __wrap_pbuf_cat(struct pbuf *head, struct pbuf *tail) {
|
||||
LWIPMutex m;
|
||||
__real_pbuf_cat(head, tail);
|
||||
}
|
||||
|
||||
extern void __real_tcp_arg(struct tcp_pcb *pcb, void *arg);
|
||||
void __wrap_tcp_arg(struct tcp_pcb *pcb, void *arg) {
|
||||
LWIPMutex m;
|
||||
__real_tcp_arg(pcb, arg);
|
||||
}
|
||||
|
||||
extern struct tcp_pcb *__real_tcp_new(void);
|
||||
struct tcp_pcb *__wrap_tcp_new(void) {
|
||||
LWIPMutex m;
|
||||
return __real_tcp_new();
|
||||
}
|
||||
|
||||
extern err_t __real_tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port);
|
||||
err_t __wrap_tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) {
|
||||
LWIPMutex m;
|
||||
return __real_tcp_bind(pcb, ipaddr, port);
|
||||
}
|
||||
|
||||
extern struct tcp_pcb *__real_tcp_listen(struct tcp_pcb *pcb);
|
||||
struct tcp_pcb *__wrap_tcp_listen(struct tcp_pcb *pcb) {
|
||||
LWIPMutex m;
|
||||
return __real_tcp_listen(pcb);
|
||||
}
|
||||
|
||||
extern struct tcp_pcb *__real_tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog);
|
||||
struct tcp_pcb *__wrap_tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) {
|
||||
LWIPMutex m;
|
||||
return __real_tcp_listen_with_backlog(pcb, backlog);
|
||||
}
|
||||
|
||||
extern void __real_tcp_accept(struct tcp_pcb *pcb, err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err));
|
||||
void __wrap_tcp_accept(struct tcp_pcb *pcb, err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err)) {
|
||||
LWIPMutex m;
|
||||
__real_tcp_accept(pcb, accept);
|
||||
}
|
||||
|
||||
extern err_t __real_tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port, err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err));
|
||||
err_t __wrap_tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port, err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err)) {
|
||||
LWIPMutex m;
|
||||
return __real_tcp_connect(pcb, ipaddr, port, connected);
|
||||
}
|
||||
|
||||
extern err_t __real_tcp_write(struct tcp_pcb *pcb, const void *dataptr, u16_t len, u8_t apiflags);
|
||||
err_t __wrap_tcp_write(struct tcp_pcb *pcb, const void *dataptr, u16_t len, u8_t apiflags) {
|
||||
LWIPMutex m;
|
||||
return __real_tcp_write(pcb, dataptr, len, apiflags);
|
||||
}
|
||||
|
||||
extern void __real_tcp_sent(struct tcp_pcb *pcb, err_t (* sent)(void *arg, struct tcp_pcb *tpcb, u16_t len));
|
||||
void __wrap_tcp_sent(struct tcp_pcb *pcb, err_t (* sent)(void *arg, struct tcp_pcb *tpcb, u16_t len)) {
|
||||
LWIPMutex m;
|
||||
__real_tcp_sent(pcb, sent);
|
||||
}
|
||||
|
||||
extern void __real_tcp_recv(struct tcp_pcb *pcb, err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err));
|
||||
void __wrap_tcp_recv(struct tcp_pcb *pcb, err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)) {
|
||||
LWIPMutex m;
|
||||
__real_tcp_recv(pcb, recv);
|
||||
}
|
||||
|
||||
extern void __real_tcp_recved(struct tcp_pcb *pcb, u16_t len);
|
||||
void __wrap_tcp_recved(struct tcp_pcb *pcb, u16_t len) {
|
||||
LWIPMutex m;
|
||||
__real_tcp_recved(pcb, len);
|
||||
}
|
||||
|
||||
extern void __real_tcp_poll(struct tcp_pcb *pcb, err_t (* poll)(void *arg, struct tcp_pcb *tpcb), u8_t interval);
|
||||
void __wrap_tcp_poll(struct tcp_pcb *pcb, err_t (* poll)(void *arg, struct tcp_pcb *tpcb), u8_t interval) {
|
||||
LWIPMutex m;
|
||||
__real_tcp_poll(pcb, poll, interval);
|
||||
}
|
||||
|
||||
extern err_t __real_tcp_close(struct tcp_pcb *pcb);
|
||||
err_t __wrap_tcp_close(struct tcp_pcb *pcb) {
|
||||
LWIPMutex m;
|
||||
return __real_tcp_close(pcb);
|
||||
}
|
||||
|
||||
extern void __real_tcp_abort(struct tcp_pcb *pcb);
|
||||
void __wrap_tcp_abort(struct tcp_pcb *pcb) {
|
||||
LWIPMutex m;
|
||||
__real_tcp_abort(pcb);
|
||||
}
|
||||
|
||||
extern void __real_tcp_err(struct tcp_pcb *pcb, void (* err)(void *arg, err_t err));
|
||||
void __wrap_tcp_err(struct tcp_pcb *pcb, void (* err)(void *arg, err_t err)) {
|
||||
LWIPMutex m;
|
||||
__real_tcp_err(pcb, err);
|
||||
}
|
||||
|
||||
extern err_t __real_tcp_output(struct tcp_pcb *pcb);
|
||||
err_t __wrap_tcp_output(struct tcp_pcb *pcb) {
|
||||
LWIPMutex m;
|
||||
return __real_tcp_output(pcb);
|
||||
}
|
||||
|
||||
extern void __real_tcp_setprio(struct tcp_pcb *pcb, u8_t prio);
|
||||
void __wrap_tcp_setprio(struct tcp_pcb *pcb, u8_t prio) {
|
||||
LWIPMutex m;
|
||||
return __real_tcp_setprio(pcb, prio);
|
||||
}
|
||||
|
||||
extern void __real_tcp_backlog_delayed(struct tcp_pcb* pcb);
|
||||
void __wrap_tcp_backlog_delayed(struct tcp_pcb* pcb) {
|
||||
LWIPMutex m;
|
||||
return __real_tcp_backlog_delayed(pcb);
|
||||
}
|
||||
|
||||
extern void __real_tcp_backlog_accepted(struct tcp_pcb* pcb);
|
||||
void __wrap_tcp_backlog_accepted(struct tcp_pcb* pcb) {
|
||||
LWIPMutex m;
|
||||
return __real_tcp_backlog_accepted(pcb);
|
||||
}
|
||||
extern struct udp_pcb *__real_udp_new(void);
|
||||
struct udp_pcb *__wrap_udp_new(void) {
|
||||
LWIPMutex m;
|
||||
return __real_udp_new();
|
||||
}
|
||||
|
||||
extern void __real_udp_remove(struct udp_pcb *pcb);
|
||||
void __wrap_udp_remove(struct udp_pcb *pcb) {
|
||||
LWIPMutex m;
|
||||
__real_udp_remove(pcb);
|
||||
}
|
||||
|
||||
extern err_t __real_udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port);
|
||||
err_t __wrap_udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) {
|
||||
LWIPMutex m;
|
||||
return __real_udp_bind(pcb, ipaddr, port);
|
||||
}
|
||||
|
||||
extern err_t __real_udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port);
|
||||
err_t __wrap_udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) {
|
||||
LWIPMutex m;
|
||||
return __real_udp_connect(pcb, ipaddr, port);
|
||||
}
|
||||
|
||||
extern err_t __real_udp_disconnect(struct udp_pcb *pcb);
|
||||
err_t __wrap_udp_disconnect(struct udp_pcb *pcb) {
|
||||
LWIPMutex m;
|
||||
return __real_udp_disconnect(pcb);
|
||||
}
|
||||
|
||||
extern err_t __real_udp_send(struct udp_pcb *pcb, struct pbuf *p);
|
||||
err_t __wrap_udp_send(struct udp_pcb *pcb, struct pbuf *p) {
|
||||
LWIPMutex m;
|
||||
return __real_udp_send(pcb, p);
|
||||
}
|
||||
|
||||
extern void __real_udp_recv(struct udp_pcb *pcb, void (* recv)(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, u16_t port), void *recv_arg);
|
||||
void __wrap_udp_recv(struct udp_pcb *pcb, void (* recv)(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, u16_t port), void *recv_arg) {
|
||||
LWIPMutex m;
|
||||
__real_udp_recv(pcb, recv, recv_arg);
|
||||
}
|
||||
|
||||
extern err_t __real_udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif);
|
||||
err_t __wrap_udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif) {
|
||||
LWIPMutex m;
|
||||
return __real_udp_sendto_if(pcb, p, dst_ip, dst_port, netif);
|
||||
}
|
||||
|
||||
extern void __real_sys_check_timeouts(void);
|
||||
void __wrap_sys_check_timeouts(void) {
|
||||
LWIPMutex m;
|
||||
__real_sys_check_timeouts();
|
||||
}
|
||||
|
||||
extern err_t __real_dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found, void *callback_arg);
|
||||
err_t __wrap_dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found, void *callback_arg) {
|
||||
LWIPMutex m;
|
||||
return __real_dns_gethostbyname(hostname, addr, found, callback_arg);
|
||||
}
|
||||
|
||||
extern err_t __real_dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_callback found, void *callback_arg, u8_t dns_addrtype);
|
||||
err_t __wrap_dns_gethostbyname_addrtype(const char *hostname, ip_addr_t *addr, dns_found_callback found, void *callback_arg, u8_t dns_addrtype) {
|
||||
LWIPMutex m;
|
||||
return __real_dns_gethostbyname_addrtype(hostname, addr, found, callback_arg, dns_addrtype);
|
||||
}
|
||||
|
||||
extern struct raw_pcb *__real_raw_new(u8_t proto);
|
||||
struct raw_pcb *__wrap_raw_new(u8_t proto) {
|
||||
LWIPMutex m;
|
||||
return __real_raw_new(proto);
|
||||
}
|
||||
|
||||
extern void __real_raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg);
|
||||
void __wrap_raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg) {
|
||||
LWIPMutex m;
|
||||
__real_raw_recv(pcb, recv, recv_arg);
|
||||
}
|
||||
|
||||
extern err_t __real_raw_bind(struct raw_pcb *pcb, const ip_addr_t *ipaddr);
|
||||
err_t __wrap_raw_bind(struct raw_pcb *pcb, const ip_addr_t *ipaddr) {
|
||||
LWIPMutex m;
|
||||
return __real_raw_bind(pcb, ipaddr);
|
||||
}
|
||||
|
||||
extern err_t __real_raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr);
|
||||
err_t __wrap_raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr) {
|
||||
LWIPMutex m;
|
||||
return __real_raw_sendto(pcb, p, ipaddr);
|
||||
}
|
||||
|
||||
extern void __real_raw_remove(struct raw_pcb *pcb);
|
||||
void __wrap_raw_remove(struct raw_pcb *pcb) {
|
||||
LWIPMutex m;
|
||||
__real_raw_remove(pcb);
|
||||
}
|
||||
|
||||
}; // extern "C"
|
||||
@@ -22,7 +22,6 @@
|
||||
#include "RP2040USB.h"
|
||||
#include <pico/stdlib.h>
|
||||
#include <pico/multicore.h>
|
||||
#include "LWIPMutex.h"
|
||||
#include <reent.h>
|
||||
|
||||
RP2040 rp2040;
|
||||
@@ -33,8 +32,6 @@ extern "C" {
|
||||
|
||||
mutex_t _pioMutex;
|
||||
|
||||
int LWIPMutex::_ref = 0;
|
||||
|
||||
extern void setup();
|
||||
extern void loop();
|
||||
|
||||
@@ -128,7 +125,6 @@ extern "C" int main() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef NO_USB
|
||||
if (!__isFreeRTOS) {
|
||||
if (setup1 || loop1) {
|
||||
rp2040.fifo.begin(2);
|
||||
@@ -137,7 +133,6 @@ extern "C" int main() {
|
||||
}
|
||||
rp2040.fifo.registerCore();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!__isFreeRTOS) {
|
||||
if (setup1 || loop1) {
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
Malloc/etc. interrupt locking wrappers
|
||||
|
||||
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>
|
||||
|
||||
extern "C" void *__real_malloc(size_t size);
|
||||
extern "C" void *__real_calloc(size_t count, size_t size);
|
||||
extern "C" void *__real_realloc(void *mem, size_t size);
|
||||
extern "C" void __real_free(void *mem);
|
||||
|
||||
extern "C" void *__wrap_malloc(size_t size) {
|
||||
noInterrupts();
|
||||
void *rc = __real_malloc(size);
|
||||
interrupts();
|
||||
return rc;
|
||||
}
|
||||
|
||||
extern "C" void *__wrap_calloc(size_t count, size_t size) {
|
||||
noInterrupts();
|
||||
void *rc = __real_calloc(count, size);
|
||||
interrupts();
|
||||
return rc;
|
||||
}
|
||||
|
||||
extern "C" void *__wrap_realloc(void *mem, size_t size) {
|
||||
noInterrupts();
|
||||
void *rc = __real_realloc(mem, size);
|
||||
interrupts();
|
||||
return rc;
|
||||
}
|
||||
|
||||
extern "C" void __wrap_free(void *mem) {
|
||||
noInterrupts();
|
||||
__real_free(mem);
|
||||
interrupts();
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
// Taken from the Pico-SDK v1.4.0 and hacked by EFP3 to allow overriding the LWIP setup
|
||||
|
||||
#include <stdio.h>
|
||||
//#include <stdio.h>
|
||||
|
||||
#include "pico/cyw43_arch.h"
|
||||
#include "pico/mutex.h"
|
||||
@@ -36,7 +36,7 @@
|
||||
#define CYW43_WL_GPIO_LED_PIN 0
|
||||
#endif
|
||||
|
||||
volatile bool __inLWIP = false;
|
||||
extern volatile bool __inLWIP;
|
||||
|
||||
// note same code
|
||||
#if PICO_CYW43_ARCH_THREADSAFE_BACKGROUND
|
||||
@@ -145,7 +145,7 @@ static void gpio_irq_handler(void) {
|
||||
static void low_priority_irq_handler(void) {
|
||||
assert(cyw43_core_num == get_core_num());
|
||||
if (recursive_mutex_try_enter(&cyw43_mutex, NULL)) {
|
||||
if (recursive_mutex_enter_count(&cyw43_mutex) != 1) {
|
||||
if (__inLWIP || (recursive_mutex_enter_count(&cyw43_mutex) != 1)) {
|
||||
low_priority_irq_missed = true;
|
||||
CYW43_STAT_INC(PENDSV_DISABLED_COUNT);
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
|
||||
|
||||
Hacked by EFP3 to allow disabling unless requested
|
||||
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "pico.h"
|
||||
#include "pico/time.h"
|
||||
#include "pico/bootrom.h"
|
||||
#include "pico/binary_info.h"
|
||||
|
||||
// PICO_CONFIG: PICO_BOOTSEL_VIA_DOUBLE_RESET_TIMEOUT_MS, Window of opportunity for a second press of a reset button to enter BOOTSEL mode (milliseconds), type=int, default=200, group=pico_bootsel_via_double_reset
|
||||
#ifndef PICO_BOOTSEL_VIA_DOUBLE_RESET_TIMEOUT_MS
|
||||
#define PICO_BOOTSEL_VIA_DOUBLE_RESET_TIMEOUT_MS 350
|
||||
#endif
|
||||
|
||||
// PICO_CONFIG: PICO_BOOTSEL_VIA_DOUBLE_RESET_ACTIVITY_LED, Optionally define a pin to use as bootloader activity LED when BOOTSEL mode is entered via reset double tap, type=int, min=0, max=29, group=pico_bootsel_via_double_reset
|
||||
|
||||
// PICO_CONFIG: PICO_BOOTSEL_VIA_DOUBLE_RESET_INTERFACE_DISABLE_MASK, Optionally disable either the mass storage interface (bit 0) or the PICOBOOT interface (bit 1) when entering BOOTSEL mode via double reset, type=int, min=0, max=3, default=0, group=pico_bootsel_via_double_reset
|
||||
#ifndef PICO_BOOTSEL_VIA_DOUBLE_RESET_INTERFACE_DISABLE_MASK
|
||||
#define PICO_BOOTSEL_VIA_DOUBLE_RESET_INTERFACE_DISABLE_MASK 0u
|
||||
#endif
|
||||
|
||||
/** \defgroup pico_bootsel_via_double_reset pico_bootsel_via_double_reset
|
||||
|
||||
When the 'pico_bootsel_via_double_reset' library is linked, a function is
|
||||
injected before main() which will detect when the system has been reset
|
||||
twice in quick succession, and enter the USB ROM bootloader (BOOTSEL mode)
|
||||
when this happens. This allows a double tap of a reset button on a
|
||||
development board to be used to enter the ROM bootloader, provided this
|
||||
library is always linked.
|
||||
*/
|
||||
|
||||
#if !PICO_NO_BI_BOOTSEL_VIA_DOUBLE_RESET
|
||||
bi_decl(bi_program_feature("double reset -> BOOTSEL"));
|
||||
#endif
|
||||
|
||||
// Doesn't make any sense for a RAM only binary
|
||||
#if !PICO_NO_FLASH
|
||||
static const uint32_t magic_token[] = {
|
||||
0xf01681de, 0xbd729b29, 0xd359be7a,
|
||||
};
|
||||
|
||||
// Place our marker on the 2nd core's stack...which will not have been touched when this code is executing
|
||||
static uint32_t *magic_location = (uint32_t*)0x20040000;
|
||||
//static uint32_t __uninitialized_ram(magic_location)[count_of(magic_token)];
|
||||
|
||||
/* Check for double reset and enter BOOTSEL mode if detected
|
||||
|
||||
This function is registered to run automatically before main(). The
|
||||
algorithm is:
|
||||
|
||||
1. Check for magic token in memory; enter BOOTSEL mode if found.
|
||||
2. Initialise that memory with that magic token.
|
||||
3. Do nothing for a short while (few hundred ms).
|
||||
4. Clear the magic token.
|
||||
5. Continue with normal boot.
|
||||
|
||||
Resetting the device twice quickly will interrupt step 3, leaving the token
|
||||
in place so that the second boot will go to the bootloader.
|
||||
*/
|
||||
|
||||
/*static*/ void __attribute__((constructor)) boot_double_tap_check(void) {
|
||||
for (uint i = 0; i < count_of(magic_token); i++) {
|
||||
if (magic_location[i] != magic_token[i]) {
|
||||
// Arm, wait, then disarm and continue booting
|
||||
for (i = 0; i < count_of(magic_token); i++) {
|
||||
magic_location[i] = magic_token[i];
|
||||
}
|
||||
busy_wait_us(PICO_BOOTSEL_VIA_DOUBLE_RESET_TIMEOUT_MS * 1000);
|
||||
magic_location[0] = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Detected a double reset, so enter USB bootloader
|
||||
magic_location[0] = 0;
|
||||
#ifdef PICO_BOOTSEL_VIA_DOUBLE_RESET_ACTIVITY_LED
|
||||
const uint32_t led_mask = 1u << PICO_BOOTSEL_VIA_DOUBLE_RESET_ACTIVITY_LED;
|
||||
#else
|
||||
const uint32_t led_mask = 0u;
|
||||
#endif
|
||||
reset_usb_boot(
|
||||
led_mask,
|
||||
PICO_BOOTSEL_VIA_DOUBLE_RESET_INTERFACE_DISABLE_MASK
|
||||
);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -26,9 +26,12 @@
|
||||
#include <hardware/pll.h>
|
||||
#include <hardware/adc.h>
|
||||
|
||||
void __clearADCPin(pin_size_t p);
|
||||
|
||||
static uint32_t analogScale = 255;
|
||||
static uint32_t analogFreq = 1000;
|
||||
static bool pwmInitted = false;
|
||||
static uint32_t pwmInitted = 0;
|
||||
static bool scaleInitted = false;
|
||||
static bool adcInitted = false;
|
||||
static uint16_t analogWritePseudoScale = 1;
|
||||
static uint16_t analogWriteSlowScale = 1;
|
||||
@@ -42,29 +45,31 @@ extern "C" void analogWriteFreq(uint32_t freq) {
|
||||
if (freq < 100) {
|
||||
DEBUGCORE("ERROR: analogWriteFreq too low (%d)\n", freq);
|
||||
analogFreq = 100;
|
||||
} else if (freq > 1'000'000) {
|
||||
} else if (freq > 10'000'000) {
|
||||
DEBUGCORE("ERROR: analogWriteFreq too high (%d)\n", freq);
|
||||
analogFreq = 1'000'000;
|
||||
analogFreq = 10'000'000;
|
||||
} else {
|
||||
analogFreq = freq;
|
||||
}
|
||||
pwmInitted = false;
|
||||
pwmInitted = 0;
|
||||
scaleInitted = false;
|
||||
}
|
||||
|
||||
extern "C" void analogWriteRange(uint32_t range) {
|
||||
if (range == analogScale) {
|
||||
return;
|
||||
}
|
||||
if ((range >= 15) && (range <= 65535)) {
|
||||
if ((range >= 3) && (range <= 65535)) {
|
||||
analogScale = range;
|
||||
pwmInitted = false;
|
||||
pwmInitted = 0;
|
||||
scaleInitted = false;
|
||||
} else {
|
||||
DEBUGCORE("ERROR: analogWriteRange out of range (%d)\n", range);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void analogWriteResolution(int res) {
|
||||
if ((res >= 4) && (res <= 16)) {
|
||||
if ((res >= 2) && (res <= 16)) {
|
||||
analogWriteRange((1 << res) - 1);
|
||||
} else {
|
||||
DEBUGCORE("ERROR: analogWriteResolution out of range (%d)\n", res);
|
||||
@@ -78,29 +83,30 @@ extern "C" void analogWrite(pin_size_t pin, int val) {
|
||||
DEBUGCORE("ERROR: Illegal analogWrite pin (%d)\n", pin);
|
||||
return;
|
||||
}
|
||||
if (!pwmInitted) {
|
||||
__clearADCPin(pin);
|
||||
if (!scaleInitted) {
|
||||
// For low frequencies, we need to scale the output max value up to achieve lower periods
|
||||
analogWritePseudoScale = 1;
|
||||
while (((clock_get_hz(clk_sys) / (float)(analogScale * analogFreq)) > 255.0) && (analogScale < 32678)) {
|
||||
while (((clock_get_hz(clk_sys) / ((float)analogScale * analogFreq)) > 255.0) && (analogScale < 32678)) {
|
||||
analogWritePseudoScale++;
|
||||
analogScale *= 2;
|
||||
DEBUGCORE("Adjusting analogWrite values PS=%d, scale=%d\n", analogWritePseudoScale, analogScale);
|
||||
}
|
||||
// For high frequencies, we need to scale the output max value down to actually hit the frequency target
|
||||
analogWriteSlowScale = 1;
|
||||
while (((clock_get_hz(clk_sys) / (float)(analogScale * analogFreq)) < 2.0) && (analogScale > 32)) {
|
||||
while (((clock_get_hz(clk_sys) / ((float)analogScale * analogFreq)) < 1.0) && (analogScale >= 6)) {
|
||||
analogWriteSlowScale++;
|
||||
analogScale /= 2;
|
||||
DEBUGCORE("Adjusting analogWrite values SS=%d, scale=%d\n", analogWriteSlowScale, analogScale);
|
||||
}
|
||||
|
||||
scaleInitted = true;
|
||||
}
|
||||
if (!(pwmInitted & (1 << pwm_gpio_to_slice_num(pin)))) {
|
||||
pwm_config c = pwm_get_default_config();
|
||||
pwm_config_set_clkdiv(&c, clock_get_hz(clk_sys) / (float)(analogScale * analogFreq));
|
||||
pwm_config_set_wrap(&c, analogScale);
|
||||
for (int i = 0; i < 30; i++) {
|
||||
pwm_init(pwm_gpio_to_slice_num(i), &c, true);
|
||||
}
|
||||
pwmInitted = true;
|
||||
pwm_config_set_clkdiv(&c, clock_get_hz(clk_sys) / ((float)analogScale * analogFreq));
|
||||
pwm_config_set_wrap(&c, analogScale - 1);
|
||||
pwm_init(pwm_gpio_to_slice_num(pin), &c, true);
|
||||
pwmInitted |= 1 << pwm_gpio_to_slice_num(pin);
|
||||
}
|
||||
|
||||
val <<= analogWritePseudoScale;
|
||||
@@ -117,7 +123,13 @@ extern "C" void analogWrite(pin_size_t pin, int val) {
|
||||
}
|
||||
|
||||
auto_init_mutex(_adcMutex);
|
||||
static int _readBits = 10;
|
||||
static uint8_t _readBits = 10;
|
||||
static uint8_t _lastADCMux = 0;
|
||||
static uint32_t _adcGPIOInit = 0;
|
||||
|
||||
void __clearADCPin(pin_size_t p) {
|
||||
_adcGPIOInit &= ~(1 << p);
|
||||
}
|
||||
|
||||
extern "C" int analogRead(pin_size_t pin) {
|
||||
CoreMutex m(&_adcMutex);
|
||||
@@ -133,12 +145,18 @@ extern "C" int analogRead(pin_size_t pin) {
|
||||
adc_init();
|
||||
adcInitted = true;
|
||||
}
|
||||
adc_gpio_init(pin);
|
||||
adc_select_input(pin - minPin);
|
||||
if (!(_adcGPIOInit & (1 << pin))) {
|
||||
adc_gpio_init(pin);
|
||||
_adcGPIOInit |= 1 << pin;
|
||||
}
|
||||
if (_lastADCMux != pin) {
|
||||
adc_select_input(pin - minPin);
|
||||
_lastADCMux = pin;
|
||||
}
|
||||
return (_readBits < 12) ? adc_read() >> (12 - _readBits) : adc_read() << (_readBits - 12);
|
||||
}
|
||||
|
||||
extern "C" float analogReadTemp() {
|
||||
extern "C" float analogReadTemp(float vref) {
|
||||
CoreMutex m(&_adcMutex);
|
||||
|
||||
if (!m) {
|
||||
@@ -148,12 +166,13 @@ extern "C" float analogReadTemp() {
|
||||
adc_init();
|
||||
adcInitted = true;
|
||||
}
|
||||
_lastADCMux = 0;
|
||||
adc_set_temp_sensor_enabled(true);
|
||||
delay(1); // Allow things to settle. Without this, readings can be erratic
|
||||
adc_select_input(4); // Temperature sensor
|
||||
int v = adc_read();
|
||||
adc_set_temp_sensor_enabled(false);
|
||||
float t = 27.0f - ((v * 3.3f / 4096.0f) - 0.706f) / 0.001721f; // From the datasheet
|
||||
float t = 27.0f - ((v * vref / pow(2, _readBits)) - 0.706f) / 0.001721f; // From the datasheet
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#include "Arduino.h"
|
||||
#include <hardware/gpio.h>
|
||||
|
||||
extern void __clearADCPin(pin_size_t p);
|
||||
|
||||
static PinMode _pm[30];
|
||||
|
||||
extern "C" void pinMode(pin_size_t ulPin, PinMode ulMode) __attribute__((weak, alias("__pinMode")));
|
||||
@@ -75,6 +77,10 @@ extern "C" void __pinMode(pin_size_t ulPin, PinMode ulMode) {
|
||||
return;
|
||||
}
|
||||
_pm[ulPin] = ulMode;
|
||||
|
||||
if ((ulPin >= std::min(A0, A3)) && (ulPin <= std::max(A0, A3))) {
|
||||
__clearADCPin(ulPin);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void digitalWrite(pin_size_t ulPin, PinStatus ulVal) __attribute__((weak, alias("__digitalWrite")));
|
||||
|
||||
@@ -22,24 +22,30 @@
|
||||
#include <CoreMutex.h>
|
||||
#include <hardware/gpio.h>
|
||||
#include <hardware/sync.h>
|
||||
#include <stack>
|
||||
#include <map>
|
||||
|
||||
// Support nested IRQ disable/re-enable
|
||||
static std::stack<uint32_t> _irqStack[2];
|
||||
#define maxIRQs 15
|
||||
static uint32_t _irqStackTop[2] = { 0, 0 };
|
||||
static uint32_t _irqStack[2][maxIRQs];
|
||||
|
||||
extern "C" void interrupts() {
|
||||
if (_irqStack[get_core_num()].empty()) {
|
||||
auto core = get_core_num();
|
||||
if (!_irqStackTop[core]) {
|
||||
// ERROR
|
||||
return;
|
||||
}
|
||||
auto oldIrqs = _irqStack[get_core_num()].top();
|
||||
_irqStack[get_core_num()].pop();
|
||||
restore_interrupts(oldIrqs);
|
||||
restore_interrupts(_irqStack[core][--_irqStackTop[core]]);
|
||||
}
|
||||
|
||||
extern "C" void noInterrupts() {
|
||||
_irqStack[get_core_num()].push(save_and_disable_interrupts());
|
||||
auto core = get_core_num();
|
||||
if (_irqStackTop[core] == maxIRQs) {
|
||||
// ERROR
|
||||
panic("IRQ stack overflow");
|
||||
}
|
||||
|
||||
_irqStack[core][_irqStackTop[core]++] = save_and_disable_interrupts();
|
||||
}
|
||||
|
||||
// Only 1 GPIO IRQ callback for all pins, so we need to look at the pin it's for and
|
||||
@@ -71,7 +77,7 @@ 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
|
||||
CoreMutex m(&_irqMutex);
|
||||
CoreMutex m(&_irqMutex, (FromISR | DebugEnable));
|
||||
if (m) {
|
||||
auto irq = _map.find(gpio);
|
||||
if (irq != _map.end()) {
|
||||
@@ -81,6 +87,15 @@ void _gpioInterruptDispatcher(uint gpio, uint32_t events) {
|
||||
}
|
||||
}
|
||||
|
||||
// To be called when appropriately protected w/IRQ and mutex protects
|
||||
static void _detachInterruptInternal(pin_size_t pin) {
|
||||
auto irq = _map.find(pin);
|
||||
if (irq != _map.end()) {
|
||||
gpio_set_irq_enabled(pin, 0x0f /* all */, false);
|
||||
_map.erase(pin);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void attachInterrupt(pin_size_t pin, voidFuncPtr callback, PinStatus mode) {
|
||||
CoreMutex m(&_irqMutex);
|
||||
if (!m) {
|
||||
@@ -97,7 +112,7 @@ extern "C" void attachInterrupt(pin_size_t pin, voidFuncPtr callback, PinStatus
|
||||
default: return; // ERROR
|
||||
}
|
||||
noInterrupts();
|
||||
detachInterrupt(pin);
|
||||
_detachInterruptInternal(pin);
|
||||
CBInfo cb(callback);
|
||||
_map.insert({pin, cb});
|
||||
gpio_set_irq_enabled_with_callback(pin, events, true, _gpioInterruptDispatcher);
|
||||
@@ -120,7 +135,7 @@ void attachInterruptParam(pin_size_t pin, voidFuncPtrParam callback, PinStatus m
|
||||
default: return; // ERROR
|
||||
}
|
||||
noInterrupts();
|
||||
detachInterrupt(pin);
|
||||
_detachInterruptInternal(pin);
|
||||
CBInfo cb(callback, param);
|
||||
_map.insert({pin, cb});
|
||||
gpio_set_irq_enabled_with_callback(pin, events, true, _gpioInterruptDispatcher);
|
||||
@@ -134,10 +149,6 @@ extern "C" void detachInterrupt(pin_size_t pin) {
|
||||
}
|
||||
|
||||
noInterrupts();
|
||||
auto irq = _map.find(pin);
|
||||
if (irq != _map.end()) {
|
||||
gpio_set_irq_enabled(pin, 0x0f /* all */, false);
|
||||
_map.erase(pin);
|
||||
}
|
||||
_detachInterruptInternal(pin);
|
||||
interrupts();
|
||||
}
|
||||
|
||||
+2
-1
@@ -18,9 +18,10 @@ void analogReadResolution(int bits)
|
||||
Determines the resolution (in bits) of the value returned by the analogRead() function.
|
||||
Default resolution is 10bit.
|
||||
|
||||
float analogReadTemp()
|
||||
float analogReadTemp(float vref = 3.3f)
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
Returns the temperature, in Celsius, of the onboard thermal sensor.
|
||||
If you have a custom Vref for the ADC on your RP2040 board, you can pass it in as a parameter. Calling with no parameters assumes the normal, 3.3V Vref.
|
||||
This reading is not exceedingly accurate and of relatively low
|
||||
resolution, so it is not a replacement for an external temperature
|
||||
sensor in many cases.
|
||||
|
||||
+2
-2
@@ -54,9 +54,9 @@ author = u'Earle F. Philhower, III'
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = u'2.5.3'
|
||||
version = u'2.7.0'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = u'2.5.3'
|
||||
release = u'2.7.0'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
||||
+4
-4
@@ -27,12 +27,12 @@ WiFiClientSecure documentation for more details.
|
||||
|
||||
// Error checking is left as an exercise for the reader...
|
||||
HTTPClient https;
|
||||
https.setInsecure(); // Use certs, but do not check their authenticity
|
||||
https.setInsecure(); // Use certs, but do not check their authenticity
|
||||
if (https.begin("https://my.secure.server/url")) {
|
||||
if (http.GET() > 0) {
|
||||
String data = http.getString();
|
||||
if (https.GET() > 0) {
|
||||
String data = https.getString();
|
||||
}
|
||||
http.end();
|
||||
https.end();
|
||||
}
|
||||
|
||||
Unlike the ESP8266 and ESP32 ``HTTPClient`` implementations it is not necessary
|
||||
|
||||
@@ -39,6 +39,8 @@ For the latest version, always check https://github.com/earlephilhower/arduino-p
|
||||
USB (Arduino and Adafruit_TinyUSB) <usb>
|
||||
Multicore Processing <multicore>
|
||||
|
||||
Single File USB Drive <singlefile>
|
||||
|
||||
FreeRTOS SMP (multicore) <freertos>
|
||||
|
||||
WiFi (Pico-W Support) <wifi>
|
||||
|
||||
+7
-18
@@ -65,25 +65,14 @@ Them hit the upload button and your sketch should upload and run.
|
||||
In some cases the Pico will encounter a hard hang and its USB port will not respond to the auto-reset request. Should this happen, just
|
||||
follow the initial procedure of holding the BOOTSEL button down while plugging in the Pico to enter the ROM bootloader.
|
||||
|
||||
Unable to Upload First Sketch
|
||||
-----------------------------
|
||||
If the Arduino IDE has never seen a serial port from a working device (Pico, AVR, or any other serial port), you
|
||||
may not be able to install using the prior directions because the ``Tools->Port`` menu will be grayed out and
|
||||
empty. In this case, a special workaround identified by @fjansson in `this issue report <https://github.com/earlephilhower/arduino-pico/issues/688>`_ .
|
||||
|
||||
To allow subsequent uploads to automatically work, you will need to manually install a UF2 binary onto the Raspberry Pi Pico one time to
|
||||
allow it to present a Serial port for the Arduino IDE to detect and save.
|
||||
|
||||
Perform the following steps to program a dummy sketch:
|
||||
|
||||
1. Open a new, empty sketch (doesn't work with a read-only example sketch).
|
||||
2. Compile it by pressing the "Verify" checkmark button.
|
||||
3. Select the ``Sketch -> Export Compiled Binary`` menu. Select a location e.g. the desktop. A folder is created there, containing a file ending in .uf2
|
||||
4. Copy this file to the Pico's drive, by drag and drop in the Explorer.
|
||||
|
||||
The Pico restarts and now now has a serial port. Now the Port menu in Arduino is not gray anymore, select the port there.
|
||||
After this, normal uploading from the Arduino editor should work.
|
||||
Uploading the First Sketch
|
||||
--------------------------
|
||||
The first time you upload a sketch to a board, you'll need to use the built-in ROM bootloader to handle the upload and not a serial port.
|
||||
|
||||
1. Hold the BOOTSEL button while plugging in the board.
|
||||
2. Select ``Tools->Port->UF2 Board`` from the menu.
|
||||
3. Upload as normal.
|
||||
4. After the board boots up, select the new serial port from the ``Tools->Port`` menu.
|
||||
|
||||
Windows 7 Driver Notes
|
||||
----------------------
|
||||
|
||||
+11
-2
@@ -38,12 +38,12 @@ void rp2040.reboot()
|
||||
Forces a hardware reboot of the Pico.
|
||||
|
||||
Hardware Watchdog
|
||||
_________________
|
||||
-----------------
|
||||
|
||||
void rp2040.wdt_begin(uint32_t delay_ms)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Enables the hardware watchdog timer with a delay value of delay_ms
|
||||
microseconds. Note that on the RP2040, once this function has called, the
|
||||
milliseconds. Note that on the RP2040, once this function has called, the
|
||||
hardware watchdog can _not_ be disabled.
|
||||
|
||||
void rp2040.wdt_reset()
|
||||
@@ -70,3 +70,12 @@ int rp2040.getTotalHeap()
|
||||
Returns the total heap that was available to this program at compile time (i.e.
|
||||
the Pico RAM size minus things like the ``.data`` and ``.bss`` sections and other
|
||||
overhead).
|
||||
|
||||
Bootloader
|
||||
----------
|
||||
|
||||
void rp2040.enableDoubleResetBootloader()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Add a call anywhere in the sketch to ``rp2040.enableDoubleResetBootloader()`` and
|
||||
the core will check for a double-tap on reset, and if found will start the USB
|
||||
bootloader.
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
SingleFileDrive
|
||||
===============
|
||||
|
||||
USB drive mode is supported through the ``SingleFileDrive`` class which
|
||||
allows the Pico to emulate a FAT-formatted USB stick while preserving the
|
||||
onboard LittleFS filesystem. A single file can be exported this way without
|
||||
needing to use FAT as the onboard filesystem (FAT is not appropriate for
|
||||
flash-based devices without complicated wear leveling because of the update
|
||||
frequency of the FAT tables).
|
||||
|
||||
This emulation is very simple and only allows for the reading of the single
|
||||
file, and deleting it.
|
||||
|
||||
Callbacks, Interrupt Safety, and File Operations
|
||||
------------------------------------------------
|
||||
|
||||
The ``SingleFileDrive`` library allows your application to get a callback
|
||||
when a PC attempts to mount or unmount the Pico as a drive. Your app can
|
||||
also get a callback if the user attempts to delete the file (but your
|
||||
sketch does not actually need to delete the file, it's up to you).
|
||||
|
||||
Note that when the USB drive is mounted by a PC it is not safe for your
|
||||
main sketch to make changes to the LittleFS filesystem or the file being
|
||||
exported. So, normally, your ``onPlug`` callback will set a flag letting
|
||||
your application know not to touch the filesystem, with the ``onUnplug``
|
||||
callback clearing this flag.
|
||||
|
||||
Also, because the USB port can be connected at any time, it is important
|
||||
to disable interrupts using ``noInterrupts()`` before writing to a file
|
||||
you will be exporting (and restoring them with ``interrupts()`` afterwards).
|
||||
It is also important to ``close()`` the file after each update, or the
|
||||
on-flash version the ``SingleFileDrive`` will attempt to export may not be
|
||||
up to date causing issues later on.
|
||||
|
||||
See the included ``DataLoggerUSB`` sketch for an example of working with
|
||||
these limitations.
|
||||
|
||||
Using SingleFileDrive
|
||||
---------------------
|
||||
|
||||
Implementing the drive requires including the header file, starting LittleFS,
|
||||
defining your callbacks, and telling the library what file to export. No
|
||||
polling or other calls are required outside of your ``setup()``. (Note that
|
||||
the callback routines allow for a parameter to be passed to them, but in most
|
||||
cases this can be safely ignored.)
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
#include <LittleFS.h>
|
||||
#include <SingleFileDrive.h>
|
||||
|
||||
void myPlugCB(uint32_t data) {
|
||||
// Tell my app not to write to flash, we're connected
|
||||
}
|
||||
|
||||
void myUnplugCB(uint32_t data) {
|
||||
// I can start writing to flash again
|
||||
}
|
||||
|
||||
void myDeleteDB(uint32_t data) {
|
||||
// Maybe LittleFS.remove("myfile.txt")? or do nothing
|
||||
}
|
||||
|
||||
void setup() {
|
||||
LittleFS.begin();
|
||||
singleFileDrive.onPlug(myPlugCB);
|
||||
singleFileDrive.onUnplug(myUnplugCB);
|
||||
singleFileDrive.onDelete(myDeleteCB);
|
||||
singleFileDrive.begin("littlefsfile.csv", "Data Recorder.csv");
|
||||
// ... rest of setup ...
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Take some measurements, delay, etc.
|
||||
if (okay-to-write) {
|
||||
noInterrupts();
|
||||
File f = LittleFS.open("littlefsfile.csv", "a");
|
||||
f.printf("%d,%d,%d\n", data1, data2, data3);
|
||||
f.close();
|
||||
interrupts();
|
||||
}
|
||||
}
|
||||
@@ -40,8 +40,6 @@ Please note that WiFi on the Pico W is a work-in-progress and there are some imp
|
||||
|
||||
* Combined STA/AP mode is not supported
|
||||
|
||||
* Certain WiFi status values (RSSI, BSSID, etc.) are not available.
|
||||
|
||||
* Multicore is supported, but only one core may run ``WiFi`` code.
|
||||
|
||||
* FreeRTOS is not yet supported due to the requirement for a very different LWIP implementation. PRs always appreciated!
|
||||
|
||||
@@ -72,15 +72,14 @@
|
||||
//------------- CLASS -------------//
|
||||
#define CFG_TUD_HID (2)
|
||||
#define CFG_TUD_CDC (1)
|
||||
#define CFG_TUD_MSC (0)
|
||||
#define CFG_TUD_MSC (1)
|
||||
#define CFG_TUD_MIDI (0)
|
||||
#define CFG_TUD_VENDOR (0)
|
||||
|
||||
#define CFG_TUD_CDC_RX_BUFSIZE (256)
|
||||
#define CFG_TUD_CDC_TX_BUFSIZE (256)
|
||||
|
||||
#define CFG_TUD_MIDI_RX_BUFSIZE (64)
|
||||
#define CFG_TUD_MIDI_TX_BUFSIZE (64)
|
||||
#define CFG_TUD_MSC_EP_BUFSIZE (64)
|
||||
|
||||
// HID buffer size Should be sufficient to hold ID (if any) + Data
|
||||
#define CFG_TUD_HID_EP_BUFSIZE (64)
|
||||
|
||||
@@ -54,6 +54,11 @@ SerialPIO KEYWORD2
|
||||
setFIFOSize KEYWORD2
|
||||
setPollingMode KEYWORD2
|
||||
|
||||
digitalWriteFast KEYWORD2
|
||||
digitalReadFast KEYWORD2
|
||||
|
||||
enableDoubleResetBootloader KEYWORD2
|
||||
|
||||
OUTPUT_2MA LITERAL1
|
||||
OUTPUT_4MA LITERAL1
|
||||
OUTPUT_8MA LITERAL1
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
source [find board/pico-debug.cfg]
|
||||
@@ -0,0 +1,2 @@
|
||||
source [find interface/picoprobe.cfg]
|
||||
source [find target/rp2040.cfg]
|
||||
@@ -144,4 +144,59 @@
|
||||
-Wl,--wrap=tanhf
|
||||
-Wl,--wrap=trunc
|
||||
-Wl,--wrap=truncf
|
||||
|
||||
-Wl,--wrap=__getreent
|
||||
|
||||
-Wl,--wrap=malloc
|
||||
-Wl,--wrap=calloc
|
||||
-Wl,--wrap=realloc
|
||||
-Wl,--wrap=free
|
||||
|
||||
-Wl,--wrap=pbuf_header
|
||||
-Wl,--wrap=pbuf_free
|
||||
-Wl,--wrap=pbuf_alloc
|
||||
-Wl,--wrap=pbuf_take
|
||||
-Wl,--wrap=pbuf_copy_partial
|
||||
-Wl,--wrap=pbuf_ref
|
||||
-Wl,--wrap=pbuf_get_at
|
||||
-Wl,--wrap=pbuf_get_contiguous
|
||||
-Wl,--wrap=pbuf_cat
|
||||
|
||||
-Wl,--wrap=tcp_arg
|
||||
-Wl,--wrap=tcp_new
|
||||
-Wl,--wrap=tcp_listen
|
||||
-Wl,--wrap=tcp_listen_with_backlog
|
||||
-Wl,--wrap=tcp_accept
|
||||
-Wl,--wrap=tcp_connect
|
||||
-Wl,--wrap=tcp_write
|
||||
-Wl,--wrap=tcp_sent
|
||||
-Wl,--wrap=tcp_recv
|
||||
-Wl,--wrap=tcp_recved
|
||||
-Wl,--wrap=tcp_poll
|
||||
-Wl,--wrap=tcp_close
|
||||
-Wl,--wrap=tcp_abort
|
||||
-Wl,--wrap=tcp_err
|
||||
-Wl,--wrap=tcp_output
|
||||
-Wl,--wrap=tcp_setprio
|
||||
-Wl,--wrap=tcp_backlog_delayed
|
||||
-Wl,--wrap=tcp_backlog_accepted
|
||||
|
||||
-Wl,--wrap=udp_new
|
||||
-Wl,--wrap=udp_remove
|
||||
-Wl,--wrap=udp_bind
|
||||
-Wl,--wrap=udp_connect
|
||||
-Wl,--wrap=udp_disconnect
|
||||
-Wl,--wrap=udp_send
|
||||
-Wl,--wrap=udp_recv
|
||||
-Wl,--wrap=udp_sendto_if
|
||||
|
||||
-Wl,--wrap=sys_check_timeouts
|
||||
|
||||
-Wl,--wrap=dns_gethostbyname
|
||||
-Wl,--wrap=dns_gethostbyname_addrtype
|
||||
|
||||
-Wl,--wrap=raw_new
|
||||
-Wl,--wrap=raw_recv
|
||||
-Wl,--wrap=raw_bind
|
||||
-Wl,--wrap=raw_sendto
|
||||
-Wl,--wrap=raw_remove
|
||||
|
||||
Submodule libraries/Adafruit_TinyUSB_Arduino updated: 5be0b21c0a...e1e922d2ca
@@ -110,7 +110,7 @@ void ArduinoOTAClass::begin(bool useMDNS) {
|
||||
_useMDNS = useMDNS;
|
||||
|
||||
if (!_hostname.length()) {
|
||||
char tmp[15];
|
||||
char tmp[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 6];
|
||||
sprintf(tmp, "pico-%s", rp2040.getChipID());
|
||||
_hostname = tmp;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
name=AudioBufferManager
|
||||
version=1.0.0
|
||||
author=Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
maintainer=Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
sentence=Manages DMA buffers for audio output
|
||||
paragraph=Manages DMA buffers for audio output
|
||||
category=Device Control
|
||||
url=https://github.com/earlephilhower/arduino-pico
|
||||
architectures=rp2040
|
||||
dot_a_linkage=true
|
||||
+116
-97
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
AudioRingBuffer for Raspnerry Pi Pico RP2040
|
||||
Implements a ring buffer for PIO DMA for I2S read or write
|
||||
AudioBufferManager for Raspnerry Pi Pico RP2040
|
||||
Implements a DMA controlled linked-list series of buffers
|
||||
|
||||
Copyright (c) 2022 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
|
||||
@@ -20,47 +20,60 @@
|
||||
*/
|
||||
|
||||
#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"
|
||||
#include "AudioBufferManager.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
|
||||
static int __channelCount = 0; // # of channels left. When we hit 0, then remove our handler
|
||||
static AudioBufferManager* __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) {
|
||||
AudioBufferManager::AudioBufferManager(size_t bufferCount, size_t bufferWords, int32_t silenceSample, PinMode direction, enum dma_channel_transfer_size dmaSize) {
|
||||
_running = false;
|
||||
_silenceSample = silenceSample;
|
||||
|
||||
// Need at least 2 DMA buffers and 1 user or this isn't going to work at all
|
||||
if (bufferCount < 3) {
|
||||
bufferCount = 3;
|
||||
}
|
||||
|
||||
_bufferCount = bufferCount;
|
||||
_wordsPerBuffer = bufferWords;
|
||||
_isOutput = direction == OUTPUT;
|
||||
_dmaSize = dmaSize;
|
||||
_overunderflow = false;
|
||||
_callback = nullptr;
|
||||
_userBuffer = -1;
|
||||
_userOff = 0;
|
||||
|
||||
// Create the silence buffer, fill with appropriate value
|
||||
_silence = new AudioBuffer;
|
||||
_silence->next = nullptr;
|
||||
_silence->buff = new uint32_t[_wordsPerBuffer];
|
||||
for (uint32_t x = 0; x < _wordsPerBuffer; x++) {
|
||||
_silence->buff[x] = silenceSample;
|
||||
}
|
||||
|
||||
// No filled buffers yet
|
||||
_filled = nullptr;
|
||||
|
||||
// Create all buffers on the empty chain
|
||||
_empty = nullptr;
|
||||
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);
|
||||
ab->next = nullptr;
|
||||
_addToList(&_empty, ab);
|
||||
}
|
||||
|
||||
_active[0] = _silence;
|
||||
_active[1] = _silence;
|
||||
}
|
||||
|
||||
AudioRingBuffer::~AudioRingBuffer() {
|
||||
AudioBufferManager::~AudioBufferManager() {
|
||||
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);
|
||||
@@ -68,23 +81,31 @@ AudioRingBuffer::~AudioRingBuffer() {
|
||||
irq_remove_handler(DMA_IRQ_0, _irq);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (_active[i] != _silence) {
|
||||
_deleteAudioBuffer(_active[i]);
|
||||
}
|
||||
}
|
||||
while (_filled) {
|
||||
auto x = _filled->next;
|
||||
_deleteAudioBuffer(_filled);
|
||||
_filled = x;
|
||||
}
|
||||
while (_empty) {
|
||||
auto x = _empty->next;
|
||||
_deleteAudioBuffer(_empty);
|
||||
_empty = x;
|
||||
}
|
||||
_deleteAudioBuffer(_silence);
|
||||
}
|
||||
|
||||
void AudioRingBuffer::setCallback(void (*fn)()) {
|
||||
void AudioBufferManager::setCallback(void (*fn)()) {
|
||||
_callback = fn;
|
||||
}
|
||||
|
||||
bool AudioRingBuffer::begin(int dreq, volatile void *pioFIFOAddr) {
|
||||
bool AudioBufferManager::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);
|
||||
@@ -99,7 +120,7 @@ bool AudioRingBuffer::begin(int dreq, volatile void *pioFIFOAddr) {
|
||||
// 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
|
||||
channel_config_set_transfer_data_size(&c, _dmaSize); // 16b/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
|
||||
@@ -112,9 +133,10 @@ bool AudioRingBuffer::begin(int dreq, volatile void *pioFIFOAddr) {
|
||||
channel_config_set_irq_quiet(&c, false); // Need IRQs
|
||||
|
||||
if (_isOutput) {
|
||||
dma_channel_configure(_channelDMA[i], &c, pioFIFOAddr, _buffers[i]->buff, _wordsPerBuffer, false);
|
||||
dma_channel_configure(_channelDMA[i], &c, pioFIFOAddr, _silence->buff, _wordsPerBuffer, false);
|
||||
} else {
|
||||
dma_channel_configure(_channelDMA[i], &c, _buffers[i]->buff, pioFIFOAddr, _wordsPerBuffer, false);
|
||||
_active[i] = _takeFromList(&_empty);
|
||||
dma_channel_configure(_channelDMA[i], &c, _active[i]->buff, pioFIFOAddr, _wordsPerBuffer, false);
|
||||
}
|
||||
dma_channel_set_irq0_enabled(_channelDMA[i], true);
|
||||
__channelMap[_channelDMA[i]] = this;
|
||||
@@ -124,130 +146,127 @@ bool AudioRingBuffer::begin(int dreq, volatile void *pioFIFOAddr) {
|
||||
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) {
|
||||
// Following 2 routines use volatile because the IRQ may update the "this"
|
||||
// pointer and change the list head while we are waiting. Volatile will
|
||||
// cause GCC to keep re-reading from memory and not use cached value read
|
||||
// on the first pass.
|
||||
|
||||
bool AudioBufferManager::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) {
|
||||
AudioBuffer ** volatile p = (AudioBuffer ** volatile)&_empty;
|
||||
if (!*p) {
|
||||
if (!sync) {
|
||||
return false;
|
||||
} else {
|
||||
while (!_buffers[_userBuffer]->empty) {
|
||||
while (!*p) {
|
||||
/* noop busy wait */
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_userBuffer == _curBuffer) {
|
||||
if (!sync) {
|
||||
return false;
|
||||
} else {
|
||||
while (_userBuffer == _curBuffer) {
|
||||
/* noop busy wait */
|
||||
}
|
||||
}
|
||||
}
|
||||
_buffers[_userBuffer]->buff[_userOff++] = v;
|
||||
(*p)->buff[_userOff++] = v;
|
||||
if (_userOff == _wordsPerBuffer) {
|
||||
_buffers[_userBuffer]->empty = false;
|
||||
_userBuffer = (_userBuffer + 1) % _bufferCount;
|
||||
_addToList(&_filled, _takeFromList(p));
|
||||
_userOff = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AudioRingBuffer::read(uint32_t *v, bool sync) {
|
||||
bool AudioBufferManager::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) {
|
||||
|
||||
AudioBuffer ** volatile p = (AudioBuffer ** volatile)&_filled;
|
||||
if (!*p) {
|
||||
if (!sync) {
|
||||
return false;
|
||||
} else {
|
||||
while (_buffers[_userBuffer]->empty) {
|
||||
while (!*p) {
|
||||
/* noop busy wait */
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_userBuffer == _curBuffer) {
|
||||
if (!sync) {
|
||||
return false;
|
||||
} else {
|
||||
while (_userBuffer == _curBuffer) {
|
||||
/* noop busy wait */
|
||||
}
|
||||
}
|
||||
}
|
||||
auto ret = _buffers[_userBuffer]->buff[_userOff++];
|
||||
auto ret = (*p)->buff[_userOff++];
|
||||
if (_userOff == _wordsPerBuffer) {
|
||||
_buffers[_userBuffer]->empty = true;
|
||||
_userBuffer = (_userBuffer + 1) % _bufferCount;
|
||||
_addToList(&_empty, _takeFromList(p));
|
||||
_userOff = 0;
|
||||
}
|
||||
*v = ret;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AudioRingBuffer::getOverUnderflow() {
|
||||
bool AudioBufferManager::getOverUnderflow() {
|
||||
bool hold = _overunderflow;
|
||||
_overunderflow = false;
|
||||
return hold;
|
||||
}
|
||||
|
||||
int AudioRingBuffer::available() {
|
||||
if (!_running) {
|
||||
int AudioBufferManager::available() {
|
||||
AudioBuffer *p = _isOutput ? _empty : _filled;
|
||||
|
||||
if (!_running || !p) {
|
||||
// No buffers available...
|
||||
return 0;
|
||||
}
|
||||
int avail;
|
||||
avail = _wordsPerBuffer - _userOff;
|
||||
avail += ((_bufferCount + _curBuffer - _userBuffer) % _bufferCount) * _wordsPerBuffer;
|
||||
|
||||
int avail = _wordsPerBuffer - _userOff; // Currently available in this buffer
|
||||
|
||||
// Each add'l buffer has wpb spaces...
|
||||
auto x = p->next;
|
||||
while (x) {
|
||||
avail += _wordsPerBuffer;
|
||||
x = x->next;
|
||||
}
|
||||
return avail;
|
||||
}
|
||||
|
||||
void AudioRingBuffer::flush() {
|
||||
while (_curBuffer != _userBuffer) {
|
||||
// busy wait
|
||||
void AudioBufferManager::flush() {
|
||||
AudioBuffer ** volatile a = (AudioBuffer ** volatile)&_active[0];
|
||||
AudioBuffer ** volatile b = (AudioBuffer ** volatile)&_active[1];
|
||||
AudioBuffer ** volatile c = (AudioBuffer ** volatile)&_filled;
|
||||
while (*c && (*b != (AudioBuffer * volatile)_silence) && (*a != (AudioBuffer * volatile)_silence)) {
|
||||
// busy wait until all user written data enroute
|
||||
}
|
||||
}
|
||||
|
||||
void __not_in_flash_func(AudioRingBuffer::_dmaIRQ)(int channel) {
|
||||
void __not_in_flash_func(AudioBufferManager::_dmaIRQ)(int channel) {
|
||||
if (_isOutput) {
|
||||
for (uint32_t x = 0; x < _wordsPerBuffer; x++) {
|
||||
_buffers[_curBuffer]->buff[x] = _silenceSample;
|
||||
if (_active[0] != _silence) {
|
||||
_addToList(&_empty, _active[0]);
|
||||
}
|
||||
_buffers[_curBuffer]-> empty = true;
|
||||
_overunderflow = _overunderflow | _buffers[_nextBuffer]->empty;
|
||||
dma_channel_set_read_addr(channel, _buffers[_nextBuffer]->buff, false);
|
||||
_active[0] = _active[1];
|
||||
if (!_filled) {
|
||||
_active[1] = _silence;
|
||||
} else {
|
||||
_active[1] = _takeFromList(&_filled);
|
||||
}
|
||||
_overunderflow = _overunderflow | (_active[1] == _silence);
|
||||
dma_channel_set_read_addr(channel, _active[0]->buff, false);
|
||||
} else {
|
||||
_buffers[_curBuffer]-> empty = false;
|
||||
_overunderflow = _overunderflow | !_buffers[_nextBuffer]->empty;
|
||||
dma_channel_set_write_addr(channel, _buffers[_nextBuffer]->buff, false);
|
||||
if (_empty) {
|
||||
_addToList(&_filled, _active[0]);
|
||||
_active[0] = _active[1];
|
||||
_active[1] = _takeFromList(&_empty);
|
||||
} else {
|
||||
_overunderflow = true;
|
||||
}
|
||||
dma_channel_set_write_addr(channel, _active[0]->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)() {
|
||||
void __not_in_flash_func(AudioBufferManager::_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,102 @@
|
||||
/*
|
||||
AudioBufferManager for Rasperry Pi Pico
|
||||
Implements a DMA controlled linked-list series of buffers
|
||||
|
||||
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 "hardware/dma.h"
|
||||
|
||||
class AudioBufferManager {
|
||||
public:
|
||||
AudioBufferManager(size_t bufferCount, size_t bufferWords, int32_t silenceSample, PinMode direction = OUTPUT, enum dma_channel_transfer_size dmaSize = DMA_SIZE_32);
|
||||
~AudioBufferManager();
|
||||
|
||||
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 AudioBuffer {
|
||||
struct AudioBuffer *next;
|
||||
uint32_t *buff;
|
||||
} AudioBuffer;
|
||||
|
||||
bool _running = false;
|
||||
|
||||
AudioBuffer *_silence = nullptr; // A single silence buffer to be looped on underflow
|
||||
AudioBuffer *_filled = nullptr; // List of buffers ready to be played
|
||||
AudioBuffer *_empty = nullptr; // List of buffers waiting to be filled. *_empty = currently writing
|
||||
AudioBuffer *_active[2] = { nullptr, nullptr }; // The 2 buffers currently in use for DMA
|
||||
|
||||
// Can't use std::list because we need to put in RAM for IRQ use, so roll our own
|
||||
void __not_in_flash_func(_addToList)(AudioBuffer **list, AudioBuffer *element) {
|
||||
noInterrupts();
|
||||
// Find end of list, if any
|
||||
while ((*list) && ((*list)->next != nullptr)) {
|
||||
list = &(*list)->next;
|
||||
}
|
||||
if (*list) {
|
||||
(*list)->next = element;
|
||||
} else {
|
||||
*list = element;
|
||||
}
|
||||
element->next = nullptr; // Belt and braces
|
||||
interrupts();
|
||||
}
|
||||
|
||||
AudioBuffer *__not_in_flash_func(_takeFromList)(AudioBuffer **list) {
|
||||
noInterrupts();
|
||||
auto ret = *list;
|
||||
if (ret) {
|
||||
*list = ret->next;
|
||||
}
|
||||
interrupts();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void _deleteAudioBuffer(AudioBuffer *ab) {
|
||||
delete[] ab->buff;
|
||||
delete ab;
|
||||
}
|
||||
|
||||
int _bitsPerSample;
|
||||
size_t _wordsPerBuffer;
|
||||
size_t _bufferCount;
|
||||
enum dma_channel_transfer_size _dmaSize;
|
||||
bool _isOutput;
|
||||
|
||||
int _channelDMA[2];
|
||||
void (*_callback)();
|
||||
|
||||
bool _overunderflow;
|
||||
|
||||
// User buffer pointer
|
||||
size_t _userOff = 0;
|
||||
};
|
||||
@@ -45,7 +45,7 @@ void EEPROMClass::begin(size_t size) {
|
||||
size = 4096;
|
||||
}
|
||||
|
||||
_size = (size + 255) & (~255); // Flash writes limited to 256 byte boundaries
|
||||
size = (size + 255) & (~255); // Flash writes limited to 256 byte boundaries
|
||||
|
||||
// In case begin() is called a 2nd+ time, don't reallocate if size is the same
|
||||
if (_data && size != _size) {
|
||||
@@ -55,6 +55,8 @@ void EEPROMClass::begin(size_t size) {
|
||||
_data = new uint8_t[size];
|
||||
}
|
||||
|
||||
_size = size;
|
||||
|
||||
memcpy(_data, _sector, _size);
|
||||
|
||||
_dirty = false; //make sure dirty is cleared in case begin() is called 2nd+ time
|
||||
|
||||
@@ -59,7 +59,7 @@ volatile bool __usbInitted = false;
|
||||
|
||||
static void __core0(void *params) {
|
||||
(void) params;
|
||||
#ifndef NO_USB
|
||||
#if !defined(NO_USB) && !defined(USE_TINYUSB)
|
||||
while (!__usbInitted) {
|
||||
delay(1);
|
||||
}
|
||||
@@ -81,7 +81,7 @@ static void __core0(void *params) {
|
||||
|
||||
static void __core1(void *params) {
|
||||
(void) params;
|
||||
#ifndef NO_USB
|
||||
#if !defined(NO_USB) && !defined(USE_TINYUSB)
|
||||
while (!__usbInitted) {
|
||||
delay(1);
|
||||
}
|
||||
@@ -414,6 +414,10 @@ extern "C" {
|
||||
xSemaphoreTake(mtx, portMAX_DELAY);
|
||||
}
|
||||
|
||||
void __freertos_mutex_take_from_isr(SemaphoreHandle_t mtx) {
|
||||
xSemaphoreTakeFromISR(mtx, NULL);
|
||||
}
|
||||
|
||||
int __freertos_mutex_try_take(SemaphoreHandle_t mtx) {
|
||||
return xSemaphoreTake(mtx, 0);
|
||||
}
|
||||
@@ -422,6 +426,10 @@ extern "C" {
|
||||
xSemaphoreGive(mtx);
|
||||
}
|
||||
|
||||
void __freertos_mutex_give_from_isr(SemaphoreHandle_t mtx) {
|
||||
xSemaphoreGiveFromISR(mtx, NULL);
|
||||
}
|
||||
|
||||
void __freertos_recursive_mutex_take(SemaphoreHandle_t mtx) {
|
||||
xSemaphoreTakeRecursive(mtx, portMAX_DELAY);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ setBCLK KEYWORD2
|
||||
setDATA KEYWORD2
|
||||
setBitsPerSample KEYWORD2
|
||||
setFrequency KEYWORD2
|
||||
setBuffers KEYWORD2
|
||||
|
||||
read8 KEYWORD2
|
||||
read16 KEYWORD2
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
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;
|
||||
};
|
||||
@@ -27,14 +27,29 @@ I2S::I2S(PinMode direction) {
|
||||
_running = false;
|
||||
_bps = 16;
|
||||
_writtenHalf = false;
|
||||
_isOutput = direction == OUTPUT;
|
||||
_pinBCLK = 26;
|
||||
_pinDOUT = 28;
|
||||
#ifdef PIN_I2S_BCLK
|
||||
_pinBCLK = PIN_I2S_BCLK;
|
||||
#endif
|
||||
|
||||
#ifdef PIN_I2S_DOUT
|
||||
if (_isOutput) {
|
||||
_pinDOUT = PIN_I2S_DOUT;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PIN_I2S_DIN
|
||||
if (!_isOutput) {
|
||||
_pinDOUT = PIN_I2S_DIN;
|
||||
}
|
||||
#endif
|
||||
_freq = 48000;
|
||||
_arb = nullptr;
|
||||
_isOutput = direction == OUTPUT;
|
||||
_cb = nullptr;
|
||||
_buffers = 8;
|
||||
_bufferWords = 16;
|
||||
_bufferWords = 0;
|
||||
_silenceSample = 0;
|
||||
}
|
||||
|
||||
@@ -121,7 +136,10 @@ bool I2S::begin() {
|
||||
uint16_t a = _silenceSample & 0xffff;
|
||||
_silenceSample = (a << 16) | a;
|
||||
}
|
||||
_arb = new AudioRingBuffer(_buffers, _bufferWords, _silenceSample, _isOutput ? OUTPUT : INPUT);
|
||||
if (!_bufferWords) {
|
||||
_bufferWords = 16 * (_bps == 32 ? 2 : 1);
|
||||
}
|
||||
_arb = new AudioBufferManager(_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);
|
||||
@@ -138,10 +156,13 @@ void I2S::end() {
|
||||
}
|
||||
|
||||
int I2S::available() {
|
||||
if (!_running || _isOutput) {
|
||||
if (!_running) {
|
||||
return 0;
|
||||
} else if (_isOutput) {
|
||||
return availableForWrite(); // Do what I mean, not what I say
|
||||
} else {
|
||||
return _arb->available();
|
||||
}
|
||||
return _arb->available();
|
||||
}
|
||||
|
||||
int I2S::read() {
|
||||
|
||||
@@ -21,8 +21,7 @@
|
||||
|
||||
#pragma once
|
||||
#include <Arduino.h>
|
||||
#include <vector>
|
||||
#include "AudioRingBuffer.h"
|
||||
#include "AudioBufferManager.h"
|
||||
|
||||
class I2S : public Stream {
|
||||
public:
|
||||
@@ -121,7 +120,7 @@ private:
|
||||
|
||||
void (*_cb)();
|
||||
|
||||
AudioRingBuffer *_arb;
|
||||
AudioBufferManager *_arb;
|
||||
PIOProgram *_i2s;
|
||||
PIO _pio;
|
||||
int _sm;
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include "ESP8266mDNS.h"
|
||||
#include "LEAmDNS_Priv.h"
|
||||
#include <LwipIntf.h> // LwipIntf::stateUpCB()
|
||||
#include <LWIPMutex.h> // LwipIntf::stateUpCB()
|
||||
#include <lwip/igmp.h>
|
||||
#include <lwip/prot/dns.h>
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
This example plays a raw, headerless, mono 16b, 44.1 sample using the PWMAudio library on GPIO 1.
|
||||
|
||||
Released to the public domain by Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
*/
|
||||
|
||||
#include <PWMAudio.h>
|
||||
#include "wav.h"
|
||||
|
||||
// The sample pointers
|
||||
const int16_t *start = (const int16_t *)out_raw;
|
||||
const int16_t *p = start;
|
||||
|
||||
// Create the PWM audio device on GPIO 1. Hook amp/speaker between GPIO1 and convenient GND.
|
||||
PWMAudio pwm(1);
|
||||
|
||||
unsigned int count = 0;
|
||||
|
||||
void cb() {
|
||||
while (pwm.availableForWrite()) {
|
||||
pwm.write(*p++);
|
||||
count += 2;
|
||||
if (count >= sizeof(out_raw)) {
|
||||
count = 0;
|
||||
p = start;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
pwm.onTransmit(cb);
|
||||
pwm.begin(44100);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
/* noop, everything is done in the CB */
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,25 @@
|
||||
#######################################
|
||||
# Syntax Coloring Map
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
PWMAudio KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
begin KEYWORD2
|
||||
end KEYWORD2
|
||||
|
||||
setPin KEYWORD2
|
||||
setFrequency KEYWORD2
|
||||
setBuffers KEYWORD2
|
||||
|
||||
onTransmit KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
@@ -0,0 +1,10 @@
|
||||
name=PWMAudio
|
||||
version=1.0
|
||||
author=Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
maintainer=Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
sentence=Plays audio on a pin using the PWM hardware, no DAC required
|
||||
paragraph=Plays audio on a pin using the PWM hardware, no DAC required
|
||||
category=Communication
|
||||
url=http://github.com/earlephilhower/arduino-pico
|
||||
architectures=rp2040
|
||||
dot_a_linkage=true
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
PWMAudio
|
||||
Plays a 16b audio stream on a user defined pin using PWM
|
||||
|
||||
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 "PWMAudio.h"
|
||||
#include <hardware/pwm.h>
|
||||
|
||||
|
||||
PWMAudio::PWMAudio(pin_size_t pin) {
|
||||
_running = false;
|
||||
_pin = pin;
|
||||
_freq = 48000;
|
||||
_arb = nullptr;
|
||||
_cb = nullptr;
|
||||
_buffers = 8;
|
||||
_bufferWords = 0;
|
||||
}
|
||||
|
||||
PWMAudio::~PWMAudio() {
|
||||
}
|
||||
|
||||
bool PWMAudio::setBuffers(size_t buffers, size_t bufferWords) {
|
||||
if (_running || (buffers < 3) || (bufferWords < 8)) {
|
||||
return false;
|
||||
}
|
||||
_buffers = buffers;
|
||||
_bufferWords = bufferWords;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PWMAudio::setFrequency(int newFreq) {
|
||||
if (_running) {
|
||||
return false;
|
||||
}
|
||||
_freq = newFreq;
|
||||
return true;
|
||||
}
|
||||
|
||||
void PWMAudio::onTransmit(void(*fn)(void)) {
|
||||
_cb = fn;
|
||||
if (_running) {
|
||||
_arb->setCallback(_cb);
|
||||
}
|
||||
}
|
||||
|
||||
bool PWMAudio::begin() {
|
||||
_running = true;
|
||||
|
||||
if (!_bufferWords) {
|
||||
_bufferWords = 16;
|
||||
}
|
||||
|
||||
// Figure out the scale factor for PWM values
|
||||
float fPWM = 65535.0 * _freq; // ideal
|
||||
|
||||
if (fPWM > clock_get_hz(clk_sys)) {
|
||||
// Need to downscale the range to hit the frequency target
|
||||
float pwmMax = (float) clock_get_hz(clk_sys) /(float) _freq;
|
||||
_pwmScale = pwmMax;
|
||||
fPWM = clock_get_hz(clk_sys);
|
||||
} else {
|
||||
_pwmScale = 1 << 16;
|
||||
}
|
||||
|
||||
pwm_config c = pwm_get_default_config();
|
||||
pwm_config_set_clkdiv(&c, clock_get_hz(clk_sys) / fPWM);
|
||||
pwm_config_set_wrap(&c, _pwmScale);
|
||||
pwm_init(pwm_gpio_to_slice_num(_pin), &c, true);
|
||||
gpio_set_function(_pin, GPIO_FUNC_PWM);
|
||||
pwm_set_gpio_level(_pin, (0x8000 * _pwmScale) >> 16);
|
||||
|
||||
uint32_t ccAddr = PWM_BASE + PWM_CH0_CC_OFFSET + pwm_gpio_to_slice_num(_pin) * 20;
|
||||
|
||||
_arb = new AudioBufferManager(_buffers, _bufferWords, 0x80008000, OUTPUT, DMA_SIZE_32);
|
||||
_arb->begin(pwm_get_dreq(pwm_gpio_to_slice_num(_pin)), (volatile void*)ccAddr);
|
||||
_arb->setCallback(_cb);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PWMAudio::end() {
|
||||
_running = false;
|
||||
delete _arb;
|
||||
_arb = nullptr;
|
||||
}
|
||||
|
||||
int PWMAudio::available() {
|
||||
return availableForWrite(); // Do what I mean, not what I say
|
||||
}
|
||||
|
||||
int PWMAudio::read() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int PWMAudio::peek() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
void PWMAudio::flush() {
|
||||
if (_running) {
|
||||
_arb->flush();
|
||||
}
|
||||
}
|
||||
|
||||
int PWMAudio::availableForWrite() {
|
||||
if (!_running) {
|
||||
return 0;
|
||||
}
|
||||
return _arb->available();
|
||||
}
|
||||
|
||||
size_t PWMAudio::write(int16_t val, bool sync) {
|
||||
if (!_running) {
|
||||
return 0;
|
||||
}
|
||||
// Go from signed -32K...32K to unsigned 0...64K
|
||||
uint32_t sample = (uint32_t) (val + 0x8000);
|
||||
// Adjust to the real range
|
||||
sample *= _pwmScale;
|
||||
sample >>= 16;
|
||||
// Duplicate sample since we don't care which PWM channel
|
||||
sample = (sample & 0xffff) | (sample << 16);
|
||||
return _arb->write(sample, sync);
|
||||
}
|
||||
|
||||
size_t PWMAudio::write(const uint8_t *buffer, size_t size) {
|
||||
// We can only write 16-bit chunks here
|
||||
if (size & 0x1) {
|
||||
return 0;
|
||||
}
|
||||
size_t writtenSize = 0;
|
||||
int16_t *p = (int16_t *)buffer;
|
||||
while (size) {
|
||||
if (!write((int16_t)*p)) {
|
||||
// Blocked, stop write here
|
||||
return writtenSize;
|
||||
} else {
|
||||
p++;
|
||||
size -= 4;
|
||||
writtenSize += 4;
|
||||
}
|
||||
}
|
||||
return writtenSize;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
PWMAudio
|
||||
Plays a signed 16b audio stream on a user defined pin using PWM
|
||||
|
||||
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 "AudioBufferManager.h"
|
||||
|
||||
class PWMAudio : public Stream {
|
||||
public:
|
||||
PWMAudio(pin_size_t pin);
|
||||
virtual ~PWMAudio();
|
||||
|
||||
bool setBuffers(size_t buffers, size_t bufferWords);
|
||||
bool setFrequency(int newFreq);
|
||||
|
||||
bool begin(long sampleRate) {
|
||||
setFrequency(sampleRate);
|
||||
return begin();
|
||||
}
|
||||
|
||||
bool begin();
|
||||
void end();
|
||||
|
||||
// from Stream
|
||||
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(const uint8_t *buffer, size_t size) override;
|
||||
virtual int availableForWrite() override;
|
||||
|
||||
virtual size_t write(uint8_t x) override {
|
||||
return write((int16_t) x, true);
|
||||
}
|
||||
|
||||
// Write 16 bit value to port, user responsible for packing/alignment, etc.
|
||||
size_t write(int16_t val, bool sync = true);
|
||||
size_t write(int val, bool sync = true) {
|
||||
return write((int16_t) val, sync);
|
||||
}
|
||||
|
||||
// Note that these callback are called from **INTERRUPT CONTEXT** and hence
|
||||
// should be in RAM, not FLASH, and should be quick to execute.
|
||||
void onTransmit(void(*)(void));
|
||||
|
||||
private:
|
||||
pin_size_t _pin;
|
||||
int _freq;
|
||||
|
||||
size_t _buffers;
|
||||
size_t _bufferWords;
|
||||
|
||||
uint32_t _pwmScale;
|
||||
|
||||
bool _running;
|
||||
|
||||
void (*_cb)();
|
||||
|
||||
AudioBufferManager *_arb;
|
||||
};
|
||||
@@ -5,6 +5,6 @@ maintainer=Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
sentence=Configures requests for OTA bootloader
|
||||
paragraph=Example repository for Ethernet drivers
|
||||
category=Device Control
|
||||
url=https://github.com/earlephilhower.arduino-pico
|
||||
url=https://github.com/earlephilhower/arduino-pico
|
||||
architectures=rp2040
|
||||
dot_a_linkage=true
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
// Simple logger with USB upload to PC
|
||||
// Uses SingleFileDrive to export an onboard LittleFS file to the computer
|
||||
// The PC can open/copy the file, and then the user can delete it to restart
|
||||
|
||||
// Released to the public domain, 2022 - Earle F. Philhower, III
|
||||
|
||||
#include <SingleFileDrive.h>
|
||||
#include <LittleFS.h>
|
||||
|
||||
uint32_t cnt = 0;
|
||||
bool okayToWrite = true;
|
||||
|
||||
// Make the CSV file and give it a simple header
|
||||
void headerCSV() {
|
||||
File f = LittleFS.open("data.csv", "w");
|
||||
f.printf("sample,millis,temp,rand\n");
|
||||
f.close();
|
||||
cnt = 0;
|
||||
}
|
||||
|
||||
// Called when the USB stick connected to a PC and the drive opened
|
||||
// Note this is from a USB IRQ so no printing to SerialUSB/etc.
|
||||
void plug(uint32_t i) {
|
||||
(void) i;
|
||||
okayToWrite = false;
|
||||
}
|
||||
|
||||
// Called when the USB is ejected or removed from a PC
|
||||
// Note this is from a USB IRQ so no printing to SerialUSB/etc.
|
||||
void unplug(uint32_t i) {
|
||||
(void) i;
|
||||
okayToWrite = true;
|
||||
}
|
||||
|
||||
// Called when the PC tries to delete the single file
|
||||
// Note this is from a USB IRQ so no printing to SerialUSB/etc.
|
||||
void deleteCSV(uint32_t i) {
|
||||
(void) i;
|
||||
LittleFS.remove("data.csv");
|
||||
headerCSV();
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin();
|
||||
delay(5000);
|
||||
|
||||
LittleFS.begin();
|
||||
|
||||
// Set up the USB disk share
|
||||
singleFileDrive.onDelete(deleteCSV);
|
||||
singleFileDrive.onPlug(plug);
|
||||
singleFileDrive.onUnplug(unplug);
|
||||
singleFileDrive.begin("data.csv", "Recorded data from the Raspberry Pi Pico.csv");
|
||||
|
||||
// Find the last written data
|
||||
File f = LittleFS.open("data.csv", "r");
|
||||
if (!f || !f.size()) {
|
||||
cnt = 1;
|
||||
headerCSV();
|
||||
} else {
|
||||
if (f.size() > 2048) {
|
||||
f.seek(f.size() - 1024);
|
||||
}
|
||||
do {
|
||||
String s = f.readStringUntil('\n');
|
||||
sscanf(s.c_str(), "%lu,", &cnt);
|
||||
} while (f.available());
|
||||
f.close();
|
||||
cnt++;
|
||||
}
|
||||
|
||||
Serial.printf("Starting acquisition at %d\n", cnt);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
float temp = analogReadTemp();
|
||||
uint32_t hwrand = rp2040.hwrand32();
|
||||
// Make sure the USB connect doesn't happen while we're writing!
|
||||
noInterrupts();
|
||||
if (okayToWrite) {
|
||||
Serial.printf("Sampling...%lu\n", cnt);
|
||||
// Don't want the USB to connect during an update!
|
||||
File f = LittleFS.open("data.csv", "a");
|
||||
if (f) {
|
||||
f.printf("%lu,%lu,%f,%lu\n", cnt++, millis(), temp, hwrand);
|
||||
f.close();
|
||||
}
|
||||
}
|
||||
interrupts();
|
||||
|
||||
delay(10000);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#######################################
|
||||
# Syntax Coloring Map
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
SingleFileDrive KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
singleFileDrive KEYWORD1
|
||||
onDelete KEYWORD1
|
||||
onPlug KEYWORD1
|
||||
onUnplug KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
@@ -0,0 +1,10 @@
|
||||
name=SingleFileDrive
|
||||
version=1.0.0
|
||||
author=Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
maintainer=Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
sentence=Allows using USB MSC (USB stick) to transfer an onboard flash file to a PC
|
||||
paragraph=Emulates a USB stick and presents a single file for users to copy over/erase
|
||||
category=Device Control
|
||||
url=https://github.com/earlephilhower/arduino-pico
|
||||
architectures=rp2040
|
||||
dot_a_linkage=true
|
||||
@@ -0,0 +1,396 @@
|
||||
/*
|
||||
SingleFileDrive - Emulates a USB stick for easy data transfer
|
||||
Copyright (c) 2022 Earle F. Philhower, III. All rights reserved.
|
||||
|
||||
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 <SingleFileDrive.h>
|
||||
#include <LittleFS.h>
|
||||
#include <class/msc/msc.h>
|
||||
|
||||
SingleFileDrive singleFileDrive;
|
||||
|
||||
static const uint32_t _hddsize = (256 * 1024 * 1024); // 256MB
|
||||
static const uint32_t _hddsects = _hddsize / 512;
|
||||
|
||||
// Ensure we are logged in to the USB framework
|
||||
void __USBInstallMassStorage() {
|
||||
/* dummy */
|
||||
}
|
||||
|
||||
SingleFileDrive::SingleFileDrive() {
|
||||
}
|
||||
|
||||
SingleFileDrive::~SingleFileDrive() {
|
||||
end();
|
||||
}
|
||||
|
||||
void SingleFileDrive::onDelete(void (*cb)(uint32_t), uint32_t cbData) {
|
||||
_cbDelete = cb;
|
||||
_cbDeleteData = cbData;
|
||||
}
|
||||
|
||||
void SingleFileDrive::onPlug(void (*cb)(uint32_t), uint32_t cbData) {
|
||||
_cbPlug = cb;
|
||||
_cbPlugData = cbData;
|
||||
}
|
||||
|
||||
void SingleFileDrive::onUnplug(void (*cb)(uint32_t), uint32_t cbData) {
|
||||
_cbUnplug = cb;
|
||||
_cbUnplugData = cbData;
|
||||
}
|
||||
|
||||
bool SingleFileDrive::begin(const char *localFile, const char *dosFile) {
|
||||
if (_started) {
|
||||
return false;
|
||||
}
|
||||
_localFile = strdup(localFile);
|
||||
_dosFile = strdup(dosFile);
|
||||
_started = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SingleFileDrive::end() {
|
||||
_started = false;
|
||||
free(_localFile);
|
||||
free(_dosFile);
|
||||
_localFile = nullptr;
|
||||
_dosFile = nullptr;
|
||||
}
|
||||
|
||||
void SingleFileDrive::bootSector(char buff[512]) {
|
||||
// 256MB FAT16 stolen from mkfs.fat
|
||||
// dd if=/dev/zero of=/tmp/fat.bin bs=1M seek=255 count=1
|
||||
// mkfs.fat -F 16 -r 16 -n PICODISK -i 12345678 -s 128 -m ':(' /tmp/fat.bin
|
||||
const uint8_t hdr[] = {
|
||||
0xeb, 0x3c, 0x90, 0x6d, 0x6b, 0x66, 0x73, 0x2e, 0x66, 0x61, 0x74, 0x00,
|
||||
0x02, 0x80, 0x80, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0xf8, 0x80, 0x00,
|
||||
0x20, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
|
||||
0x80, 0x00, 0x29, 0x78, 0x56, 0x34, 0x12, 0x50, 0x49, 0x43, 0x4f, 0x44,
|
||||
0x49, 0x53, 0x4b, 0x20, 0x20, 0x20, 0x46, 0x41, 0x54, 0x31, 0x36, 0x20,
|
||||
0x20, 0x20, 0x0e, 0x1f, 0xbe, 0x5b, 0x7c, 0xac, 0x22, 0xc0, 0x74, 0x0b,
|
||||
0x56, 0xb4, 0x0e, 0xbb, 0x07, 0x00, 0xcd, 0x10, 0x5e, 0xeb, 0xf0, 0x32,
|
||||
0xe4, 0xcd, 0x16, 0xcd, 0x19, 0xeb, 0xfe, 0x3a, 0x28, 0x0d, 0x0a, 0x00
|
||||
};
|
||||
memset(buff, 0, 512);
|
||||
memcpy(buff, hdr, sizeof(hdr));
|
||||
buff[0x1fe] = 0x55;
|
||||
buff[0x1ff] = 0xff;
|
||||
}
|
||||
|
||||
static char _toLegalFATChar(char c) {
|
||||
const char *odds = "!#$%&'()-@^_`{}~";
|
||||
c = toupper(c);
|
||||
if (((c >= '0') && (c <= '9')) || ((c >= 'A') && (c <= 'Z')) || strchr(odds, c)) {
|
||||
return c;
|
||||
} else {
|
||||
return '~';
|
||||
}
|
||||
}
|
||||
|
||||
void SingleFileDrive::directorySector(char buff[512]) {
|
||||
const uint8_t lbl[] = {
|
||||
0x50, 0x49, 0x43, 0x4f, 0x44, 0x49, 0x53, 0x4b, 0x20, 0x20, 0x20, 0x08, 0x00, 0x00, 0xac, 0x56,
|
||||
0x82, 0x55, 0x82, 0x55, 0x00, 0x00, 0xac, 0x56, 0x82, 0x55
|
||||
}; //, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
memset(buff, 0, 512);
|
||||
memcpy(buff, lbl, sizeof(lbl));
|
||||
buff += 32; // Skip the just-set label
|
||||
|
||||
// Create a legal 11-char UPPERCASE FILENAME WITH 0x20 PAD
|
||||
char SFN[11];
|
||||
memset(SFN, ' ', 11);
|
||||
for (int i = 0; (i < 8) && _dosFile[i] && (_dosFile[i] != '.'); i++) {
|
||||
SFN[i] = _toLegalFATChar(_dosFile[i]);
|
||||
}
|
||||
char *dot = _dosFile + strlen(_dosFile) - 1;
|
||||
while ((dot >= _dosFile) && (*dot != '.')) {
|
||||
dot--;
|
||||
}
|
||||
if (*dot == '.') {
|
||||
dot++;
|
||||
for (int i = 0; (i < 3) && dot[i]; i++) {
|
||||
SFN[8 + i] = _toLegalFATChar(dot[i]);
|
||||
}
|
||||
}
|
||||
uint8_t chksum = 0; // for LFN
|
||||
for (int i = 0; i < 11; i++) {
|
||||
chksum = (chksum >> 1) + (chksum << 7) + SFN[i];
|
||||
}
|
||||
|
||||
// Create LFN structure
|
||||
int entries = (strlen(_dosFile) + 12) / 13; // round up
|
||||
for (int i = 0; i < entries; i++) {
|
||||
*buff++ = (entries - i) | (i == 0 ? 0x40 : 0);
|
||||
const char *partname = _dosFile + 13 * (entries - i - 1);
|
||||
for (int j = 0; j < 13; j++) {
|
||||
uint16_t u;
|
||||
if (j > (int)strlen(partname)) {
|
||||
u = 0xffff;
|
||||
} else {
|
||||
u = partname[j] & 0xff;
|
||||
}
|
||||
*buff++ = u & 0xff;
|
||||
*buff++ = (u >> 8) & 0xff;
|
||||
if (j == 4) {
|
||||
*buff++ = 0x0f; // LFN ATTR
|
||||
*buff++ = 0;
|
||||
*buff++ = chksum;
|
||||
} else if (j == 10) {
|
||||
*buff++ = 0;
|
||||
*buff++ = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create SFN
|
||||
memset(buff, 0, 32);
|
||||
for (int i = 0; i < 11; i++) {
|
||||
buff[i] = SFN[i];
|
||||
}
|
||||
buff[0x0b] = 0x20; // ATTR = Archive
|
||||
// Ignore creation data/time, etc.
|
||||
buff[0x1a] = 0x03; // Starting cluster 3
|
||||
File f = LittleFS.open(_localFile, "r");
|
||||
int size = f.size();
|
||||
f.close();
|
||||
buff[0x1c] = size & 255;
|
||||
buff[0x1d] = (size >> 8) & 255;
|
||||
buff[0x1e] = (size >> 16) & 255; // 16MB or smaller
|
||||
}
|
||||
|
||||
void SingleFileDrive::fatSector(char fat[512]) {
|
||||
memset(fat, 0, 512);
|
||||
fat[0x00] = 0xff;
|
||||
fat[0x01] = 0xf8;
|
||||
fat[0x02] = 0xff;
|
||||
fat[0x03] = 0xff;
|
||||
int cluster = 3;
|
||||
File f = LittleFS.open(_localFile, "r");
|
||||
int size = f.size();
|
||||
f.close();
|
||||
while (size > 65536) {
|
||||
fat[cluster * 2] = (cluster + 1) & 0xff;
|
||||
fat[cluster * 2 + 1] = ((cluster + 1) >> 8) & 0xff;
|
||||
cluster++;
|
||||
size -= 65536;
|
||||
}
|
||||
fat[cluster * 2] = 0xff;
|
||||
fat[cluster * 2 + 1] = 0xff;
|
||||
}
|
||||
|
||||
// Invoked to determine max LUN
|
||||
extern "C" uint8_t tud_msc_get_maxlun_cb(void) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Invoked when received SCSI_CMD_INQUIRY
|
||||
// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively
|
||||
extern "C" void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) {
|
||||
(void) lun;
|
||||
|
||||
const char vid[] = "PicoDisk";
|
||||
const char pid[] = "Mass Storage";
|
||||
const char rev[] = "1.0";
|
||||
|
||||
memcpy(vendor_id, vid, strlen(vid));
|
||||
memcpy(product_id, pid, strlen(pid));
|
||||
memcpy(product_rev, rev, strlen(rev));
|
||||
}
|
||||
|
||||
bool SingleFileDrive::testUnitReady() {
|
||||
return _started;
|
||||
}
|
||||
|
||||
// Invoked when received Test Unit Ready command.
|
||||
// return true allowing host to read/write this LUN e.g SD card inserted
|
||||
extern "C" bool tud_msc_test_unit_ready_cb(uint8_t lun) {
|
||||
(void) lun;
|
||||
|
||||
return singleFileDrive.testUnitReady();
|
||||
}
|
||||
|
||||
// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size
|
||||
// Application update block count and block size
|
||||
extern "C" void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) {
|
||||
(void) lun;
|
||||
*block_count = _hddsects;
|
||||
*block_size = 512;
|
||||
}
|
||||
|
||||
|
||||
// Callback invoked when received READ10 command.
|
||||
// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
|
||||
extern "C" int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) {
|
||||
(void) lun;
|
||||
return singleFileDrive.read10(lba, offset, buffer, bufsize);
|
||||
}
|
||||
|
||||
int32_t SingleFileDrive::read10(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) {
|
||||
if (!_started || (lba >= _hddsects)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t toread = bufsize;
|
||||
char buff[512];
|
||||
uint8_t *curbuff = (uint8_t *)buffer;
|
||||
|
||||
while (bufsize > 0) {
|
||||
if (lba == 0) {
|
||||
bootSector(buff);
|
||||
} else if ((lba == 128) || (lba == 256)) {
|
||||
fatSector(buff);
|
||||
} else if (lba == 384) {
|
||||
directorySector(buff);
|
||||
} else if (lba >= 640) {
|
||||
File f = LittleFS.open(_localFile, "r");
|
||||
f.seek((lba - 640) * 512);
|
||||
f.read((uint8_t*)buff, 512);
|
||||
f.close();
|
||||
} else {
|
||||
memset(buff, 0, sizeof(buff));
|
||||
}
|
||||
|
||||
uint32_t cplen = 512 - offset;
|
||||
if (bufsize < cplen) {
|
||||
cplen = bufsize;
|
||||
}
|
||||
memcpy(curbuff, buff + offset, cplen);
|
||||
curbuff += cplen;
|
||||
offset = 0;
|
||||
lba++;
|
||||
bufsize -= cplen;
|
||||
}
|
||||
|
||||
return toread;
|
||||
}
|
||||
|
||||
extern "C" bool tud_msc_is_writable_cb(uint8_t lun) {
|
||||
(void) lun;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Callback invoked when received WRITE10 command.
|
||||
// Process data in buffer to disk's storage and return number of written bytes
|
||||
extern "C" int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) {
|
||||
(void) lun;
|
||||
return singleFileDrive.write10(lba, offset, buffer, bufsize);
|
||||
}
|
||||
|
||||
int32_t SingleFileDrive::write10(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) {
|
||||
if (!_started || (lba >= _hddsects)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t addr = lba * 512 + offset;
|
||||
uint32_t hotspot = 384 * 512 + 0x20;
|
||||
if ((addr > hotspot) || (addr + bufsize < hotspot)) {
|
||||
// Did not try and erase the file entry, ignore
|
||||
return bufsize;
|
||||
}
|
||||
int off = hotspot - addr;
|
||||
uint8_t *ptr = (uint8_t *)buffer;
|
||||
ptr += off;
|
||||
if (*ptr == 0xe5) {
|
||||
if (_cbDelete) {
|
||||
_cbDelete(_cbDeleteData);
|
||||
}
|
||||
}
|
||||
|
||||
return bufsize;
|
||||
}
|
||||
|
||||
extern "C" bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, uint8_t add_sense_qualifier);
|
||||
|
||||
// Callback invoked when received an SCSI command not in built-in list below
|
||||
// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
|
||||
// - READ10 and WRITE10 has their own callbacks
|
||||
extern "C" int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) {
|
||||
const int SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL = 0x1E;
|
||||
const int SCSI_CMD_START_STOP_UNIT = 0x1B;
|
||||
const int SCSI_SENSE_ILLEGAL_REQUEST = 0x05;
|
||||
|
||||
void const* response = NULL;
|
||||
int32_t resplen = 0;
|
||||
|
||||
// most scsi handled is input
|
||||
bool in_xfer = true;
|
||||
scsi_start_stop_unit_t const * start_stop = (scsi_start_stop_unit_t const *) scsi_cmd;
|
||||
switch (scsi_cmd[0]) {
|
||||
case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
|
||||
// Host is about to read/write etc ... better not to disconnect disk
|
||||
if (scsi_cmd[4] & 1) {
|
||||
singleFileDrive.plug();
|
||||
}
|
||||
resplen = 0;
|
||||
break;
|
||||
case SCSI_CMD_START_STOP_UNIT:
|
||||
// Host try to eject/safe remove/poweroff us. We could safely disconnect with disk storage, or go into lower power
|
||||
if (!start_stop->start && start_stop->load_eject) {
|
||||
singleFileDrive.unplug();
|
||||
} else if (start_stop->start && start_stop->load_eject) {
|
||||
singleFileDrive.plug();
|
||||
}
|
||||
resplen = 0;
|
||||
break;
|
||||
default:
|
||||
// Set Sense = Invalid Command Operation
|
||||
tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
|
||||
// negative means error -> tinyusb could stall and/or response with failed status
|
||||
resplen = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
// return resplen must not larger than bufsize
|
||||
if (resplen > bufsize) {
|
||||
resplen = bufsize;
|
||||
}
|
||||
|
||||
if (response && (resplen > 0)) {
|
||||
if (in_xfer) {
|
||||
memcpy(buffer, response, resplen);
|
||||
} else {
|
||||
// SCSI output
|
||||
}
|
||||
}
|
||||
|
||||
return resplen;
|
||||
}
|
||||
|
||||
void SingleFileDrive::plug() {
|
||||
if (_started && _cbPlug) {
|
||||
_cbPlug(_cbPlugData);
|
||||
}
|
||||
}
|
||||
|
||||
void SingleFileDrive::unplug() {
|
||||
if (_started && _cbUnplug) {
|
||||
_cbUnplug(_cbUnplugData);
|
||||
}
|
||||
}
|
||||
|
||||
// Callback invoked on start/stop
|
||||
extern "C" bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) {
|
||||
(void) lun;
|
||||
(void) power_condition;
|
||||
if (start && load_eject) {
|
||||
singleFileDrive.plug();
|
||||
} else if (!start && load_eject) {
|
||||
singleFileDrive.unplug();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
SingleFileDrive - Emulates a USB stick for easy data transfer
|
||||
Copyright (c) 2022 Earle F. Philhower, III. All rights reserved.
|
||||
|
||||
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>
|
||||
|
||||
class SingleFileDrive {
|
||||
public:
|
||||
SingleFileDrive();
|
||||
~SingleFileDrive();
|
||||
|
||||
bool begin(const char *localFile, const char *dosFile);
|
||||
void end();
|
||||
|
||||
void onDelete(void (*cb)(uint32_t), uint32_t cbData = 0);
|
||||
void onPlug(void (*cb)(uint32_t), uint32_t cbData = 0);
|
||||
void onUnplug(void (*cb)(uint32_t), uint32_t cbData = 0);
|
||||
|
||||
// Only for internal TinyUSB callback use
|
||||
bool testUnitReady();
|
||||
int32_t read10(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize);
|
||||
int32_t write10(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize);
|
||||
void plug();;
|
||||
void unplug();
|
||||
|
||||
private:
|
||||
void bootSector(char buff[512]);
|
||||
void directorySector(char buff[512]);
|
||||
void fatSector(char buff[512]);
|
||||
|
||||
private:
|
||||
bool _started = false;
|
||||
char *_localFile = nullptr;
|
||||
char *_dosFile = nullptr;
|
||||
|
||||
void (*_cbDelete)(uint32_t) = nullptr;
|
||||
uint32_t _cbDeleteData = 0;
|
||||
|
||||
void (*_cbPlug)(uint32_t) = nullptr;
|
||||
uint32_t _cbPlugData = 0;
|
||||
|
||||
void (*_cbUnplug)(uint32_t) = nullptr;
|
||||
uint32_t _cbUnplugData = 0;
|
||||
};
|
||||
|
||||
extern SingleFileDrive singleFileDrive;
|
||||
@@ -43,9 +43,10 @@ const char *password = STAPSK;
|
||||
|
||||
WebServer server(80);
|
||||
|
||||
const int led = 13;
|
||||
const int led = LED_BUILTIN;
|
||||
|
||||
void handleRoot() {
|
||||
static int cnt = 0;
|
||||
digitalWrite(led, 1);
|
||||
char temp[400];
|
||||
int sec = millis() / 1000;
|
||||
@@ -65,11 +66,13 @@ void handleRoot() {
|
||||
<body>\
|
||||
<h1>Hello from the Pico W!</h1>\
|
||||
<p>Uptime: %02d:%02d:%02d</p>\
|
||||
<p>Free Memory: %d</p>\
|
||||
<p>Page Count: %d</p>\
|
||||
<img src=\"/test.svg\" />\
|
||||
</body>\
|
||||
</html>",
|
||||
|
||||
hr, min % 60, sec % 60);
|
||||
hr, min % 60, sec % 60, rp2040.getFreeHeap(), ++cnt);
|
||||
server.send(200, "text/html", temp);
|
||||
digitalWrite(led, 0);
|
||||
}
|
||||
|
||||
@@ -280,7 +280,10 @@ void HTTPServer::httpHandleClient() {
|
||||
}
|
||||
|
||||
if (!keepCurrentClient) {
|
||||
_currentClient = nullptr;
|
||||
if (_currentClient) {
|
||||
delete _currentClient;
|
||||
_currentClient = nullptr;
|
||||
}
|
||||
_currentStatus = HC_NONE;
|
||||
_currentUpload.reset();
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ gatewayIP KEYWORD2
|
||||
SSID KEYWORD2
|
||||
BSSID KEYWORD2
|
||||
RSSI KEYWORD2
|
||||
channel KEYWORD2
|
||||
encryptionType KEYWORD2
|
||||
beginPacket KEYWORD2
|
||||
endPacket KEYWORD2
|
||||
@@ -56,7 +57,8 @@ beginEnterprise KEYWORD2
|
||||
setHostname KEYWORD2
|
||||
end KEYWORD2
|
||||
getTime KEYWORD2
|
||||
lowPowerMode KEYWORD2
|
||||
aggressiveLowPowerMode KEYWORD2
|
||||
defaultLowPowerMode KEYWORD2
|
||||
noLowPowerMode KEYWORD2
|
||||
ping KEYWORD2
|
||||
beginMulticast KEYWORD2
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
#include "wl_definitions.h"
|
||||
#include "wl_types.h"
|
||||
|
||||
#include "LWIPMutex.h"
|
||||
|
||||
#include "WiFiClass.h"
|
||||
#include "WiFiClient.h"
|
||||
#include "WiFiServer.h"
|
||||
|
||||
@@ -44,17 +44,20 @@ const char* WiFiClass::firmwareVersion() {
|
||||
return PICO_SDK_VERSION_STRING;
|
||||
}
|
||||
|
||||
void WiFiClass::mode(_wifiModeESP m) {
|
||||
void WiFiClass::mode(WiFiMode_t m) {
|
||||
_calledESP = true;
|
||||
switch (m) {
|
||||
case WIFI_OFF:
|
||||
case WiFiMode_t::WIFI_OFF:
|
||||
end();
|
||||
break;
|
||||
case WIFI_AP:
|
||||
_modeESP = WIFI_AP;
|
||||
case WiFiMode_t::WIFI_AP:
|
||||
_modeESP = WiFiMode_t::WIFI_AP;
|
||||
break;
|
||||
case WIFI_STA:
|
||||
_modeESP = WIFI_STA;
|
||||
case WiFiMode_t::WIFI_STA:
|
||||
_modeESP = WiFiMode_t::WIFI_STA;
|
||||
break;
|
||||
case WiFiMode_t::WIFI_AP_STA:
|
||||
_modeESP = WiFiMode_t::WIFI_STA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -86,7 +89,7 @@ int WiFiClass::begin(const char* ssid, const char *passphrase) {
|
||||
|
||||
_ssid = ssid;
|
||||
_password = passphrase;
|
||||
_wifi.setSSID(ssid);
|
||||
_wifi.setSSID(_ssid.c_str());
|
||||
_wifi.setPassword(passphrase);
|
||||
_wifi.setTimeout(_timeout);
|
||||
_wifi.setSTA();
|
||||
@@ -96,6 +99,7 @@ int WiFiClass::begin(const char* ssid, const char *passphrase) {
|
||||
if (!_wifi.begin()) {
|
||||
return WL_IDLE_STATUS;
|
||||
}
|
||||
noLowPowerMode();
|
||||
// Enable CYW43 event debugging (make sure Debug Port is set)
|
||||
//cyw43_state.trace_flags = 0xffff;
|
||||
while (!_calledESP && ((millis() - start < (uint32_t)2 * _timeout)) && !connected()) {
|
||||
@@ -123,7 +127,7 @@ uint8_t WiFiClass::beginAP(const char *ssid, const char* passphrase) {
|
||||
|
||||
_ssid = ssid;
|
||||
_password = passphrase;
|
||||
_wifi.setSSID(ssid);
|
||||
_wifi.setSSID(_ssid.c_str());
|
||||
_wifi.setPassword(passphrase);
|
||||
_wifi.setTimeout(_timeout);
|
||||
_wifi.setAP();
|
||||
@@ -131,6 +135,7 @@ uint8_t WiFiClass::beginAP(const char *ssid, const char* passphrase) {
|
||||
if (!_wifi.begin()) {
|
||||
return WL_IDLE_STATUS;
|
||||
}
|
||||
noLowPowerMode();
|
||||
IPAddress gw = _wifi.gatewayIP();
|
||||
if (!gw.isSet()) {
|
||||
gw = IPAddress(192, 168, 42, 1);
|
||||
@@ -234,7 +239,7 @@ const char *WiFiClass::getHostname() {
|
||||
|
||||
return: one value of wl_status_t enum
|
||||
*/
|
||||
int WiFiClass::disconnect(void) {
|
||||
int WiFiClass::disconnect(bool wifi_off __unused) {
|
||||
if (_dhcpServer) {
|
||||
dhcp_server_deinit(_dhcpServer);
|
||||
free(_dhcpServer);
|
||||
@@ -300,7 +305,7 @@ IPAddress WiFiClass::gatewayIP() {
|
||||
|
||||
return: ssid string
|
||||
*/
|
||||
const char* WiFiClass::SSID() {
|
||||
const String &WiFiClass::SSID() {
|
||||
return _ssid;
|
||||
}
|
||||
|
||||
@@ -311,11 +316,33 @@ const char* WiFiClass::SSID() {
|
||||
return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH
|
||||
*/
|
||||
uint8_t* WiFiClass::BSSID(uint8_t* bssid) {
|
||||
// TODO - driver does not return this?!
|
||||
memset(bssid, 0xee, WL_MAC_ADDR_LENGTH);
|
||||
#ifndef CYW43_IOCTL_GET_BSSID
|
||||
#define CYW43_IOCTL_GET_BSSID ( (uint32_t)23 * 2 )
|
||||
#endif
|
||||
|
||||
if (_wifi.connected()) {
|
||||
cyw43_ioctl(&cyw43_state, CYW43_IOCTL_GET_BSSID, WL_MAC_ADDR_LENGTH, bssid, CYW43_ITF_STA);
|
||||
} else {
|
||||
memset(bssid, 0, WL_MAC_ADDR_LENGTH);
|
||||
}
|
||||
return bssid;
|
||||
}
|
||||
|
||||
int WiFiClass::channel() {
|
||||
#ifndef CYW43_IOCTL_GET_CHANNEL
|
||||
#define CYW43_IOCTL_GET_CHANNEL 0x3a
|
||||
#endif
|
||||
|
||||
int32_t channel;
|
||||
if (_wifi.connected()) {
|
||||
cyw43_ioctl(&cyw43_state, CYW43_IOCTL_GET_CHANNEL, sizeof channel, (uint8_t *)&channel, CYW43_ITF_STA);
|
||||
} else {
|
||||
channel = -1;
|
||||
}
|
||||
return channel;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Return the current RSSI /Received Signal Strength in dBm)
|
||||
associated with the network
|
||||
@@ -323,8 +350,17 @@ uint8_t* WiFiClass::BSSID(uint8_t* bssid) {
|
||||
return: signed value
|
||||
*/
|
||||
int32_t WiFiClass::RSSI() {
|
||||
// TODO - driver does not return this?!
|
||||
return 0;
|
||||
#ifndef CYW43_IOCTL_GET_RSSI
|
||||
#define CYW43_IOCTL_GET_RSSI 0xFE
|
||||
#endif
|
||||
|
||||
int32_t rssi;
|
||||
if (_wifi.connected()) {
|
||||
cyw43_ioctl(&cyw43_state, CYW43_IOCTL_GET_RSSI, sizeof rssi, (uint8_t *)&rssi, CYW43_ITF_STA);
|
||||
} else {
|
||||
rssi = -255;
|
||||
}
|
||||
return rssi;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -365,7 +401,7 @@ int WiFiClass::_scanCB(void *env, const cyw43_ev_scan_result_t *result) {
|
||||
|
||||
return: Number of discovered networks
|
||||
*/
|
||||
int8_t WiFiClass::scanNetworks() {
|
||||
int8_t WiFiClass::scanNetworks(bool async) {
|
||||
cyw43_wifi_scan_options_t scan_options;
|
||||
memset(&scan_options, 0, sizeof(scan_options));
|
||||
_scan.clear();
|
||||
@@ -378,11 +414,27 @@ int8_t WiFiClass::scanNetworks() {
|
||||
if (err) {
|
||||
return 0;
|
||||
}
|
||||
uint32_t now = millis();
|
||||
while (cyw43_wifi_scan_active(&cyw43_state) && (millis() - now < 10000)) {
|
||||
delay(10);
|
||||
if (!async) {
|
||||
uint32_t now = millis();
|
||||
while (cyw43_wifi_scan_active(&cyw43_state) && (millis() - now < 10000)) {
|
||||
delay(10);
|
||||
}
|
||||
return _scan.size();
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
return _scan.size();
|
||||
}
|
||||
|
||||
int8_t WiFiClass::scanComplete() {
|
||||
if (cyw43_wifi_scan_active(&cyw43_state)) {
|
||||
return -1;
|
||||
} else {
|
||||
return _scan.size();
|
||||
}
|
||||
}
|
||||
|
||||
void WiFiClass::scanDelete() {
|
||||
_scan.clear();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -515,14 +567,19 @@ unsigned long WiFiClass::getTime() {
|
||||
return millis();
|
||||
}
|
||||
|
||||
void WiFiClass::lowPowerMode() {
|
||||
void WiFiClass::aggressiveLowPowerMode() {
|
||||
cyw43_wifi_pm(&cyw43_state, CYW43_AGGRESSIVE_PM);
|
||||
}
|
||||
|
||||
void WiFiClass::noLowPowerMode() {
|
||||
void WiFiClass::defaultLowPowerMode() {
|
||||
cyw43_wifi_pm(&cyw43_state, CYW43_DEFAULT_PM);
|
||||
}
|
||||
|
||||
// The difference between the default CYW43_DEFAULT_PM (0xA11142) and not low power (0xA11140) is that it changed from "Powersave mode on specified interface with High throughput" to "No Powersave mode". All other parameters stayed the same.
|
||||
void WiFiClass::noLowPowerMode() {
|
||||
cyw43_wifi_pm(&cyw43_state, 0xA11140);
|
||||
}
|
||||
|
||||
int WiFiClass::ping(const char* hostname, uint8_t ttl) {
|
||||
IPAddress ip;
|
||||
if (!hostByName(hostname, ip)) {
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
typedef void(*FeedHostProcessorWatchdogFuncPointer)();
|
||||
|
||||
typedef enum { WIFI_STA, WIFI_AP, WIFI_OFF } _wifiModeESP; // For ESP8266 compatibility
|
||||
typedef enum { WIFI_OFF = 0, WIFI_STA = 1, WIFI_AP = 2, WIFI_AP_STA = 3 } WiFiMode_t; // For ESP8266 compatibility
|
||||
|
||||
class WiFiClass {
|
||||
public:
|
||||
@@ -46,7 +46,18 @@ public:
|
||||
*/
|
||||
static const char* firmwareVersion();
|
||||
|
||||
void mode(_wifiModeESP m); // For ESP8266 compatibility
|
||||
void mode(WiFiMode_t m); // For ESP8266 compatibility
|
||||
|
||||
WiFiMode_t getMode() {
|
||||
if (_wifiHWInitted) {
|
||||
if (_apMode) {
|
||||
return WiFiMode_t::WIFI_AP;
|
||||
} else {
|
||||
return WiFiMode_t::WIFI_STA;
|
||||
}
|
||||
}
|
||||
return WiFiMode_t::WIFI_OFF;
|
||||
};
|
||||
|
||||
/* Start WiFi connection for OPEN networks
|
||||
|
||||
@@ -138,7 +149,7 @@ public:
|
||||
}
|
||||
|
||||
String softAPSSID() {
|
||||
return String(SSID());
|
||||
return SSID();
|
||||
}
|
||||
|
||||
|
||||
@@ -205,7 +216,7 @@ public:
|
||||
|
||||
return: one value of wl_status_t enum
|
||||
*/
|
||||
int disconnect(void);
|
||||
int disconnect(bool wifi_off = false);
|
||||
|
||||
void end(void);
|
||||
|
||||
@@ -249,7 +260,7 @@ public:
|
||||
|
||||
return: ssid string
|
||||
*/
|
||||
const char* SSID();
|
||||
const String &SSID();
|
||||
|
||||
/*
|
||||
Return the current BSSID associated with the network.
|
||||
@@ -267,6 +278,10 @@ public:
|
||||
*/
|
||||
int32_t RSSI();
|
||||
|
||||
|
||||
/* Return the current network channel */
|
||||
int channel();
|
||||
|
||||
/*
|
||||
Return the Encryption Type associated with the network
|
||||
|
||||
@@ -277,9 +292,23 @@ public:
|
||||
/*
|
||||
Start scan WiFi networks available
|
||||
|
||||
param async: whether to perform asynchronous scan
|
||||
|
||||
return: Number of discovered networks
|
||||
*/
|
||||
int8_t scanNetworks();
|
||||
int8_t scanNetworks(bool async = false);
|
||||
|
||||
/*
|
||||
Return number of scanned WiFi networks
|
||||
|
||||
return: Number of discovered networks
|
||||
*/
|
||||
int8_t scanComplete();
|
||||
|
||||
/*
|
||||
Delete scan results
|
||||
*/
|
||||
void scanDelete();
|
||||
|
||||
/*
|
||||
Return the SSID discovered during the network scan.
|
||||
@@ -339,7 +368,8 @@ public:
|
||||
|
||||
unsigned long getTime();
|
||||
|
||||
void lowPowerMode();
|
||||
void aggressiveLowPowerMode();
|
||||
void defaultLowPowerMode();
|
||||
void noLowPowerMode();
|
||||
|
||||
int ping(const char* hostname, uint8_t ttl = 128);
|
||||
@@ -352,9 +382,9 @@ public:
|
||||
void feedWatchdog();
|
||||
|
||||
private:
|
||||
int _timeout = 10000;
|
||||
const char * _ssid = nullptr;
|
||||
const char * _password = nullptr;
|
||||
int _timeout = 15000;
|
||||
String _ssid;
|
||||
String _password;
|
||||
bool _wifiHWInitted = false;
|
||||
bool _apMode = false;
|
||||
|
||||
@@ -367,7 +397,7 @@ private:
|
||||
|
||||
// ESP compat
|
||||
bool _calledESP = false; // Should we behave like the ESP8266 for connect?
|
||||
_wifiModeESP _modeESP = WIFI_STA;
|
||||
WiFiMode_t _modeESP = WIFI_STA;
|
||||
};
|
||||
|
||||
extern WiFiClass WiFi;
|
||||
|
||||
@@ -130,8 +130,6 @@ int WiFiClient::connect(IPAddress ip, uint16_t port) {
|
||||
_client = nullptr;
|
||||
}
|
||||
|
||||
LWIPMutex m; // Block the timer sys_check_timeouts call
|
||||
|
||||
tcp_pcb* pcb = tcp_new();
|
||||
if (!pcb) {
|
||||
return 0;
|
||||
|
||||
@@ -56,8 +56,6 @@ void WiFiServer::begin(uint16_t port, uint8_t backlog) {
|
||||
}
|
||||
_port = port;
|
||||
|
||||
LWIPMutex m; // Block the timer sys_check_timeouts call
|
||||
|
||||
tcp_pcb* pcb = tcp_new();
|
||||
if (!pcb) {
|
||||
return;
|
||||
@@ -134,7 +132,6 @@ WiFiClient WiFiServer::accept() {
|
||||
|
||||
// pcb can be null when peer has already closed the connection
|
||||
if (_unclaimed->getPCB()) {
|
||||
LWIPMutex m; // Block the timer sys_check_timeouts call
|
||||
// give permission to lwIP to accept one more peer
|
||||
tcp_backlog_accepted(_unclaimed->getPCB());
|
||||
}
|
||||
@@ -162,7 +159,6 @@ void WiFiServer::close() {
|
||||
if (!_listen_pcb) {
|
||||
return;
|
||||
}
|
||||
LWIPMutex m; // Block the timer sys_check_timeouts call
|
||||
tcp_close(_listen_pcb);
|
||||
_listen_pcb = nullptr;
|
||||
}
|
||||
@@ -197,7 +193,6 @@ err_t WiFiServer::_accept(tcp_pcb* apcb, err_t err) {
|
||||
// https://www.nongnu.org/lwip/2_1_x/group__tcp__raw.html#gaeff14f321d1eecd0431611f382fcd338
|
||||
|
||||
// increase lwIP's backlog
|
||||
LWIPMutex m; // Block the timer sys_check_timeouts call
|
||||
tcp_backlog_delayed(apcb);
|
||||
|
||||
_unclaimed = slist_append_tail(_unclaimed, client);
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include <wl_definitions.h>
|
||||
struct tcp_pcb;
|
||||
|
||||
#include <LWIPMutex.h>
|
||||
#include <Server.h>
|
||||
#include <IPAddress.h>
|
||||
#include <lwip/err.h>
|
||||
|
||||
@@ -27,6 +27,8 @@ class WiFiClient;
|
||||
typedef void (*discard_cb_t)(void*, ClientContext*);
|
||||
|
||||
#include <assert.h>
|
||||
#include "lwip/timeouts.h"
|
||||
|
||||
//#include <esp_priv.h>
|
||||
//#include <coredecls.h>
|
||||
|
||||
@@ -36,6 +38,7 @@ template <typename T>
|
||||
inline void esp_delay(const uint32_t timeout_ms, T&& blocked, const uint32_t intvl_ms) {
|
||||
const auto start_ms = millis();
|
||||
while ((((uint32_t)millis() - start_ms) < timeout_ms) && blocked()) {
|
||||
sys_check_timeouts();
|
||||
delay(intvl_ms);
|
||||
}
|
||||
}
|
||||
@@ -68,7 +71,6 @@ public:
|
||||
tcp_recv(_pcb, nullptr);
|
||||
tcp_err(_pcb, nullptr);
|
||||
tcp_poll(_pcb, nullptr, 0);
|
||||
LWIPMutex m; // Block the timer sys_check_timeouts call
|
||||
tcp_abort(_pcb);
|
||||
_pcb = nullptr;
|
||||
}
|
||||
@@ -84,7 +86,6 @@ public:
|
||||
tcp_recv(_pcb, nullptr);
|
||||
tcp_err(_pcb, nullptr);
|
||||
tcp_poll(_pcb, nullptr, 0);
|
||||
LWIPMutex m; // Block the timer sys_check_timeouts call
|
||||
err = tcp_close(_pcb);
|
||||
if (err != ERR_OK) {
|
||||
DEBUGV(":tc err %d\r\n", (int) err);
|
||||
@@ -136,7 +137,6 @@ public:
|
||||
ip6_addr_assign_zone(ip_2_ip6(addr), IP6_UNKNOWN, netif_default);
|
||||
}
|
||||
#endif
|
||||
LWIPMutex m; // Block the timer sys_check_timeouts call
|
||||
err_t err = tcp_connect(_pcb, addr, port, &ClientContext::_s_connected);
|
||||
if (err != ERR_OK) {
|
||||
return 0;
|
||||
@@ -162,7 +162,6 @@ public:
|
||||
}
|
||||
|
||||
size_t availableForWrite() const {
|
||||
LWIPMutex m; // Block the timer sys_check_timeouts call
|
||||
return _pcb ? tcp_sndbuf(_pcb) : 0;
|
||||
}
|
||||
|
||||
@@ -170,7 +169,6 @@ public:
|
||||
if (!_pcb) {
|
||||
return;
|
||||
}
|
||||
LWIPMutex m; // Block the timer sys_check_timeouts call
|
||||
if (nodelay) {
|
||||
tcp_nagle_disable(_pcb);
|
||||
} else {
|
||||
@@ -182,7 +180,6 @@ public:
|
||||
if (!_pcb) {
|
||||
return false;
|
||||
}
|
||||
LWIPMutex m; // Block the timer sys_check_timeouts call
|
||||
return tcp_nagle_disabled(_pcb);
|
||||
}
|
||||
|
||||
@@ -300,7 +297,6 @@ public:
|
||||
if (!_rx_buf) {
|
||||
return;
|
||||
}
|
||||
LWIPMutex m; // Block the timer sys_check_timeouts call
|
||||
if (_pcb) {
|
||||
tcp_recved(_pcb, (size_t) _rx_buf->tot_len);
|
||||
}
|
||||
@@ -332,7 +328,6 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
LWIPMutex m; // Block the timer sys_check_timeouts call
|
||||
|
||||
// force lwIP to send what can be sent
|
||||
tcp_output(_pcb);
|
||||
@@ -379,12 +374,22 @@ public:
|
||||
return 0;
|
||||
}
|
||||
size_t sent = 0;
|
||||
uint8_t buff[256];
|
||||
while (stream.available()) {
|
||||
char b;
|
||||
b = stream.read();
|
||||
if (write(&b, 1)) {
|
||||
sent ++;
|
||||
// Stream only lets you read 1 byte at a time, so buffer in local copy
|
||||
size_t i;
|
||||
for (i = 0; (i < sizeof(buff)) && stream.available(); i++) {
|
||||
buff[i] = stream.read();
|
||||
}
|
||||
if (i) {
|
||||
// Send as a single packet
|
||||
int len = write((const char *)buff, i);
|
||||
sent += len;
|
||||
if (len != (int)i) {
|
||||
break; // Write error...
|
||||
}
|
||||
} else {
|
||||
// Out of data...
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -517,7 +522,6 @@ protected:
|
||||
const auto remaining = _datalen - _written;
|
||||
size_t next_chunk_size;
|
||||
{
|
||||
LWIPMutex m; // Block the timer sys_check_timeouts call, just for this call
|
||||
next_chunk_size = std::min((size_t)tcp_sndbuf(_pcb), remaining);
|
||||
// Potentially reduce transmit size if we are tight on memory, but only if it doesn't return a 0 chunk size
|
||||
if (next_chunk_size > (size_t)(1 << scale)) {
|
||||
@@ -571,7 +575,6 @@ protected:
|
||||
// lwIP's tcp_output doc: "Find out what we can send and send it"
|
||||
// *with respect to Nagle*
|
||||
// more info: https://lists.gnu.org/archive/html/lwip-users/2017-11/msg00134.html
|
||||
LWIPMutex m; // Block the timer sys_check_timeouts call
|
||||
tcp_output(_pcb);
|
||||
}
|
||||
|
||||
@@ -596,7 +599,6 @@ protected:
|
||||
|
||||
void _consume(size_t size) {
|
||||
ptrdiff_t left = _rx_buf->len - _rx_buf_offset - size;
|
||||
LWIPMutex m; // Block the timer sys_check_timeouts call
|
||||
if (left > 0) {
|
||||
_rx_buf_offset += size;
|
||||
} else if (!_rx_buf->next) {
|
||||
@@ -638,7 +640,6 @@ protected:
|
||||
|
||||
if (_rx_buf) {
|
||||
DEBUGV(":rch %d, %d\r\n", _rx_buf->tot_len, pb->tot_len);
|
||||
LWIPMutex m; // Block the timer sys_check_timeouts call
|
||||
pbuf_cat(_rx_buf, pb);
|
||||
} else {
|
||||
DEBUGV(":rn %d\r\n", pb->tot_len);
|
||||
@@ -676,24 +677,44 @@ protected:
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
// We may receive a nullptr as arg in the case when an IRQ happens during a shutdown sequence
|
||||
// In that case, just ignore the CB
|
||||
static err_t _s_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *pb, err_t err) {
|
||||
return reinterpret_cast<ClientContext*>(arg)->_recv(tpcb, pb, err);
|
||||
if (arg) {
|
||||
return reinterpret_cast<ClientContext*>(arg)->_recv(tpcb, pb, err);
|
||||
} else {
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
static void _s_error(void *arg, err_t err) {
|
||||
reinterpret_cast<ClientContext*>(arg)->_error(err);
|
||||
if (arg) {
|
||||
reinterpret_cast<ClientContext*>(arg)->_error(err);
|
||||
}
|
||||
}
|
||||
|
||||
static err_t _s_poll(void *arg, struct tcp_pcb *tpcb) {
|
||||
return reinterpret_cast<ClientContext*>(arg)->_poll(tpcb);
|
||||
if (arg) {
|
||||
return reinterpret_cast<ClientContext*>(arg)->_poll(tpcb);
|
||||
} else {
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
static err_t _s_acked(void *arg, struct tcp_pcb *tpcb, uint16_t len) {
|
||||
return reinterpret_cast<ClientContext*>(arg)->_acked(tpcb, len);
|
||||
if (arg) {
|
||||
return reinterpret_cast<ClientContext*>(arg)->_acked(tpcb, len);
|
||||
} else {
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
static err_t _s_connected(void* arg, struct tcp_pcb *pcb, err_t err) {
|
||||
return reinterpret_cast<ClientContext*>(arg)->_connected(pcb, err);
|
||||
if (arg) {
|
||||
return reinterpret_cast<ClientContext*>(arg)->_connected(pcb, err);
|
||||
} else {
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -29,6 +29,8 @@ extern "C" {
|
||||
|
||||
#include <AddrList.h>
|
||||
#include <Arduino.h>
|
||||
#include "lwip/timeouts.h"
|
||||
|
||||
//#include <PolledTimeout.h>
|
||||
|
||||
#define PBUF_ALIGNER_ADJUST 4
|
||||
@@ -383,6 +385,7 @@ public:
|
||||
uint32_t start = millis();
|
||||
while (((err = trySend(addr, port, /* keep buffer on error */true)) != ERR_OK) && (millis() - start < timeoutMs)) {
|
||||
delay(1);
|
||||
sys_check_timeouts();
|
||||
}
|
||||
if (err != ERR_OK) {
|
||||
cancelBuffer(); // get rid of buffer kept on error after timeout
|
||||
|
||||
+42
-31
@@ -140,23 +140,52 @@ void TwoWire::begin(uint8_t addr) {
|
||||
_running = true;
|
||||
}
|
||||
|
||||
// See: https://github.com/earlephilhower/arduino-pico/issues/979#issuecomment-1328237128
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("O0")
|
||||
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;
|
||||
// Make a local copy of the IRQ status up front. If it changes while we're
|
||||
// running the IRQ callback will fire again after returning. Avoids potential
|
||||
// race conditions
|
||||
uint32_t irqstat = _i2c->hw->intr_stat;
|
||||
if (irqstat == 0) {
|
||||
return;
|
||||
}
|
||||
if (_i2c->hw->intr_stat & (1 << 10)) {
|
||||
_buffLen = 0;
|
||||
_buffOff = 0;
|
||||
|
||||
// First, pull off any data available
|
||||
if (irqstat & (1 << 2)) {
|
||||
// RX_FULL
|
||||
if (_buffLen < (int)sizeof(_buff)) {
|
||||
_buff[_buffLen++] = _i2c->hw->data_cmd & 0xff;
|
||||
} else {
|
||||
_i2c->hw->data_cmd;
|
||||
}
|
||||
}
|
||||
// RD_REQ
|
||||
if (irqstat & (1 << 5)) {
|
||||
if (_onRequestCallback) {
|
||||
_onRequestCallback();
|
||||
}
|
||||
_i2c->hw->clr_rd_req;
|
||||
}
|
||||
// TX_ABRT
|
||||
if (irqstat & (1 << 6)) {
|
||||
_i2c->hw->clr_tx_abrt;
|
||||
}
|
||||
// START_DET
|
||||
if (irqstat & (1 << 10)) {
|
||||
_slaveStartDet = true;
|
||||
_i2c->hw->clr_start_det;
|
||||
}
|
||||
if (_i2c->hw->intr_stat & (1 << 9)) {
|
||||
// RESTART_DET
|
||||
if (irqstat & (1 << 12)) {
|
||||
if (_onReceiveCallback && _buffLen) {
|
||||
_onReceiveCallback(_buffLen);
|
||||
}
|
||||
_i2c->hw->clr_restart_det;
|
||||
}
|
||||
// STOP_DET
|
||||
if (irqstat & (1 << 9)) {
|
||||
if (_onReceiveCallback && _buffLen) {
|
||||
_onReceiveCallback(_buffLen);
|
||||
}
|
||||
@@ -165,26 +194,8 @@ void TwoWire::onIRQ() {
|
||||
_slaveStartDet = false;
|
||||
_i2c->hw->clr_stop_det;
|
||||
}
|
||||
if (_i2c->hw->intr_stat & (1 << 6)) {
|
||||
// TX_ABRT
|
||||
_i2c->hw->clr_tx_abrt;
|
||||
}
|
||||
if (_i2c->hw->intr_stat & (1 << 5)) {
|
||||
// RD_REQ
|
||||
if (_onRequestCallback) {
|
||||
_onRequestCallback();
|
||||
}
|
||||
_i2c->hw->clr_rd_req;
|
||||
}
|
||||
if (_i2c->hw->intr_stat & (1 << 2)) {
|
||||
// RX_FULL
|
||||
if (_slaveStartDet && (_buffLen < (int)sizeof(_buff))) {
|
||||
_buff[_buffLen++] = _i2c->hw->data_cmd & 0xff;
|
||||
} else {
|
||||
_i2c->hw->data_cmd;
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma GCC pop_options
|
||||
|
||||
void TwoWire::end() {
|
||||
if (!_running) {
|
||||
|
||||
@@ -39,6 +39,7 @@ extern "C" {
|
||||
|
||||
|
||||
netif *CYW43::_netif = nullptr;
|
||||
extern "C" volatile bool __inLWIP;
|
||||
|
||||
CYW43::CYW43(int8_t cs, arduino::SPIClass& spi, int8_t intrpin) {
|
||||
(void) cs;
|
||||
@@ -99,7 +100,20 @@ uint16_t CYW43::readFrame(uint8_t* buffer, uint16_t bufsize) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// CB from the cyg32_driver
|
||||
//#define MAXWAIT 16
|
||||
//static struct pbuf *_pbufWaiting[MAXWAIT];
|
||||
//static bool _pbufHold(struct pbuf *p) {
|
||||
// for (int i = 0; i < MAXWAIT; i++) {
|
||||
// if (!_pbufWaiting[i]) {
|
||||
// _pbufWaiting[i] = p;
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// return false;
|
||||
//}
|
||||
|
||||
|
||||
// CB from the cyw43 driver
|
||||
extern "C" void cyw43_cb_process_ethernet(void *cb_data, int itf, size_t len, const uint8_t *buf) {
|
||||
//cyw43_t *self = (cyw43_t *)cb_data
|
||||
(void) cb_data;
|
||||
@@ -114,7 +128,7 @@ extern "C" void cyw43_cb_process_ethernet(void *cb_data, int itf, size_t len, co
|
||||
struct pbuf *p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
|
||||
if (p != nullptr) {
|
||||
pbuf_take(p, buf, len);
|
||||
if (netif->input(p, netif) != ERR_OK) {
|
||||
if (__inLWIP || (netif->input(p, netif) != ERR_OK)) {
|
||||
pbuf_free(p);
|
||||
}
|
||||
CYW43_STAT_INC(PACKET_IN_COUNT);
|
||||
|
||||
@@ -26,8 +26,6 @@
|
||||
// TODO:
|
||||
// unchain pbufs
|
||||
|
||||
#include <LWIPMutex.h>
|
||||
|
||||
#include <netif/ethernet.h>
|
||||
#include <lwip/init.h>
|
||||
#include <lwip/netif.h>
|
||||
@@ -176,7 +174,6 @@ int LwipIntfDev<RawDev>::hostByName(const char* aHostname, IPAddress& aResult, i
|
||||
return 1;
|
||||
}
|
||||
|
||||
LWIPMutex m;
|
||||
_dns_cb_t cb = { &aResult, this };
|
||||
#if LWIP_IPV4 && LWIP_IPV6
|
||||
err_t err = dns_gethostbyname_addrtype(aHostname, &addr, &_dns_found_callback, &cb, LWIP_DNS_ADDRTYPE_DEFAULT);
|
||||
@@ -230,8 +227,6 @@ int LwipIntfDev<RawDev>::ping(IPAddress host, uint8_t ttl, uint32_t _timeout) {
|
||||
auto ping_pcb = raw_new(IP_PROTO_ICMP);
|
||||
ping_pcb->ttl = ttl;
|
||||
|
||||
LWIPMutex m;
|
||||
|
||||
raw_recv(ping_pcb, _pingCB, this);
|
||||
raw_bind(ping_pcb, IP_ADDR_ANY);
|
||||
|
||||
@@ -256,7 +251,7 @@ int LwipIntfDev<RawDev>::ping(IPAddress host, uint8_t ttl, uint32_t _timeout) {
|
||||
uint32_t now = millis();
|
||||
while ((millis() - now < _timeout) && (_ping_ttl < 0)) {
|
||||
sys_check_timeouts();
|
||||
delay(10);
|
||||
delay(1);
|
||||
}
|
||||
pbuf_free(p);
|
||||
raw_remove(ping_pcb);
|
||||
@@ -408,6 +403,7 @@ void LwipIntfDev<RawDev>::end() {
|
||||
RawDev::end();
|
||||
netif_remove(&_netif);
|
||||
memset(&_netif, 0, sizeof(_netif));
|
||||
_started = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "framework-arduinopico",
|
||||
"version": "1.20503.0",
|
||||
"version": "1.20700.0",
|
||||
"description": "Arduino Wiring-based Framework (RPi Pico RP2040)",
|
||||
"keywords": [
|
||||
"framework",
|
||||
|
||||
@@ -72,7 +72,6 @@ cat << EOF > exclude.txt
|
||||
.travis.yml
|
||||
package
|
||||
doc
|
||||
ArduinoCore-API
|
||||
EOF
|
||||
# Also include all files which are ignored by git
|
||||
git ls-files --other --directory >> exclude.txt
|
||||
@@ -114,6 +113,12 @@ 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/^discovery.rp2040.pattern=.*//g' | \
|
||||
sed 's/^#discovery.rp2040.pattern=/discovery.rp2040.pattern=/g' | \
|
||||
sed 's/^pluggable_discovery.rp2040.pattern=.*//g' | \
|
||||
sed 's/^#pluggable_discovery.rp2040.pattern=/pluggable_discovery.rp2040.pattern=/g' | \
|
||||
sed 's/^tools.uf2conv-network.cmd=.*//g' | \
|
||||
sed 's/^#tools.uf2conv-network.cmd=/tools.uf2conv-network.cmd=/g' | \
|
||||
sed "s/version=.*/version=$ver/g" |\
|
||||
sed -E "s/name=([a-zA-Z0-9\ -]+).*/name=\1($ver)/g"\
|
||||
> $outdir/platform.txt
|
||||
|
||||
@@ -26,6 +26,9 @@
|
||||
{
|
||||
"name": "Adafruit Feather RP2040"
|
||||
},
|
||||
{
|
||||
"name": "Adafruit Feather RP2040 SCORPIO"
|
||||
},
|
||||
{
|
||||
"name": "Adafruit ItsyBitsy RP2040"
|
||||
},
|
||||
@@ -47,12 +50,18 @@
|
||||
{
|
||||
"name": "Arduino Nano RP2040 Connect"
|
||||
},
|
||||
{
|
||||
"name": "BridgeTek IDM2040-7A"
|
||||
},
|
||||
{
|
||||
"name": "Cytron Maker Nano RP2040"
|
||||
},
|
||||
{
|
||||
"name": "Cytron Maker Pi RP2040"
|
||||
},
|
||||
{
|
||||
"name": "DatanoiseTV PicoADK"
|
||||
},
|
||||
{
|
||||
"name": "DeRuiLab FlyBoard2040Core"
|
||||
},
|
||||
@@ -92,9 +101,18 @@
|
||||
{
|
||||
"name": "iLabs RPICO32"
|
||||
},
|
||||
{
|
||||
"name": "Melopero Cookie RP2040"
|
||||
},
|
||||
{
|
||||
"name": "Melopero Shake RP2040"
|
||||
},
|
||||
{
|
||||
"name": "nullbits Bit-C PRO"
|
||||
},
|
||||
{
|
||||
"name": "Pimoroni PGA2040"
|
||||
},
|
||||
{
|
||||
"name": "Solder Party RP2040 Stamp"
|
||||
},
|
||||
@@ -110,6 +128,27 @@
|
||||
{
|
||||
"name": "Seeed XIAO RP2040"
|
||||
},
|
||||
{
|
||||
"name": "Viyalab Mizu RP2040"
|
||||
},
|
||||
{
|
||||
"name": "Waveshare RP2040 Zero"
|
||||
},
|
||||
{
|
||||
"name": "Waveshare RP2040 One"
|
||||
},
|
||||
{
|
||||
"name": "Waveshare RP2040 Plus 4MB"
|
||||
},
|
||||
{
|
||||
"name": "Waveshare RP2040 Plus 16MB"
|
||||
},
|
||||
{
|
||||
"name": "Waveshare RP2040 LCD 0.96"
|
||||
},
|
||||
{
|
||||
"name": "Waveshare RP2040 LCD 1.28"
|
||||
},
|
||||
{
|
||||
"name": "WIZnet W5100S-EVB-Pico"
|
||||
},
|
||||
@@ -126,22 +165,22 @@
|
||||
"toolsDependencies": [
|
||||
{
|
||||
"packager": "rp2040",
|
||||
"version": "1.4.0-c-0196c06",
|
||||
"version": "1.5.0-a-5007782",
|
||||
"name": "pqt-gcc"
|
||||
},
|
||||
{
|
||||
"packager": "rp2040",
|
||||
"version": "1.4.0-c-0196c06",
|
||||
"version": "1.5.0-a-5007782",
|
||||
"name": "pqt-mklittlefs"
|
||||
},
|
||||
{
|
||||
"packager": "rp2040",
|
||||
"version": "1.4.0-c-0196c06",
|
||||
"version": "1.5.0-a-5007782",
|
||||
"name": "pqt-elf2uf2"
|
||||
},
|
||||
{
|
||||
"packager": "rp2040",
|
||||
"version": "1.4.0-c-0196c06",
|
||||
"version": "1.5.0-a-5007782",
|
||||
"name": "pqt-pioasm"
|
||||
},
|
||||
{
|
||||
@@ -151,7 +190,7 @@
|
||||
},
|
||||
{
|
||||
"packager": "rp2040",
|
||||
"version": "1.4.0-c-0196c06",
|
||||
"version": "1.5.0-a-5007782",
|
||||
"name": "pqt-openocd"
|
||||
}
|
||||
],
|
||||
@@ -162,57 +201,57 @@
|
||||
],
|
||||
"tools": [
|
||||
{
|
||||
"version": "1.4.0-c-0196c06",
|
||||
"version": "1.5.0-a-5007782",
|
||||
"name": "pqt-openocd",
|
||||
"systems": [
|
||||
{
|
||||
"host": "aarch64-linux-gnu",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/aarch64-linux-gnu.openocd-e3428fadb.220714.tar.gz",
|
||||
"archiveFileName": "aarch64-linux-gnu.openocd-e3428fadb.220714.tar.gz",
|
||||
"checksum": "SHA-256:8da4fd922fd7392e87c0057b193e67962606cd13450af935c9846992f2bce916",
|
||||
"size": "5607131"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/aarch64-linux-gnu.openocd-228ede43d.221223.tar.gz",
|
||||
"archiveFileName": "aarch64-linux-gnu.openocd-228ede43d.221223.tar.gz",
|
||||
"checksum": "SHA-256:aa3f7a24af6afca5bacd9172f943f59d1f7ca9a3525e7e9c445dba9f8c6c8b68",
|
||||
"size": "5807317"
|
||||
},
|
||||
{
|
||||
"host": "arm-linux-gnueabihf",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/arm-linux-gnueabihf.openocd-e3428fadb.220714.tar.gz",
|
||||
"archiveFileName": "arm-linux-gnueabihf.openocd-e3428fadb.220714.tar.gz",
|
||||
"checksum": "SHA-256:ce7650961c8200fe2cc2d4a88efc952fe1bb7b4175f2cf650a9a7d992ae08298",
|
||||
"size": "5344149"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/arm-linux-gnueabihf.openocd-228ede43d.221223.tar.gz",
|
||||
"archiveFileName": "arm-linux-gnueabihf.openocd-228ede43d.221223.tar.gz",
|
||||
"checksum": "SHA-256:40a623e198eccafaec210e3f1b425369e6fe79cef0d94b7a910d63223c37cc50",
|
||||
"size": "5538300"
|
||||
},
|
||||
{
|
||||
"host": "i686-pc-linux-gnu",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/i686-linux-gnu.openocd-e3428fadb.220714.tar.gz",
|
||||
"archiveFileName": "i686-linux-gnu.openocd-e3428fadb.220714.tar.gz",
|
||||
"checksum": "SHA-256:9391ae74c6474f685f45ccefb82e18f382f1a59f3e13e2b22fe00967264d2482",
|
||||
"size": "5168334"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/i686-linux-gnu.openocd-228ede43d.221223.tar.gz",
|
||||
"archiveFileName": "i686-linux-gnu.openocd-228ede43d.221223.tar.gz",
|
||||
"checksum": "SHA-256:b80eb819e302130bde5ed303f23645e615bc2440303223d924742ee89dc6d477",
|
||||
"size": "5341706"
|
||||
},
|
||||
{
|
||||
"host": "i686-mingw32",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/i686-w64-mingw32.openocd-e3428fadb.220714.zip",
|
||||
"archiveFileName": "i686-w64-mingw32.openocd-e3428fadb.220714.zip",
|
||||
"checksum": "SHA-256:f4b7803527a0a587fe95e52bcf056fcbe58d64b78705edd38810655d3abee1fe",
|
||||
"size": "2156831"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/i686-w64-mingw32.openocd-228ede43d.221223.zip",
|
||||
"archiveFileName": "i686-w64-mingw32.openocd-228ede43d.221223.zip",
|
||||
"checksum": "SHA-256:02d9fba9d4e66de31cd99af0ade3a6150d258d034aa5f85f7f4601c849b8bc80",
|
||||
"size": "2207879"
|
||||
},
|
||||
{
|
||||
"host": "x86_64-apple-darwin",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-apple-darwin14.openocd-e3428fadb.220714.tar.gz",
|
||||
"archiveFileName": "x86_64-apple-darwin14.openocd-e3428fadb.220714.tar.gz",
|
||||
"checksum": "SHA-256:4e6a8da43758941478e6740e023ea5be051f09bf92e49d65c2b54a1ca4a2660c",
|
||||
"size": "2002508"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-apple-darwin14.openocd-228ede43d.221223.tar.gz",
|
||||
"archiveFileName": "x86_64-apple-darwin14.openocd-228ede43d.221223.tar.gz",
|
||||
"checksum": "SHA-256:f92b87bd2ec81260c4c76e9e74ede41888d943ac0a97c11ec5f579d450ba72b1",
|
||||
"size": "2599689"
|
||||
},
|
||||
{
|
||||
"host": "x86_64-pc-linux-gnu",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-linux-gnu.openocd-e3428fadb.220714.tar.gz",
|
||||
"archiveFileName": "x86_64-linux-gnu.openocd-e3428fadb.220714.tar.gz",
|
||||
"checksum": "SHA-256:2518c6451c0e4c148c8c6cb9330e216075177003b064c509b168f42a44a6eb5a",
|
||||
"size": "5540574"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-linux-gnu.openocd-228ede43d.221223.tar.gz",
|
||||
"archiveFileName": "x86_64-linux-gnu.openocd-228ede43d.221223.tar.gz",
|
||||
"checksum": "SHA-256:cf4c30151c9f4583964579f11ffbc66229508b21d83d2f1d7c87eb28d1f0cca9",
|
||||
"size": "5727971"
|
||||
},
|
||||
{
|
||||
"host": "x86_64-mingw32",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-w64-mingw32.openocd-e3428fadb.220714.zip",
|
||||
"archiveFileName": "x86_64-w64-mingw32.openocd-e3428fadb.220714.zip",
|
||||
"checksum": "SHA-256:c2da993d74152ec8ca80b350ede77ee94942518081a48dafd7a3b49631778e75",
|
||||
"size": "2156831"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-w64-mingw32.openocd-228ede43d.221223.zip",
|
||||
"archiveFileName": "x86_64-w64-mingw32.openocd-228ede43d.221223.zip",
|
||||
"checksum": "SHA-256:5f0c4f67f0bba6cf3b9968ba27796fe98ef8787e56f0a160dede8d05d578586c",
|
||||
"size": "2168940"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -279,222 +318,222 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.4.0-c-0196c06",
|
||||
"version": "1.5.0-a-5007782",
|
||||
"name": "pqt-gcc",
|
||||
"systems": [
|
||||
{
|
||||
"host": "aarch64-linux-gnu",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/aarch64-linux-gnu.arm-none-eabi-0196c06.220714.tar.gz",
|
||||
"archiveFileName": "aarch64-linux-gnu.arm-none-eabi-0196c06.220714.tar.gz",
|
||||
"checksum": "SHA-256:0bc906c2eb4b3999285ea8a71ec0c95a20a21f2ff46b1bdd264f2fd3c30fe580",
|
||||
"size": "77889379"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/aarch64-linux-gnu.arm-none-eabi-5007782.221223.tar.gz",
|
||||
"archiveFileName": "aarch64-linux-gnu.arm-none-eabi-5007782.221223.tar.gz",
|
||||
"checksum": "SHA-256:baff843fce38393565babf81ecfddfab17df8046d901faad3c5f93ee072d395b",
|
||||
"size": "81474410"
|
||||
},
|
||||
{
|
||||
"host": "arm-linux-gnueabihf",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/arm-linux-gnueabihf.arm-none-eabi-0196c06.220714.tar.gz",
|
||||
"archiveFileName": "arm-linux-gnueabihf.arm-none-eabi-0196c06.220714.tar.gz",
|
||||
"checksum": "SHA-256:2bf9f691d1fa97cea3b835a364fc24d06102181725001a00fe3e77526f90e2bd",
|
||||
"size": "73342377"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/arm-linux-gnueabihf.arm-none-eabi-5007782.221223.tar.gz",
|
||||
"archiveFileName": "arm-linux-gnueabihf.arm-none-eabi-5007782.221223.tar.gz",
|
||||
"checksum": "SHA-256:35144f4aded62ab45ab7ddabf63c189af70b57534438cf00281c11b5ef90d316",
|
||||
"size": "76138344"
|
||||
},
|
||||
{
|
||||
"host": "i686-pc-linux-gnu",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/i686-linux-gnu.arm-none-eabi-0196c06.220714.tar.gz",
|
||||
"archiveFileName": "i686-linux-gnu.arm-none-eabi-0196c06.220714.tar.gz",
|
||||
"checksum": "SHA-256:e0fe347f2602247ffbc16bb7b74653fdb78c4f75b90037f2e82fc5498b5d1cb9",
|
||||
"size": "79511866"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/i686-linux-gnu.arm-none-eabi-5007782.221223.tar.gz",
|
||||
"archiveFileName": "i686-linux-gnu.arm-none-eabi-5007782.221223.tar.gz",
|
||||
"checksum": "SHA-256:d1d5121c4a5e4fa42047daf58c112a90beeb3533d1f133f4928db4b337030351",
|
||||
"size": "83712710"
|
||||
},
|
||||
{
|
||||
"host": "i686-mingw32",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/i686-w64-mingw32.arm-none-eabi-0196c06.220714.zip",
|
||||
"archiveFileName": "i686-w64-mingw32.arm-none-eabi-0196c06.220714.zip",
|
||||
"checksum": "SHA-256:d1ee0f00c97dc50dc06487d6fb6b5dd94bbb3cf1579c975bcd23d7a7922e53b7",
|
||||
"size": "82626868"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/i686-w64-mingw32.arm-none-eabi-5007782.221223.zip",
|
||||
"archiveFileName": "i686-w64-mingw32.arm-none-eabi-5007782.221223.zip",
|
||||
"checksum": "SHA-256:71e0858689b644e5b0aaa07ec5257919ab292ff9404bfc9c52dc31593828f391",
|
||||
"size": "85628083"
|
||||
},
|
||||
{
|
||||
"host": "x86_64-apple-darwin",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-apple-darwin14.arm-none-eabi-0196c06.220714.tar.gz",
|
||||
"archiveFileName": "x86_64-apple-darwin14.arm-none-eabi-0196c06.220714.tar.gz",
|
||||
"checksum": "SHA-256:1b030451a5a6ddf42ac796c46b2f077f90f6d56586f4537a3486ce47670996cd",
|
||||
"size": "82119254"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-apple-darwin14.arm-none-eabi-5007782.221223.tar.gz",
|
||||
"archiveFileName": "x86_64-apple-darwin14.arm-none-eabi-5007782.221223.tar.gz",
|
||||
"checksum": "SHA-256:ad984927785d17ddd34cfc7bc76d4d1371d6f6905d8708d3535a261b244b32d9",
|
||||
"size": "84968911"
|
||||
},
|
||||
{
|
||||
"host": "x86_64-pc-linux-gnu",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-linux-gnu.arm-none-eabi-0196c06.220714.tar.gz",
|
||||
"archiveFileName": "x86_64-linux-gnu.arm-none-eabi-0196c06.220714.tar.gz",
|
||||
"checksum": "SHA-256:73d032ba42d33f6e9c1d5de79b73bf5e9740b8e6b7fee37de3db03814c553694",
|
||||
"size": "80363125"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-linux-gnu.arm-none-eabi-5007782.221223.tar.gz",
|
||||
"archiveFileName": "x86_64-linux-gnu.arm-none-eabi-5007782.221223.tar.gz",
|
||||
"checksum": "SHA-256:591af0c27b08b31d11b3135a56bbd3c447cd9e6cac2987cdb3ab25a86d7eb3e3",
|
||||
"size": "83660106"
|
||||
},
|
||||
{
|
||||
"host": "x86_64-mingw32",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-w64-mingw32.arm-none-eabi-0196c06.220714.zip",
|
||||
"archiveFileName": "x86_64-w64-mingw32.arm-none-eabi-0196c06.220714.zip",
|
||||
"checksum": "SHA-256:3f67e15adbe49ebaee72734e9d469bd6b34fd1be30ccdb6e55a1e05a0be4e1db",
|
||||
"size": "86064664"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-w64-mingw32.arm-none-eabi-5007782.221223.zip",
|
||||
"archiveFileName": "x86_64-w64-mingw32.arm-none-eabi-5007782.221223.zip",
|
||||
"checksum": "SHA-256:f2cf872ce5bd07efa2cfa044de28458034be9466f5ccae4e7e9cd229aabefa11",
|
||||
"size": "88351413"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.4.0-c-0196c06",
|
||||
"version": "1.5.0-a-5007782",
|
||||
"name": "pqt-elf2uf2",
|
||||
"systems": [
|
||||
{
|
||||
"host": "aarch64-linux-gnu",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/aarch64-linux-gnu.elf2uf2-2e6142b.220714.tar.gz",
|
||||
"archiveFileName": "aarch64-linux-gnu.elf2uf2-2e6142b.220714.tar.gz",
|
||||
"checksum": "SHA-256:14d7c1be08151bcddcc19fdb5741bf52b435f08f52daff2d498a07c5ebfb5bfb",
|
||||
"size": "82682"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/aarch64-linux-gnu.elf2uf2-2e6142b.221223.tar.gz",
|
||||
"archiveFileName": "aarch64-linux-gnu.elf2uf2-2e6142b.221223.tar.gz",
|
||||
"checksum": "SHA-256:266151dc2523ec707b88256e7220a5e89c819ad1e134a7f492cf9fbe07ccf8a1",
|
||||
"size": "82684"
|
||||
},
|
||||
{
|
||||
"host": "arm-linux-gnueabihf",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/arm-linux-gnueabihf.elf2uf2-2e6142b.220714.tar.gz",
|
||||
"archiveFileName": "arm-linux-gnueabihf.elf2uf2-2e6142b.220714.tar.gz",
|
||||
"checksum": "SHA-256:31b790b5a19bbb5950212098aa42be43702fb4db50aa541c9f40b2320e2280be",
|
||||
"size": "55991"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/arm-linux-gnueabihf.elf2uf2-2e6142b.221223.tar.gz",
|
||||
"archiveFileName": "arm-linux-gnueabihf.elf2uf2-2e6142b.221223.tar.gz",
|
||||
"checksum": "SHA-256:e30f1243259361a635a21d69e81bf2d913e194882159eba8c652d5b45cf2591b",
|
||||
"size": "55998"
|
||||
},
|
||||
{
|
||||
"host": "i686-pc-linux-gnu",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/i686-linux-gnu.elf2uf2-2e6142b.220714.tar.gz",
|
||||
"archiveFileName": "i686-linux-gnu.elf2uf2-2e6142b.220714.tar.gz",
|
||||
"checksum": "SHA-256:a3dd93861857fd81f8c9ed01509a0af012f446f23f405bc696f6a4d2f344262c",
|
||||
"size": "91386"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/i686-linux-gnu.elf2uf2-2e6142b.221223.tar.gz",
|
||||
"archiveFileName": "i686-linux-gnu.elf2uf2-2e6142b.221223.tar.gz",
|
||||
"checksum": "SHA-256:17ebb211916bc74a9cd3263f6d5e9721bb91d54a836c4369c1e01e9147e4f477",
|
||||
"size": "91387"
|
||||
},
|
||||
{
|
||||
"host": "i686-mingw32",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/i686-w64-mingw32.elf2uf2-2e6142b.220714.zip",
|
||||
"archiveFileName": "i686-w64-mingw32.elf2uf2-2e6142b.220714.zip",
|
||||
"checksum": "SHA-256:25d6a934643074590c3006468ec051f62d02298abbff27d7e3643ee147e818e0",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/i686-w64-mingw32.elf2uf2-2e6142b.221223.zip",
|
||||
"archiveFileName": "i686-w64-mingw32.elf2uf2-2e6142b.221223.zip",
|
||||
"checksum": "SHA-256:80f740ffdb0a1812212f631598060216361b1a8e55d2092e729afee3b3b1ad95",
|
||||
"size": "71949"
|
||||
},
|
||||
{
|
||||
"host": "x86_64-apple-darwin",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-apple-darwin14.elf2uf2-2e6142b.220714.tar.gz",
|
||||
"archiveFileName": "x86_64-apple-darwin14.elf2uf2-2e6142b.220714.tar.gz",
|
||||
"checksum": "SHA-256:f2743d086d1992599d656aaa9a38a736d443bdc96619fd5bcabdc7fcb05225c8",
|
||||
"size": "86600"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-apple-darwin14.elf2uf2-2e6142b.221223.tar.gz",
|
||||
"archiveFileName": "x86_64-apple-darwin14.elf2uf2-2e6142b.221223.tar.gz",
|
||||
"checksum": "SHA-256:bebf3f984c59b36cfdc1a5b41bc3368c674c03eea54586419872c0ce2ad71430",
|
||||
"size": "86604"
|
||||
},
|
||||
{
|
||||
"host": "x86_64-pc-linux-gnu",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-linux-gnu.elf2uf2-2e6142b.220714.tar.gz",
|
||||
"archiveFileName": "x86_64-linux-gnu.elf2uf2-2e6142b.220714.tar.gz",
|
||||
"checksum": "SHA-256:5b0e79bfd9d7e5f4d5e5cb0e6e2b685e10fdf3071139c00bf6274a5ca9b9717e",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-linux-gnu.elf2uf2-2e6142b.221223.tar.gz",
|
||||
"archiveFileName": "x86_64-linux-gnu.elf2uf2-2e6142b.221223.tar.gz",
|
||||
"checksum": "SHA-256:d7d0e77a8b4c5cf879bb92d20bbfb213d568fec86fb96fc08c60bd9a3fb38712",
|
||||
"size": "82339"
|
||||
},
|
||||
{
|
||||
"host": "x86_64-mingw32",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-w64-mingw32.elf2uf2-2e6142b.220714.zip",
|
||||
"archiveFileName": "x86_64-w64-mingw32.elf2uf2-2e6142b.220714.zip",
|
||||
"checksum": "SHA-256:f09e022cbb1fe73315ccf16a2af6bc687b64d0c44066f801fb9dee8326e941b1",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-w64-mingw32.elf2uf2-2e6142b.221223.zip",
|
||||
"archiveFileName": "x86_64-w64-mingw32.elf2uf2-2e6142b.221223.zip",
|
||||
"checksum": "SHA-256:25840973640fd28817a37a4213dfbad81da91a7b75a1ecb14cdee56c2bd1a8ee",
|
||||
"size": "80399"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.4.0-c-0196c06",
|
||||
"version": "1.5.0-a-5007782",
|
||||
"name": "pqt-pioasm",
|
||||
"systems": [
|
||||
{
|
||||
"host": "aarch64-linux-gnu",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/aarch64-linux-gnu.pioasm-2e6142b.220714.tar.gz",
|
||||
"archiveFileName": "aarch64-linux-gnu.pioasm-2e6142b.220714.tar.gz",
|
||||
"checksum": "SHA-256:d4ac4b39841984178babd75f5c09cad87e06bd2fb18cf04e40f561d72e604a5d",
|
||||
"size": "453440"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/aarch64-linux-gnu.pioasm-2e6142b.221223.tar.gz",
|
||||
"archiveFileName": "aarch64-linux-gnu.pioasm-2e6142b.221223.tar.gz",
|
||||
"checksum": "SHA-256:38ae80646805781c1df2264ae6b8ff41cc0dbfcefd4dfaae9f5e355bce4890c7",
|
||||
"size": "453442"
|
||||
},
|
||||
{
|
||||
"host": "arm-linux-gnueabihf",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/arm-linux-gnueabihf.pioasm-2e6142b.220714.tar.gz",
|
||||
"archiveFileName": "arm-linux-gnueabihf.pioasm-2e6142b.220714.tar.gz",
|
||||
"checksum": "SHA-256:568ebdd7b1a47c6dbf45793f9bf019855a1b14182fbeb7ed7e342979c6632eef",
|
||||
"size": "360675"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/arm-linux-gnueabihf.pioasm-2e6142b.221223.tar.gz",
|
||||
"archiveFileName": "arm-linux-gnueabihf.pioasm-2e6142b.221223.tar.gz",
|
||||
"checksum": "SHA-256:3ab67c8b0f40806e8e2a53fe22b274f3b79ccc12189ab80dc2db3b4e80e34de2",
|
||||
"size": "360686"
|
||||
},
|
||||
{
|
||||
"host": "i686-pc-linux-gnu",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/i686-linux-gnu.pioasm-2e6142b.220714.tar.gz",
|
||||
"archiveFileName": "i686-linux-gnu.pioasm-2e6142b.220714.tar.gz",
|
||||
"checksum": "SHA-256:2abac2bef690f7ffadfcf74af4832bfcc0e212606efbed21b385bda0517554ef",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/i686-linux-gnu.pioasm-2e6142b.221223.tar.gz",
|
||||
"archiveFileName": "i686-linux-gnu.pioasm-2e6142b.221223.tar.gz",
|
||||
"checksum": "SHA-256:ed5d190b3726caa58a63b08785aff17f6f412810cc7bef21405a6342717e6c6b",
|
||||
"size": "511442"
|
||||
},
|
||||
{
|
||||
"host": "i686-mingw32",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/i686-w64-mingw32.pioasm-2e6142b.220714.zip",
|
||||
"archiveFileName": "i686-w64-mingw32.pioasm-2e6142b.220714.zip",
|
||||
"checksum": "SHA-256:0b1336b999a31d164248248d37fa550aa14a06dae8ef5b215818c5f0597ca80b",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/i686-w64-mingw32.pioasm-2e6142b.221223.zip",
|
||||
"archiveFileName": "i686-w64-mingw32.pioasm-2e6142b.221223.zip",
|
||||
"checksum": "SHA-256:713be116f8fbdd7a77ae294f2b8a72fcfcb0bd43f013124bde6e569dd284ad43",
|
||||
"size": "385882"
|
||||
},
|
||||
{
|
||||
"host": "x86_64-apple-darwin",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-apple-darwin14.pioasm-2e6142b.220714.tar.gz",
|
||||
"archiveFileName": "x86_64-apple-darwin14.pioasm-2e6142b.220714.tar.gz",
|
||||
"checksum": "SHA-256:7057ba222a54ff9bd43a6a4232a6355100f29e0cc20d3facb5d600180f418e68",
|
||||
"size": "480538"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-apple-darwin14.pioasm-2e6142b.221223.tar.gz",
|
||||
"archiveFileName": "x86_64-apple-darwin14.pioasm-2e6142b.221223.tar.gz",
|
||||
"checksum": "SHA-256:16feb332e66b8ed7f911eceb153484565d1947a87eb7c9db774bd38a9a7b0043",
|
||||
"size": "480539"
|
||||
},
|
||||
{
|
||||
"host": "x86_64-pc-linux-gnu",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-linux-gnu.pioasm-2e6142b.220714.tar.gz",
|
||||
"archiveFileName": "x86_64-linux-gnu.pioasm-2e6142b.220714.tar.gz",
|
||||
"checksum": "SHA-256:30b367e8d2cd4ccdf151e728b4137bad1d993c42f0d640307e27d5fc55fce2c0",
|
||||
"size": "458691"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-linux-gnu.pioasm-2e6142b.221223.tar.gz",
|
||||
"archiveFileName": "x86_64-linux-gnu.pioasm-2e6142b.221223.tar.gz",
|
||||
"checksum": "SHA-256:367b14d59bb5394c068bacd1ab3dfd77116208ad28213af01372d5a93bb0ead3",
|
||||
"size": "458693"
|
||||
},
|
||||
{
|
||||
"host": "x86_64-mingw32",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-w64-mingw32.pioasm-2e6142b.220714.zip",
|
||||
"archiveFileName": "x86_64-w64-mingw32.pioasm-2e6142b.220714.zip",
|
||||
"checksum": "SHA-256:b7b340862e673f9e57287f02219b2d56094a497fe9d8c451acf28aaef721e038",
|
||||
"size": "409101"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-w64-mingw32.pioasm-2e6142b.221223.zip",
|
||||
"archiveFileName": "x86_64-w64-mingw32.pioasm-2e6142b.221223.zip",
|
||||
"checksum": "SHA-256:c18d5499308c4938b1c2230724f3adb2de8071583b9185b77705747555c9a50f",
|
||||
"size": "409100"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.4.0-c-0196c06",
|
||||
"version": "1.5.0-a-5007782",
|
||||
"name": "pqt-mklittlefs",
|
||||
"systems": [
|
||||
{
|
||||
"host": "aarch64-linux-gnu",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/aarch64-linux-gnu.mklittlefs-affa497.220714.tar.gz",
|
||||
"archiveFileName": "aarch64-linux-gnu.mklittlefs-affa497.220714.tar.gz",
|
||||
"checksum": "SHA-256:ad0af70d568e10a9a2a74c6e0a3cf8659a47b80fbf594b01731579bc21a5c212",
|
||||
"size": "47287"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/aarch64-linux-gnu.mklittlefs-30b7fc1.221223.tar.gz",
|
||||
"archiveFileName": "aarch64-linux-gnu.mklittlefs-30b7fc1.221223.tar.gz",
|
||||
"checksum": "SHA-256:6e20ef3f0c8f4eedd18377cd8e7626a724b3c11ce914e66e23fe021493b519b6",
|
||||
"size": "60993"
|
||||
},
|
||||
{
|
||||
"host": "arm-linux-gnueabihf",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/arm-linux-gnueabihf.mklittlefs-affa497.220714.tar.gz",
|
||||
"archiveFileName": "arm-linux-gnueabihf.mklittlefs-affa497.220714.tar.gz",
|
||||
"checksum": "SHA-256:f8f1a1dd7b02220f11cf0f6a6c88692f7e056eb245fbc41017c33d333751980e",
|
||||
"size": "40826"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/arm-linux-gnueabihf.mklittlefs-30b7fc1.221223.tar.gz",
|
||||
"archiveFileName": "arm-linux-gnueabihf.mklittlefs-30b7fc1.221223.tar.gz",
|
||||
"checksum": "SHA-256:092501f939d78625f876644a5c1d3264f2310e1798ea6d12a2845274a50a0b54",
|
||||
"size": "51573"
|
||||
},
|
||||
{
|
||||
"host": "i686-pc-linux-gnu",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/i686-linux-gnu.mklittlefs-affa497.220714.tar.gz",
|
||||
"archiveFileName": "i686-linux-gnu.mklittlefs-affa497.220714.tar.gz",
|
||||
"checksum": "SHA-256:4d10a2bc6a8fa41a7e5642aa30128f797f84b099e1bb2282c6c2d62a06e81e21",
|
||||
"size": "50925"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/i686-linux-gnu.mklittlefs-30b7fc1.221223.tar.gz",
|
||||
"archiveFileName": "i686-linux-gnu.mklittlefs-30b7fc1.221223.tar.gz",
|
||||
"checksum": "SHA-256:c2d8b5d8c903b024ae88bd5a97d9759049fbc1e7ab84ea19ea6ea2546f0aa496",
|
||||
"size": "67720"
|
||||
},
|
||||
{
|
||||
"host": "i686-mingw32",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/i686-w64-mingw32.mklittlefs-affa497.220714.zip",
|
||||
"archiveFileName": "i686-w64-mingw32.mklittlefs-affa497.220714.zip",
|
||||
"checksum": "SHA-256:71117412351ea2486848848d76f4d1e3c7a507a4d7546f6b0646bbc10c96d557",
|
||||
"size": "334062"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/i686-w64-mingw32.mklittlefs-30b7fc1.221223.zip",
|
||||
"archiveFileName": "i686-w64-mingw32.mklittlefs-30b7fc1.221223.zip",
|
||||
"checksum": "SHA-256:9f66d5b6bdfce13b1c246ae2d8abfcab623828337a16a1f2571eeed1b71096b9",
|
||||
"size": "345497"
|
||||
},
|
||||
{
|
||||
"host": "x86_64-apple-darwin",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-apple-darwin14.mklittlefs-affa497.220714.tar.gz",
|
||||
"archiveFileName": "x86_64-apple-darwin14.mklittlefs-affa497.220714.tar.gz",
|
||||
"checksum": "SHA-256:b3d0c30f942982337cd4c0e4f70855f8eabcf1d378eac78465c7fee39ab5915f",
|
||||
"size": "365780"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-apple-darwin14.mklittlefs-30b7fc1.221223.tar.gz",
|
||||
"archiveFileName": "x86_64-apple-darwin14.mklittlefs-30b7fc1.221223.tar.gz",
|
||||
"checksum": "SHA-256:1f7e675700ff4b5de21d1ea37a0969683ad54685d94bf0b42de13c26aa42f13f",
|
||||
"size": "377123"
|
||||
},
|
||||
{
|
||||
"host": "x86_64-pc-linux-gnu",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-linux-gnu.mklittlefs-affa497.220714.tar.gz",
|
||||
"archiveFileName": "x86_64-linux-gnu.mklittlefs-affa497.220714.tar.gz",
|
||||
"checksum": "SHA-256:9241e8e642748048bd32c7ccf4a8200e8bc104d6e328fe7437e8727866f29d94",
|
||||
"size": "49787"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-linux-gnu.mklittlefs-30b7fc1.221223.tar.gz",
|
||||
"archiveFileName": "x86_64-linux-gnu.mklittlefs-30b7fc1.221223.tar.gz",
|
||||
"checksum": "SHA-256:2773b0e7a5af33052b84959893cd9e7f3223236730f2109546399ec52d6a7a70",
|
||||
"size": "62741"
|
||||
},
|
||||
{
|
||||
"host": "x86_64-mingw32",
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.4.0-c/x86_64-w64-mingw32.mklittlefs-affa497.220714.zip",
|
||||
"archiveFileName": "x86_64-w64-mingw32.mklittlefs-affa497.220714.zip",
|
||||
"checksum": "SHA-256:2f39dd727e9cb61dbc631d00f543a99b6224fb24ffde0dff0cb2b70c9561ae69",
|
||||
"size": "347612"
|
||||
"url": "https://github.com/earlephilhower/pico-quick-toolchain/releases/download/1.5.0-a/x86_64-w64-mingw32.mklittlefs-30b7fc1.221223.zip",
|
||||
"archiveFileName": "x86_64-w64-mingw32.mklittlefs-30b7fc1.221223.zip",
|
||||
"checksum": "SHA-256:ee9a6caad229cd9530465926c755a4dc68a89bd5a6ff642c060dfa05f0c01a2a",
|
||||
"size": "357313"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+31
-5
@@ -20,14 +20,14 @@
|
||||
# https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification
|
||||
|
||||
name=Raspberry Pi RP2040 Boards
|
||||
version=2.5.3
|
||||
version=2.7.0
|
||||
|
||||
runtime.tools.pqt-gcc.path={runtime.platform.path}/system/arm-none-eabi
|
||||
runtime.tools.pqt-python3.path={runtime.platform.path}/system/python3
|
||||
runtime.tools.pqt-mklittlefs.path={runtime.platform.path}/system/mklittlefs
|
||||
runtime.tools.pqt-pioasm.path={runtime.platform.path}/system/pioasm
|
||||
runtime.tools.pqt-elf2uf2.path={runtime.platform.path}/system/elf2uf2
|
||||
|
||||
runtime.tools.pqt-openocd.path={runtime.platform.path}/system/openocd
|
||||
compiler.path={runtime.tools.pqt-gcc.path}/bin/
|
||||
|
||||
compiler.libraries.ldflags=
|
||||
@@ -42,7 +42,7 @@ compiler.warning_flags.more=-Wall -Werror=return-type -Wno-ignored-qualifiers
|
||||
compiler.warning_flags.all=-Wall -Wextra -Werror=return-type -Wno-ignored-qualifiers
|
||||
|
||||
compiler.netdefines=-DPICO_CYW43_ARCH_THREADSAFE_BACKGROUND=1 -DCYW43_LWIP=0 {build.lwipdefs} -DLWIP_IGMP=1 -DLWIP_CHECKSUM_CTRL_PER_NETIF=1
|
||||
compiler.defines={build.led} {build.usbstack_flags} -DCFG_TUSB_MCU=OPT_MCU_RP2040 -DUSB_VID={build.vid} -DUSB_PID={build.pid} '-DUSB_MANUFACTURER={build.usb_manufacturer}' '-DUSB_PRODUCT={build.usb_product}' {compiler.netdefines} -DARDUINO_VARIANT="{build.variant}"
|
||||
compiler.defines={build.led} {build.usbstack_flags} -DCFG_TUSB_MCU=OPT_MCU_RP2040 -DUSB_VID={build.vid} -DUSB_PID={build.pid} '-DUSB_MANUFACTURER={build.usb_manufacturer}' '-DUSB_PRODUCT={build.usb_product}' {compiler.netdefines} -DARDUINO_VARIANT="{build.variant}" -DTARGET_RP2040
|
||||
compiler.includes="-iprefix{runtime.platform.path}/" "@{runtime.platform.path}/lib/platform_inc.txt" "-I{runtime.platform.path}/include"
|
||||
compiler.flags=-march=armv6-m -mcpu=cortex-m0plus -mthumb -ffunction-sections -fdata-sections {build.flags.exceptions} {build.flags.stackprotect} {build.flags.cmsis}
|
||||
compiler.wrap="@{runtime.platform.path}/lib/platform_wrap.txt"
|
||||
@@ -95,9 +95,14 @@ build.flags.stackprotect=
|
||||
build.libpico=libpico.a
|
||||
build.boot2=boot2_generic_03h_4_padded_checksum
|
||||
build.lwipdefs=-DLWIP_IPV6=0 -DLWIP_IPV4=1
|
||||
build.wificc=-DWIFICC=CYW43_COUNTRY_WORLDWIDE
|
||||
build.debugscript=picoprobe.tcl
|
||||
|
||||
# Allow Pico boards do be auto-discovered by the IDE
|
||||
discovery.rp2040.pattern="{runtime.tools.pqt-python3.path}/python3" -I "{runtime.platform.path}/tools/discovery.py"
|
||||
#discovery.rp2040.pattern={runtime.tools.pqt-python3.path}/python3 -I "{runtime.platform.path}/tools/pluggable_discovery.py"
|
||||
discovery.rp2040.pattern={runtime.platform.path}/system/python3/python3 -I "{runtime.platform.path}/tools/pluggable_discovery.py"
|
||||
#pluggable_discovery.rp2040.pattern="{runtime.tools.pqt-python3.path}/python3" -I "{runtime.platform.path}/tools/pluggable_discovery.py"
|
||||
pluggable_discovery.rp2040.pattern="{runtime.platform.path}/system/python3/python3" -I "{runtime.platform.path}/tools/pluggable_discovery.py"
|
||||
|
||||
|
||||
# Compile patterns
|
||||
@@ -110,7 +115,7 @@ recipe.hooks.sketch.prebuild.pattern="{runtime.tools.pqt-python3.path}/python3"
|
||||
recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} {build.usbpid} {build.usbpwr} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DBOARD_NAME="{build.board}" -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {build.debug_port} {build.debug_level} {build.flags.optimize} {includes} "{source_file}" -o "{object_file}"
|
||||
|
||||
## Compile c++ files
|
||||
recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" -I "{build.path}/core" {compiler.cpp.flags} {build.usbpid} {build.usbpwr} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DBOARD_NAME="{build.board}" -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {build.debug_port} {build.debug_level} {build.flags.optimize} {includes} "{source_file}" -o "{object_file}"
|
||||
recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" -I "{build.path}/core" {compiler.cpp.flags} {build.usbpid} {build.usbpwr} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DBOARD_NAME="{build.board}" -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {build.debug_port} {build.debug_level} {build.flags.optimize} {build.wificc} {includes} "{source_file}" -o "{object_file}"
|
||||
|
||||
## Compile S files
|
||||
recipe.S.o.pattern="{compiler.path}{compiler.S.cmd}" {compiler.S.flags} {build.usbpid} {build.usbpwr} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DBOARD_NAME="{build.board}" -DARDUINO_ARCH_{build.arch} {compiler.S.extra_flags} {build.extra_flags} {build.debug_port} {build.debug_level} {includes} "{source_file}" -o "{object_file}"
|
||||
@@ -148,6 +153,19 @@ recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build
|
||||
recipe.size.regex=^(?:\.boot2|\.text|\.rodata|\.ARM\.extab|\.ARM\.exidx)\s+([0-9]+).*
|
||||
recipe.size.regex.data=^(?:\.data|\.bss|\.ram_vector_table|\.uninitialized_data)\s+([0-9]+).*
|
||||
|
||||
|
||||
# Debugging
|
||||
debug.executable={build.path}/{build.project_name}.elf
|
||||
debug.toolchain=gcc
|
||||
debug.toolchain.path={runtime.tools.pqt-gcc.path}/bin/
|
||||
debug.toolchain.prefix=arm-none-eabi-
|
||||
debug.server=openocd
|
||||
debug.server.openocd.path={runtime.tools.pqt-openocd.path}/bin/openocd
|
||||
debug.server.openocd.scripts_dir={runtime.tools.pqt-openocd.path}/share/openocd/scripts/
|
||||
debug.server.openocd.script={runtime.platform.path}/lib/{build.debugscript}
|
||||
|
||||
|
||||
|
||||
tools.uf2conv.path=
|
||||
# Because the variable expansion doesn't allow one tool to find another, the following lines
|
||||
# will point to "{runtime.platform.path}/tools/python3/python3" in GIT and
|
||||
@@ -162,6 +180,14 @@ tools.uf2conv.upload.params.quiet=
|
||||
tools.uf2conv.upload.pattern="{cmd}" -I "{runtime.platform.path}/tools/uf2conv.py" --serial "{serial.port}" --family RP2040 --deploy "{build.path}/{build.project_name}.uf2"
|
||||
tools.uf2conv.upload.network_pattern="{network_cmd}" -I "{runtime.platform.path}/tools/espota.py" -i "{serial.port}" -p "{network.port}" "--auth={network.password}" -f "{build.path}/{build.project_name}.bin"
|
||||
|
||||
#tools.uf2conv-network.cmd={runtime.tools.pqt-python3.path}/python3
|
||||
tools.uf2conv-network.cmd={runtime.platform.path}/system/python3/python3
|
||||
tools.uf2conv-network.upload.protocol=uf2
|
||||
tools.uf2conv-network.upload.params.verbose=
|
||||
tools.uf2conv-network.upload.params.quiet=
|
||||
tools.uf2conv-network.upload.pattern="{cmd}" -I "{runtime.platform.path}/tools/espota.py" -i "{upload.port.address}" -p "{upload.port.properties.port}" "--auth={upload.field.password}" -f "{build.path}/{build.project_name}.bin"
|
||||
|
||||
|
||||
#tools.picoprobe.cmd={runtime.tools.pqt-openocd.path}
|
||||
tools.picoprobe.cmd={runtime.platform.path}/system/openocd
|
||||
tools.picoprobe.upload.protocol=picoprobe
|
||||
|
||||
+2
-1
@@ -80,7 +80,8 @@ function build_sketches()
|
||||
continue # Not ours to do
|
||||
fi
|
||||
|
||||
if [ -e $cache_dir/core/*.a ]; then
|
||||
cacheas=( $cache_dir/core/*.a )
|
||||
if [ -e ${cacheas[0]} ]; then
|
||||
# We need to preserve the build.options.json file and replace the last .ino
|
||||
# with this sketch's ino file, or builder will throw everything away.
|
||||
jq '."sketchLocation" = "'$sketch'"' $build_dir/build.options.json > $build_dir/build.options.json.tmp
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
for dir in ./cores/rp2040 ./libraries/EEPROM ./libraries/I2S \
|
||||
for dir in ./cores/rp2040 ./libraries/EEPROM ./libraries/I2S ./libraries/SingleFileDrive \
|
||||
./libraries/LittleFS/src ./libraries/LittleFS/examples \
|
||||
./libraries/rp2040 ./libraries/SD ./libraries/ESP8266SdFat \
|
||||
./libraries/Servo ./libraries/SPI ./libraries/Wire ./libraries/PDM \
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import time
|
||||
import subprocess
|
||||
import uf2conv
|
||||
|
||||
boards = False
|
||||
while True:
|
||||
l = uf2conv.get_drives()
|
||||
if (len(l) > 0) and (not boards):
|
||||
print ("""
|
||||
{
|
||||
"eventType": "add",
|
||||
"port": {
|
||||
"address": "1",
|
||||
"label": "Board",
|
||||
"boardName": "RPI 2040",
|
||||
"protocol": "uf2",
|
||||
"protocolLabel": "UF2 Devices",
|
||||
"prefs": {},
|
||||
"identificationPrefs": {}
|
||||
}
|
||||
}""", flush=True)
|
||||
boards = True
|
||||
elif (len(l) == 0) and boards:
|
||||
print ("""
|
||||
{
|
||||
"eventType": "remove",
|
||||
"port": {
|
||||
"address": "1",
|
||||
"label": "Board",
|
||||
"boardName": "RPI 2040",
|
||||
"protocol": "uf2",
|
||||
"protocolLabel": "UF2 Devices",
|
||||
"prefs": {},
|
||||
"identificationPrefs": {}
|
||||
}
|
||||
}""", flush=True)
|
||||
boards = False
|
||||
time.sleep(1)
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"earlephilhower": {
|
||||
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
|
||||
"usb_vid": "0x239A",
|
||||
"usb_pid": "0x8121"
|
||||
}
|
||||
},
|
||||
"core": "earlephilhower",
|
||||
"cpu": "cortex-m0plus",
|
||||
"extra_flags": "-D ARDUINO_ADAFRUIT_FEATHER_RP2040_SCORPIO -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=250",
|
||||
"f_cpu": "133000000L",
|
||||
"hwids": [
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x00C0"
|
||||
],
|
||||
[
|
||||
"0x239A",
|
||||
"0x8121"
|
||||
]
|
||||
],
|
||||
"mcu": "rp2040",
|
||||
"variant": "adafruit_feather_scorpio"
|
||||
},
|
||||
"debug": {
|
||||
"jlink_device": "RP2040_M0_0",
|
||||
"openocd_target": "rp2040.cfg",
|
||||
"svd_path": "rp2040.svd"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino"
|
||||
],
|
||||
"name": "Feather RP2040 SCORPIO",
|
||||
"upload": {
|
||||
"maximum_ram_size": 270336,
|
||||
"maximum_size": 8388608,
|
||||
"require_upload_port": true,
|
||||
"native_usb": true,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": false,
|
||||
"protocol": "picotool",
|
||||
"protocols": [
|
||||
"cmsis-dap",
|
||||
"jlink",
|
||||
"raspberrypi-swd",
|
||||
"picotool",
|
||||
"picoprobe"
|
||||
]
|
||||
},
|
||||
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
|
||||
"vendor": "Adafruit"
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
"earlephilhower": {
|
||||
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
|
||||
"usb_vid": "0x2341",
|
||||
"usb_pid": "0x0058"
|
||||
"usb_pid": "0x005E"
|
||||
}
|
||||
},
|
||||
"core": "earlephilhower",
|
||||
@@ -18,7 +18,7 @@
|
||||
],
|
||||
[
|
||||
"0x2341",
|
||||
"0x0058"
|
||||
"0x005E"
|
||||
]
|
||||
],
|
||||
"mcu": "rp2040",
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"earlephilhower": {
|
||||
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
|
||||
"usb_vid": "0x2E8A",
|
||||
"usb_pid": "0x1041"
|
||||
}
|
||||
},
|
||||
"core": "earlephilhower",
|
||||
"cpu": "cortex-m0plus",
|
||||
"extra_flags": "-D ARDUINO_BRIDGETEK_IDM2040-7A -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=250 -DFT8XX_TYPE=BT817 -DDISPLAY_RES=WVGA -DPLATFORM_RP2040",
|
||||
"f_cpu": "133000000L",
|
||||
"hwids": [
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x00C0"
|
||||
],
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x1041"
|
||||
]
|
||||
],
|
||||
"mcu": "rp2040",
|
||||
"variant": "bridgetek_idm2040-7a"
|
||||
},
|
||||
"debug": {
|
||||
"jlink_device": "RP2040_M0_0",
|
||||
"openocd_target": "rp2040.cfg",
|
||||
"svd_path": "rp2040.svd"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino"
|
||||
],
|
||||
"name": "IDM2040-7A",
|
||||
"upload": {
|
||||
"maximum_ram_size": 270336,
|
||||
"maximum_size": 8388608,
|
||||
"require_upload_port": true,
|
||||
"native_usb": true,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": false,
|
||||
"protocol": "picotool",
|
||||
"protocols": [
|
||||
"cmsis-dap",
|
||||
"jlink",
|
||||
"raspberrypi-swd",
|
||||
"picotool",
|
||||
"picoprobe"
|
||||
]
|
||||
},
|
||||
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
|
||||
"vendor": "BridgeTek"
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"earlephilhower": {
|
||||
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
|
||||
"usb_vid": "0x2E8A",
|
||||
"usb_pid": "0x000A"
|
||||
}
|
||||
},
|
||||
"core": "earlephilhower",
|
||||
"cpu": "cortex-m0plus",
|
||||
"extra_flags": "-D ARDUINO_DATANOISETV_PICOADK -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=250",
|
||||
"f_cpu": "133000000L",
|
||||
"hwids": [
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x00C0"
|
||||
],
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x000A"
|
||||
]
|
||||
],
|
||||
"mcu": "rp2040",
|
||||
"variant": "datanoisetv_picoadk"
|
||||
},
|
||||
"debug": {
|
||||
"jlink_device": "RP2040_M0_0",
|
||||
"openocd_target": "rp2040.cfg",
|
||||
"svd_path": "rp2040.svd"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino"
|
||||
],
|
||||
"name": "PicoADK",
|
||||
"upload": {
|
||||
"maximum_ram_size": 270336,
|
||||
"maximum_size": 2097152,
|
||||
"require_upload_port": true,
|
||||
"native_usb": true,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": false,
|
||||
"protocol": "picotool",
|
||||
"protocols": [
|
||||
"cmsis-dap",
|
||||
"jlink",
|
||||
"raspberrypi-swd",
|
||||
"picotool",
|
||||
"picoprobe"
|
||||
]
|
||||
},
|
||||
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
|
||||
"vendor": "DatanoiseTV"
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"earlephilhower": {
|
||||
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
|
||||
"usb_vid": "0x2E8A",
|
||||
"usb_pid": "0x1037"
|
||||
}
|
||||
},
|
||||
"core": "earlephilhower",
|
||||
"cpu": "cortex-m0plus",
|
||||
"extra_flags": "-D ARDUINO_ELECTRONICCATS_HUNTERCAT_NFC -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=500",
|
||||
"f_cpu": "133000000L",
|
||||
"hwids": [
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x00C0"
|
||||
],
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x1037"
|
||||
]
|
||||
],
|
||||
"mcu": "rp2040",
|
||||
"variant": "electroniccats_huntercat_nfc"
|
||||
},
|
||||
"debug": {
|
||||
"jlink_device": "RP2040_M0_0",
|
||||
"openocd_target": "rp2040.cfg",
|
||||
"svd_path": "rp2040.svd"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino"
|
||||
],
|
||||
"name": "HunterCat NFC RP2040",
|
||||
"upload": {
|
||||
"maximum_ram_size": 270336,
|
||||
"maximum_size": 2097152,
|
||||
"require_upload_port": true,
|
||||
"native_usb": true,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": false,
|
||||
"protocol": "picotool",
|
||||
"protocols": [
|
||||
"cmsis-dap",
|
||||
"jlink",
|
||||
"raspberrypi-swd",
|
||||
"picotool",
|
||||
"picoprobe"
|
||||
]
|
||||
},
|
||||
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
|
||||
"vendor": "ElectronicCats"
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
"build": {
|
||||
"arduino": {
|
||||
"earlephilhower": {
|
||||
"boot2_source": "boot2_generic_03h_4_padded_checksum.S",
|
||||
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
|
||||
"usb_vid": "0x2E8A",
|
||||
"usb_pid": "0x008A"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"earlephilhower": {
|
||||
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
|
||||
"usb_vid": "0x2E8A",
|
||||
"usb_pid": "0x1011"
|
||||
}
|
||||
},
|
||||
"core": "earlephilhower",
|
||||
"cpu": "cortex-m0plus",
|
||||
"extra_flags": "-D ARDUINO_MELOPERO_COOKIE_RP2040 -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=250",
|
||||
"f_cpu": "133000000L",
|
||||
"hwids": [
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x00C0"
|
||||
],
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x1011"
|
||||
]
|
||||
],
|
||||
"mcu": "rp2040",
|
||||
"variant": "melopero_cookie_rp2040"
|
||||
},
|
||||
"debug": {
|
||||
"jlink_device": "RP2040_M0_0",
|
||||
"openocd_target": "rp2040.cfg",
|
||||
"svd_path": "rp2040.svd"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino"
|
||||
],
|
||||
"name": "Cookie RP2040",
|
||||
"upload": {
|
||||
"maximum_ram_size": 270336,
|
||||
"maximum_size": 8388608,
|
||||
"require_upload_port": true,
|
||||
"native_usb": true,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": false,
|
||||
"protocol": "picotool",
|
||||
"protocols": [
|
||||
"cmsis-dap",
|
||||
"jlink",
|
||||
"raspberrypi-swd",
|
||||
"picotool",
|
||||
"picoprobe"
|
||||
]
|
||||
},
|
||||
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
|
||||
"vendor": "Melopero"
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"earlephilhower": {
|
||||
"boot2_source": "boot2_w25x10cl_4_padded_checksum.S",
|
||||
"usb_vid": "0x2E8A",
|
||||
"usb_pid": "0x6E61"
|
||||
}
|
||||
},
|
||||
"core": "earlephilhower",
|
||||
"cpu": "cortex-m0plus",
|
||||
"extra_flags": "-D ARDUINO_NULLBITS_BIT_C_PRO -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=500",
|
||||
"f_cpu": "133000000L",
|
||||
"hwids": [
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x00C0"
|
||||
],
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x6E61"
|
||||
]
|
||||
],
|
||||
"mcu": "rp2040",
|
||||
"variant": "nullbits_bit_c_pro"
|
||||
},
|
||||
"debug": {
|
||||
"jlink_device": "RP2040_M0_0",
|
||||
"openocd_target": "rp2040.cfg",
|
||||
"svd_path": "rp2040.svd"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino"
|
||||
],
|
||||
"name": "Bit-C PRO",
|
||||
"upload": {
|
||||
"maximum_ram_size": 270336,
|
||||
"maximum_size": 4194304,
|
||||
"require_upload_port": true,
|
||||
"native_usb": true,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": false,
|
||||
"protocol": "picotool",
|
||||
"protocols": [
|
||||
"cmsis-dap",
|
||||
"jlink",
|
||||
"raspberrypi-swd",
|
||||
"picotool",
|
||||
"picoprobe"
|
||||
]
|
||||
},
|
||||
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
|
||||
"vendor": "nullbits"
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"earlephilhower": {
|
||||
"boot2_source": "boot2_w25q64jv_4_padded_checksum.S",
|
||||
"usb_vid": "0x2E8A",
|
||||
"usb_pid": "0x1008"
|
||||
}
|
||||
},
|
||||
"core": "earlephilhower",
|
||||
"cpu": "cortex-m0plus",
|
||||
"extra_flags": "-D ARDUINO_PIMORONI_PGA2040 -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=250",
|
||||
"f_cpu": "133000000L",
|
||||
"hwids": [
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x00C0"
|
||||
],
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x1008"
|
||||
]
|
||||
],
|
||||
"mcu": "rp2040",
|
||||
"variant": "pimoroni_pga2040"
|
||||
},
|
||||
"debug": {
|
||||
"jlink_device": "RP2040_M0_0",
|
||||
"openocd_target": "rp2040.cfg",
|
||||
"svd_path": "rp2040.svd"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino"
|
||||
],
|
||||
"name": "PGA2040",
|
||||
"upload": {
|
||||
"maximum_ram_size": 270336,
|
||||
"maximum_size": 8388608,
|
||||
"require_upload_port": true,
|
||||
"native_usb": true,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": false,
|
||||
"protocol": "picotool",
|
||||
"protocols": [
|
||||
"cmsis-dap",
|
||||
"jlink",
|
||||
"raspberrypi-swd",
|
||||
"picotool",
|
||||
"picoprobe"
|
||||
]
|
||||
},
|
||||
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
|
||||
"vendor": "Pimoroni"
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"earlephilhower": {
|
||||
"boot2_source": "boot2_generic_03h_4_padded_checksum.S",
|
||||
"usb_vid": "0x2E8A",
|
||||
"usb_pid": "0x000A"
|
||||
}
|
||||
},
|
||||
"core": "earlephilhower",
|
||||
"cpu": "cortex-m0plus",
|
||||
"extra_flags": "-D ARDUINO_VIYALAB_MIZU_RP2040 -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=250",
|
||||
"f_cpu": "133000000L",
|
||||
"hwids": [
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x00C0"
|
||||
],
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x000A"
|
||||
]
|
||||
],
|
||||
"mcu": "rp2040",
|
||||
"variant": "viyalab_mizu"
|
||||
},
|
||||
"debug": {
|
||||
"jlink_device": "RP2040_M0_0",
|
||||
"openocd_target": "rp2040.cfg",
|
||||
"svd_path": "rp2040.svd"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino"
|
||||
],
|
||||
"name": "Mizu RP2040",
|
||||
"upload": {
|
||||
"maximum_ram_size": 270336,
|
||||
"maximum_size": 8388608,
|
||||
"require_upload_port": true,
|
||||
"native_usb": true,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": false,
|
||||
"protocol": "picotool",
|
||||
"protocols": [
|
||||
"cmsis-dap",
|
||||
"jlink",
|
||||
"raspberrypi-swd",
|
||||
"picotool",
|
||||
"picoprobe"
|
||||
]
|
||||
},
|
||||
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
|
||||
"vendor": "Viyalab"
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"earlephilhower": {
|
||||
"boot2_source": "boot2_w25q16jvxq_4_padded_checksum.S",
|
||||
"usb_vid": "0x2E8A",
|
||||
"usb_pid": "0x1021"
|
||||
}
|
||||
},
|
||||
"core": "earlephilhower",
|
||||
"cpu": "cortex-m0plus",
|
||||
"extra_flags": "-D ARDUINO_WAVESHARE_RP2040_LCD_0_96 -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=500",
|
||||
"f_cpu": "133000000L",
|
||||
"hwids": [
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x00C0"
|
||||
],
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x1021"
|
||||
]
|
||||
],
|
||||
"mcu": "rp2040",
|
||||
"variant": "waveshare_rp2040_lcd_0_96"
|
||||
},
|
||||
"debug": {
|
||||
"jlink_device": "RP2040_M0_0",
|
||||
"openocd_target": "rp2040.cfg",
|
||||
"svd_path": "rp2040.svd"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino"
|
||||
],
|
||||
"name": "RP2040 LCD 0.96",
|
||||
"upload": {
|
||||
"maximum_ram_size": 270336,
|
||||
"maximum_size": 2097152,
|
||||
"require_upload_port": true,
|
||||
"native_usb": true,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": false,
|
||||
"protocol": "picotool",
|
||||
"protocols": [
|
||||
"cmsis-dap",
|
||||
"jlink",
|
||||
"raspberrypi-swd",
|
||||
"picotool",
|
||||
"picoprobe"
|
||||
]
|
||||
},
|
||||
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
|
||||
"vendor": "Waveshare"
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user