Compare commits
@@ -6,35 +6,23 @@ name: Arduino-Pico CI
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
TRAVIS_BUILD_DIR: ${{ github.workspace }}
|
||||
TRAVIS_TAG: ${{ github.ref }}
|
||||
|
||||
|
||||
jobs:
|
||||
|
||||
# Me no spell so good
|
||||
code-spell:
|
||||
name: Check spelling
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
- 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,./.git
|
||||
ignore_words_list: ser,dout
|
||||
|
||||
# Consistent style
|
||||
# Consistent style, spelling
|
||||
astyle:
|
||||
name: Style, Boards, Package
|
||||
name: Spelling, Style, Boards, Package
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: false
|
||||
- name: Run codespell
|
||||
uses: codespell-project/actions-codespell@v2
|
||||
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,./.git,./libraries/FatFS/lib/fatfs,./libraries/FatFS/src/diskio.h,./libraries/FatFS/src/ff.cpp,./libraries/FatFS/src/ffconf.h,./libraries/FatFS/src/ffsystem.cpp,./libraries/FatFS/src/ff.h,./libraries/lwIP_WINC1500/src/driver,./libraries/lwIP_WINC1500/src/common,./libraries/lwIP_WINC1500/src/bus_wrapper,./libraries/lwIP_WINC1500/src/spi_flash
|
||||
ignore_words_list: ser,dout,shiftIn,acount
|
||||
- name: Get submodules for following tests
|
||||
run: git submodule update --init
|
||||
- name: Check package references
|
||||
run: |
|
||||
./tests/ci/pkgrefs_test.sh
|
||||
@@ -59,15 +47,15 @@ jobs:
|
||||
matrix:
|
||||
chunk: [0, 1, 2, 3, 4, 5]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- uses: actions/setup-python@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Cache Linux toolchain
|
||||
id: cache-linux
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ./tools/dist
|
||||
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
|
||||
@@ -82,20 +70,82 @@ jobs:
|
||||
cd ..
|
||||
bash ./tests/build.sh
|
||||
|
||||
# Build all rp2350 examples on linux (core and Arduino IDE)
|
||||
build-rp2350-linux:
|
||||
name: Build RP2350 ${{ matrix.chunk }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
chunk: [0, 1, 2, 3, 4, 5]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Cache Linux toolchain
|
||||
id: cache-linux
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ./tools/dist
|
||||
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
|
||||
- name: Build Sketches
|
||||
env:
|
||||
BUILD_PARITY: custom
|
||||
mod: 6
|
||||
rem: ${{ matrix.chunk }}
|
||||
run: |
|
||||
cd pico-sdk
|
||||
git submodule update --init
|
||||
cd ..
|
||||
bash ./tests/build-rp2350.sh
|
||||
|
||||
# Build all rp2350-riscv examples on linux (core and Arduino IDE)
|
||||
build-rp2350-riscv-linux:
|
||||
name: Build RP2350-RISCV ${{ matrix.chunk }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
chunk: [0, 1, 2, 3, 4, 5]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Cache Linux toolchain
|
||||
id: cache-linux
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ./tools/dist
|
||||
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
|
||||
- name: Build Sketches
|
||||
env:
|
||||
BUILD_PARITY: custom
|
||||
mod: 6
|
||||
rem: ${{ matrix.chunk }}
|
||||
run: |
|
||||
cd pico-sdk
|
||||
git submodule update --init
|
||||
cd ..
|
||||
bash ./tests/build-rp2350-riscv.sh
|
||||
|
||||
# Build TinyUSB examples, requires custom build command line
|
||||
build-tinyusb:
|
||||
name: Build TinyUSB Examples
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- uses: actions/setup-python@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Cache Linux toolchain
|
||||
id: cache-linux
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ./tools/dist
|
||||
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
|
||||
@@ -113,15 +163,15 @@ jobs:
|
||||
name: Windows
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- uses: actions/setup-python@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Cache Windows toolchain
|
||||
id: cache-windows
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ./tools/dist
|
||||
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
|
||||
@@ -144,17 +194,20 @@ jobs:
|
||||
# Single build under macOS to ensure the Mac toolchain is good.
|
||||
build-mac:
|
||||
name: Mac
|
||||
runs-on: macOS-12
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macOS-12, macOS-14]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- uses: actions/setup-python@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Cache Mac toolchain
|
||||
id: cache-mac
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ./tools/dist
|
||||
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
|
||||
@@ -165,17 +218,23 @@ jobs:
|
||||
mod: 500
|
||||
rem: 1
|
||||
run: |
|
||||
brew update
|
||||
brew install bash
|
||||
/usr/bin/env bash --version
|
||||
uname -a
|
||||
cd pico-sdk
|
||||
git submodule update --init
|
||||
cd ..
|
||||
bash ./tests/build.sh
|
||||
/usr/bin/env bash ./tests/build.sh
|
||||
./system/picotool/picotool version
|
||||
otool -L ./system/picotool/picotool
|
||||
|
||||
# Build a few examples with PlatformIO to test if integration works
|
||||
build-platformio:
|
||||
name: Build PlatformIO Examples
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'true'
|
||||
- name: Initialize needed submodules
|
||||
@@ -186,19 +245,19 @@ jobs:
|
||||
git submodule update --init
|
||||
cd ../..
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
- name: Cache PlatformIO
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install PlatformIO
|
||||
@@ -206,9 +265,13 @@ jobs:
|
||||
python -m pip install --upgrade pip
|
||||
pip install --upgrade platformio
|
||||
pio pkg install --global --platform https://github.com/maxgerhardt/platform-raspberrypi.git
|
||||
pio pkg update --global --platform https://github.com/maxgerhardt/platform-raspberrypi.git
|
||||
pio pkg install --global --tool symlink://.
|
||||
cp -f /home/runner/work/arduino-pico/arduino-pico/tools/json/*.json /home/runner/.platformio/platforms/raspberrypi/boards/.
|
||||
- name: Build Multicore Example
|
||||
run: pio ci --board=rpipico --board=adafruit_feather -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/rp2040/examples/Multicore/Multicore.ino
|
||||
run: pio ci -v --board=rpipico --board=rpipico2 --board=adafruit_feather -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/rp2040/examples/Multicore/Multicore.ino
|
||||
- name: Build Multicore Example (RISC-V)
|
||||
run: pio ci -v --board=rpipico2 -O "board_build.mcu = rp2350-riscv" -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/rp2040/examples/Multicore/Multicore.ino
|
||||
- name: Build Fade Example
|
||||
run: pio ci --board=rpipico --board=adafruit_feather -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/rp2040/examples/Fade/Fade.ino
|
||||
- name: Build TinyUSB Example
|
||||
@@ -219,3 +282,56 @@ jobs:
|
||||
run: pio ci --board=rpipicow -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/ArduinoOTA/examples/SignedOTA/SignedOTA.ino
|
||||
- name: Build Bluetooth Example
|
||||
run: pio ci --board=rpipicow -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" -O "build_flags=-DPIO_FRAMEWORK_ARDUINO_ENABLE_BLUETOOTH" libraries/MouseBLE/examples/BLECircle/BLECircle.ino
|
||||
|
||||
# Build every variant using PIO for simplicity
|
||||
build-variants:
|
||||
name: Build Every Variant ${{ matrix.chunk }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
chunk: [0, 1]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'true'
|
||||
- name: Initialize needed submodules
|
||||
run: |
|
||||
cd pico-sdk
|
||||
git submodule update --init
|
||||
cd ../libraries/Adafruit_TinyUSB_Arduino
|
||||
git submodule update --init
|
||||
cd ../..
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
- name: Cache PlatformIO
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install PlatformIO
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install --upgrade platformio
|
||||
pio pkg install --global --platform https://github.com/maxgerhardt/platform-raspberrypi.git
|
||||
pio pkg update --global --platform https://github.com/maxgerhardt/platform-raspberrypi.git
|
||||
pio pkg install --global --tool symlink://.
|
||||
cp -f /home/runner/work/arduino-pico/arduino-pico/tools/json/*.json /home/runner/.platformio/platforms/raspberrypi/boards/.
|
||||
- name: Build Every Variant
|
||||
run: |
|
||||
cnt=0
|
||||
for b in $(cut -f1 -d. /home/runner/work/arduino-pico/arduino-pico/boards.txt | sed 's/#.*//' | sed 's/^menu$//' | sort -u); do
|
||||
cnt=$((cnt + 1))
|
||||
rem=$((cnt % 2))
|
||||
if [ $rem == ${{ matrix.chunk }} ]; then
|
||||
pio ci --board=$b -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/rp2040/examples/Bootsel/Bootsel.ino
|
||||
fi
|
||||
done
|
||||
|
||||
@@ -9,31 +9,30 @@ jobs:
|
||||
name: Update master JSON file
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
- name: Cache PlatformIO
|
||||
uses: actions/cache@v3
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install PlatformIO
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install --upgrade platformio
|
||||
python-version: '3.x'
|
||||
# - name: Cache PlatformIO
|
||||
# uses: actions/cache@v4
|
||||
# with:
|
||||
# path: ~/.platformio
|
||||
# key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
||||
# - name: Install PlatformIO
|
||||
# run: |
|
||||
# python -m pip install --upgrade pip
|
||||
# pip install --upgrade platformio
|
||||
- name: Deploy updated JSON
|
||||
env:
|
||||
TRAVIS_BUILD_DIR: ${{ github.workspace }}
|
||||
BUILD_TYPE: package
|
||||
CI_GITHUB_API_KEY: ${{ secrets.GITHUB_TOKEN }}
|
||||
PLATFORMIO_AUTH_TOKEN: ${{ secrets.PLATFORMIO_AUTH_TOKEN }}
|
||||
@@ -43,5 +42,5 @@ jobs:
|
||||
curl -L -o package_rp2040_index.json "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/releases/download/$TAG/package_rp2040_index.json"
|
||||
./package/update_release.py --token ${CI_GITHUB_API_KEY} --repo "$GITHUB_REPOSITORY" --tag global package_rp2040_index.json
|
||||
# Upload to Platform.IO
|
||||
curl -LO $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/releases/download/$TAG/rp2040-$TAG.zip
|
||||
pio package publish rp2040-$TAG.zip --non-interactive
|
||||
# curl -LO $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/releases/download/$TAG/rp2040-$TAG.zip
|
||||
# pio package publish rp2040-$TAG.zip --non-interactive
|
||||
|
||||
@@ -15,16 +15,15 @@ jobs:
|
||||
name: Package
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Build package JSON
|
||||
env:
|
||||
TRAVIS_BUILD_DIR: ${{ github.workspace }}
|
||||
BUILD_TYPE: package
|
||||
CI_GITHUB_API_KEY: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
|
||||
+12
@@ -37,3 +37,15 @@
|
||||
[submodule "libraries/http_parser/lib/http-parser"]
|
||||
path = libraries/http-parser/lib/http-parser
|
||||
url = https://github.com/nodejs/http-parser.git
|
||||
[submodule "libraries/FatFS/lib/SPIFTL"]
|
||||
path = libraries/FatFS/lib/SPIFTL
|
||||
url = https://github.com/earlephilhower/SPIFTL.git
|
||||
[submodule "libraries/AsyncUDP"]
|
||||
path = libraries/AsyncUDP
|
||||
url = https://github.com/earlephilhower/AsyncUDP.git
|
||||
[submodule "cores/rp2040/tlsf"]
|
||||
path = lib/tlsf
|
||||
url = https://github.com/earlephilhower/tlsf.git
|
||||
[submodule "libraries/ESPHost"]
|
||||
path = libraries/ESPHost
|
||||
url = https://github.com/Networking-for-Arduino/ESPHost.git
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
# Read the Docs configuration file for Sphinx projects
|
||||
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
||||
|
||||
# Required
|
||||
version: 2
|
||||
|
||||
# Set the OS, Python version and other tools you might need
|
||||
|
||||
build:
|
||||
os: ubuntu-22.04
|
||||
tools:
|
||||
python: "3.12"
|
||||
jobs:
|
||||
post_create_environment:
|
||||
- python -m pip install sphinx_rtd_theme
|
||||
# You can also specify other tool versions:
|
||||
# nodejs: "20"
|
||||
# rust: "1.70"
|
||||
# golang: "1.20"
|
||||
|
||||
|
||||
# Build documentation in the "docs/" directory with Sphinx
|
||||
|
||||
sphinx:
|
||||
configuration: docs/conf.py
|
||||
# You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
|
||||
# builder: "dirhtml"
|
||||
# Fail on all warnings to avoid broken references
|
||||
# fail_on_warning: true
|
||||
|
||||
# Optionally build your docs in additional formats such as PDF and ePub
|
||||
# formats:
|
||||
# - pdf
|
||||
# - epub
|
||||
|
||||
# Optional but recommended, declare the Python requirements required
|
||||
# to build your documentation
|
||||
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
|
||||
# python:
|
||||
# install:
|
||||
# - requirements: docs/requirements.txt
|
||||
+1
-1
Submodule ArduinoCore-API updated: e37df85425...ece6e68f29
@@ -2,9 +2,9 @@
|
||||
[](https://github.com/earlephilhower/arduino-pico/releases)
|
||||
[](https://gitter.im/arduino-pico/community)
|
||||
|
||||
Raspberry Pi Pico Arduino core, for all RP2040 boards
|
||||
Raspberry Pi Pico Arduino core, for all RP2040 and RP2350 boards
|
||||
|
||||
This is a port of the RP2040 (Raspberry Pi Pico processor) to the Arduino ecosystem. It uses the bare Raspberry Pi Pico SDK and a custom GCC 10.3/Newlib 4.0 toolchain.
|
||||
This is a port of Arduino to the RP2040 (Raspberry Pi Pico processor) and RP2350 (Raspberry Pi Pico 2 processor). It uses the bare Raspberry Pi Pico SDK and a custom GCC 14.2/Newlib 4.3 toolchain and supports ARM and RISC-V cores.
|
||||
|
||||
# Documentation
|
||||
See https://arduino-pico.readthedocs.io/en/latest/ along with the examples for more detailed usage information.
|
||||
@@ -15,42 +15,81 @@ Read the [Contributing Guide](https://github.com/earlephilhower/arduino-pico/blo
|
||||
# Supported Boards
|
||||
* Raspberry Pi Pico
|
||||
* Raspberry Pi Pico W
|
||||
* Raspberry Pi Pico 2
|
||||
* 0xCB Helios
|
||||
* Adafruit Feather RP2040
|
||||
* Adafruit Feather RP2040 SCORPIO
|
||||
* Adafruit ItsyBitsy RP2040
|
||||
* Adafruit KB2040
|
||||
* Adafruit Macropad RP2040
|
||||
* Adafruit Metro RP2040
|
||||
* Adafruit QTPy RP2040
|
||||
* Adafruit STEMMA Friend RP2040
|
||||
* Adafruit Trinkey RP2040 QT
|
||||
* Amken Bunny
|
||||
* Amken Revelop
|
||||
* Amken Revelop Plus
|
||||
* Amken Revelop eS
|
||||
* Architeuthis Flux Jumperless
|
||||
* Architeuthis Flux Jumperless V5
|
||||
* Arduino Nano RP2040 Connect
|
||||
* ArtronShop RP2 Nano
|
||||
* Breadstick Raspberry
|
||||
* BridgeTek IDM2040-7A
|
||||
* BridgeTek IDM2040-43A
|
||||
* Cytron IRIV IO Controller
|
||||
* Cytron Maker Pi RP2040
|
||||
* Cytron Maker Nano RP2040
|
||||
* DatanoiseTV PicoADK+
|
||||
* Cytron Maker Uno RP2040
|
||||
* Cytron Motion 2350 Pro
|
||||
* Datanoise PicoADK v1
|
||||
* Datanoise PicoADK v2 (RP2350)
|
||||
* Degz Suibo RP2040
|
||||
* DeRuiLab FlyBoard2040 Core
|
||||
* DFRobot Beetle RP2040
|
||||
* ElectronicCats Hunter Cat NFC
|
||||
* EVN Alpha
|
||||
* ExtremeElectronics RC2040
|
||||
* GroundStudio Marble Pico
|
||||
* Invector Labs Challenger RP2040 WiFi
|
||||
* Invector Labs Challenger RP2040 WiFi/BLE
|
||||
* Invector Labs Challenger RP2040 WiFi6/BLE
|
||||
* Invector Labs Challenger NB RP2040 WiFi
|
||||
* Invector Labs Challenger RP2040 LTE
|
||||
* Invector Labs Challenger RP2040 LoRa
|
||||
* Invector Labs Challenger RP2040 SubGHz
|
||||
* Invector Labs Challenger RP2040 SD/RTC
|
||||
* Invector Labs Challenger RP2040 UWB
|
||||
* Invector Labs Challenger RP2350 BConnect
|
||||
* Invector Labs Challenger RP2350 WiFi/BLE
|
||||
* Invector Labs RPICO32
|
||||
* Melopero Cookie RP2040
|
||||
* Melopero Shake RP2040
|
||||
* METE HOCA Akana R1
|
||||
* Neko Systems BL2040 Mini
|
||||
* Olimex RP2040-Pico30
|
||||
* Newsan Archi
|
||||
* nullbits Bit-C PRO
|
||||
* Pimoroni PGA2040
|
||||
* Pimoroni Pico Plus 2
|
||||
* Pimoroni Plasma2040
|
||||
* Pimoroni Tiny2040
|
||||
* Pimoroni Tiny2350
|
||||
* Pintronix PinMax
|
||||
* RAKwireless RAK11300
|
||||
* Redscorp RP2040-Eins
|
||||
* Redscorp RP2040-ProMini
|
||||
* Sea-Picro
|
||||
* Seeed Indicator RP2040
|
||||
* Seeed XIAO RP2040
|
||||
* Seeed XIAO RP2350
|
||||
* Silicognition RP2040-Shim
|
||||
* Solder Party RP2040 Stamp
|
||||
* Solder Party RP2350 Stamp
|
||||
* Solder Party RP2350 Stamp XL
|
||||
* SparkFun MicroMod RP2040
|
||||
* SparkFun ProMicro RP2040
|
||||
* SparkFun ProMicro RP2350
|
||||
* SparkFun Thing Plus RP2040
|
||||
* uPesy RP2040 DevKit
|
||||
* VCC-GND YD-RP2040
|
||||
@@ -60,10 +99,45 @@ Read the [Contributing Guide](https://github.com/earlephilhower/arduino-pico/blo
|
||||
* Waveshare RP2040 Plus
|
||||
* Waveshare RP2040 LCD 0.96
|
||||
* Waveshare RP2040 LCD 1.28
|
||||
* Waveshare RP2040 Matrix
|
||||
* Waveshare RP2040 PiZero
|
||||
* WIZnet W5100S-EVB-Pico
|
||||
* WIZnet W5500-EVB-Pico
|
||||
* WIZnet WizFi360-EVB-Pico
|
||||
* Generic (configurable flash, I/O pins)
|
||||
* Generic RP2040 (configurable flash, I/O pins)
|
||||
* Generic RP2350 (configurable flash, I/O pins)
|
||||
|
||||
# Features
|
||||
* Adafruit TinyUSB Arduino (USB mouse, keyboard, flash drive, generic HID, CDC Serial, MIDI, WebUSB, others)
|
||||
* Bluetooth on the PicoW (Classic and BLE) with Keyboard, Mouse, Joystick, and Virtual Serial
|
||||
* Bluetooth Classic and BLE HID master mode (connect to BT keyboard, mouse, or joystick)
|
||||
* Generic Arduino USB Serial, Keyboard, Joystick, and Mouse emulation
|
||||
* WiFi (Pico W, ESP32-based ESPHost, Atmel WINC1500)
|
||||
* Ethernet (Wired WizNet W6100, WizNet W5500, WizNet W5100, ENC28J60)
|
||||
* HTTP client and server (WebServer)
|
||||
* SSL/TLS/HTTPS
|
||||
* Over-the-Air (OTA) upgrades
|
||||
* Filesystems (LittleFS and SD/SDFS)
|
||||
* Multicore support (setup1() and loop1())
|
||||
* FreeRTOS SMP support
|
||||
* Overclocking and underclocking from the menus
|
||||
* digitalWrite/Read, shiftIn/Out, tone, analogWrite(PWM)/Read, temperature
|
||||
* Analog stereo audio in using DMA and the built-in ADC
|
||||
* Analog stereo audio out using PWM hardware
|
||||
* Bluetooth A2DP audio source (output) and sink (input) on the PicoW
|
||||
* USB drive mode for data loggers (SingleFileDrive, FatFSUSB)
|
||||
* Peripherals: SPI master/slave, Wire(I2C) master/slave, dual UART, emulated EEPROM, I2S audio input/output, Servo
|
||||
* printf (i.e. debug) output over USB serial
|
||||
* Transparent use of PSRAM globals and heap (RP2350 only)
|
||||
* ARM or RISC-V (Hazard3) support for the RP2350
|
||||
|
||||
The RP2040 PIO state machines (SMs) are used to generate jitter-free:
|
||||
* Servos
|
||||
* Tones
|
||||
* I2S Input
|
||||
* I2S Output
|
||||
* Software UARTs (Serial ports)
|
||||
|
||||
|
||||
# Installing via Arduino Boards Manager
|
||||
## Windows-specific Notes
|
||||
@@ -128,11 +202,6 @@ cd ../tools
|
||||
python3 ./get.py
|
||||
`````
|
||||
|
||||
# Installing both Arduino and CMake
|
||||
Tom's Hardware presented a very nice writeup on installing `arduino-pico` on both Windows and Linux, available at https://www.tomshardware.com/how-to/program-raspberry-pi-pico-with-arduino-ide
|
||||
|
||||
If you follow Les' step-by-step you will also have a fully functional `CMake`-based environment to build Pico apps on if you outgrow the Arduino ecosystem.
|
||||
|
||||
# Uploading Sketches
|
||||
To upload your first sketch, you will need to hold the BOOTSEL button down while plugging in the Pico to your computer.
|
||||
Then hit the upload button and the sketch should be transferred and start to run.
|
||||
@@ -153,83 +222,30 @@ To install, follow the directions in
|
||||
* https://github.com/earlephilhower/arduino-pico-littlefs-plugin/blob/master/README.md
|
||||
|
||||
For detailed usage information, please check the ESP8266 repo documentation (ignore SPIFFS related notes) available at
|
||||
* https://arduino-esp8266.readthedocs.io/en/latest/filesystem.html
|
||||
* https://arduino-pico.readthedocs.io/en/latest/fs.html
|
||||
|
||||
# Uploading Sketches with Picoprobe
|
||||
# Uploading Sketches with Picoprobe/Debugprobe
|
||||
If you have built a Raspberry Pi Picoprobe, you can use OpenOCD to handle your sketch uploads and for debugging with GDB.
|
||||
|
||||
Under Windows a local admin user should be able to access the Picoprobe port automatically, but under Linux `udev` must be told about the device and to allow normal users access.
|
||||
|
||||
To set up user-level access to Picoprobes on Ubuntu (and other OSes which use `udev`):
|
||||
````
|
||||
echo 'SUBSYSTEMS=="usb", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="0004", GROUP="users", MODE="0666"' | sudo tee -a /etc/udev/rules.d/98-PicoProbe.rules
|
||||
echo 'SUBSYSTEM=="usb", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="0004", MODE="660", GROUP-"plugdev"' | sudo tee -a /etc/udev/rules.d/98-PicoProbe.rules
|
||||
echo 'SUBSYSTEM=="usb", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="000a", MODE="660", GROUP="plugdev"' | sudo tee -a /etc/udev/rules.d/98-PicoProbe.rules
|
||||
echo 'SUBSYSTEM=="usb", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="000f", MODE="660", GROUP="plugdev"' | sudo tee -a /etc/udev/rules.d/98-PicoProbe.rules
|
||||
sudo udevadm control --reload
|
||||
sudo udevadm trigger -w -s usb
|
||||
````
|
||||
|
||||
The first line creates a file with the USB vendor and ID of the Picoprobe and tells UDEV to give users full access to it. The second causes `udev` to load this new rule. Note that you will need to unplug and re-plug in your device the first time you create this file, to allow udev to make the device node properly.
|
||||
The first line creates a device file in `/dev` matching the USB vendor and product ID of the Picoprobe, and it enables global read+write permissions. The second line causes `udev` to load this new rule. The third line requests the kernel generate "device change" events that will cause our new `udev` rule to run.
|
||||
|
||||
If for some reason the device file does not appear, manually unplug and re-plug the USB connection and check again. The output from `dmesg` can reveal useful diagnostics if the device file remains absent.
|
||||
|
||||
Once Picoprobe permissions are set up properly, then select the board "Raspberry Pi Pico (Picoprobe)" in the Tools menu and upload as normal.
|
||||
|
||||
# Uploading Sketches with pico-debug
|
||||
[pico-debug](https://github.com/majbthrd/pico-debug/) differs from Picoprobe in that pico-debug is a virtual debug pod that runs side-by-side on the same RP2040 that you run your code on; so, you only need one RP2040 board instead of two. pico-debug also differs from Picoprobe in that pico-debug is standards-based; it uses the CMSIS-DAP protocol, which means even software not specially written for the Raspberry Pi Pico can support it. pico-debug uses OpenOCD to handle your sketch uploads, and debugging can be accomplished with CMSIS-DAP capable debuggers including GDB.
|
||||
|
||||
Under Windows and macOS, any user should be able to access pico-debug automatically, but under Linux `udev` must be told about the device and to allow normal users access.
|
||||
|
||||
To set up user-level access to all CMSIS-DAP adapters on Ubuntu (and other OSes which use `udev`):
|
||||
````
|
||||
echo 'ATTRS{product}=="*CMSIS-DAP*", MODE="664", GROUP="plugdev"' | sudo tee -a /etc/udev/rules.d/98-CMSIS-DAP.rules
|
||||
sudo udevadm control --reload
|
||||
````
|
||||
|
||||
The first line creates a file that recognizes all CMSIS-DAP adapters and tells UDEV to give users full access to it. The second causes `udev` to load this new rule. Note that you will need to unplug and re-plug in your device the first time you create this file, to allow udev to make the device node properly.
|
||||
|
||||
Once CMSIS-DAP permissions are set up properly, then select the board "Raspberry Pi Pico (pico-debug)" in the Tools menu.
|
||||
|
||||
When first connecting the USB port to your PC, you must copy [pico-debug-gimmecache.uf2](https://github.com/majbthrd/pico-debug/releases/) to the Pi Pico to load pico-debug into RAM; after this, upload as normal.
|
||||
|
||||
# Debugging with Picoprobe/pico-debug, OpenOCD, and GDB
|
||||
The installed tools include a version of OpenOCD (in the pqt-openocd directory) and GDB (in the pqt-gcc directory). These may be used to run GDB in an interactive window as documented in the Pico Getting Started manuals from the Raspberry Pi Foundation. For [pico-debug](https://github.com/majbthrd/pico-debug/), replace the raspberrypi-swd and picoprobe example OpenOCD arguments of "-f interface/raspberrypi-swd.cfg -f target/rp2040.cfg" or "-f interface/picoprobe.cfg -f target/rp2040.cfg" respectively in the Pico Getting Started manual with "-f board/pico-debug.cfg".
|
||||
|
||||
# Features
|
||||
* Adafruit TinyUSB Arduino (USB mouse, keyboard, flash drive, generic HID, CDC Serial, MIDI, WebUSB, others)
|
||||
* Bluetooth on the PicoW (Classic and BLE) with Keyboard, Mouse, Joystick, and Virtual Serial
|
||||
* Generic Arduino USB Serial, Keyboard, Joystick, and Mouse emulation
|
||||
* WiFi (Pico W)
|
||||
* HTTP client and server (WebServer)
|
||||
* SSL/TLS/HTTPS
|
||||
* Over-the-Air (OTA) upgrades
|
||||
* Filesystems (LittleFS and SD/SDFS)
|
||||
* Multicore support (setup1() and loop1())
|
||||
* FreeRTOS SMP support
|
||||
* Overclocking and underclocking from the menus
|
||||
* digitalWrite/Read, shiftIn/Out, tone, analogWrite(PWM)/Read, temperature
|
||||
* Analog stereo audio in using DMA and the built-in ADC
|
||||
* Analog stereo audio out using PWM hardware
|
||||
* USB drive mode for data loggers (SingleFileDrive)
|
||||
* Peripherals: SPI master, Wire(I2C) master/slave, dual UART, emulated EEPROM, I2S audio input, I2S audio output, Servo
|
||||
* printf (i.e. debug) output over USB serial
|
||||
|
||||
The RP2040 PIO state machines (SMs) are used to generate jitter-free:
|
||||
* Servos
|
||||
* Tones
|
||||
* I2S Input
|
||||
* I2S Output
|
||||
* Software UARTs (Serial ports)
|
||||
|
||||
# Tutorials from Across the Web
|
||||
Here are some links to coverage and additional tutorials for using `arduino-pico`
|
||||
* The File:: class is taken from the ESP8266. See https://arduino-esp8266.readthedocs.io/en/latest/filesystem.html
|
||||
* Arduino Support for the Pi Pico available! And how fast is the Pico? - https://youtu.be/-XHh17cuH5E
|
||||
* Pre-release Adafruit QT Py RP2040 - https://www.youtube.com/watch?v=sfC1msqXX0I
|
||||
* Adafruit Feather RP2040 running LCD + TMP117 - https://www.youtube.com/watch?v=fKDeqZiIwHg
|
||||
* Demonstration of Servos and I2C in Korean - https://cafe.naver.com/arduinoshield/1201
|
||||
* Home Assistant Pico W integration starter project using Arduino - https://github.com/daniloc/PicoW_HomeAssistant_Starter
|
||||
* Tutorials for the Raspberry Pi Pico / uPesy RP2040 DevKit board
|
||||
- English version: https://www.upesy.com/blogs/tutorials/best-tutorials-for-rpi-pi-pico-with-arduino-code
|
||||
- French version: https://www.upesy.fr/blogs/tutorials/best-tutorials-for-rpi-pi-pico-with-arduino-code
|
||||
|
||||
# Contributing
|
||||
If you want to contribute or have bugfixes, drop me a note at <earlephilhower@yahoo.com> or open an issue/PR here.
|
||||
# Debugging with Picoprobe, OpenOCD, and GDB
|
||||
The installed tools include a version of OpenOCD (in the pqt-openocd directory) and GDB (in the pqt-gcc directory). These may be used to run GDB in an interactive window as documented in the Pico Getting Started manuals from the Raspberry Pi Foundation. Use the command line `./system/openocd/bin/openocd -f ./lib/rp2040/picoprobe_cmsis_dap.tcl` or `./system/openocd/bin/openocd -f ./lib/rp2350/picoprobe_cmsis_dap.tcl` from the `git` installation directory.
|
||||
|
||||
# Licensing and Credits
|
||||
* The [Arduino IDE and ArduinoCore-API](https://arduino.cc) are developed and maintained by the Arduino team. The IDE is licensed under GPL.
|
||||
@@ -240,14 +256,17 @@ If you want to contribute or have bugfixes, drop me a note at <earlephilhower@ya
|
||||
* [UF2CONV.PY](https://github.com/microsoft/uf2) is by Microsoft Corporation and licensed under the MIT license.
|
||||
* Networking and filesystem code taken from the [ESP8266 Arduino Core](https://github.com/esp8266/Arduino) and licensed under the LGPL.
|
||||
* DHCP server for AP host mode from the [Micropython Project](https://micropython.org), distributed under the MIT License.
|
||||
* [FreeRTOS](https://freertos.org) is Copyright Amazon.com, Inc. or its affiliates, and distributed under the MIT license.
|
||||
* [FreeRTOS](https://freertos.org) is copyright Amazon.com, Inc. or its affiliates, and distributed under the MIT license.
|
||||
* [lwIP](https://savannah.nongnu.org/projects/lwip/) is (c) the Swedish Institute of Computer Science and licenced under the BSD license.
|
||||
* [BearSSL](https://bearssl.org) library written by Thomas Pornin, is distributed under the [MIT License](https://bearssl.org/#legal-details).
|
||||
* [UZLib](https://github.com/pfalcon/uzlib) is copyright (c) 2003 Joergen Ibsen and distributed under the zlib license.
|
||||
* [LEAmDNS](https://github.com/LaborEtArs/ESP8266mDNS) is copyright multiple authors and distributed under the MIT license.
|
||||
* [http-parser](https://github.com/nodejs/http-parser) is copyright Joyent, Inc. and other Node contributors.
|
||||
* WebServer code modified from the [ESP32 WebServer](https://github.com/espressif/arduino-esp32/tree/master/libraries/WebServer) and is copyright (c) 2015 Ivan Grokhotkov and others
|
||||
|
||||
* WebServer code modified from the [ESP32 WebServer](https://github.com/espressif/arduino-esp32/tree/master/libraries/WebServer) and is copyright (c) 2015 Ivan Grokhotkov and others.
|
||||
* [Xoshiro-cpp](https://github.com/Reputeless/Xoshiro-cpp) is copyright (c) 2020 Ryo Suzuki and distributed under the MIT license.
|
||||
* [FatFS low-level filesystem](http://elm-chan.org/fsw/ff/) code is Copyright (C) 2024, ChaN, all rights reserved.
|
||||
* [TLSF memory manager for PSRAM from Espressif fork](https://github.com/espressif/tlsf) of [original](https://github.com/mattconte/tlsf) by Matthew Conte is copyright Matthew Conte and licensed under the MIT license.
|
||||
* [ESPHost library](https://github.com/Networking-for-Arduino/ESPHost) is LGPL licensed by its maintainers.
|
||||
|
||||
-Earle F. Philhower, III
|
||||
earlephilhower@yahoo.com
|
||||
|
||||
+17708
-1789
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,23 @@
|
||||
// Padded and checksummed version of: generated\Winbond\W25Q32JVxQ\boot2.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
|
||||
@@ -0,0 +1,4 @@
|
||||
.section .boot2, "ax"
|
||||
|
||||
.global __boot2_entry_point
|
||||
__boot2_entry_point:
|
||||
@@ -0,0 +1,4 @@
|
||||
.section .boot2, "ax"
|
||||
|
||||
.global __boot2_entry_point
|
||||
__boot2_entry_point:
|
||||
+37
-8
@@ -28,9 +28,8 @@
|
||||
#include "api/ArduinoAPI.h"
|
||||
#include "api/itoa.h" // ARM toolchain doesn't provide itoa etc, provide them
|
||||
#include <pins_arduino.h>
|
||||
#include "hardware/gpio.h" // Required for the port*Register macros
|
||||
#include <hardware/gpio.h> // Required for the port*Register macros
|
||||
#include "debug_internal.h"
|
||||
#include <RP2040.h> // CMSIS
|
||||
|
||||
// Try and make the best of the old Arduino abs() macro. When in C++, use
|
||||
// the sane std::abs() call, but for C code use their macro since stdlib abs()
|
||||
@@ -38,7 +37,7 @@
|
||||
#ifdef abs
|
||||
#undef abs
|
||||
#endif // abs
|
||||
#ifdef __cplusplus
|
||||
#if defined(__cplusplus) && !defined(__riscv)
|
||||
using std::abs;
|
||||
using std::round;
|
||||
#else
|
||||
@@ -59,15 +58,24 @@ extern "C" {
|
||||
void interrupts();
|
||||
void noInterrupts();
|
||||
|
||||
// Only implemented on some RP2350 boards, not the OG Pico 2
|
||||
#ifdef RP2350_PSRAM_CS
|
||||
void *pmalloc(size_t size);
|
||||
void *pcalloc(size_t count, size_t size);
|
||||
#else
|
||||
[[deprecated("This chip does not have PSRAM, pmalloc will always fail")]] void *pmalloc(size_t size);
|
||||
[[deprecated("This chip does not have PSRAM, pcalloc will always fail")]] void *pcalloc(size_t count, size_t size);
|
||||
#endif
|
||||
|
||||
// AVR compatibility macros...naughty and accesses the HW directly
|
||||
#define digitalPinToPort(pin) (0)
|
||||
#define digitalPinToBitMask(pin) (1UL << (pin))
|
||||
#define digitalPinToTimer(pin) (0)
|
||||
#define digitalPinToInterrupt(pin) (pin)
|
||||
#define NOT_AN_INTERRUPT (-1)
|
||||
#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 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)
|
||||
#define sei() interrupts()
|
||||
@@ -125,7 +133,28 @@ extern const String emptyString;
|
||||
// Template which will evaluate at *compile time* to a single 32b number
|
||||
// with the specified bits set.
|
||||
template <size_t N>
|
||||
constexpr uint32_t __bitset(const int (&a)[N], size_t i = 0U) {
|
||||
return i < N ? (1L << a[i]) | __bitset(a, i + 1) : 0;
|
||||
constexpr uint64_t __bitset(const int (&a)[N], size_t i = 0U) {
|
||||
return i < N ? (1LL << a[i]) | __bitset(a, i + 1) : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Warn users trying to use Pico SDK's STDIO implementation
|
||||
#include <pico/stdio.h> // Ensure it won't be re-included elsewhere
|
||||
#undef stdio_uart_init
|
||||
#define stdio_uart_init(...) static_assert(0, "stdio_uart_init is not supported or needed. Either use Serial.printf() or set the debug port in the IDE to Serial/1/2 and use printf(). See https://github.com/earlephilhower/arduino-pico/issues/1433#issuecomment-1540354673 and https://github.com/earlephilhower/arduino-pico/issues/1433#issuecomment-1546783109")
|
||||
#undef stdio_init_all
|
||||
#define stdio_init_all(...) static_assert(0, "stdio_init_all is not supported or needed. Either use Serial.printf() or set the debug port in the IDE to Serial/1/2 and use printf(). See https://github.com/earlephilhower/arduino-pico/issues/1433#issuecomment-1540354673 and https://github.com/earlephilhower/arduino-pico/issues/1433#issuecomment-1546783109")
|
||||
#undef stdio_usb_init
|
||||
#define stdio_usb_init(...) static_assert(0, "stdio_usb_init is not supported or needed. Either use Serial.printf() or set the debug port in the IDE to Serial/1/2 and use printf(). See https://github.com/earlephilhower/arduino-pico/issues/1433#issuecomment-1540354673 and https://github.com/earlephilhower/arduino-pico/issues/1433#issuecomment-1546783109")
|
||||
|
||||
// PSRAM decorator
|
||||
#define PSRAM __attribute__((section("\".psram\"")))
|
||||
|
||||
// General GPIO/ADC layout info
|
||||
#ifdef PICO_RP2350B
|
||||
#define __GPIOCNT 48
|
||||
#define __FIRSTANALOGGPIO 40
|
||||
#else
|
||||
#define __GPIOCNT 30
|
||||
#define __FIRSTANALOGGPIO 26
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
Enable BTStack debugging to a Print-able object
|
||||
|
||||
Copyright (c) 2023 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
|
||||
*/
|
||||
|
||||
#if defined(ENABLE_CLASSIC) || defined(ENABLE_BLE)
|
||||
#include <Arduino.h>
|
||||
#include <btstack.h>
|
||||
#include <hci_dump.h>
|
||||
|
||||
static Print *_print;
|
||||
|
||||
static void _log_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len) {
|
||||
if (!_print) {
|
||||
return;
|
||||
}
|
||||
_print->printf("[BT @%lu] ", millis());
|
||||
|
||||
switch (packet_type) {
|
||||
case HCI_COMMAND_DATA_PACKET:
|
||||
_print->printf("CMD => ");
|
||||
break;
|
||||
case HCI_EVENT_PACKET:
|
||||
_print->printf("EVT <= ");
|
||||
break;
|
||||
case HCI_ACL_DATA_PACKET:
|
||||
_print->printf("ACL %s ", in ? "<=" : "=>");
|
||||
break;
|
||||
case HCI_SCO_DATA_PACKET:
|
||||
_print->printf("SCO %s ", in ? "<=" : "=>");
|
||||
break;
|
||||
case HCI_ISO_DATA_PACKET:
|
||||
_print->printf("ISO %s ", in ? "<=" : "=>");
|
||||
break;
|
||||
case LOG_MESSAGE_PACKET:
|
||||
_print->printf("LOG -- %s\n", (char*) packet);
|
||||
return;
|
||||
default:
|
||||
_print->printf("UNK(%x) %s ", packet_type, in ? "<=" : "=>");
|
||||
break;
|
||||
}
|
||||
|
||||
for (uint16_t i = 0; i < len; i++) {
|
||||
_print->printf("%02X ", packet[i]);
|
||||
}
|
||||
_print->printf("\n");
|
||||
}
|
||||
|
||||
static void _log_message(int log_level, const char * format, va_list argptr) {
|
||||
(void)log_level;
|
||||
char log_message_buffer[HCI_DUMP_MAX_MESSAGE_LEN];
|
||||
if (!_print) {
|
||||
return;
|
||||
}
|
||||
vsnprintf(log_message_buffer, sizeof(log_message_buffer), format, argptr);
|
||||
_print->printf("[BT @%lu] LOG -- %s\n", millis(), log_message_buffer);
|
||||
}
|
||||
|
||||
|
||||
static const hci_dump_t hci_dump_instance = {
|
||||
NULL,
|
||||
_log_packet,
|
||||
_log_message
|
||||
};
|
||||
|
||||
|
||||
void __EnableBluetoothDebug(Print &print) {
|
||||
_print = &print;
|
||||
hci_dump_init(&hci_dump_instance);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -4,11 +4,11 @@
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
#include <Arduino.h>
|
||||
#include "pico/stdlib.h"
|
||||
#include "hardware/gpio.h"
|
||||
#include "hardware/sync.h"
|
||||
#include "hardware/structs/ioqspi.h"
|
||||
#include "hardware/structs/sio.h"
|
||||
#include <pico/stdlib.h>
|
||||
#include <hardware/gpio.h>
|
||||
#include <hardware/sync.h>
|
||||
#include <hardware/structs/ioqspi.h>
|
||||
#include <hardware/structs/sio.h>
|
||||
|
||||
// This example blinks the Pico LED when the BOOTSEL button is pressed.
|
||||
//
|
||||
@@ -26,7 +26,9 @@ static bool __no_inline_not_in_flash_func(get_bootsel_button)() {
|
||||
|
||||
// Must disable interrupts, as interrupt handlers may be in flash, and we
|
||||
// are about to temporarily disable flash access!
|
||||
noInterrupts();
|
||||
if (!__isFreeRTOS) {
|
||||
noInterrupts();
|
||||
}
|
||||
rp2040.idleOtherCore();
|
||||
|
||||
// Set chip select to Hi-Z
|
||||
@@ -39,7 +41,12 @@ static bool __no_inline_not_in_flash_func(get_bootsel_button)() {
|
||||
|
||||
// The HI GPIO registers in SIO can observe and control the 6 QSPI pins.
|
||||
// Note the button pulls the pin *low* when pressed.
|
||||
bool button_state = !(sio_hw->gpio_hi_in & (1u << CS_PIN_INDEX));
|
||||
#if PICO_RP2040
|
||||
#define CS_BIT (1u << 1)
|
||||
#else
|
||||
#define CS_BIT SIO_GPIO_HI_IN_QSPI_CSN_BITS
|
||||
#endif
|
||||
bool button_state = !(sio_hw->gpio_hi_in & CS_BIT);
|
||||
|
||||
// Need to restore the state of chip select, else we are going to have a
|
||||
// bad time when we return to code in flash!
|
||||
@@ -48,7 +55,9 @@ static bool __no_inline_not_in_flash_func(get_bootsel_button)() {
|
||||
IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS);
|
||||
|
||||
rp2040.resumeOtherCore();
|
||||
interrupts();
|
||||
if (!__isFreeRTOS) {
|
||||
interrupts();
|
||||
}
|
||||
|
||||
return button_state;
|
||||
}
|
||||
|
||||
@@ -28,14 +28,18 @@ CoreMutex::CoreMutex(mutex_t *mutex, uint8_t option) {
|
||||
_mutex = mutex;
|
||||
_acquired = false;
|
||||
_option = option;
|
||||
_pxHigherPriorityTaskWoken = 0; // pdFALSE
|
||||
if (__isFreeRTOS) {
|
||||
auto m = __get_freertos_mutex_for_ptr(mutex);
|
||||
if (_option & FromISR) {
|
||||
__freertos_mutex_take_from_isr(m);
|
||||
} else {
|
||||
if (!__freertos_mutex_try_take(m)) {
|
||||
|
||||
if (__freertos_check_if_in_isr()) {
|
||||
if (!__freertos_mutex_take_from_isr(m, &_pxHigherPriorityTaskWoken)) {
|
||||
return;
|
||||
}
|
||||
// At this point we have the mutex in ISR
|
||||
} else {
|
||||
// Grab the mutex normally, possibly waking other tasks to get it
|
||||
__freertos_mutex_take(m);
|
||||
}
|
||||
} else {
|
||||
uint32_t owner;
|
||||
@@ -56,8 +60,8 @@ CoreMutex::~CoreMutex() {
|
||||
if (_acquired) {
|
||||
if (__isFreeRTOS) {
|
||||
auto m = __get_freertos_mutex_for_ptr(_mutex);
|
||||
if (_option & FromISR) {
|
||||
__freertos_mutex_give_from_isr(m);
|
||||
if (__freertos_check_if_in_isr()) {
|
||||
__freertos_mutex_give_from_isr(m, &_pxHigherPriorityTaskWoken);
|
||||
} else {
|
||||
__freertos_mutex_give(m);
|
||||
}
|
||||
|
||||
@@ -23,12 +23,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pico/mutex.h"
|
||||
#include <pico/mutex.h>
|
||||
#include "_freertos.h"
|
||||
|
||||
enum {
|
||||
DebugEnable = 1,
|
||||
FromISR = 1 << 1,
|
||||
DebugEnable = 1
|
||||
};
|
||||
|
||||
class CoreMutex {
|
||||
@@ -44,4 +43,5 @@ private:
|
||||
mutex_t *_mutex;
|
||||
bool _acquired;
|
||||
uint8_t _option;
|
||||
BaseType_t _pxHigherPriorityTaskWoken;
|
||||
};
|
||||
|
||||
+26
-7
@@ -225,6 +225,21 @@ void File::setTimeCallback(time_t (*cb)(void)) {
|
||||
_timeCallback = cb;
|
||||
}
|
||||
|
||||
bool File::stat(FSStat *st) {
|
||||
if (!_p) {
|
||||
return false;
|
||||
}
|
||||
size_t pos = position();
|
||||
seek(0, SeekEnd);
|
||||
st->size = position() - pos;
|
||||
seek(pos, SeekSet);
|
||||
st->blocksize = 0; // Not set here
|
||||
st->ctime = getCreationTime();
|
||||
st->atime = getLastWrite();
|
||||
st->isDir = isDirectory();
|
||||
return true;
|
||||
}
|
||||
|
||||
File Dir::openFile(const char* mode) {
|
||||
if (!_impl) {
|
||||
return File();
|
||||
@@ -366,13 +381,6 @@ bool FS::info(FSInfo& info) {
|
||||
return _impl->info(info);
|
||||
}
|
||||
|
||||
bool FS::info64(FSInfo64& info) {
|
||||
if (!_impl) {
|
||||
return false;
|
||||
}
|
||||
return _impl->info64(info);
|
||||
}
|
||||
|
||||
File FS::open(const String& path, const char* mode) {
|
||||
return open(path.c_str(), mode);
|
||||
}
|
||||
@@ -462,6 +470,17 @@ bool FS::rename(const String& pathFrom, const String& pathTo) {
|
||||
return rename(pathFrom.c_str(), pathTo.c_str());
|
||||
}
|
||||
|
||||
bool FS::stat(const char *path, FSStat *st) {
|
||||
if (!_impl) {
|
||||
return false;
|
||||
}
|
||||
return _impl->stat(path, st);
|
||||
}
|
||||
|
||||
bool FS::stat(const String& path, FSStat *st) {
|
||||
return stat(path.c_str(), st);
|
||||
}
|
||||
|
||||
time_t FS::getCreationTime() {
|
||||
if (!_impl) {
|
||||
return 0;
|
||||
|
||||
+14
-13
@@ -48,6 +48,14 @@ enum SeekMode {
|
||||
SeekEnd = 2
|
||||
};
|
||||
|
||||
struct FSStat {
|
||||
size_t size;
|
||||
size_t blocksize;
|
||||
time_t ctime;
|
||||
time_t atime;
|
||||
bool isDir;
|
||||
};
|
||||
|
||||
class File : public Stream {
|
||||
public:
|
||||
File(FileImplPtr p = FileImplPtr(), FS *baseFS = nullptr) : _p(p), _fakeDir(nullptr), _baseFS(baseFS) {
|
||||
@@ -119,6 +127,8 @@ public:
|
||||
time_t getCreationTime();
|
||||
void setTimeCallback(time_t (*cb)(void));
|
||||
|
||||
bool stat(FSStat *st);
|
||||
|
||||
protected:
|
||||
FileImplPtr _p;
|
||||
time_t (*_timeCallback)(void) = nullptr;
|
||||
@@ -152,18 +162,8 @@ protected:
|
||||
time_t (*_timeCallback)(void) = nullptr;
|
||||
};
|
||||
|
||||
// Backwards compatible, <4GB filesystem usage
|
||||
struct FSInfo {
|
||||
size_t totalBytes;
|
||||
size_t usedBytes;
|
||||
size_t blockSize;
|
||||
size_t pageSize;
|
||||
size_t maxOpenFiles;
|
||||
size_t maxPathLength;
|
||||
};
|
||||
|
||||
// Support > 4GB filesystems (SD, etc.)
|
||||
struct FSInfo64 {
|
||||
struct FSInfo {
|
||||
uint64_t totalBytes;
|
||||
uint64_t usedBytes;
|
||||
size_t blockSize;
|
||||
@@ -172,7 +172,6 @@ struct FSInfo64 {
|
||||
size_t maxPathLength;
|
||||
};
|
||||
|
||||
|
||||
class FSConfig {
|
||||
public:
|
||||
static constexpr uint32_t FSId = 0x00000000;
|
||||
@@ -201,7 +200,6 @@ public:
|
||||
|
||||
bool format();
|
||||
bool info(FSInfo& info);
|
||||
bool info64(FSInfo64& info);
|
||||
|
||||
File open(const char* path, const char* mode);
|
||||
File open(const String& path, const char* mode);
|
||||
@@ -224,6 +222,9 @@ public:
|
||||
bool rmdir(const char* path);
|
||||
bool rmdir(const String& path);
|
||||
|
||||
bool stat(const char *path, FSStat *st);
|
||||
bool stat(const String& path, FSStat *st);
|
||||
|
||||
// Low-level FS routines, not needed by most applications
|
||||
bool gc();
|
||||
bool check();
|
||||
|
||||
@@ -119,7 +119,6 @@ public:
|
||||
virtual void end() = 0;
|
||||
virtual bool format() = 0;
|
||||
virtual bool info(FSInfo& info) = 0;
|
||||
virtual bool info64(FSInfo64& info) = 0;
|
||||
virtual FileImplPtr open(const char* path, OpenMode openMode, AccessMode accessMode) = 0;
|
||||
virtual bool exists(const char* path) = 0;
|
||||
virtual DirImplPtr openDir(const char* path) = 0;
|
||||
@@ -127,6 +126,7 @@ public:
|
||||
virtual bool remove(const char* path) = 0;
|
||||
virtual bool mkdir(const char* path) = 0;
|
||||
virtual bool rmdir(const char* path) = 0;
|
||||
virtual bool stat(const char *path, FSStat *st) = 0;
|
||||
virtual bool gc() {
|
||||
return true; // May not be implemented in all file systems.
|
||||
}
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
RP2040 PIO utility class
|
||||
|
||||
Copyright (c) 2023 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 "PIOProgram.h"
|
||||
#include <map>
|
||||
#include <hardware/claim.h>
|
||||
|
||||
#if defined(PICO_RP2350)
|
||||
#define PIOS pio0, pio1, pio2
|
||||
#define PIOCNT 3
|
||||
#elif defined(PICO_RP2040)
|
||||
#define PIOS pio0, pio1
|
||||
#define PIOCNT 2
|
||||
#endif
|
||||
|
||||
static std::map<const pio_program_t *, int> __pioMap[PIOCNT];
|
||||
static bool __pioAllocated[PIOCNT];
|
||||
static bool __pioHighGPIO[PIOCNT];
|
||||
auto_init_mutex(_pioMutex);
|
||||
|
||||
PIOProgram::PIOProgram(const pio_program_t *pgm) {
|
||||
_pgm = pgm;
|
||||
_pio = nullptr;
|
||||
_sm = -1;
|
||||
}
|
||||
|
||||
// We leave the INSN loaded in INSN RAM
|
||||
PIOProgram::~PIOProgram() {
|
||||
if (_pio) {
|
||||
pio_sm_unclaim(_pio, _sm);
|
||||
}
|
||||
}
|
||||
|
||||
// Possibly load into a PIO and allocate a SM
|
||||
bool PIOProgram::prepare(PIO *pio, int *sm, int *offset, int start, int cnt) {
|
||||
CoreMutex m(&_pioMutex);
|
||||
PIO pi[PIOCNT] = { PIOS };
|
||||
|
||||
#if 0
|
||||
uint usm;
|
||||
uint uoff;
|
||||
auto ret = pio_claim_free_sm_and_add_program_for_gpio_range(_pgm, pio, &usm, &uoff, start, cnt, true);
|
||||
*sm = usm;
|
||||
*offset = uoff;
|
||||
DEBUGV("clain %d\n", ret);
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
bool needsHigh = (start + cnt) >= 32;
|
||||
DEBUGV("PIOProgram %p: Searching for high=%d, pins %d-%d\n", _pgm, needsHigh ? 1 : 0, start, start + cnt - 1);
|
||||
|
||||
// If it's already loaded into PIO IRAM, try and allocate in that specific PIO
|
||||
for (int o = 0; o < PIOCNT; o++) {
|
||||
auto p = __pioMap[o].find(_pgm);
|
||||
if ((p != __pioMap[o].end()) && (__pioHighGPIO[o] == needsHigh)) {
|
||||
int idx = pio_claim_unused_sm(pi[o], false);
|
||||
if (idx >= 0) {
|
||||
DEBUGV("PIOProgram %p: Reusing IMEM ON PIO %p(high=%d) for pins %d-%d\n", _pgm, pi[o], __pioHighGPIO[o] ? 1 : 0, start, start + cnt - 1);
|
||||
_pio = pi[o];
|
||||
_sm = idx;
|
||||
*pio = pi[o];
|
||||
*sm = idx;
|
||||
*offset = p->second;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Not in any PIO IRAM, so try and add
|
||||
for (int o = 0; o < PIOCNT; o++) {
|
||||
if (__pioAllocated[o] && (__pioHighGPIO[o] == needsHigh)) {
|
||||
DEBUGV("PIOProgram: Checking PIO %p\n", pi[o]);
|
||||
if (pio_can_add_program(pi[o], _pgm)) {
|
||||
int idx = pio_claim_unused_sm(pi[o], false);
|
||||
if (idx >= 0) {
|
||||
DEBUGV("PIOProgram %p: Adding IMEM ON PIO %p(high=%d) for pins %d-%d\n", _pgm, pi[o], __pioHighGPIO[o] ? 1 : 0, start, start + cnt - 1);
|
||||
int off = pio_add_program(pi[o], _pgm);
|
||||
__pioMap[o].insert({_pgm, off});
|
||||
_pio = pi[o];
|
||||
_sm = idx;
|
||||
*pio = pi[o];
|
||||
*sm = idx;
|
||||
*offset = off;
|
||||
return true;
|
||||
} else {
|
||||
DEBUGV("PIOProgram: can't claim unused SM\n");
|
||||
}
|
||||
} else {
|
||||
DEBUGV("PIOProgram: can't add program\n");
|
||||
}
|
||||
} else {
|
||||
DEBUGV("PIOProgram: Skipping PIO %p, wrong allocated/needhi\n", pi[o]);
|
||||
}
|
||||
}
|
||||
|
||||
// No existing PIOs can meet, is there an unallocated one we can allocate?
|
||||
PIO p;
|
||||
uint idx;
|
||||
uint off;
|
||||
auto rc = pio_claim_free_sm_and_add_program_for_gpio_range(_pgm, &p, &idx, &off, start, cnt, true);
|
||||
if (rc) {
|
||||
int o = 0;
|
||||
while (p != pi[o]) {
|
||||
o++;
|
||||
}
|
||||
assert(!__pioAllocated[o]);
|
||||
__pioAllocated[o] = true;
|
||||
__pioHighGPIO[o] = needsHigh;
|
||||
DEBUGV("PIOProgram %p: Allocating new PIO %p(high=%d) for pins %d-%d\n", _pgm, pi[o], __pioHighGPIO[o] ? 1 : 0, start, start + cnt - 1);
|
||||
__pioMap[o].insert({_pgm, off});
|
||||
_pio = pi[o];
|
||||
_sm = idx;
|
||||
*pio = pi[o];
|
||||
*sm = idx;
|
||||
*offset = off;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Nope, no room either for SMs or INSNs
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
RP2040 PIO utility class
|
||||
|
||||
Copyright (c) 2023 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 <hardware/pio.h>
|
||||
|
||||
// Wrapper class for PIO programs, abstracting common operations out
|
||||
class PIOProgram {
|
||||
public:
|
||||
PIOProgram(const pio_program_t *pgm);
|
||||
~PIOProgram();
|
||||
// Possibly load into a PIO and allocate a SM
|
||||
bool prepare(PIO *pio, int *sm, int *offset, int gpio_start = 0, int gpio_cnt = 1);
|
||||
|
||||
private:
|
||||
const pio_program_t *_pgm;
|
||||
PIO _pio;
|
||||
int _sm;
|
||||
};
|
||||
+183
-66
@@ -22,14 +22,22 @@
|
||||
#include <hardware/irq.h>
|
||||
#include <hardware/pio.h>
|
||||
#include <pico/unique_id.h>
|
||||
#ifdef PICO_RP2350
|
||||
#include <hardware/regs/powman.h>
|
||||
#else
|
||||
#include <hardware/regs/vreg_and_chip_reset.h>
|
||||
#endif
|
||||
#include <hardware/exception.h>
|
||||
#include <hardware/watchdog.h>
|
||||
#include <hardware/structs/rosc.h>
|
||||
#include <hardware/structs/systick.h>
|
||||
#include <pico/multicore.h>
|
||||
#include <hardware/dma.h>
|
||||
#include <pico/rand.h>
|
||||
#include <pico/util/queue.h>
|
||||
#include <pico/bootrom.h>
|
||||
#include "CoreMutex.h"
|
||||
#include "PIOProgram.h"
|
||||
#include "ccount.pio.h"
|
||||
#include <malloc.h>
|
||||
|
||||
@@ -57,8 +65,13 @@ public:
|
||||
void registerCore() {
|
||||
if (!__isFreeRTOS) {
|
||||
multicore_fifo_clear_irq();
|
||||
#ifdef PICO_RP2350
|
||||
irq_set_exclusive_handler(SIO_IRQ_FIFO, _irq);
|
||||
irq_set_enabled(SIO_IRQ_FIFO, true);
|
||||
#else
|
||||
irq_set_exclusive_handler(SIO_IRQ_PROC0 + get_core_num(), _irq);
|
||||
irq_set_enabled(SIO_IRQ_PROC0 + get_core_num(), true);
|
||||
#endif
|
||||
}
|
||||
// FreeRTOS port.c will handle the IRQ hooking
|
||||
}
|
||||
@@ -91,15 +104,14 @@ public:
|
||||
if (!_multicore) {
|
||||
return;
|
||||
}
|
||||
__holdUpPendSV = 1;
|
||||
if (__isFreeRTOS) {
|
||||
vTaskPreemptionDisable(nullptr);
|
||||
vTaskSuspendAll();
|
||||
__freertos_idle_other_core();
|
||||
} else {
|
||||
mutex_enter_blocking(&_idleMutex);
|
||||
__otherCoreIdled = false;
|
||||
multicore_fifo_push_blocking(_GOTOSLEEP);
|
||||
while (!__otherCoreIdled) { /* noop */ }
|
||||
}
|
||||
mutex_enter_blocking(&_idleMutex);
|
||||
__otherCoreIdled = false;
|
||||
multicore_fifo_push_blocking(_GOTOSLEEP);
|
||||
while (!__otherCoreIdled) { /* noop */ }
|
||||
}
|
||||
|
||||
void resumeOtherCore() {
|
||||
@@ -109,10 +121,8 @@ public:
|
||||
mutex_exit(&_idleMutex);
|
||||
__otherCoreIdled = false;
|
||||
if (__isFreeRTOS) {
|
||||
xTaskResumeAll();
|
||||
vTaskPreemptionEnable(nullptr);
|
||||
__freertos_resume_other_core();
|
||||
}
|
||||
__holdUpPendSV = 0;
|
||||
|
||||
// Other core will exit busy-loop and return to operation
|
||||
// once __otherCoreIdled == false.
|
||||
@@ -156,64 +166,12 @@ private:
|
||||
class RP2040;
|
||||
extern RP2040 rp2040;
|
||||
extern "C" void main1();
|
||||
class PIOProgram;
|
||||
|
||||
extern "C" char __StackLimit;
|
||||
extern "C" char __bss_end__;
|
||||
|
||||
// Wrapper class for PIO programs, abstracting common operations out
|
||||
// TODO - Add unload/destructor
|
||||
class PIOProgram {
|
||||
public:
|
||||
PIOProgram(const pio_program_t *pgm) {
|
||||
_pgm = pgm;
|
||||
}
|
||||
|
||||
// Possibly load into a PIO and allocate a SM
|
||||
bool prepare(PIO *pio, int *sm, int *offset) {
|
||||
extern mutex_t _pioMutex;
|
||||
CoreMutex m(&_pioMutex);
|
||||
// Is there an open slot to run in, first?
|
||||
if (!_findFreeSM(pio, sm)) {
|
||||
return false;
|
||||
}
|
||||
// Is it loaded on that PIO?
|
||||
if (_offset[pio_get_index(*pio)] < 0) {
|
||||
// Nope, need to load it
|
||||
if (!pio_can_add_program(*pio, _pgm)) {
|
||||
return false;
|
||||
}
|
||||
_offset[pio_get_index(*pio)] = pio_add_program(*pio, _pgm);
|
||||
}
|
||||
// Here it's guaranteed loaded, return values
|
||||
// PIO and SM already set
|
||||
*offset = _offset[pio_get_index(*pio)];
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
// Find an unused PIO state machine to grab, returns false when none available
|
||||
static bool _findFreeSM(PIO *pio, int *sm) {
|
||||
int idx = pio_claim_unused_sm(pio0, false);
|
||||
if (idx >= 0) {
|
||||
*pio = pio0;
|
||||
*sm = idx;
|
||||
return true;
|
||||
}
|
||||
idx = pio_claim_unused_sm(pio1, false);
|
||||
if (idx >= 0) {
|
||||
*pio = pio1;
|
||||
*sm = idx;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
int _offset[2] = { -1, -1 };
|
||||
const pio_program_t *_pgm;
|
||||
};
|
||||
extern "C" void setup1() __attribute__((weak));
|
||||
extern "C" void loop1() __attribute__((weak));
|
||||
extern "C" bool core1_separate_stack;
|
||||
extern "C" uint32_t* core1_separate_stack_address;
|
||||
|
||||
class RP2040 {
|
||||
public:
|
||||
@@ -222,18 +180,22 @@ public:
|
||||
|
||||
void begin() {
|
||||
_epoch = 0;
|
||||
#if !defined(__riscv)
|
||||
if (!__isFreeRTOS) {
|
||||
// Enable SYSTICK exception
|
||||
exception_set_exclusive_handler(SYSTICK_EXCEPTION, _SystickHandler);
|
||||
systick_hw->csr = 0x7;
|
||||
systick_hw->rvr = 0x00FFFFFF;
|
||||
} else {
|
||||
#endif
|
||||
int off = 0;
|
||||
_ccountPgm = new PIOProgram(&ccount_program);
|
||||
_ccountPgm->prepare(&_pio, &_sm, &off);
|
||||
ccount_program_init(_pio, _sm, off);
|
||||
pio_sm_set_enabled(_pio, _sm, true);
|
||||
#if !defined(__riscv)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Convert from microseconds to PIO clock cycles
|
||||
@@ -255,6 +217,7 @@ public:
|
||||
// Get CPU cycle count. Needs to do magic to extens 24b HW to something longer
|
||||
volatile uint64_t _epoch = 0;
|
||||
inline uint32_t getCycleCount() {
|
||||
#if !defined(__riscv)
|
||||
if (!__isFreeRTOS) {
|
||||
uint32_t epoch;
|
||||
uint32_t ctr;
|
||||
@@ -264,11 +227,15 @@ public:
|
||||
} while (epoch != (uint32_t)_epoch);
|
||||
return epoch + (1 << 24) - ctr; /* CTR counts down from 1<<24-1 */
|
||||
} else {
|
||||
#endif
|
||||
return ccount_read(_pio, _sm);
|
||||
#if !defined(__riscv)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
inline uint64_t getCycleCount64() {
|
||||
#if !defined(__riscv)
|
||||
if (!__isFreeRTOS) {
|
||||
uint64_t epoch;
|
||||
uint64_t ctr;
|
||||
@@ -278,8 +245,11 @@ public:
|
||||
} while (epoch != _epoch);
|
||||
return epoch + (1LL << 24) - ctr;
|
||||
} else {
|
||||
#endif
|
||||
return ccount_read(_pio, _sm);
|
||||
#if !defined(__riscv)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int getFreeHeap() {
|
||||
@@ -295,6 +265,60 @@ public:
|
||||
return &__StackLimit - &__bss_end__;
|
||||
}
|
||||
|
||||
inline int getFreePSRAMHeap() {
|
||||
return getTotalPSRAMHeap() - getUsedPSRAMHeap();
|
||||
}
|
||||
|
||||
inline int getUsedPSRAMHeap() {
|
||||
#if defined(RP2350_PSRAM_CS)
|
||||
extern size_t __psram_total_used();
|
||||
return __psram_total_used();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int getTotalPSRAMHeap() {
|
||||
#if defined(RP2350_PSRAM_CS)
|
||||
extern size_t __psram_total_space();
|
||||
return __psram_total_space();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline uint32_t getStackPointer() {
|
||||
uint32_t *sp;
|
||||
#if defined(__riscv)
|
||||
asm volatile("mv %0, sp" : "=r"(sp));
|
||||
#else
|
||||
asm volatile("mov %0, sp" : "=r"(sp));
|
||||
#endif
|
||||
return (uint32_t)sp;
|
||||
}
|
||||
|
||||
inline int getFreeStack() {
|
||||
const unsigned int sp = getStackPointer();
|
||||
uint32_t ref = 0x20040000;
|
||||
if (setup1 || loop1) {
|
||||
if (core1_separate_stack) {
|
||||
ref = cpuid() ? (unsigned int)core1_separate_stack_address : 0x20040000;
|
||||
} else {
|
||||
ref = cpuid() ? 0x20040000 : 0x20041000;
|
||||
}
|
||||
}
|
||||
return sp - ref;
|
||||
}
|
||||
|
||||
inline size_t getPSRAMSize() {
|
||||
#if defined(RP2350_PSRAM_CS)
|
||||
extern size_t __psram_size;
|
||||
return __psram_size;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void idleOtherCore() {
|
||||
fifo.idleOtherCore();
|
||||
}
|
||||
@@ -320,6 +344,13 @@ public:
|
||||
reboot();
|
||||
}
|
||||
|
||||
inline void rebootToBootloader() {
|
||||
reset_usb_boot(0, 0);
|
||||
while (1) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
static void enableDoubleResetBootloader();
|
||||
|
||||
void wdt_begin(uint32_t delay_ms) {
|
||||
@@ -330,6 +361,61 @@ public:
|
||||
watchdog_update();
|
||||
}
|
||||
|
||||
enum resetReason_t {UNKNOWN_RESET, PWRON_RESET, RUN_PIN_RESET, SOFT_RESET, WDT_RESET, DEBUG_RESET, GLITCH_RESET, BROWNOUT_RESET};
|
||||
|
||||
resetReason_t getResetReason(void) {
|
||||
io_rw_32 *WD_reason_reg = (io_rw_32 *)(WATCHDOG_BASE + WATCHDOG_REASON_OFFSET);
|
||||
|
||||
if (watchdog_caused_reboot() && watchdog_enable_caused_reboot()) { // watchdog timer
|
||||
return WDT_RESET;
|
||||
}
|
||||
|
||||
if (*WD_reason_reg & WATCHDOG_REASON_TIMER_BITS) { // soft reset() or reboot()
|
||||
return SOFT_RESET;
|
||||
}
|
||||
|
||||
#ifdef PICO_RP2350
|
||||
// **** RP2350 is untested ****
|
||||
io_rw_32 *rrp = (io_rw_32 *)(POWMAN_BASE + POWMAN_CHIP_RESET_OFFSET);
|
||||
|
||||
if (*rrp & POWMAN_CHIP_RESET_HAD_POR_BITS) { // POR: power-on reset (brownout is separately detected on RP2350)
|
||||
return PWRON_RESET;
|
||||
}
|
||||
|
||||
if (*rrp & POWMAN_CHIP_RESET_HAD_RUN_LOW_BITS) { // RUN pin
|
||||
return RUN_PIN_RESET;
|
||||
}
|
||||
|
||||
if ((*rrp & POWMAN_CHIP_RESET_HAD_DP_RESET_REQ_BITS) || (*rrp & POWMAN_CHIP_RESET_HAD_RESCUE_BITS) || (*rrp & POWMAN_CHIP_RESET_HAD_HZD_SYS_RESET_REQ_BITS)) { // DEBUG port
|
||||
return DEBUG_RESET;
|
||||
}
|
||||
|
||||
if (*rrp & POWMAN_CHIP_RESET_HAD_GLITCH_DETECT_BITS) { // power supply glitch
|
||||
return GLITCH_RESET;
|
||||
}
|
||||
|
||||
if (*rrp & POWMAN_CHIP_RESET_HAD_BOR_BITS) { // power supply brownout reset
|
||||
return BROWNOUT_RESET;
|
||||
}
|
||||
|
||||
#else
|
||||
io_rw_32 *rrp = (io_rw_32 *)(VREG_AND_CHIP_RESET_BASE + VREG_AND_CHIP_RESET_CHIP_RESET_OFFSET);
|
||||
|
||||
if (*rrp & VREG_AND_CHIP_RESET_CHIP_RESET_HAD_POR_BITS) { // POR: power-on reset or brown-out detection
|
||||
return PWRON_RESET;
|
||||
}
|
||||
|
||||
if (*rrp & VREG_AND_CHIP_RESET_CHIP_RESET_HAD_RUN_BITS) { // RUN pin
|
||||
return RUN_PIN_RESET;
|
||||
}
|
||||
|
||||
if (*rrp & VREG_AND_CHIP_RESET_CHIP_RESET_HAD_PSM_RESTART_BITS) { // DEBUG port
|
||||
return DEBUG_RESET; // **** untested **** debug reset may just cause a rebootToBootloader()
|
||||
}
|
||||
#endif
|
||||
return UNKNOWN_RESET;
|
||||
}
|
||||
|
||||
const char *getChipID() {
|
||||
static char id[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1] = { 0 };
|
||||
if (!id[0]) {
|
||||
@@ -338,6 +424,36 @@ public:
|
||||
return id;
|
||||
}
|
||||
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("Os")
|
||||
void *memcpyDMA(void *dest, const void *src, size_t n) {
|
||||
// Allocate a DMA channel on 1st call, reuse it every call after
|
||||
if (memcpyDMAChannel < 1) {
|
||||
memcpyDMAChannel = dma_claim_unused_channel(true);
|
||||
dma_channel_config c = dma_channel_get_default_config(memcpyDMAChannel);
|
||||
channel_config_set_transfer_data_size(&c, DMA_SIZE_32);
|
||||
channel_config_set_read_increment(&c, true);
|
||||
channel_config_set_write_increment(&c, true);
|
||||
channel_config_set_irq_quiet(&c, true);
|
||||
dma_channel_set_config(memcpyDMAChannel, &c, false);
|
||||
}
|
||||
// If there's any misalignment or too small, use regular memcpy which can handle it
|
||||
if ((n < 64) || (((uint32_t)dest) | ((uint32_t)src) | n) & 3) {
|
||||
return memcpy(dest, src, n);
|
||||
}
|
||||
|
||||
int words = n / 4;
|
||||
dma_channel_set_read_addr(memcpyDMAChannel, src, false);
|
||||
dma_channel_set_write_addr(memcpyDMAChannel, dest, false);
|
||||
dma_channel_set_trans_count(memcpyDMAChannel, words, false);
|
||||
dma_channel_start(memcpyDMAChannel);
|
||||
while (dma_channel_is_busy(memcpyDMAChannel)) {
|
||||
/* busy wait dma */
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
#pragma GCC pop_options
|
||||
|
||||
// Multicore comms FIFO
|
||||
_MFIFO fifo;
|
||||
|
||||
@@ -363,4 +479,5 @@ private:
|
||||
PIO _pio;
|
||||
int _sm;
|
||||
PIOProgram *_ccountPgm;
|
||||
int memcpyDMAChannel = -1;
|
||||
};
|
||||
|
||||
+79
-15
@@ -25,18 +25,17 @@
|
||||
#include "CoreMutex.h"
|
||||
#include "RP2040USB.h"
|
||||
|
||||
#include "tusb.h"
|
||||
#include "class/hid/hid_device.h"
|
||||
#include "class/audio/audio.h"
|
||||
#include "class/midi/midi.h"
|
||||
#include "pico/time.h"
|
||||
#include "hardware/irq.h"
|
||||
#include "pico/mutex.h"
|
||||
#include "pico/unique_id.h"
|
||||
#include "pico/usb_reset_interface.h"
|
||||
#include "hardware/watchdog.h"
|
||||
#include "pico/bootrom.h"
|
||||
#include "sdkoverride/tusb_absmouse.h"
|
||||
#include <tusb.h>
|
||||
#include <class/hid/hid_device.h>
|
||||
#include <class/audio/audio.h>
|
||||
#include <pico/time.h>
|
||||
#include <hardware/irq.h>
|
||||
#include <pico/mutex.h>
|
||||
#include <pico/unique_id.h>
|
||||
#include <pico/usb_reset_interface.h>
|
||||
#include <hardware/watchdog.h>
|
||||
#include <pico/bootrom.h>
|
||||
#include "sdkoverride/tusb_gamepad16.h"
|
||||
#include <device/usbd_pvt.h>
|
||||
|
||||
// Big, global USB mutex, shared with all USB devices to make sure we don't
|
||||
@@ -84,6 +83,8 @@ static int __usb_task_irq;
|
||||
9, TUSB_DESC_INTERFACE, _itfnum, 0, 0, TUSB_CLASS_VENDOR_SPECIFIC, RESET_INTERFACE_SUBCLASS, RESET_INTERFACE_PROTOCOL, _stridx,
|
||||
|
||||
|
||||
int usb_hid_poll_interval __attribute__((weak)) = 10;
|
||||
|
||||
const uint8_t *tud_descriptor_device_cb(void) {
|
||||
static tusb_desc_device_t usbd_desc_device = {
|
||||
.bLength = sizeof(tusb_desc_device_t),
|
||||
@@ -158,7 +159,7 @@ void __SetupDescHIDReport() {
|
||||
//allocate memory for the HID report descriptors. We don't use them, but need the size here.
|
||||
uint8_t desc_hid_report_mouse[] = { TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(1)) };
|
||||
uint8_t desc_hid_report_absmouse[] = { TUD_HID_REPORT_DESC_ABSMOUSE(HID_REPORT_ID(1)) };
|
||||
uint8_t desc_hid_report_joystick[] = { TUD_HID_REPORT_DESC_GAMEPAD(HID_REPORT_ID(1)) };
|
||||
uint8_t desc_hid_report_joystick[] = { TUD_HID_REPORT_DESC_GAMEPAD16(HID_REPORT_ID(1)) };
|
||||
uint8_t desc_hid_report_keyboard[] = { TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(1)), TUD_HID_REPORT_DESC_CONSUMER(HID_REPORT_ID(2)) };
|
||||
int size = 0;
|
||||
|
||||
@@ -228,7 +229,7 @@ void __SetupDescHIDReport() {
|
||||
reportid++;
|
||||
offset += sizeof(desc_hid_report_absmouse);
|
||||
}
|
||||
uint8_t desc_local[] = { TUD_HID_REPORT_DESC_GAMEPAD(HID_REPORT_ID(reportid)) };
|
||||
uint8_t desc_local[] = { TUD_HID_REPORT_DESC_GAMEPAD16(HID_REPORT_ID(reportid)) };
|
||||
memcpy(__hid_report + offset, desc_local, sizeof(desc_local));
|
||||
}
|
||||
}
|
||||
@@ -264,7 +265,7 @@ void __SetupUSBDescriptor() {
|
||||
uint8_t hid_itf = __USBInstallSerial ? 2 : 0;
|
||||
uint8_t hid_desc[TUD_HID_DESC_LEN] = {
|
||||
// Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval
|
||||
TUD_HID_DESCRIPTOR(hid_itf, 0, HID_ITF_PROTOCOL_NONE, hid_report_len, EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 10)
|
||||
TUD_HID_DESCRIPTOR(hid_itf, 0, HID_ITF_PROTOCOL_NONE, hid_report_len, EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, (uint8_t)usb_hid_poll_interval)
|
||||
};
|
||||
|
||||
uint8_t msd_itf = interface_count - 1;
|
||||
@@ -395,6 +396,18 @@ void __USBStart() {
|
||||
}
|
||||
|
||||
|
||||
bool __USBHIDReady() {
|
||||
uint32_t start = millis();
|
||||
const uint32_t timeout = 500;
|
||||
|
||||
while (((millis() - start) < timeout) && tud_ready() && !tud_hid_ready()) {
|
||||
tud_task();
|
||||
delayMicroseconds(1);
|
||||
}
|
||||
return tud_hid_ready();
|
||||
}
|
||||
|
||||
|
||||
// Invoked when received GET_REPORT control request
|
||||
// Application must fill buffer report's content and return its length.
|
||||
// Return zero will cause the stack to STALL request
|
||||
@@ -550,6 +563,57 @@ usbd_class_driver_t const *usbd_app_driver_get_cb(uint8_t *driver_count) {
|
||||
*driver_count = 1;
|
||||
return &_resetd_driver;
|
||||
}
|
||||
|
||||
#elif defined NO_USB
|
||||
|
||||
#warning "NO_USB selected. No output to Serial will occur!"
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
void SerialUSB::begin(unsigned long baud) {
|
||||
}
|
||||
|
||||
void SerialUSB::end() {
|
||||
|
||||
}
|
||||
|
||||
int SerialUSB::peek() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SerialUSB::read() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int SerialUSB::available() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SerialUSB::availableForWrite() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SerialUSB::flush() {
|
||||
|
||||
}
|
||||
|
||||
size_t SerialUSB::write(uint8_t c) {
|
||||
(void) c;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t SerialUSB::write(const uint8_t *buf, size_t length) {
|
||||
(void) buf;
|
||||
(void) length;
|
||||
return 0;
|
||||
}
|
||||
|
||||
SerialUSB::operator bool() {
|
||||
return false;
|
||||
}
|
||||
|
||||
SerialUSB Serial;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "pico/mutex.h"
|
||||
#include <pico/mutex.h>
|
||||
|
||||
// Weak function definitions for each type of endpoint
|
||||
extern void __USBInstallSerial() __attribute__((weak));
|
||||
@@ -45,3 +45,6 @@ int __USBGetJoystickReportID();
|
||||
|
||||
// Called by main() to init the USB HW/SW.
|
||||
void __USBStart();
|
||||
|
||||
// Helper class for HID report sending with wait and timeout
|
||||
bool __USBHIDReady();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#define ARDUINO_PICO_MAJOR 3
|
||||
#define ARDUINO_PICO_MAJOR 4
|
||||
#define ARDUINO_PICO_MINOR 2
|
||||
#define ARDUINO_PICO_REVISION 0
|
||||
#define ARDUINO_PICO_VERSION_STR "3.2.0"
|
||||
#define ARDUINO_PICO_VERSION_STR "4.2.0"
|
||||
|
||||
@@ -33,6 +33,7 @@ static std::map<int, PIOProgram*> _rxMap;
|
||||
// Duplicate a program and replace the first insn with a "set x, repl"
|
||||
static pio_program_t *pio_make_uart_prog(int repl, const pio_program_t *pg) {
|
||||
pio_program_t *p = new pio_program_t;
|
||||
memcpy(p, pg, sizeof(*p));
|
||||
p->length = pg->length;
|
||||
p->origin = pg->origin;
|
||||
uint16_t *insn = (uint16_t *)malloc(p->length * 2);
|
||||
@@ -78,9 +79,9 @@ static int _parity(int bits, int data) {
|
||||
|
||||
// We need to cache generated SerialPIOs so we can add data to them from
|
||||
// the shared handler
|
||||
static SerialPIO *_pioSP[2][4];
|
||||
static SerialPIO *_pioSP[3][4];
|
||||
static void __not_in_flash_func(_fifoIRQ)() {
|
||||
for (int p = 0; p < 2; p++) {
|
||||
for (int p = 0; p < 3; p++) {
|
||||
for (int sm = 0; sm < 4; sm++) {
|
||||
SerialPIO *s = _pioSP[p][sm];
|
||||
if (s) {
|
||||
@@ -138,6 +139,8 @@ SerialPIO::SerialPIO(pin_size_t tx, pin_size_t rx, size_t fifoSize) {
|
||||
_fifoSize = fifoSize + 1; // Always one unused entry
|
||||
_queue = new uint8_t[_fifoSize];
|
||||
mutex_init(&_mutex);
|
||||
_invertTX = false;
|
||||
_invertRX = false;
|
||||
}
|
||||
|
||||
SerialPIO::~SerialPIO() {
|
||||
@@ -145,6 +148,21 @@ SerialPIO::~SerialPIO() {
|
||||
delete[] _queue;
|
||||
}
|
||||
|
||||
static int pio_irq_0(PIO p) {
|
||||
switch (pio_get_index(p)) {
|
||||
case 0:
|
||||
return PIO0_IRQ_0;
|
||||
case 1:
|
||||
return PIO1_IRQ_0;
|
||||
#if defined(PICO_RP2350)
|
||||
case 2:
|
||||
return PIO2_IRQ_0;
|
||||
#endif
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void SerialPIO::begin(unsigned long baud, uint16_t config) {
|
||||
_overflow = false;
|
||||
_baud = baud;
|
||||
@@ -191,7 +209,7 @@ void SerialPIO::begin(unsigned long baud, uint16_t config) {
|
||||
_txBits = _bits + _stop + (_parity != UART_PARITY_NONE ? 1 : 0) + 1/*start bit*/;
|
||||
_txPgm = _getTxProgram(_txBits);
|
||||
int off;
|
||||
if (!_txPgm->prepare(&_txPIO, &_txSM, &off)) {
|
||||
if (!_txPgm->prepare(&_txPIO, &_txSM, &off, _tx, 1)) {
|
||||
DEBUGCORE("ERROR: Unable to allocate PIO TX UART, out of PIO resources\n");
|
||||
// ERROR, no free slots
|
||||
return;
|
||||
@@ -209,6 +227,7 @@ void SerialPIO::begin(unsigned long baud, uint16_t config) {
|
||||
pio_sm_exec(_txPIO, _txSM, pio_encode_mov(pio_isr, pio_osr));
|
||||
|
||||
// Start running!
|
||||
gpio_set_outover(_tx, _invertTX);
|
||||
pio_sm_set_enabled(_txPIO, _txSM, true);
|
||||
}
|
||||
if (_rx != NOPIN) {
|
||||
@@ -218,7 +237,7 @@ void SerialPIO::begin(unsigned long baud, uint16_t config) {
|
||||
_rxBits = 2 * (_bits + _stop + (_parity != UART_PARITY_NONE ? 1 : 0) + 1) - 1;
|
||||
_rxPgm = _getRxProgram(_rxBits);
|
||||
int off;
|
||||
if (!_rxPgm->prepare(&_rxPIO, &_rxSM, &off)) {
|
||||
if (!_rxPgm->prepare(&_rxPIO, &_rxSM, &off, _rx, 1)) {
|
||||
DEBUGCORE("ERROR: Unable to allocate PIO RX UART, out of PIO resources\n");
|
||||
return;
|
||||
}
|
||||
@@ -243,10 +262,11 @@ void SerialPIO::begin(unsigned long baud, uint16_t config) {
|
||||
case 2: pio_set_irq0_source_enabled(_rxPIO, pis_sm2_rx_fifo_not_empty, true); break;
|
||||
case 3: pio_set_irq0_source_enabled(_rxPIO, pis_sm3_rx_fifo_not_empty, true); break;
|
||||
}
|
||||
auto irqno = pio_get_index(_rxPIO) == 0 ? PIO0_IRQ_0 : PIO1_IRQ_0;
|
||||
auto irqno = pio_irq_0(_rxPIO);
|
||||
irq_set_exclusive_handler(irqno, _fifoIRQ);
|
||||
irq_set_enabled(irqno, true);
|
||||
|
||||
gpio_set_inover(_rx, _invertRX);
|
||||
pio_sm_set_enabled(_rxPIO, _rxSM, true);
|
||||
}
|
||||
|
||||
@@ -260,6 +280,7 @@ void SerialPIO::end() {
|
||||
if (_tx != NOPIN) {
|
||||
pio_sm_set_enabled(_txPIO, _txSM, false);
|
||||
pio_sm_unclaim(_txPIO, _txSM);
|
||||
gpio_set_outover(_tx, 0);
|
||||
}
|
||||
if (_rx != NOPIN) {
|
||||
pio_sm_set_enabled(_rxPIO, _rxSM, false);
|
||||
@@ -272,9 +293,10 @@ void SerialPIO::end() {
|
||||
used = used || !!_pioSP[pioNum][i];
|
||||
}
|
||||
if (!used) {
|
||||
auto irqno = pioNum == 0 ? PIO0_IRQ_0 : PIO1_IRQ_0;
|
||||
auto irqno = pio_irq_0(_rxPIO);
|
||||
irq_set_enabled(irqno, false);
|
||||
}
|
||||
gpio_set_inover(_rx, 0);
|
||||
}
|
||||
_running = false;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,23 @@ public:
|
||||
void begin(unsigned long baud, uint16_t config) override;
|
||||
void end() override;
|
||||
|
||||
void setInverted(bool invTx = true, bool invRx = true) {
|
||||
setInvertTX(invTx);
|
||||
setInvertRX(invRx);
|
||||
}
|
||||
bool setInvertTX(bool invert = true) {
|
||||
if (!_running) {
|
||||
_invertTX = invert;
|
||||
}
|
||||
return !_running;
|
||||
}
|
||||
bool setInvertRX(bool invert = true) {
|
||||
if (!_running) {
|
||||
_invertRX = invert;
|
||||
}
|
||||
return !_running;
|
||||
}
|
||||
|
||||
virtual int peek() override;
|
||||
virtual int read() override;
|
||||
virtual int available() override;
|
||||
@@ -51,7 +68,7 @@ public:
|
||||
using Print::write;
|
||||
operator bool() override;
|
||||
|
||||
// Not to be called by users, only from the IRQ handler. In public so that the C-language IQR callback can access it
|
||||
// Not to be called by users, only from the IRQ handler. In public so that the C-language IRQ callback can access it
|
||||
void _handleIRQ();
|
||||
|
||||
protected:
|
||||
@@ -63,6 +80,8 @@ protected:
|
||||
int _stop;
|
||||
bool _overflow;
|
||||
mutex_t _mutex;
|
||||
bool _invertTX;
|
||||
bool _invertRX;
|
||||
|
||||
PIOProgram *_txPgm;
|
||||
PIO _txPIO;
|
||||
|
||||
@@ -32,14 +32,24 @@ extern void serialEvent1() __attribute__((weak));
|
||||
extern void serialEvent2() __attribute__((weak));
|
||||
|
||||
bool SerialUART::setRX(pin_size_t pin) {
|
||||
constexpr uint32_t valid[2] = { __bitset({1, 13, 17, 29}) /* UART0 */,
|
||||
#ifdef PICO_RP2350B
|
||||
constexpr uint64_t valid[2] = { __bitset({1, 13, 17, 29, 33, 45}) /* UART0 */,
|
||||
__bitset({5, 9, 21, 25, 37, 41}) /* UART1 */
|
||||
};
|
||||
#else
|
||||
constexpr uint64_t valid[2] = { __bitset({1, 13, 17, 29}) /* UART0 */,
|
||||
__bitset({5, 9, 21, 25}) /* UART1 */
|
||||
};
|
||||
if ((!_running) && ((1 << pin) & valid[uart_get_index(_uart)])) {
|
||||
#endif
|
||||
if ((!_running) && ((1LL << pin) & valid[uart_get_index(_uart)])) {
|
||||
_rx = pin;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_rx == pin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_running) {
|
||||
panic("FATAL: Attempting to set Serial%d.RX while running", uart_get_index(_uart) + 1);
|
||||
} else {
|
||||
@@ -49,14 +59,24 @@ bool SerialUART::setRX(pin_size_t pin) {
|
||||
}
|
||||
|
||||
bool SerialUART::setTX(pin_size_t pin) {
|
||||
constexpr uint32_t valid[2] = { __bitset({0, 12, 16, 28}) /* UART0 */,
|
||||
#ifdef PICO_RP2350B
|
||||
constexpr uint64_t valid[2] = { __bitset({0, 12, 16, 28, 32, 44}) /* UART0 */,
|
||||
__bitset({4, 8, 20, 24, 36, 40}) /* UART1 */
|
||||
};
|
||||
#else
|
||||
constexpr uint64_t valid[2] = { __bitset({0, 12, 16, 28}) /* UART0 */,
|
||||
__bitset({4, 8, 20, 24}) /* UART1 */
|
||||
};
|
||||
if ((!_running) && ((1 << pin) & valid[uart_get_index(_uart)])) {
|
||||
#endif
|
||||
if ((!_running) && ((1LL << pin) & valid[uart_get_index(_uart)])) {
|
||||
_tx = pin;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_tx == pin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_running) {
|
||||
panic("FATAL: Attempting to set Serial%d.TX while running", uart_get_index(_uart) + 1);
|
||||
} else {
|
||||
@@ -66,14 +86,24 @@ bool SerialUART::setTX(pin_size_t pin) {
|
||||
}
|
||||
|
||||
bool SerialUART::setRTS(pin_size_t pin) {
|
||||
constexpr uint32_t valid[2] = { __bitset({3, 15, 19}) /* UART0 */,
|
||||
#ifdef PICO_RP2350B
|
||||
constexpr uint64_t valid[2] = { __bitset({3, 15, 19, 31, 35, 47}) /* UART0 */,
|
||||
__bitset({7, 11, 23, 27, 39, 43}) /* UART1 */
|
||||
};
|
||||
#else
|
||||
constexpr uint64_t valid[2] = { __bitset({3, 15, 19}) /* UART0 */,
|
||||
__bitset({7, 11, 23, 27}) /* UART1 */
|
||||
};
|
||||
if ((!_running) && ((pin == UART_PIN_NOT_DEFINED) || ((1 << pin) & valid[uart_get_index(_uart)]))) {
|
||||
#endif
|
||||
if ((!_running) && ((pin == UART_PIN_NOT_DEFINED) || ((1LL << pin) & valid[uart_get_index(_uart)]))) {
|
||||
_rts = pin;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_rts == pin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_running) {
|
||||
panic("FATAL: Attempting to set Serial%d.RTS while running", uart_get_index(_uart) + 1);
|
||||
} else {
|
||||
@@ -83,14 +113,24 @@ bool SerialUART::setRTS(pin_size_t pin) {
|
||||
}
|
||||
|
||||
bool SerialUART::setCTS(pin_size_t pin) {
|
||||
constexpr uint32_t valid[2] = { __bitset({2, 14, 18}) /* UART0 */,
|
||||
#ifdef PICO_RP2350B
|
||||
constexpr uint64_t valid[2] = { __bitset({2, 14, 18, 30, 34, 46}) /* UART0 */,
|
||||
__bitset({6, 10, 22, 26, 38, 42}) /* UART1 */
|
||||
};
|
||||
#else
|
||||
constexpr uint64_t valid[2] = { __bitset({2, 14, 18}) /* UART0 */,
|
||||
__bitset({6, 10, 22, 26}) /* UART1 */
|
||||
};
|
||||
if ((!_running) && ((pin == UART_PIN_NOT_DEFINED) || ((1 << pin) & valid[uart_get_index(_uart)]))) {
|
||||
#endif
|
||||
if ((!_running) && ((pin == UART_PIN_NOT_DEFINED) || ((1LL << pin) & valid[uart_get_index(_uart)]))) {
|
||||
_cts = pin;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_cts == pin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_running) {
|
||||
panic("FATAL: Attempting to set Serial%d.CTS while running", uart_get_index(_uart) + 1);
|
||||
} else {
|
||||
@@ -122,6 +162,9 @@ SerialUART::SerialUART(uart_inst_t *uart, pin_size_t tx, pin_size_t rx, pin_size
|
||||
_cts = cts;
|
||||
mutex_init(&_mutex);
|
||||
mutex_init(&_fifoMutex);
|
||||
_invertTX = false;
|
||||
_invertRX = false;
|
||||
_invertControl = false;
|
||||
}
|
||||
|
||||
static void _uart0IRQ();
|
||||
@@ -138,14 +181,18 @@ void SerialUART::begin(unsigned long baud, uint16_t config) {
|
||||
_fcnTx = gpio_get_function(_tx);
|
||||
_fcnRx = gpio_get_function(_rx);
|
||||
gpio_set_function(_tx, GPIO_FUNC_UART);
|
||||
gpio_set_outover(_tx, _invertTX ? 1 : 0);
|
||||
gpio_set_function(_rx, GPIO_FUNC_UART);
|
||||
gpio_set_inover(_rx, _invertRX ? 1 : 0);
|
||||
if (_rts != UART_PIN_NOT_DEFINED) {
|
||||
_fcnRts = gpio_get_function(_rts);
|
||||
gpio_set_function(_rts, GPIO_FUNC_UART);
|
||||
gpio_set_outover(_rts, _invertControl ? 1 : 0);
|
||||
}
|
||||
if (_cts != UART_PIN_NOT_DEFINED) {
|
||||
_fcnCts = gpio_get_function(_cts);
|
||||
gpio_set_function(_cts, GPIO_FUNC_UART);
|
||||
gpio_set_inover(_cts, _invertControl ? 1 : 0);
|
||||
}
|
||||
|
||||
uart_init(_uart, baud);
|
||||
@@ -185,7 +232,7 @@ void SerialUART::begin(unsigned long baud, uint16_t config) {
|
||||
break;
|
||||
}
|
||||
uart_set_format(_uart, bits, stop, parity);
|
||||
uart_set_hw_flow(_uart, _rts != UART_PIN_NOT_DEFINED, _cts != UART_PIN_NOT_DEFINED);
|
||||
uart_set_hw_flow(_uart, _cts != UART_PIN_NOT_DEFINED, _rts != UART_PIN_NOT_DEFINED);
|
||||
_writer = 0;
|
||||
_reader = 0;
|
||||
|
||||
@@ -230,12 +277,16 @@ void SerialUART::end() {
|
||||
|
||||
// Restore pin functions
|
||||
gpio_set_function(_tx, _fcnTx);
|
||||
gpio_set_outover(_tx, 0);
|
||||
gpio_set_function(_rx, _fcnRx);
|
||||
gpio_set_inover(_rx, 0);
|
||||
if (_rts != UART_PIN_NOT_DEFINED) {
|
||||
gpio_set_function(_rts, _fcnRts);
|
||||
gpio_set_outover(_rts, 0);
|
||||
}
|
||||
if (_cts != UART_PIN_NOT_DEFINED) {
|
||||
gpio_set_function(_cts, _fcnCts);
|
||||
gpio_set_inover(_cts, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,26 @@ public:
|
||||
ret &= setTX(tx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool setInvertTX(bool invert = true) {
|
||||
if (!_running) {
|
||||
_invertTX = invert;
|
||||
}
|
||||
return !_running;
|
||||
}
|
||||
bool setInvertRX(bool invert = true) {
|
||||
if (!_running) {
|
||||
_invertRX = invert;
|
||||
}
|
||||
return !_running;
|
||||
}
|
||||
bool setInvertControl(bool invert = true) {
|
||||
if (!_running) {
|
||||
_invertControl = invert;
|
||||
}
|
||||
return !_running;
|
||||
}
|
||||
|
||||
bool setFIFOSize(size_t size);
|
||||
bool setPollingMode(bool mode = true);
|
||||
|
||||
@@ -80,12 +100,13 @@ private:
|
||||
uart_inst_t *_uart;
|
||||
pin_size_t _tx, _rx;
|
||||
pin_size_t _rts, _cts;
|
||||
enum gpio_function _fcnTx, _fcnRx, _fcnRts, _fcnCts;
|
||||
gpio_function_t _fcnTx, _fcnRx, _fcnRts, _fcnCts;
|
||||
int _baud;
|
||||
mutex_t _mutex;
|
||||
bool _polling = false;
|
||||
bool _overflow;
|
||||
bool _break;
|
||||
bool _invertTX, _invertRX, _invertControl;
|
||||
|
||||
// Lockless, IRQ-handled circular queue
|
||||
uint32_t _writer;
|
||||
|
||||
+25
-13
@@ -25,15 +25,15 @@
|
||||
#include <Arduino.h>
|
||||
#include "CoreMutex.h"
|
||||
|
||||
#include "tusb.h"
|
||||
#include "pico/time.h"
|
||||
#include "pico/binary_info.h"
|
||||
#include "pico/bootrom.h"
|
||||
#include "hardware/irq.h"
|
||||
#include "pico/mutex.h"
|
||||
#include "hardware/watchdog.h"
|
||||
#include "pico/unique_id.h"
|
||||
#include "hardware/resets.h"
|
||||
#include <tusb.h>
|
||||
#include <pico/time.h>
|
||||
#include <pico/binary_info.h>
|
||||
#include <pico/bootrom.h>
|
||||
#include <hardware/irq.h>
|
||||
#include <pico/mutex.h>
|
||||
#include <hardware/watchdog.h>
|
||||
#include <pico/unique_id.h>
|
||||
#include <hardware/resets.h>
|
||||
|
||||
#ifndef DISABLE_USB_SERIAL
|
||||
// Ensure we are installed in the USB chain
|
||||
@@ -130,7 +130,7 @@ size_t SerialUSB::write(const uint8_t *buf, size_t length) {
|
||||
|
||||
static uint64_t last_avail_time;
|
||||
int written = 0;
|
||||
if (tud_cdc_connected()) {
|
||||
if (tud_cdc_connected() || _ignoreFlowControl) {
|
||||
for (size_t i = 0; i < length;) {
|
||||
int n = length - i;
|
||||
int avail = tud_cdc_write_available();
|
||||
@@ -171,14 +171,19 @@ SerialUSB::operator bool() {
|
||||
return tud_cdc_connected();
|
||||
}
|
||||
|
||||
void SerialUSB::ignoreFlowControl(bool ignore) {
|
||||
_ignoreFlowControl = ignore;
|
||||
}
|
||||
|
||||
static bool _dtr = false;
|
||||
static bool _rts = false;
|
||||
static int _bps = 115200;
|
||||
static bool _rebooting = false;
|
||||
static void CheckSerialReset() {
|
||||
__holdUpPendSV = 1; // Ensure we don't get swapped out by FreeRTOS
|
||||
if (!_rebooting && (_bps == 1200) && (!_dtr)) {
|
||||
if (__isFreeRTOS) {
|
||||
__freertos_idle_other_core();
|
||||
}
|
||||
_rebooting = true;
|
||||
// Disable NVIC IRQ, so that we don't get bothered anymore
|
||||
irq_set_enabled(USBCTRL_IRQ, false);
|
||||
@@ -186,11 +191,18 @@ static void CheckSerialReset() {
|
||||
reset_block(RESETS_RESET_USBCTRL_BITS);
|
||||
unreset_block(RESETS_RESET_USBCTRL_BITS);
|
||||
// Delay a bit, so the PC can figure out that we have disconnected.
|
||||
sleep_ms(3);
|
||||
busy_wait_ms(3);
|
||||
reset_usb_boot(0, 0);
|
||||
while (1); // WDT will fire here
|
||||
}
|
||||
__holdUpPendSV = 0;
|
||||
}
|
||||
|
||||
bool SerialUSB::dtr() {
|
||||
return _dtr;
|
||||
}
|
||||
|
||||
bool SerialUSB::rts() {
|
||||
return _rts;
|
||||
}
|
||||
|
||||
extern "C" void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) {
|
||||
|
||||
@@ -43,6 +43,10 @@ public:
|
||||
virtual size_t write(const uint8_t *p, size_t len) override;
|
||||
using Print::write;
|
||||
operator bool() override;
|
||||
bool dtr();
|
||||
bool rts();
|
||||
|
||||
void ignoreFlowControl(bool ignore = true);
|
||||
|
||||
// ESP8266 compat
|
||||
void setDebugOutput(bool unused) {
|
||||
@@ -51,6 +55,7 @@ public:
|
||||
|
||||
private:
|
||||
bool _running = false;
|
||||
bool _ignoreFlowControl = false;
|
||||
};
|
||||
|
||||
extern SerialUSB Serial;
|
||||
|
||||
@@ -30,10 +30,6 @@ public:
|
||||
}
|
||||
|
||||
~SoftwareSerial() {
|
||||
if (_invert) {
|
||||
gpio_set_outover(_tx, 0);
|
||||
gpio_set_outover(_rx, 0);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void begin(unsigned long baud = 115200) override {
|
||||
@@ -41,11 +37,9 @@ public:
|
||||
};
|
||||
|
||||
void begin(unsigned long baud, uint16_t config) override {
|
||||
setInvertTX(_invert);
|
||||
setInvertRX(_invert);
|
||||
SerialPIO::begin(baud, config);
|
||||
if (_invert) {
|
||||
gpio_set_outover(_tx, GPIO_OVERRIDE_INVERT);
|
||||
gpio_set_inover(_rx, GPIO_OVERRIDE_INVERT);
|
||||
}
|
||||
}
|
||||
|
||||
void listen() { /* noop */ }
|
||||
|
||||
@@ -0,0 +1,474 @@
|
||||
|
||||
// autogenerated from https://raw.githubusercontent.com/nayarsystems/posix_tz_db/master/zones.csv
|
||||
// by script <rp2040 arduino core>/tools/tzupdate.sh
|
||||
// Sat 20 Jan 2024 08:54:45 PM UTC
|
||||
//
|
||||
// This database is autogenerated from IANA timezone database
|
||||
// https://raw.githubusercontent.com/nayarsystems/posix_tz_db/master/zones.csv
|
||||
// (using https://www.iana.org/time-zones)
|
||||
// and can be updated on demand in this repository
|
||||
// or by yourself using the above script
|
||||
|
||||
#pragma once
|
||||
|
||||
#define TZ_Africa_Abidjan ("GMT0")
|
||||
#define TZ_Africa_Accra ("GMT0")
|
||||
#define TZ_Africa_Addis_Ababa ("EAT-3")
|
||||
#define TZ_Africa_Algiers ("CET-1")
|
||||
#define TZ_Africa_Asmara ("EAT-3")
|
||||
#define TZ_Africa_Bamako ("GMT0")
|
||||
#define TZ_Africa_Bangui ("WAT-1")
|
||||
#define TZ_Africa_Banjul ("GMT0")
|
||||
#define TZ_Africa_Bissau ("GMT0")
|
||||
#define TZ_Africa_Blantyre ("CAT-2")
|
||||
#define TZ_Africa_Brazzaville ("WAT-1")
|
||||
#define TZ_Africa_Bujumbura ("CAT-2")
|
||||
#define TZ_Africa_Cairo ("EET-2EEST,M4.5.5/0,M10.5.4/24")
|
||||
#define TZ_Africa_Casablanca ("<+01>-1")
|
||||
#define TZ_Africa_Ceuta ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Africa_Conakry ("GMT0")
|
||||
#define TZ_Africa_Dakar ("GMT0")
|
||||
#define TZ_Africa_Dar_es_Salaam ("EAT-3")
|
||||
#define TZ_Africa_Djibouti ("EAT-3")
|
||||
#define TZ_Africa_Douala ("WAT-1")
|
||||
#define TZ_Africa_El_Aaiun ("<+01>-1")
|
||||
#define TZ_Africa_Freetown ("GMT0")
|
||||
#define TZ_Africa_Gaborone ("CAT-2")
|
||||
#define TZ_Africa_Harare ("CAT-2")
|
||||
#define TZ_Africa_Johannesburg ("SAST-2")
|
||||
#define TZ_Africa_Juba ("CAT-2")
|
||||
#define TZ_Africa_Kampala ("EAT-3")
|
||||
#define TZ_Africa_Khartoum ("CAT-2")
|
||||
#define TZ_Africa_Kigali ("CAT-2")
|
||||
#define TZ_Africa_Kinshasa ("WAT-1")
|
||||
#define TZ_Africa_Lagos ("WAT-1")
|
||||
#define TZ_Africa_Libreville ("WAT-1")
|
||||
#define TZ_Africa_Lome ("GMT0")
|
||||
#define TZ_Africa_Luanda ("WAT-1")
|
||||
#define TZ_Africa_Lubumbashi ("CAT-2")
|
||||
#define TZ_Africa_Lusaka ("CAT-2")
|
||||
#define TZ_Africa_Malabo ("WAT-1")
|
||||
#define TZ_Africa_Maputo ("CAT-2")
|
||||
#define TZ_Africa_Maseru ("SAST-2")
|
||||
#define TZ_Africa_Mbabane ("SAST-2")
|
||||
#define TZ_Africa_Mogadishu ("EAT-3")
|
||||
#define TZ_Africa_Monrovia ("GMT0")
|
||||
#define TZ_Africa_Nairobi ("EAT-3")
|
||||
#define TZ_Africa_Ndjamena ("WAT-1")
|
||||
#define TZ_Africa_Niamey ("WAT-1")
|
||||
#define TZ_Africa_Nouakchott ("GMT0")
|
||||
#define TZ_Africa_Ouagadougou ("GMT0")
|
||||
#define TZ_Africa_PortomNovo ("WAT-1")
|
||||
#define TZ_Africa_Sao_Tome ("GMT0")
|
||||
#define TZ_Africa_Tripoli ("EET-2")
|
||||
#define TZ_Africa_Tunis ("CET-1")
|
||||
#define TZ_Africa_Windhoek ("CAT-2")
|
||||
#define TZ_America_Adak ("HST10HDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Anchorage ("AKST9AKDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Anguilla ("AST4")
|
||||
#define TZ_America_Antigua ("AST4")
|
||||
#define TZ_America_Araguaina ("<-03>3")
|
||||
#define TZ_America_Argentina_Buenos_Aires ("<-03>3")
|
||||
#define TZ_America_Argentina_Catamarca ("<-03>3")
|
||||
#define TZ_America_Argentina_Cordoba ("<-03>3")
|
||||
#define TZ_America_Argentina_Jujuy ("<-03>3")
|
||||
#define TZ_America_Argentina_La_Rioja ("<-03>3")
|
||||
#define TZ_America_Argentina_Mendoza ("<-03>3")
|
||||
#define TZ_America_Argentina_Rio_Gallegos ("<-03>3")
|
||||
#define TZ_America_Argentina_Salta ("<-03>3")
|
||||
#define TZ_America_Argentina_San_Juan ("<-03>3")
|
||||
#define TZ_America_Argentina_San_Luis ("<-03>3")
|
||||
#define TZ_America_Argentina_Tucuman ("<-03>3")
|
||||
#define TZ_America_Argentina_Ushuaia ("<-03>3")
|
||||
#define TZ_America_Aruba ("AST4")
|
||||
#define TZ_America_Asuncion ("<-04>4<-03>,M10.1.0/0,M3.4.0/0")
|
||||
#define TZ_America_Atikokan ("EST5")
|
||||
#define TZ_America_Bahia ("<-03>3")
|
||||
#define TZ_America_Bahia_Banderas ("CST6")
|
||||
#define TZ_America_Barbados ("AST4")
|
||||
#define TZ_America_Belem ("<-03>3")
|
||||
#define TZ_America_Belize ("CST6")
|
||||
#define TZ_America_BlancmSablon ("AST4")
|
||||
#define TZ_America_Boa_Vista ("<-04>4")
|
||||
#define TZ_America_Bogota ("<-05>5")
|
||||
#define TZ_America_Boise ("MST7MDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Cambridge_Bay ("MST7MDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Campo_Grande ("<-04>4")
|
||||
#define TZ_America_Cancun ("EST5")
|
||||
#define TZ_America_Caracas ("<-04>4")
|
||||
#define TZ_America_Cayenne ("<-03>3")
|
||||
#define TZ_America_Cayman ("EST5")
|
||||
#define TZ_America_Chicago ("CST6CDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Chihuahua ("CST6")
|
||||
#define TZ_America_Costa_Rica ("CST6")
|
||||
#define TZ_America_Creston ("MST7")
|
||||
#define TZ_America_Cuiaba ("<-04>4")
|
||||
#define TZ_America_Curacao ("AST4")
|
||||
#define TZ_America_Danmarkshavn ("GMT0")
|
||||
#define TZ_America_Dawson ("MST7")
|
||||
#define TZ_America_Dawson_Creek ("MST7")
|
||||
#define TZ_America_Denver ("MST7MDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Detroit ("EST5EDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Dominica ("AST4")
|
||||
#define TZ_America_Edmonton ("MST7MDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Eirunepe ("<-05>5")
|
||||
#define TZ_America_El_Salvador ("CST6")
|
||||
#define TZ_America_Fortaleza ("<-03>3")
|
||||
#define TZ_America_Fort_Nelson ("MST7")
|
||||
#define TZ_America_Glace_Bay ("AST4ADT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Godthab ("<-02>2<-01>,M3.5.0/-1,M10.5.0/0")
|
||||
#define TZ_America_Goose_Bay ("AST4ADT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Grand_Turk ("EST5EDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Grenada ("AST4")
|
||||
#define TZ_America_Guadeloupe ("AST4")
|
||||
#define TZ_America_Guatemala ("CST6")
|
||||
#define TZ_America_Guayaquil ("<-05>5")
|
||||
#define TZ_America_Guyana ("<-04>4")
|
||||
#define TZ_America_Halifax ("AST4ADT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Havana ("CST5CDT,M3.2.0/0,M11.1.0/1")
|
||||
#define TZ_America_Hermosillo ("MST7")
|
||||
#define TZ_America_Indiana_Indianapolis ("EST5EDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Indiana_Knox ("CST6CDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Indiana_Marengo ("EST5EDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Indiana_Petersburg ("EST5EDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Indiana_Tell_City ("CST6CDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Indiana_Vevay ("EST5EDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Indiana_Vincennes ("EST5EDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Indiana_Winamac ("EST5EDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Inuvik ("MST7MDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Iqaluit ("EST5EDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Jamaica ("EST5")
|
||||
#define TZ_America_Juneau ("AKST9AKDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Kentucky_Louisville ("EST5EDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Kentucky_Monticello ("EST5EDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Kralendijk ("AST4")
|
||||
#define TZ_America_La_Paz ("<-04>4")
|
||||
#define TZ_America_Lima ("<-05>5")
|
||||
#define TZ_America_Los_Angeles ("PST8PDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Lower_Princes ("AST4")
|
||||
#define TZ_America_Maceio ("<-03>3")
|
||||
#define TZ_America_Managua ("CST6")
|
||||
#define TZ_America_Manaus ("<-04>4")
|
||||
#define TZ_America_Marigot ("AST4")
|
||||
#define TZ_America_Martinique ("AST4")
|
||||
#define TZ_America_Matamoros ("CST6CDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Mazatlan ("MST7")
|
||||
#define TZ_America_Menominee ("CST6CDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Merida ("CST6")
|
||||
#define TZ_America_Metlakatla ("AKST9AKDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Mexico_City ("CST6")
|
||||
#define TZ_America_Miquelon ("<-03>3<-02>,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Moncton ("AST4ADT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Monterrey ("CST6")
|
||||
#define TZ_America_Montevideo ("<-03>3")
|
||||
#define TZ_America_Montreal ("EST5EDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Montserrat ("AST4")
|
||||
#define TZ_America_Nassau ("EST5EDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_New_York ("EST5EDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Nipigon ("EST5EDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Nome ("AKST9AKDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Noronha ("<-02>2")
|
||||
#define TZ_America_North_Dakota_Beulah ("CST6CDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_North_Dakota_Center ("CST6CDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_North_Dakota_New_Salem ("CST6CDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Nuuk ("<-02>2<-01>,M3.5.0/-1,M10.5.0/0")
|
||||
#define TZ_America_Ojinaga ("CST6CDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Panama ("EST5")
|
||||
#define TZ_America_Pangnirtung ("EST5EDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Paramaribo ("<-03>3")
|
||||
#define TZ_America_Phoenix ("MST7")
|
||||
#define TZ_America_PortmaumPrince ("EST5EDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Port_of_Spain ("AST4")
|
||||
#define TZ_America_Porto_Velho ("<-04>4")
|
||||
#define TZ_America_Puerto_Rico ("AST4")
|
||||
#define TZ_America_Punta_Arenas ("<-03>3")
|
||||
#define TZ_America_Rainy_River ("CST6CDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Rankin_Inlet ("CST6CDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Recife ("<-03>3")
|
||||
#define TZ_America_Regina ("CST6")
|
||||
#define TZ_America_Resolute ("CST6CDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Rio_Branco ("<-05>5")
|
||||
#define TZ_America_Santarem ("<-03>3")
|
||||
#define TZ_America_Santiago ("<-04>4<-03>,M9.1.6/24,M4.1.6/24")
|
||||
#define TZ_America_Santo_Domingo ("AST4")
|
||||
#define TZ_America_Sao_Paulo ("<-03>3")
|
||||
#define TZ_America_Scoresbysund ("<-01>1<+00>,M3.5.0/0,M10.5.0/1")
|
||||
#define TZ_America_Sitka ("AKST9AKDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_St_Barthelemy ("AST4")
|
||||
#define TZ_America_St_Johns ("NST3:30NDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_St_Kitts ("AST4")
|
||||
#define TZ_America_St_Lucia ("AST4")
|
||||
#define TZ_America_St_Thomas ("AST4")
|
||||
#define TZ_America_St_Vincent ("AST4")
|
||||
#define TZ_America_Swift_Current ("CST6")
|
||||
#define TZ_America_Tegucigalpa ("CST6")
|
||||
#define TZ_America_Thule ("AST4ADT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Thunder_Bay ("EST5EDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Tijuana ("PST8PDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Toronto ("EST5EDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Tortola ("AST4")
|
||||
#define TZ_America_Vancouver ("PST8PDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Whitehorse ("MST7")
|
||||
#define TZ_America_Winnipeg ("CST6CDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Yakutat ("AKST9AKDT,M3.2.0,M11.1.0")
|
||||
#define TZ_America_Yellowknife ("MST7MDT,M3.2.0,M11.1.0")
|
||||
#define TZ_Antarctica_Casey ("<+11>-11")
|
||||
#define TZ_Antarctica_Davis ("<+07>-7")
|
||||
#define TZ_Antarctica_DumontDUrville ("<+10>-10")
|
||||
#define TZ_Antarctica_Macquarie ("AEST-10AEDT,M10.1.0,M4.1.0/3")
|
||||
#define TZ_Antarctica_Mawson ("<+05>-5")
|
||||
#define TZ_Antarctica_McMurdo ("NZST-12NZDT,M9.5.0,M4.1.0/3")
|
||||
#define TZ_Antarctica_Palmer ("<-03>3")
|
||||
#define TZ_Antarctica_Rothera ("<-03>3")
|
||||
#define TZ_Antarctica_Syowa ("<+03>-3")
|
||||
#define TZ_Antarctica_Troll ("<+00>0<+02>-2,M3.5.0/1,M10.5.0/3")
|
||||
#define TZ_Antarctica_Vostok ("<+06>-6")
|
||||
#define TZ_Arctic_Longyearbyen ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Asia_Aden ("<+03>-3")
|
||||
#define TZ_Asia_Almaty ("<+06>-6")
|
||||
#define TZ_Asia_Amman ("<+03>-3")
|
||||
#define TZ_Asia_Anadyr ("<+12>-12")
|
||||
#define TZ_Asia_Aqtau ("<+05>-5")
|
||||
#define TZ_Asia_Aqtobe ("<+05>-5")
|
||||
#define TZ_Asia_Ashgabat ("<+05>-5")
|
||||
#define TZ_Asia_Atyrau ("<+05>-5")
|
||||
#define TZ_Asia_Baghdad ("<+03>-3")
|
||||
#define TZ_Asia_Bahrain ("<+03>-3")
|
||||
#define TZ_Asia_Baku ("<+04>-4")
|
||||
#define TZ_Asia_Bangkok ("<+07>-7")
|
||||
#define TZ_Asia_Barnaul ("<+07>-7")
|
||||
#define TZ_Asia_Beirut ("EET-2EEST,M3.5.0/0,M10.5.0/0")
|
||||
#define TZ_Asia_Bishkek ("<+06>-6")
|
||||
#define TZ_Asia_Brunei ("<+08>-8")
|
||||
#define TZ_Asia_Chita ("<+09>-9")
|
||||
#define TZ_Asia_Choibalsan ("<+08>-8")
|
||||
#define TZ_Asia_Colombo ("<+0530>-5:30")
|
||||
#define TZ_Asia_Damascus ("<+03>-3")
|
||||
#define TZ_Asia_Dhaka ("<+06>-6")
|
||||
#define TZ_Asia_Dili ("<+09>-9")
|
||||
#define TZ_Asia_Dubai ("<+04>-4")
|
||||
#define TZ_Asia_Dushanbe ("<+05>-5")
|
||||
#define TZ_Asia_Famagusta ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
||||
#define TZ_Asia_Gaza ("EET-2EEST,M3.4.4/50,M10.4.4/50")
|
||||
#define TZ_Asia_Hebron ("EET-2EEST,M3.4.4/50,M10.4.4/50")
|
||||
#define TZ_Asia_Ho_Chi_Minh ("<+07>-7")
|
||||
#define TZ_Asia_Hong_Kong ("HKT-8")
|
||||
#define TZ_Asia_Hovd ("<+07>-7")
|
||||
#define TZ_Asia_Irkutsk ("<+08>-8")
|
||||
#define TZ_Asia_Jakarta ("WIB-7")
|
||||
#define TZ_Asia_Jayapura ("WIT-9")
|
||||
#define TZ_Asia_Jerusalem ("IST-2IDT,M3.4.4/26,M10.5.0")
|
||||
#define TZ_Asia_Kabul ("<+0430>-4:30")
|
||||
#define TZ_Asia_Kamchatka ("<+12>-12")
|
||||
#define TZ_Asia_Karachi ("PKT-5")
|
||||
#define TZ_Asia_Kathmandu ("<+0545>-5:45")
|
||||
#define TZ_Asia_Khandyga ("<+09>-9")
|
||||
#define TZ_Asia_Kolkata ("IST-5:30")
|
||||
#define TZ_Asia_Krasnoyarsk ("<+07>-7")
|
||||
#define TZ_Asia_Kuala_Lumpur ("<+08>-8")
|
||||
#define TZ_Asia_Kuching ("<+08>-8")
|
||||
#define TZ_Asia_Kuwait ("<+03>-3")
|
||||
#define TZ_Asia_Macau ("CST-8")
|
||||
#define TZ_Asia_Magadan ("<+11>-11")
|
||||
#define TZ_Asia_Makassar ("WITA-8")
|
||||
#define TZ_Asia_Manila ("PST-8")
|
||||
#define TZ_Asia_Muscat ("<+04>-4")
|
||||
#define TZ_Asia_Nicosia ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
||||
#define TZ_Asia_Novokuznetsk ("<+07>-7")
|
||||
#define TZ_Asia_Novosibirsk ("<+07>-7")
|
||||
#define TZ_Asia_Omsk ("<+06>-6")
|
||||
#define TZ_Asia_Oral ("<+05>-5")
|
||||
#define TZ_Asia_Phnom_Penh ("<+07>-7")
|
||||
#define TZ_Asia_Pontianak ("WIB-7")
|
||||
#define TZ_Asia_Pyongyang ("KST-9")
|
||||
#define TZ_Asia_Qatar ("<+03>-3")
|
||||
#define TZ_Asia_Qyzylorda ("<+05>-5")
|
||||
#define TZ_Asia_Riyadh ("<+03>-3")
|
||||
#define TZ_Asia_Sakhalin ("<+11>-11")
|
||||
#define TZ_Asia_Samarkand ("<+05>-5")
|
||||
#define TZ_Asia_Seoul ("KST-9")
|
||||
#define TZ_Asia_Shanghai ("CST-8")
|
||||
#define TZ_Asia_Singapore ("<+08>-8")
|
||||
#define TZ_Asia_Srednekolymsk ("<+11>-11")
|
||||
#define TZ_Asia_Taipei ("CST-8")
|
||||
#define TZ_Asia_Tashkent ("<+05>-5")
|
||||
#define TZ_Asia_Tbilisi ("<+04>-4")
|
||||
#define TZ_Asia_Tehran ("<+0330>-3:30")
|
||||
#define TZ_Asia_Thimphu ("<+06>-6")
|
||||
#define TZ_Asia_Tokyo ("JST-9")
|
||||
#define TZ_Asia_Tomsk ("<+07>-7")
|
||||
#define TZ_Asia_Ulaanbaatar ("<+08>-8")
|
||||
#define TZ_Asia_Urumqi ("<+06>-6")
|
||||
#define TZ_Asia_UstmNera ("<+10>-10")
|
||||
#define TZ_Asia_Vientiane ("<+07>-7")
|
||||
#define TZ_Asia_Vladivostok ("<+10>-10")
|
||||
#define TZ_Asia_Yakutsk ("<+09>-9")
|
||||
#define TZ_Asia_Yangon ("<+0630>-6:30")
|
||||
#define TZ_Asia_Yekaterinburg ("<+05>-5")
|
||||
#define TZ_Asia_Yerevan ("<+04>-4")
|
||||
#define TZ_Atlantic_Azores ("<-01>1<+00>,M3.5.0/0,M10.5.0/1")
|
||||
#define TZ_Atlantic_Bermuda ("AST4ADT,M3.2.0,M11.1.0")
|
||||
#define TZ_Atlantic_Canary ("WET0WEST,M3.5.0/1,M10.5.0")
|
||||
#define TZ_Atlantic_Cape_Verde ("<-01>1")
|
||||
#define TZ_Atlantic_Faroe ("WET0WEST,M3.5.0/1,M10.5.0")
|
||||
#define TZ_Atlantic_Madeira ("WET0WEST,M3.5.0/1,M10.5.0")
|
||||
#define TZ_Atlantic_Reykjavik ("GMT0")
|
||||
#define TZ_Atlantic_South_Georgia ("<-02>2")
|
||||
#define TZ_Atlantic_Stanley ("<-03>3")
|
||||
#define TZ_Atlantic_St_Helena ("GMT0")
|
||||
#define TZ_Australia_Adelaide ("ACST-9:30ACDT,M10.1.0,M4.1.0/3")
|
||||
#define TZ_Australia_Brisbane ("AEST-10")
|
||||
#define TZ_Australia_Broken_Hill ("ACST-9:30ACDT,M10.1.0,M4.1.0/3")
|
||||
#define TZ_Australia_Currie ("AEST-10AEDT,M10.1.0,M4.1.0/3")
|
||||
#define TZ_Australia_Darwin ("ACST-9:30")
|
||||
#define TZ_Australia_Eucla ("<+0845>-8:45")
|
||||
#define TZ_Australia_Hobart ("AEST-10AEDT,M10.1.0,M4.1.0/3")
|
||||
#define TZ_Australia_Lindeman ("AEST-10")
|
||||
#define TZ_Australia_Lord_Howe ("<+1030>-10:30<+11>-11,M10.1.0,M4.1.0")
|
||||
#define TZ_Australia_Melbourne ("AEST-10AEDT,M10.1.0,M4.1.0/3")
|
||||
#define TZ_Australia_Perth ("AWST-8")
|
||||
#define TZ_Australia_Sydney ("AEST-10AEDT,M10.1.0,M4.1.0/3")
|
||||
#define TZ_Europe_Amsterdam ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Europe_Andorra ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Europe_Astrakhan ("<+04>-4")
|
||||
#define TZ_Europe_Athens ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
||||
#define TZ_Europe_Belgrade ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Europe_Berlin ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Europe_Bratislava ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Europe_Brussels ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Europe_Bucharest ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
||||
#define TZ_Europe_Budapest ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Europe_Busingen ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Europe_Chisinau ("EET-2EEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Europe_Copenhagen ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Europe_Dublin ("IST-1GMT0,M10.5.0,M3.5.0/1")
|
||||
#define TZ_Europe_Gibraltar ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Europe_Guernsey ("GMT0BST,M3.5.0/1,M10.5.0")
|
||||
#define TZ_Europe_Helsinki ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
||||
#define TZ_Europe_Isle_of_Man ("GMT0BST,M3.5.0/1,M10.5.0")
|
||||
#define TZ_Europe_Istanbul ("<+03>-3")
|
||||
#define TZ_Europe_Jersey ("GMT0BST,M3.5.0/1,M10.5.0")
|
||||
#define TZ_Europe_Kaliningrad ("EET-2")
|
||||
#define TZ_Europe_Kiev ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
||||
#define TZ_Europe_Kirov ("MSK-3")
|
||||
#define TZ_Europe_Lisbon ("WET0WEST,M3.5.0/1,M10.5.0")
|
||||
#define TZ_Europe_Ljubljana ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Europe_London ("GMT0BST,M3.5.0/1,M10.5.0")
|
||||
#define TZ_Europe_Luxembourg ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Europe_Madrid ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Europe_Malta ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Europe_Mariehamn ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
||||
#define TZ_Europe_Minsk ("<+03>-3")
|
||||
#define TZ_Europe_Monaco ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Europe_Moscow ("MSK-3")
|
||||
#define TZ_Europe_Oslo ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Europe_Paris ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Europe_Podgorica ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Europe_Prague ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Europe_Riga ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
||||
#define TZ_Europe_Rome ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Europe_Samara ("<+04>-4")
|
||||
#define TZ_Europe_San_Marino ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Europe_Sarajevo ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Europe_Saratov ("<+04>-4")
|
||||
#define TZ_Europe_Simferopol ("MSK-3")
|
||||
#define TZ_Europe_Skopje ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Europe_Sofia ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
||||
#define TZ_Europe_Stockholm ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Europe_Tallinn ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
||||
#define TZ_Europe_Tirane ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Europe_Ulyanovsk ("<+04>-4")
|
||||
#define TZ_Europe_Uzhgorod ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
||||
#define TZ_Europe_Vaduz ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Europe_Vatican ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Europe_Vienna ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Europe_Vilnius ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
||||
#define TZ_Europe_Volgograd ("MSK-3")
|
||||
#define TZ_Europe_Warsaw ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Europe_Zagreb ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Europe_Zaporozhye ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
||||
#define TZ_Europe_Zurich ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||
#define TZ_Indian_Antananarivo ("EAT-3")
|
||||
#define TZ_Indian_Chagos ("<+06>-6")
|
||||
#define TZ_Indian_Christmas ("<+07>-7")
|
||||
#define TZ_Indian_Cocos ("<+0630>-6:30")
|
||||
#define TZ_Indian_Comoro ("EAT-3")
|
||||
#define TZ_Indian_Kerguelen ("<+05>-5")
|
||||
#define TZ_Indian_Mahe ("<+04>-4")
|
||||
#define TZ_Indian_Maldives ("<+05>-5")
|
||||
#define TZ_Indian_Mauritius ("<+04>-4")
|
||||
#define TZ_Indian_Mayotte ("EAT-3")
|
||||
#define TZ_Indian_Reunion ("<+04>-4")
|
||||
#define TZ_Pacific_Apia ("<+13>-13")
|
||||
#define TZ_Pacific_Auckland ("NZST-12NZDT,M9.5.0,M4.1.0/3")
|
||||
#define TZ_Pacific_Bougainville ("<+11>-11")
|
||||
#define TZ_Pacific_Chatham ("<+1245>-12:45<+1345>,M9.5.0/2:45,M4.1.0/3:45")
|
||||
#define TZ_Pacific_Chuuk ("<+10>-10")
|
||||
#define TZ_Pacific_Easter ("<-06>6<-05>,M9.1.6/22,M4.1.6/22")
|
||||
#define TZ_Pacific_Efate ("<+11>-11")
|
||||
#define TZ_Pacific_Enderbury ("<+13>-13")
|
||||
#define TZ_Pacific_Fakaofo ("<+13>-13")
|
||||
#define TZ_Pacific_Fiji ("<+12>-12")
|
||||
#define TZ_Pacific_Funafuti ("<+12>-12")
|
||||
#define TZ_Pacific_Galapagos ("<-06>6")
|
||||
#define TZ_Pacific_Gambier ("<-09>9")
|
||||
#define TZ_Pacific_Guadalcanal ("<+11>-11")
|
||||
#define TZ_Pacific_Guam ("ChST-10")
|
||||
#define TZ_Pacific_Honolulu ("HST10")
|
||||
#define TZ_Pacific_Kiritimati ("<+14>-14")
|
||||
#define TZ_Pacific_Kosrae ("<+11>-11")
|
||||
#define TZ_Pacific_Kwajalein ("<+12>-12")
|
||||
#define TZ_Pacific_Majuro ("<+12>-12")
|
||||
#define TZ_Pacific_Marquesas ("<-0930>9:30")
|
||||
#define TZ_Pacific_Midway ("SST11")
|
||||
#define TZ_Pacific_Nauru ("<+12>-12")
|
||||
#define TZ_Pacific_Niue ("<-11>11")
|
||||
#define TZ_Pacific_Norfolk ("<+11>-11<+12>,M10.1.0,M4.1.0/3")
|
||||
#define TZ_Pacific_Noumea ("<+11>-11")
|
||||
#define TZ_Pacific_Pago_Pago ("SST11")
|
||||
#define TZ_Pacific_Palau ("<+09>-9")
|
||||
#define TZ_Pacific_Pitcairn ("<-08>8")
|
||||
#define TZ_Pacific_Pohnpei ("<+11>-11")
|
||||
#define TZ_Pacific_Port_Moresby ("<+10>-10")
|
||||
#define TZ_Pacific_Rarotonga ("<-10>10")
|
||||
#define TZ_Pacific_Saipan ("ChST-10")
|
||||
#define TZ_Pacific_Tahiti ("<-10>10")
|
||||
#define TZ_Pacific_Tarawa ("<+12>-12")
|
||||
#define TZ_Pacific_Tongatapu ("<+13>-13")
|
||||
#define TZ_Pacific_Wake ("<+12>-12")
|
||||
#define TZ_Pacific_Wallis ("<+12>-12")
|
||||
#define TZ_Etc_GMT ("GMT0")
|
||||
#define TZ_Etc_GMTm0 ("GMT0")
|
||||
#define TZ_Etc_GMTm1 ("<+01>-1")
|
||||
#define TZ_Etc_GMTm2 ("<+02>-2")
|
||||
#define TZ_Etc_GMTm3 ("<+03>-3")
|
||||
#define TZ_Etc_GMTm4 ("<+04>-4")
|
||||
#define TZ_Etc_GMTm5 ("<+05>-5")
|
||||
#define TZ_Etc_GMTm6 ("<+06>-6")
|
||||
#define TZ_Etc_GMTm7 ("<+07>-7")
|
||||
#define TZ_Etc_GMTm8 ("<+08>-8")
|
||||
#define TZ_Etc_GMTm9 ("<+09>-9")
|
||||
#define TZ_Etc_GMTm10 ("<+10>-10")
|
||||
#define TZ_Etc_GMTm11 ("<+11>-11")
|
||||
#define TZ_Etc_GMTm12 ("<+12>-12")
|
||||
#define TZ_Etc_GMTm13 ("<+13>-13")
|
||||
#define TZ_Etc_GMTm14 ("<+14>-14")
|
||||
#define TZ_Etc_GMT0 ("GMT0")
|
||||
#define TZ_Etc_GMTp0 ("GMT0")
|
||||
#define TZ_Etc_GMTp1 ("<-01>1")
|
||||
#define TZ_Etc_GMTp2 ("<-02>2")
|
||||
#define TZ_Etc_GMTp3 ("<-03>3")
|
||||
#define TZ_Etc_GMTp4 ("<-04>4")
|
||||
#define TZ_Etc_GMTp5 ("<-05>5")
|
||||
#define TZ_Etc_GMTp6 ("<-06>6")
|
||||
#define TZ_Etc_GMTp7 ("<-07>7")
|
||||
#define TZ_Etc_GMTp8 ("<-08>8")
|
||||
#define TZ_Etc_GMTp9 ("<-09>9")
|
||||
#define TZ_Etc_GMTp10 ("<-10>10")
|
||||
#define TZ_Etc_GMTp11 ("<-11>11")
|
||||
#define TZ_Etc_GMTp12 ("<-12>12")
|
||||
#define TZ_Etc_UCT ("UTC0")
|
||||
#define TZ_Etc_UTC ("UTC0")
|
||||
#define TZ_Etc_Greenwich ("GMT0")
|
||||
#define TZ_Etc_Universal ("UTC0")
|
||||
#define TZ_Etc_Zulu ("UTC0")
|
||||
@@ -56,7 +56,7 @@ int64_t _stopTonePIO(alarm_id_t id, void *user_data) {
|
||||
}
|
||||
|
||||
void tone(uint8_t pin, unsigned int frequency, unsigned long duration) {
|
||||
if (pin > 29) {
|
||||
if (pin >= __GPIOCNT) {
|
||||
DEBUGCORE("ERROR: Illegal pin in tone (%d)\n", pin);
|
||||
return;
|
||||
}
|
||||
@@ -81,7 +81,7 @@ void tone(uint8_t pin, unsigned int frequency, unsigned long duration) {
|
||||
newTone = new Tone();
|
||||
newTone->pin = pin;
|
||||
pinMode(pin, OUTPUT);
|
||||
if (!_tone2Pgm.prepare(&newTone->pio, &newTone->sm, &newTone->off)) {
|
||||
if (!_tone2Pgm.prepare(&newTone->pio, &newTone->sm, &newTone->off, pin, 1)) {
|
||||
DEBUGCORE("ERROR: tone unable to start, out of PIO resources\n");
|
||||
// ERROR, no free slots
|
||||
delete newTone;
|
||||
@@ -100,6 +100,8 @@ void tone(uint8_t pin, unsigned int frequency, unsigned long duration) {
|
||||
}
|
||||
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_exec(newTone->pio, newTone->sm, pio_encode_pull(false, false));
|
||||
pio_sm_exec(newTone->pio, newTone->sm, pio_encode_mov(pio_x, pio_osr));
|
||||
pio_sm_set_enabled(newTone->pio, newTone->sm, true);
|
||||
|
||||
_toneMap.insert({pin, newTone});
|
||||
@@ -118,7 +120,7 @@ void tone(uint8_t pin, unsigned int frequency, unsigned long duration) {
|
||||
void noTone(uint8_t pin) {
|
||||
CoreMutex m(&_toneMutex);
|
||||
|
||||
if ((pin > 29) || !m) {
|
||||
if ((pin > __GPIOCNT) || !m) {
|
||||
DEBUGCORE("ERROR: Illegal pin in tone (%d)\n", pin);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "stdlib.h"
|
||||
#include "stdint.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void randomSeed(uint32_t dwSeed) {
|
||||
if (dwSeed != 0) {
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
*/
|
||||
|
||||
#include "_freertos.h"
|
||||
#include "pico/mutex.h"
|
||||
#include <pico/mutex.h>
|
||||
#include <stdlib.h>
|
||||
#include "Arduino.h"
|
||||
|
||||
@@ -31,7 +31,7 @@ typedef struct {
|
||||
static FMMap *_map = nullptr;
|
||||
SemaphoreHandle_t __get_freertos_mutex_for_ptr(mutex_t *m, bool recursive) {
|
||||
if (!_map) {
|
||||
_map = (FMMap *)calloc(sizeof(FMMap), 16);
|
||||
_map = (FMMap *)calloc(16, sizeof(FMMap));
|
||||
}
|
||||
// Pre-existing map
|
||||
for (int i = 0; i < 16; i++) {
|
||||
@@ -60,45 +60,3 @@ SemaphoreHandle_t __get_freertos_mutex_for_ptr(mutex_t *m, bool recursive) {
|
||||
}
|
||||
return nullptr; // Need to make space for more mutex maps!
|
||||
}
|
||||
|
||||
|
||||
// The HW Random code needs a precise sleep_until() in order to assure it
|
||||
// grabs the ROSC bit when it wants. Unfortunately, under FreeRTOS the
|
||||
// sleep_until() becomes imprecise and the "did I get the bit when I wanted"
|
||||
// check in the pico_rand code always fails and you get an infinite loop.
|
||||
|
||||
// This block wraps the 2 get_rand calls to set a flag to convert
|
||||
// sleep_until() (which can do a task swap and cause bad timing) into a
|
||||
// busy wait.
|
||||
|
||||
extern "C" {
|
||||
static bool __inRand = false;
|
||||
|
||||
extern uint64_t __real_get_rand_64();
|
||||
uint64_t __wrap_get_rand_64() {
|
||||
if (__isFreeRTOS) {
|
||||
rp2040.idleOtherCore();
|
||||
__inRand = true;
|
||||
auto r = __real_get_rand_64();
|
||||
__inRand = false;
|
||||
rp2040.resumeOtherCore();
|
||||
return r;
|
||||
} else {
|
||||
return __real_get_rand_64();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t __wrap_get_rand_32() {
|
||||
return (uint32_t) __wrap_get_rand_64();
|
||||
}
|
||||
|
||||
extern void __real_sleep_until(absolute_time_t t);
|
||||
void __wrap_sleep_until(absolute_time_t t) {
|
||||
if (__inRand) {
|
||||
busy_wait_until(t);
|
||||
} else {
|
||||
__real_sleep_until(t);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+11
-16
@@ -19,7 +19,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "pico/mutex.h"
|
||||
#include <pico/mutex.h>
|
||||
|
||||
// Cannot include refs to FreeRTOS's actual semaphore calls because they
|
||||
// are implemented as macros, so we have a wrapper in our variant hook
|
||||
@@ -31,36 +31,31 @@ extern bool __isFreeRTOS;
|
||||
extern volatile bool __freeRTOSinitted;
|
||||
|
||||
extern "C" {
|
||||
#ifndef INC_FREERTOS_H
|
||||
struct QueueDefinition; /* Using old naming convention so as not to break kernel aware debuggers. */
|
||||
typedef struct QueueDefinition * QueueHandle_t;
|
||||
typedef QueueHandle_t SemaphoreHandle_t;
|
||||
#endif
|
||||
typedef int32_t BaseType_t;
|
||||
|
||||
extern bool __freertos_check_if_in_isr() __attribute__((weak));
|
||||
|
||||
extern SemaphoreHandle_t __freertos_mutex_create() __attribute__((weak));
|
||||
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_take_from_isr(SemaphoreHandle_t mtx, BaseType_t* pxHigherPriorityTaskWoken) __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_mutex_give_from_isr(SemaphoreHandle_t mtx, BaseType_t* pxHigherPriorityTaskWoken) __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));
|
||||
extern void __freertos_recursive_mutex_give(SemaphoreHandle_t mtx) __attribute__((weak));
|
||||
|
||||
#ifndef INC_FREERTOS_H
|
||||
extern void vTaskSuspendAll() __attribute__((weak));
|
||||
extern int32_t xTaskResumeAll() __attribute__((weak));
|
||||
|
||||
typedef struct tskTaskControlBlock * TaskHandle_t;
|
||||
extern void vTaskPreemptionDisable(TaskHandle_t p) __attribute__((weak));
|
||||
extern void vTaskPreemptionEnable(TaskHandle_t p) __attribute__((weak));
|
||||
#endif
|
||||
extern void __freertos_idle_other_core() __attribute__((weak));
|
||||
extern void __freertos_resume_other_core() __attribute__((weak));
|
||||
|
||||
extern void __freertos_task_exit_critical() __attribute__((weak));
|
||||
extern void __freertos_task_enter_critical() __attribute__((weak));
|
||||
}
|
||||
extern SemaphoreHandle_t __get_freertos_mutex_for_ptr(mutex_t *m, bool recursive = false);
|
||||
|
||||
// Halt the FreeRTOS PendSV task switching magic
|
||||
extern "C" int __holdUpPendSV;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,6 +14,7 @@
|
||||
|
||||
#define ccount_wrap_target 0
|
||||
#define ccount_wrap 1
|
||||
#define ccount_pio_version 0
|
||||
|
||||
static const uint16_t ccount_program_instructions[] = {
|
||||
// .wrap_target
|
||||
@@ -27,6 +28,10 @@ static const struct pio_program ccount_program = {
|
||||
.instructions = ccount_program_instructions,
|
||||
.length = 2,
|
||||
.origin = -1,
|
||||
.pio_version = 0,
|
||||
#if PICO_PIO_VERSION > 0
|
||||
.used_gpio_ranges = 0x0
|
||||
#endif
|
||||
};
|
||||
|
||||
static inline pio_sm_config ccount_program_get_default_config(uint offset) {
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
// Use to create a callback thunk from C to C++
|
||||
// #define CCALLBACKNAME to a unique per-file name and #include this file
|
||||
// To make a CB use a define of the form:
|
||||
/*
|
||||
#define PACKETHANDLERCB(class, cbFcn) \
|
||||
(CCALLBACKNAME<void(uint8_t, uint16_t, uint8_t*, uint16_t), __COUNTER__>::func = std::bind(&class::cbFcn, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4), \
|
||||
static_cast<btstack_packet_handler_t>(<CCALLBACKNAMEvoid(uint8_t, uint16_t, uint8_t*, uint16_t), __COUNTER__ - 1>::callback))
|
||||
*/
|
||||
|
||||
#include <functional>
|
||||
|
||||
// Thank you to https://stackoverflow.com/questions/66474621/multiple-non-static-callbacks-of-c-member-functions for the following beautiful hack
|
||||
|
||||
#ifndef CCALLBACKNAME
|
||||
#define CCALLBACKNAME _CCallback
|
||||
#endif
|
||||
|
||||
template <typename T, int tag>
|
||||
struct CCALLBACKNAME;
|
||||
|
||||
template <typename Ret, typename... Params, int tag>
|
||||
struct CCALLBACKNAME<Ret(Params...), tag> {
|
||||
template <typename... Args>
|
||||
static Ret callback(Args... args) {
|
||||
return func(args...);
|
||||
}
|
||||
int _tag = tag;
|
||||
static std::function<Ret(Params...)> func;
|
||||
};
|
||||
|
||||
template <typename Ret, typename... Params, int tag>
|
||||
std::function<Ret(Params...)> CCALLBACKNAME<Ret(Params...), tag>::func;
|
||||
@@ -19,12 +19,12 @@
|
||||
|
||||
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
|
||||
|
||||
#include "lwip/netif.h"
|
||||
#include <lwip/netif.h>
|
||||
extern "C" {
|
||||
#include "cyw43.h"
|
||||
#include "cyw43_stats.h"
|
||||
#include <cyw43.h>
|
||||
#include <cyw43_stats.h>
|
||||
}
|
||||
#include "pico/cyw43_arch.h"
|
||||
#include <pico/cyw43_arch.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
// From cyw43_ctrl.c
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
Flash wrappers to protect PSRAM access on the RP2350
|
||||
|
||||
Copyright (c) 2024 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 <hardware/flash.h>
|
||||
|
||||
#ifdef PICO_RP2350
|
||||
#include <hardware/structs/qmi.h>
|
||||
#endif
|
||||
|
||||
#if defined(PICO_RP2350) && defined(RP2350_PSRAM_CS)
|
||||
static void __no_inline_not_in_flash_func(flushcache)() {
|
||||
// From https://forums.raspberrypi.com/viewtopic.php?t=378249#p2263677
|
||||
// Perform clean-by-set/way on all lines
|
||||
for (uint32_t i = 0; i < 2048; ++i) {
|
||||
// Use the upper 16k of the maintenance space (0x1bffc000 through 0x1bffffff):
|
||||
*(volatile uint8_t*)(XIP_SRAM_BASE + (XIP_MAINTENANCE_BASE - XIP_BASE) + i * 8u + 0x1u) = 0;
|
||||
}
|
||||
}
|
||||
#elif defined(PICO_RP2350)
|
||||
static void __no_inline_not_in_flash_func(flushcache)() {
|
||||
// Null
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
extern "C" {
|
||||
extern void __real_flash_range_erase(uint32_t flash_offs, size_t count);
|
||||
void __wrap_flash_range_erase(uint32_t flash_offs, size_t count) {
|
||||
#ifdef PICO_RP2350
|
||||
auto s = qmi_hw->m[1];
|
||||
flushcache();
|
||||
#endif
|
||||
__real_flash_range_erase(flash_offs, count);
|
||||
#ifdef PICO_RP2350
|
||||
qmi_hw->m[1] = s;
|
||||
__compiler_memory_barrier();
|
||||
#endif
|
||||
}
|
||||
|
||||
extern void __real_flash_range_program(uint32_t flash_offs, const uint8_t *data, size_t count);
|
||||
void __wrap_flash_range_program(uint32_t flash_offs, const uint8_t *data, size_t count) {
|
||||
#ifdef PICO_RP2350
|
||||
auto s = qmi_hw->m[1];
|
||||
flushcache();
|
||||
#endif
|
||||
__real_flash_range_program(flash_offs, data, count);
|
||||
#ifdef PICO_RP2350
|
||||
qmi_hw->m[1] = s;
|
||||
__compiler_memory_barrier();
|
||||
#endif
|
||||
}
|
||||
|
||||
extern void __real_flash_get_unique_id(uint8_t *id_out);
|
||||
void __wrap_flash_get_unique_id(uint8_t *id_out) {
|
||||
#ifdef PICO_RP2350
|
||||
auto s = qmi_hw->m[1];
|
||||
flushcache();
|
||||
#endif
|
||||
__real_flash_get_unique_id(id_out);
|
||||
#ifdef PICO_RP2350
|
||||
qmi_hw->m[1] = s;
|
||||
__compiler_memory_barrier();
|
||||
#endif
|
||||
}
|
||||
|
||||
extern void __real_flash_do_cmd(const uint8_t *txbuf, uint8_t *rxbuf, size_t count);
|
||||
void __wrap_flash_do_cmd(const uint8_t *txbuf, uint8_t *rxbuf, size_t count) {
|
||||
#ifdef PICO_RP2350
|
||||
auto s = qmi_hw->m[1];
|
||||
flushcache();
|
||||
#endif
|
||||
__real_flash_do_cmd(txbuf, rxbuf, count);
|
||||
#ifdef PICO_RP2350
|
||||
qmi_hw->m[1] = s;
|
||||
__compiler_memory_barrier();
|
||||
#endif
|
||||
}
|
||||
};
|
||||
@@ -99,7 +99,7 @@ static SemaphoreHandle_t __getFreeRTOSRecursiveMutex(_LOCK_T lock) {
|
||||
return __get_freertos_mutex_for_ptr((mutex_t *)l, true);
|
||||
}
|
||||
|
||||
void __retarget_lock_init(_LOCK_T *lock) {
|
||||
void __retarget_lock_init(_LOCK_T lock) {
|
||||
if (__freeRTOSinitted) {
|
||||
mutex_t *l = (mutex_t *)lock;
|
||||
if ((l == &__lock___at_quick_exit_mutex) || (l == &__lock___tz_mutex) || (l == &__lock___dd_hash_mutex) || (l == &__lock___arc4random_mutex)) {
|
||||
@@ -113,7 +113,7 @@ void __retarget_lock_init(_LOCK_T *lock) {
|
||||
}
|
||||
}
|
||||
|
||||
void __retarget_lock_init_recursive(_LOCK_T *lock) {
|
||||
void __retarget_lock_init_recursive(_LOCK_T lock) {
|
||||
if (__freeRTOSinitted) {
|
||||
recursive_mutex_t *l = (recursive_mutex_t *)lock;
|
||||
if ((l == &__lock___sinit_recursive_mutex) || (l == &__lock___sfp_recursive_mutex) || (l == &__lock___atexit_recursive_mutex) || (l == &__lock___malloc_recursive_mutex) || (l == &__lock___env_recursive_mutex)) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
LWIP wrappers to protect against timer-based re-entrancy
|
||||
|
||||
Copyright (c) 202s Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
Copyright (c) 2023 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
|
||||
@@ -18,6 +18,7 @@
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <pico/mutex.h>
|
||||
#include <lwip/pbuf.h>
|
||||
#include <lwip/udp.h>
|
||||
@@ -25,21 +26,76 @@
|
||||
#include <lwip/dns.h>
|
||||
#include <lwip/raw.h>
|
||||
#include <lwip/timeouts.h>
|
||||
#ifdef PICO_RP2040
|
||||
#include <pico/cyw43_arch.h>
|
||||
#endif
|
||||
#include <pico/mutex.h>
|
||||
#include <sys/lock.h>
|
||||
#include "_xoshiro.h"
|
||||
|
||||
extern void ethernet_arch_lwip_begin() __attribute__((weak));
|
||||
extern void ethernet_arch_lwip_end() __attribute__((weak));
|
||||
extern void ethernet_arch_lwip_gpio_mask() __attribute__((weak));
|
||||
extern void ethernet_arch_lwip_gpio_unmask() __attribute__((weak));
|
||||
|
||||
auto_init_recursive_mutex(__lwipMutex); // Only for case with no Ethernet or PicoW, but still doing LWIP (PPP?)
|
||||
|
||||
class LWIPMutex {
|
||||
public:
|
||||
LWIPMutex() {
|
||||
cyw43_arch_lwip_begin();
|
||||
if (ethernet_arch_lwip_gpio_mask) {
|
||||
ethernet_arch_lwip_gpio_mask();
|
||||
}
|
||||
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
|
||||
if (rp2040.isPicoW()) {
|
||||
cyw43_arch_lwip_begin();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (ethernet_arch_lwip_begin) {
|
||||
ethernet_arch_lwip_begin();
|
||||
} else {
|
||||
recursive_mutex_enter_blocking(&__lwipMutex);
|
||||
}
|
||||
}
|
||||
|
||||
~LWIPMutex() {
|
||||
cyw43_arch_lwip_end();
|
||||
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
|
||||
if (rp2040.isPicoW()) {
|
||||
cyw43_arch_lwip_end();
|
||||
} else {
|
||||
#endif
|
||||
if (ethernet_arch_lwip_end) {
|
||||
ethernet_arch_lwip_end();
|
||||
} else {
|
||||
recursive_mutex_exit(&__lwipMutex);
|
||||
}
|
||||
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
|
||||
}
|
||||
#endif
|
||||
if (ethernet_arch_lwip_gpio_unmask) {
|
||||
ethernet_arch_lwip_gpio_unmask();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
|
||||
static XoshiroCpp::Xoshiro256PlusPlus *_lwip_rng = nullptr;
|
||||
// Random number generator for LWIP
|
||||
unsigned long __lwip_rand() {
|
||||
return (unsigned long)(*_lwip_rng)();
|
||||
}
|
||||
|
||||
// Avoid calling lwip_init multiple times
|
||||
extern void __real_lwip_init();
|
||||
void __wrap_lwip_init() {
|
||||
if (!_lwip_rng) {
|
||||
_lwip_rng = new XoshiroCpp::Xoshiro256PlusPlus(micros() * rp2040.getCycleCount());
|
||||
__real_lwip_init();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -193,19 +249,19 @@ extern "C" {
|
||||
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);
|
||||
__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);
|
||||
__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);
|
||||
__real_tcp_backlog_accepted(pcb);
|
||||
}
|
||||
extern struct udp_pcb *__real_udp_new(void);
|
||||
struct udp_pcb *__wrap_udp_new(void) {
|
||||
@@ -304,4 +360,16 @@ extern "C" {
|
||||
__real_raw_remove(pcb);
|
||||
}
|
||||
|
||||
extern struct netif *__real_netif_add(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input);
|
||||
struct netif *__wrap_netif_add(struct netif *netif, const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input) {
|
||||
LWIPMutex m;
|
||||
return __real_netif_add(netif, ipaddr, netmask, gw, state, init, input);
|
||||
}
|
||||
|
||||
extern void __real_netif_remove(struct netif *netif);
|
||||
void __wrap_netif_remove(struct netif *netif) {
|
||||
LWIPMutex m;
|
||||
__real_netif_remove(netif);
|
||||
}
|
||||
|
||||
}; // extern "C"
|
||||
|
||||
+15
-9
@@ -27,11 +27,9 @@
|
||||
RP2040 rp2040;
|
||||
extern "C" {
|
||||
volatile bool __otherCoreIdled = false;
|
||||
int __holdUpPendSV = 0;
|
||||
uint32_t* core1_separate_stack_address = nullptr;
|
||||
};
|
||||
|
||||
mutex_t _pioMutex;
|
||||
|
||||
extern void setup();
|
||||
extern void loop();
|
||||
|
||||
@@ -41,12 +39,14 @@ extern void startFreeRTOS() __attribute__((weak));
|
||||
bool __isFreeRTOS;
|
||||
volatile bool __freeRTOSinitted;
|
||||
|
||||
extern void __EnableBluetoothDebug(Print &);
|
||||
|
||||
// Weak empty variant initialization. May be redefined by variant files.
|
||||
void initVariant() __attribute__((weak));
|
||||
void initVariant() { }
|
||||
|
||||
// Optional 2nd core setup and loop
|
||||
bool core1_separate_stack __attribute__((weak)) = false;
|
||||
extern void setup1() __attribute__((weak));
|
||||
extern void loop1() __attribute__((weak));
|
||||
extern "C" void main1() {
|
||||
@@ -79,7 +79,7 @@ extern void __loop() {
|
||||
static struct _reent *_impure_ptr1 = nullptr;
|
||||
|
||||
extern "C" int main() {
|
||||
#if F_CPU != 125000000
|
||||
#if (defined(PICO_RP2040) && (F_CPU != 125000000)) || (defined(PICO_RP2350) && (F_CPU != 150000000))
|
||||
set_sys_clock_khz(F_CPU / 1000, true);
|
||||
#endif
|
||||
|
||||
@@ -88,12 +88,10 @@ extern "C" int main() {
|
||||
|
||||
// Allocate impure_ptr (newlib temps) if there is a 2nd core running
|
||||
if (!__isFreeRTOS && (setup1 || loop1)) {
|
||||
_impure_ptr1 = (struct _reent*)calloc(sizeof(struct _reent), 1);
|
||||
_impure_ptr1 = (struct _reent*)calloc(1, sizeof(struct _reent));
|
||||
_REENT_INIT_PTR(_impure_ptr1);
|
||||
}
|
||||
|
||||
mutex_init(&_pioMutex);
|
||||
|
||||
rp2040.begin();
|
||||
|
||||
initVariant();
|
||||
@@ -122,6 +120,9 @@ extern "C" int main() {
|
||||
#if defined DEBUG_RP2040_PORT
|
||||
if (!__isFreeRTOS) {
|
||||
DEBUG_RP2040_PORT.begin(115200);
|
||||
#if (defined(ENABLE_BLUETOOTH) || defined(ENABLE_BLE)) && defined(DEBUG_RP2040_BLUETOOTH)
|
||||
__EnableBluetoothDebug(DEBUG_RP2040_PORT);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -133,11 +134,15 @@ extern "C" int main() {
|
||||
}
|
||||
rp2040.fifo.registerCore();
|
||||
}
|
||||
|
||||
if (!__isFreeRTOS) {
|
||||
if (setup1 || loop1) {
|
||||
delay(1); // Needed to make Picoprobe upload start 2nd core
|
||||
multicore_launch_core1(main1);
|
||||
if (core1_separate_stack) {
|
||||
core1_separate_stack_address = (uint32_t*)malloc(0x2000);
|
||||
multicore_launch_core1_with_stack(main1, core1_separate_stack_address, 0x2000);
|
||||
} else {
|
||||
multicore_launch_core1(main1);
|
||||
}
|
||||
}
|
||||
setup();
|
||||
while (true) {
|
||||
@@ -163,6 +168,7 @@ extern "C" void __register_impure_ptr(struct _reent *p) {
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" struct _reent *__wrap___getreent() __attribute__((weak));
|
||||
extern "C" struct _reent *__wrap___getreent() {
|
||||
if (get_core_num() == 0) {
|
||||
return _impure_ptr;
|
||||
|
||||
@@ -19,11 +19,25 @@
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <malloc.h>
|
||||
#include <reent.h>
|
||||
#include "psram.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" struct mallinfo __real_mallinfo();
|
||||
|
||||
#ifdef RP2350_PSRAM_CS
|
||||
extern "C" {
|
||||
extern uint8_t __psram_start__;
|
||||
extern uint8_t __psram_heap_start__;
|
||||
void __malloc_lock(struct _reent *ptr);
|
||||
void __malloc_unlock(struct _reent *ptr);
|
||||
static void *__ram_start = (void *)0x20000000; // TODO - Is there a SDK exposed variable/macro?
|
||||
}
|
||||
#endif
|
||||
|
||||
extern "C" void *__wrap_malloc(size_t size) {
|
||||
noInterrupts();
|
||||
@@ -39,15 +53,72 @@ extern "C" void *__wrap_calloc(size_t count, size_t size) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
extern "C" void *__wrap_realloc(void *mem, size_t size) {
|
||||
#ifdef RP2350_PSRAM_CS
|
||||
// Utilize the existing malloc lock infrastructure and interrupt blocking
|
||||
// to work with multicore and FreeRTOS
|
||||
extern "C" void *pmalloc(size_t size) {
|
||||
noInterrupts();
|
||||
void *rc = __real_realloc(mem, size);
|
||||
__malloc_lock(__getreent());
|
||||
auto rc = __psram_malloc(size);
|
||||
__malloc_unlock(__getreent());
|
||||
interrupts();
|
||||
return rc;
|
||||
}
|
||||
|
||||
extern "C" void *pcalloc(size_t count, size_t size) {
|
||||
noInterrupts();
|
||||
__malloc_lock(__getreent());
|
||||
auto rc = __psram_calloc(count, size);
|
||||
__malloc_unlock(__getreent());
|
||||
interrupts();
|
||||
return rc;
|
||||
}
|
||||
#else
|
||||
// No PSRAM, always fail
|
||||
extern "C" void *pmalloc(size_t size) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
extern "C" void *pcalloc(size_t count, size_t size) {
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern "C" void *__wrap_realloc(void *mem, size_t size) {
|
||||
void *rc;
|
||||
noInterrupts();
|
||||
#ifdef RP2350_PSRAM_CS
|
||||
if (mem && (mem < __ram_start)) {
|
||||
rc = __psram_realloc(mem, size);
|
||||
} else {
|
||||
rc = __real_realloc(mem, size);
|
||||
}
|
||||
#else
|
||||
rc = __real_realloc(mem, size);
|
||||
#endif
|
||||
interrupts();
|
||||
return rc;
|
||||
}
|
||||
|
||||
extern "C" void __wrap_free(void *mem) {
|
||||
noInterrupts();
|
||||
#ifdef RP2350_PSRAM_CS
|
||||
if (mem && (mem < __ram_start)) {
|
||||
__psram_free(mem);
|
||||
} else {
|
||||
__real_free(mem);
|
||||
}
|
||||
#else
|
||||
__real_free(mem);
|
||||
#endif
|
||||
interrupts();
|
||||
}
|
||||
|
||||
extern "C" struct mallinfo __wrap_mallinfo() {
|
||||
noInterrupts();
|
||||
__malloc_lock(__getreent());
|
||||
auto ret = __real_mallinfo();
|
||||
__malloc_unlock(__getreent());
|
||||
interrupts();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
; We shift out the start and stop bit as part of the FIFO
|
||||
set x, 9
|
||||
|
||||
pull side 1 ; Force stop bit
|
||||
pull side 1 ; Force stop bit high
|
||||
|
||||
; Send the bits
|
||||
bitloop:
|
||||
@@ -39,15 +39,13 @@ wait_bit:
|
||||
jmp y-- wait_bit
|
||||
jmp x-- bitloop
|
||||
|
||||
|
||||
|
||||
% c-sdk {
|
||||
|
||||
static inline void pio_tx_program_init(PIO pio, uint sm, uint offset, uint pin_tx) {
|
||||
// Tell PIO to initially drive output-high on the selected pin, then map PIO
|
||||
// onto that pin with the IO muxes.
|
||||
pio_sm_set_pins_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx);
|
||||
pio_sm_set_pindirs_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx);
|
||||
pio_sm_set_set_pins(pio, sm, pin_tx, 1);
|
||||
pio_sm_set_consecutive_pindirs(pio, sm, pin_tx, 1, true);
|
||||
pio_gpio_init(pio, pin_tx);
|
||||
|
||||
pio_sm_config c = pio_tx_program_get_default_config(offset);
|
||||
@@ -68,7 +66,7 @@ static inline void pio_tx_program_init(PIO pio, uint sm, uint offset, uint pin_t
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
|
||||
|
||||
.program pio_rx
|
||||
|
||||
@@ -90,7 +88,6 @@ wait_half:
|
||||
|
||||
push ; Stuff it and wait for next start
|
||||
|
||||
|
||||
% c-sdk {
|
||||
static inline void pio_rx_program_init(PIO pio, uint sm, uint offset, uint pin) {
|
||||
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false);
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// This file is autogenerated by pioasm; do not edit! //
|
||||
// -------------------------------------------------- //
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !PICO_NO_HARDWARE
|
||||
#include "hardware/pio.h"
|
||||
#endif
|
||||
@@ -12,6 +14,7 @@
|
||||
|
||||
#define pio_tx_wrap_target 0
|
||||
#define pio_tx_wrap 5
|
||||
#define pio_tx_pio_version 0
|
||||
|
||||
static const uint16_t pio_tx_program_instructions[] = {
|
||||
// .wrap_target
|
||||
@@ -29,6 +32,10 @@ static const struct pio_program pio_tx_program = {
|
||||
.instructions = pio_tx_program_instructions,
|
||||
.length = 6,
|
||||
.origin = -1,
|
||||
.pio_version = 0,
|
||||
#if PICO_PIO_VERSION > 0
|
||||
.used_gpio_ranges = 0x0
|
||||
#endif
|
||||
};
|
||||
|
||||
static inline pio_sm_config pio_tx_program_get_default_config(uint offset) {
|
||||
@@ -41,8 +48,8 @@ static inline pio_sm_config pio_tx_program_get_default_config(uint offset) {
|
||||
static inline void pio_tx_program_init(PIO pio, uint sm, uint offset, uint pin_tx) {
|
||||
// Tell PIO to initially drive output-high on the selected pin, then map PIO
|
||||
// onto that pin with the IO muxes.
|
||||
pio_sm_set_pins_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx);
|
||||
pio_sm_set_pindirs_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx);
|
||||
pio_sm_set_set_pins(pio, sm, pin_tx, 1);
|
||||
pio_sm_set_consecutive_pindirs(pio, sm, pin_tx, 1, true);
|
||||
pio_gpio_init(pio, pin_tx);
|
||||
pio_sm_config c = pio_tx_program_get_default_config(offset);
|
||||
// OUT shifts to right, no autopull
|
||||
@@ -65,6 +72,7 @@ static inline void pio_tx_program_init(PIO pio, uint sm, uint offset, uint pin_t
|
||||
|
||||
#define pio_rx_wrap_target 0
|
||||
#define pio_rx_wrap 6
|
||||
#define pio_rx_pio_version 0
|
||||
|
||||
static const uint16_t pio_rx_program_instructions[] = {
|
||||
// .wrap_target
|
||||
@@ -83,6 +91,10 @@ static const struct pio_program pio_rx_program = {
|
||||
.instructions = pio_rx_program_instructions,
|
||||
.length = 7,
|
||||
.origin = -1,
|
||||
.pio_version = 0,
|
||||
#if PICO_PIO_VERSION > 0
|
||||
.used_gpio_ranges = 0x0
|
||||
#endif
|
||||
};
|
||||
|
||||
static inline pio_sm_config pio_rx_program_get_default_config(uint offset) {
|
||||
|
||||
+39
-13
@@ -33,7 +33,9 @@
|
||||
|
||||
extern "C" int errno;
|
||||
|
||||
extern "C" ssize_t _write(int fd, const void *buf, size_t count) {
|
||||
extern "C"
|
||||
__attribute((weak))
|
||||
ssize_t _write(int fd, const void *buf, size_t count) {
|
||||
#if defined DEBUG_RP2040_PORT
|
||||
(void) fd;
|
||||
return DEBUG_RP2040_PORT.write((const char *)buf, count);
|
||||
@@ -45,7 +47,9 @@ extern "C" ssize_t _write(int fd, const void *buf, size_t count) {
|
||||
#endif
|
||||
}
|
||||
|
||||
extern "C" int _chown(const char *path, uid_t owner, gid_t group) {
|
||||
extern "C"
|
||||
__attribute((weak))
|
||||
int _chown(const char *path, uid_t owner, gid_t group) {
|
||||
(void) path;
|
||||
(void) owner;
|
||||
(void) group;
|
||||
@@ -53,7 +57,9 @@ extern "C" int _chown(const char *path, uid_t owner, gid_t group) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" int _close(int fd) {
|
||||
extern "C"
|
||||
__attribute((weak))
|
||||
int _close(int fd) {
|
||||
(void) fd;
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
@@ -72,7 +78,9 @@ extern "C" int _fork(void) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" int _fstat(int fd, struct stat *st) {
|
||||
extern "C"
|
||||
__attribute((weak))
|
||||
int _fstat(int fd, struct stat *st) {
|
||||
(void) fd;
|
||||
(void) st;
|
||||
errno = ENOSYS;
|
||||
@@ -115,7 +123,9 @@ extern "C" void __setSystemTime(unsigned long long sec, unsigned long usec) {
|
||||
__timedelta_us = newnow_us - now_us;
|
||||
}
|
||||
|
||||
extern "C" int _isatty(int file) {
|
||||
extern "C"
|
||||
__attribute((weak))
|
||||
int _isatty(int file) {
|
||||
(void) file;
|
||||
errno = ENOSYS;
|
||||
return 0;
|
||||
@@ -128,14 +138,18 @@ extern "C" int _kill(int pid, int sig) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" int _link(char *existing, char *newlink) {
|
||||
extern "C"
|
||||
__attribute((weak))
|
||||
int _link(char *existing, char *newlink) {
|
||||
(void) existing;
|
||||
(void) newlink;
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" int _lseek(int file, int ptr, int dir) {
|
||||
extern "C"
|
||||
__attribute((weak))
|
||||
int _lseek(int file, int ptr, int dir) {
|
||||
(void) file;
|
||||
(void) ptr;
|
||||
(void) dir;
|
||||
@@ -143,7 +157,9 @@ extern "C" int _lseek(int file, int ptr, int dir) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" int _open(char *file, int flags, int mode) {
|
||||
extern "C"
|
||||
__attribute((weak))
|
||||
int _open(char *file, int flags, int mode) {
|
||||
(void) file;
|
||||
(void) flags;
|
||||
(void) mode;
|
||||
@@ -151,7 +167,9 @@ extern "C" int _open(char *file, int flags, int mode) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" int _read(int file, char *ptr, int len) {
|
||||
extern "C"
|
||||
__attribute((weak))
|
||||
int _read(int file, char *ptr, int len) {
|
||||
(void) file;
|
||||
(void) ptr;
|
||||
(void) len;
|
||||
@@ -159,7 +177,9 @@ extern "C" int _read(int file, char *ptr, int len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" int _readlink(const char *path, char *buf, size_t bufsize) {
|
||||
extern "C"
|
||||
__attribute((weak))
|
||||
int _readlink(const char *path, char *buf, size_t bufsize) {
|
||||
(void) path;
|
||||
(void) buf;
|
||||
(void) bufsize;
|
||||
@@ -167,14 +187,18 @@ extern "C" int _readlink(const char *path, char *buf, size_t bufsize) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" int _stat(const char *file, struct stat *st) {
|
||||
extern "C"
|
||||
__attribute((weak))
|
||||
int _stat(const char *file, struct stat *st) {
|
||||
(void) file;
|
||||
(void) st;
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" int _symlink(const char *path1, const char *path2) {
|
||||
extern "C"
|
||||
__attribute((weak))
|
||||
int _symlink(const char *path1, const char *path2) {
|
||||
(void) path1;
|
||||
(void) path2;
|
||||
errno = ENOSYS;
|
||||
@@ -187,7 +211,9 @@ extern "C" clock_t _times(struct tms *buf) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" int _unlink(char *name) {
|
||||
extern "C"
|
||||
__attribute((weak))
|
||||
int _unlink(char *name) {
|
||||
(void) name;
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
|
||||
@@ -0,0 +1,437 @@
|
||||
// Originally from https://github.com/sparkfun/sparkfun-pico
|
||||
/**
|
||||
@file sfe_psram.c
|
||||
|
||||
@brief This file contains a function that is used to detect and initialize PSRAM on
|
||||
SparkFun rp2350 boards.
|
||||
*/
|
||||
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2024 SparkFun Electronics
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions: The
|
||||
above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
|
||||
"AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Hacked by Earle Philhower to work with the Arduino-Pico core
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#ifdef RP2350_PSRAM_CS
|
||||
|
||||
#include <hardware/address_mapped.h>
|
||||
#include <hardware/clocks.h>
|
||||
#include <hardware/gpio.h>
|
||||
#include <hardware/regs/addressmap.h>
|
||||
#include <hardware/spi.h>
|
||||
#include <hardware/structs/qmi.h>
|
||||
#include <hardware/structs/xip_ctrl.h>
|
||||
#include <pico/runtime_init.h>
|
||||
|
||||
// Include TLSF in this compilation unit
|
||||
#include "../../lib/tlsf/tlsf.c"
|
||||
static tlsf_t _mem_heap = nullptr;
|
||||
static pool_t _mem_psram_pool = nullptr;
|
||||
|
||||
// PSRAM heap minus PSRAM global/static variables from the linker
|
||||
extern "C" {
|
||||
extern uint8_t __psram_start__;
|
||||
extern uint8_t __psram_heap_start__;
|
||||
}
|
||||
|
||||
static bool _bInitalized = false;
|
||||
size_t __psram_size = 0;
|
||||
size_t __psram_heap_size = 0;
|
||||
|
||||
#define PICO_RUNTIME_INIT_PSRAM "11001" // Towards the end, after alarms
|
||||
|
||||
#ifndef RP2350_PSRAM_MAX_SELECT_FS64
|
||||
#define RP2350_PSRAM_MAX_SELECT_FS64 (125'000'000)
|
||||
#endif
|
||||
|
||||
#ifndef RP2350_PSRAM_MIN_DESELECT_FS
|
||||
#define RP2350_PSRAM_MIN_DESELECT_FS (50'000'000)
|
||||
#endif
|
||||
|
||||
#ifndef RP2350_PSRAM_MAX_SCK_HZ
|
||||
#define RP2350_PSRAM_MAX_SCK_HZ (109'000'000)
|
||||
#endif
|
||||
|
||||
#ifndef RP2350_PSRAM_ID
|
||||
#define RP2350_PSRAM_ID (0x5D)
|
||||
#endif
|
||||
|
||||
// DETAILS/
|
||||
//
|
||||
// SparkFun RP2350 boards use the following PSRAM IC:
|
||||
//
|
||||
// apmemory APS6404L-3SQR-ZR
|
||||
// https://www.mouser.com/ProductDetail/AP-Memory/APS6404L-3SQR-ZR?qs=IS%252B4QmGtzzpDOdsCIglviw%3D%3D
|
||||
//
|
||||
// The origin of this logic is from the Circuit Python code that was downloaded from:
|
||||
// https://github.com/raspberrypi/pico-sdk-rp2350/issues/12#issuecomment-2055274428
|
||||
//
|
||||
|
||||
// Details on the PSRAM IC that are used during setup/configuration of PSRAM on SparkFun RP2350 boards.
|
||||
|
||||
// For PSRAM timing calculations - to use int math, we work in femto seconds (fs) (1e-15),
|
||||
// NOTE: This idea is from micro python work on psram..
|
||||
|
||||
#define SFE_SEC_TO_FS 1000000000000000ll
|
||||
|
||||
// max select pulse width = 8us => 8e6 ns => 8000 ns => 8000 * 1e6 fs => 8000e6 fs
|
||||
// Additionally, the MAX select is in units of 64 clock cycles - will use a constant that
|
||||
// takes this into account - so 8000e6 fs / 64 = 125e6 fs
|
||||
|
||||
const uint32_t SFE_PSRAM_MAX_SELECT_FS64 = RP2350_PSRAM_MAX_SELECT_FS64;
|
||||
|
||||
// min deselect pulse width = 50ns => 50 * 1e6 fs => 50e7 fs
|
||||
const uint32_t SFE_PSRAM_MIN_DESELECT_FS = RP2350_PSRAM_MIN_DESELECT_FS;
|
||||
|
||||
// from psram datasheet - max Freq with VDDat 3.3v - SparkFun RP2350 boards run at 3.3v.
|
||||
// If VDD = 3.0 Max Freq is 133 Mhz
|
||||
const uint32_t SFE_PSRAM_MAX_SCK_HZ = RP2350_PSRAM_MAX_SCK_HZ;
|
||||
|
||||
// PSRAM SPI command codes
|
||||
const uint8_t PSRAM_CMD_QUAD_END = 0xF5;
|
||||
const uint8_t PSRAM_CMD_QUAD_ENABLE = 0x35;
|
||||
const uint8_t PSRAM_CMD_READ_ID = 0x9F;
|
||||
const uint8_t PSRAM_CMD_RSTEN = 0x66;
|
||||
const uint8_t PSRAM_CMD_RST = 0x99;
|
||||
const uint8_t PSRAM_CMD_QUAD_READ = 0xEB;
|
||||
const uint8_t PSRAM_CMD_QUAD_WRITE = 0x38;
|
||||
const uint8_t PSRAM_CMD_NOOP = 0xFF;
|
||||
|
||||
const uint8_t PSRAM_ID = RP2350_PSRAM_ID;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @brief Communicate directly with the PSRAM IC - validate it is present and return the size
|
||||
///
|
||||
/// @return size_t The size of the PSRAM
|
||||
///
|
||||
/// @note This function expects the CS pin set
|
||||
static size_t __no_inline_not_in_flash_func(get_psram_size)(void) {
|
||||
size_t psram_size = 0;
|
||||
uint32_t intr_stash = save_and_disable_interrupts();
|
||||
|
||||
// Try and read the PSRAM ID via direct_csr.
|
||||
qmi_hw->direct_csr = 30 << QMI_DIRECT_CSR_CLKDIV_LSB | QMI_DIRECT_CSR_EN_BITS;
|
||||
|
||||
// Need to poll for the cooldown on the last XIP transfer to expire
|
||||
// (via direct-mode BUSY flag) before it is safe to perform the first
|
||||
// direct-mode operation
|
||||
while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) != 0) {
|
||||
}
|
||||
|
||||
// Exit out of QMI in case we've inited already
|
||||
qmi_hw->direct_csr |= QMI_DIRECT_CSR_ASSERT_CS1N_BITS;
|
||||
|
||||
// Transmit the command to exit QPI quad mode - read ID as standard SPI
|
||||
qmi_hw->direct_tx =
|
||||
QMI_DIRECT_TX_OE_BITS | QMI_DIRECT_TX_IWIDTH_VALUE_Q << QMI_DIRECT_TX_IWIDTH_LSB | PSRAM_CMD_QUAD_END;
|
||||
|
||||
while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) != 0) {
|
||||
}
|
||||
|
||||
(void)qmi_hw->direct_rx;
|
||||
qmi_hw->direct_csr &= ~(QMI_DIRECT_CSR_ASSERT_CS1N_BITS);
|
||||
|
||||
// Read the id
|
||||
qmi_hw->direct_csr |= QMI_DIRECT_CSR_ASSERT_CS1N_BITS;
|
||||
uint8_t kgd = 0;
|
||||
uint8_t eid = 0;
|
||||
for (size_t i = 0; i < 7; i++) {
|
||||
qmi_hw->direct_tx = (i == 0 ? PSRAM_CMD_READ_ID : PSRAM_CMD_NOOP);
|
||||
|
||||
while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_TXEMPTY_BITS) == 0) {
|
||||
}
|
||||
while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) != 0) {
|
||||
}
|
||||
if (i == 5) {
|
||||
kgd = qmi_hw->direct_rx;
|
||||
} else if (i == 6) {
|
||||
eid = qmi_hw->direct_rx;
|
||||
} else {
|
||||
(void)qmi_hw->direct_rx; // just read and discard
|
||||
}
|
||||
}
|
||||
|
||||
// Disable direct csr.
|
||||
qmi_hw->direct_csr &= ~(QMI_DIRECT_CSR_ASSERT_CS1N_BITS | QMI_DIRECT_CSR_EN_BITS);
|
||||
|
||||
// is this the PSRAM we're looking for obi-wan?
|
||||
if (kgd == PSRAM_ID) {
|
||||
// PSRAM size
|
||||
psram_size = 1024 * 1024; // 1 MiB
|
||||
uint8_t size_id = eid >> 5;
|
||||
if (eid == 0x26 || size_id == 2) {
|
||||
psram_size *= 8;
|
||||
} else if (size_id == 0) {
|
||||
psram_size *= 2;
|
||||
} else if (size_id == 1) {
|
||||
psram_size *= 4;
|
||||
}
|
||||
}
|
||||
restore_interrupts(intr_stash);
|
||||
return psram_size;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @brief Update the PSRAM timing configuration based on system clock
|
||||
///
|
||||
/// @note This function expects interrupts to be enabled on entry
|
||||
|
||||
static void __no_inline_not_in_flash_func(set_psram_timing)(void) {
|
||||
// Get secs / cycle for the system clock - get before disabling interrupts.
|
||||
uint32_t sysHz = (uint32_t)clock_get_hz(clk_sys);
|
||||
|
||||
// Calculate the clock divider - goal to get clock used for PSRAM <= what
|
||||
// the PSRAM IC can handle - which is defined in SFE_PSRAM_MAX_SCK_HZ
|
||||
volatile uint8_t clockDivider = (sysHz + SFE_PSRAM_MAX_SCK_HZ - 1) / SFE_PSRAM_MAX_SCK_HZ;
|
||||
|
||||
uint32_t intr_stash = save_and_disable_interrupts();
|
||||
|
||||
// Get the clock femto seconds per cycle.
|
||||
|
||||
uint32_t fsPerCycle = SFE_SEC_TO_FS / sysHz;
|
||||
|
||||
// the maxSelect value is defined in units of 64 clock cycles
|
||||
// So maxFS / (64 * fsPerCycle) = maxSelect = SFE_PSRAM_MAX_SELECT_FS64/fsPerCycle
|
||||
volatile uint8_t maxSelect = SFE_PSRAM_MAX_SELECT_FS64 / fsPerCycle;
|
||||
|
||||
// minDeselect time - in system clock cycle
|
||||
// Must be higher than 50ns (min deselect time for PSRAM) so add a fsPerCycle - 1 to round up
|
||||
// So minFS/fsPerCycle = minDeselect = SFE_PSRAM_MIN_DESELECT_FS/fsPerCycle
|
||||
|
||||
volatile uint8_t minDeselect = (SFE_PSRAM_MIN_DESELECT_FS + fsPerCycle - 1) / fsPerCycle;
|
||||
|
||||
// printf("Max Select: %d, Min Deselect: %d, clock divider: %d\n", maxSelect, minDeselect, clockDivider);
|
||||
|
||||
qmi_hw->m[1].timing = QMI_M1_TIMING_PAGEBREAK_VALUE_1024 << QMI_M1_TIMING_PAGEBREAK_LSB | // Break between pages.
|
||||
3 << QMI_M1_TIMING_SELECT_HOLD_LSB | // Delay releasing CS for 3 extra system cycles.
|
||||
1 << QMI_M1_TIMING_COOLDOWN_LSB | 1 << QMI_M1_TIMING_RXDELAY_LSB |
|
||||
maxSelect << QMI_M1_TIMING_MAX_SELECT_LSB | minDeselect << QMI_M1_TIMING_MIN_DESELECT_LSB |
|
||||
clockDivider << QMI_M1_TIMING_CLKDIV_LSB;
|
||||
|
||||
restore_interrupts(intr_stash);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @brief The setup_psram function - note that this is not in flash
|
||||
///
|
||||
///
|
||||
static void __no_inline_not_in_flash_func(runtime_init_setup_psram)(/*uint32_t psram_cs_pin*/) {
|
||||
// Set the PSRAM CS pin in the SDK
|
||||
gpio_set_function(RP2350_PSRAM_CS, GPIO_FUNC_XIP_CS1);
|
||||
|
||||
// start with zero size
|
||||
size_t psram_size = get_psram_size();
|
||||
|
||||
// No PSRAM - no dice
|
||||
if (psram_size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t intr_stash = save_and_disable_interrupts();
|
||||
// Enable quad mode.
|
||||
qmi_hw->direct_csr = 30 << QMI_DIRECT_CSR_CLKDIV_LSB | QMI_DIRECT_CSR_EN_BITS;
|
||||
|
||||
// Need to poll for the cooldown on the last XIP transfer to expire
|
||||
// (via direct-mode BUSY flag) before it is safe to perform the first
|
||||
// direct-mode operation
|
||||
while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) != 0) {
|
||||
}
|
||||
|
||||
// RESETEN, RESET and quad enable
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
qmi_hw->direct_csr |= QMI_DIRECT_CSR_ASSERT_CS1N_BITS;
|
||||
if (i == 0) {
|
||||
qmi_hw->direct_tx = PSRAM_CMD_RSTEN;
|
||||
} else if (i == 1) {
|
||||
qmi_hw->direct_tx = PSRAM_CMD_RST;
|
||||
} else {
|
||||
qmi_hw->direct_tx = PSRAM_CMD_QUAD_ENABLE;
|
||||
}
|
||||
|
||||
while ((qmi_hw->direct_csr & QMI_DIRECT_CSR_BUSY_BITS) != 0) {
|
||||
}
|
||||
qmi_hw->direct_csr &= ~(QMI_DIRECT_CSR_ASSERT_CS1N_BITS);
|
||||
for (size_t j = 0; j < 20; j++) {
|
||||
asm("nop");
|
||||
}
|
||||
|
||||
(void)qmi_hw->direct_rx;
|
||||
}
|
||||
|
||||
// Disable direct csr.
|
||||
qmi_hw->direct_csr &= ~(QMI_DIRECT_CSR_ASSERT_CS1N_BITS | QMI_DIRECT_CSR_EN_BITS);
|
||||
|
||||
// check our interrupts and setup the timing
|
||||
restore_interrupts(intr_stash);
|
||||
set_psram_timing();
|
||||
|
||||
// and now stash interrupts again
|
||||
intr_stash = save_and_disable_interrupts();
|
||||
|
||||
qmi_hw->m[1].rfmt = (QMI_M1_RFMT_PREFIX_WIDTH_VALUE_Q << QMI_M1_RFMT_PREFIX_WIDTH_LSB |
|
||||
QMI_M1_RFMT_ADDR_WIDTH_VALUE_Q << QMI_M1_RFMT_ADDR_WIDTH_LSB |
|
||||
QMI_M1_RFMT_SUFFIX_WIDTH_VALUE_Q << QMI_M1_RFMT_SUFFIX_WIDTH_LSB |
|
||||
QMI_M1_RFMT_DUMMY_WIDTH_VALUE_Q << QMI_M1_RFMT_DUMMY_WIDTH_LSB |
|
||||
QMI_M1_RFMT_DUMMY_LEN_VALUE_24 << QMI_M1_RFMT_DUMMY_LEN_LSB |
|
||||
QMI_M1_RFMT_DATA_WIDTH_VALUE_Q << QMI_M1_RFMT_DATA_WIDTH_LSB |
|
||||
QMI_M1_RFMT_PREFIX_LEN_VALUE_8 << QMI_M1_RFMT_PREFIX_LEN_LSB |
|
||||
QMI_M1_RFMT_SUFFIX_LEN_VALUE_NONE << QMI_M1_RFMT_SUFFIX_LEN_LSB);
|
||||
|
||||
qmi_hw->m[1].rcmd = PSRAM_CMD_QUAD_READ << QMI_M1_RCMD_PREFIX_LSB | 0 << QMI_M1_RCMD_SUFFIX_LSB;
|
||||
|
||||
qmi_hw->m[1].wfmt = (QMI_M1_WFMT_PREFIX_WIDTH_VALUE_Q << QMI_M1_WFMT_PREFIX_WIDTH_LSB |
|
||||
QMI_M1_WFMT_ADDR_WIDTH_VALUE_Q << QMI_M1_WFMT_ADDR_WIDTH_LSB |
|
||||
QMI_M1_WFMT_SUFFIX_WIDTH_VALUE_Q << QMI_M1_WFMT_SUFFIX_WIDTH_LSB |
|
||||
QMI_M1_WFMT_DUMMY_WIDTH_VALUE_Q << QMI_M1_WFMT_DUMMY_WIDTH_LSB |
|
||||
QMI_M1_WFMT_DUMMY_LEN_VALUE_NONE << QMI_M1_WFMT_DUMMY_LEN_LSB |
|
||||
QMI_M1_WFMT_DATA_WIDTH_VALUE_Q << QMI_M1_WFMT_DATA_WIDTH_LSB |
|
||||
QMI_M1_WFMT_PREFIX_LEN_VALUE_8 << QMI_M1_WFMT_PREFIX_LEN_LSB |
|
||||
QMI_M1_WFMT_SUFFIX_LEN_VALUE_NONE << QMI_M1_WFMT_SUFFIX_LEN_LSB);
|
||||
|
||||
qmi_hw->m[1].wcmd = PSRAM_CMD_QUAD_WRITE << QMI_M1_WCMD_PREFIX_LSB | 0 << QMI_M1_WCMD_SUFFIX_LSB;
|
||||
|
||||
// Mark that we can write to PSRAM.
|
||||
xip_ctrl_hw->ctrl |= XIP_CTRL_WRITABLE_M1_BITS;
|
||||
|
||||
restore_interrupts(intr_stash);
|
||||
|
||||
__psram_size = psram_size;
|
||||
|
||||
uint32_t used_psram_size = &__psram_heap_start__ - &__psram_start__;
|
||||
__psram_heap_size = __psram_size - used_psram_size;
|
||||
}
|
||||
PICO_RUNTIME_INIT_FUNC_RUNTIME(runtime_init_setup_psram, PICO_RUNTIME_INIT_PSRAM);
|
||||
|
||||
// update timing -- used if the system clock/timing was changed.
|
||||
void psram_reinit_timing() {
|
||||
set_psram_timing();
|
||||
}
|
||||
|
||||
static bool __psram_heap_init() {
|
||||
if (_bInitalized) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!__psram_heap_size) {
|
||||
return false;
|
||||
}
|
||||
_mem_heap = NULL;
|
||||
_mem_psram_pool = NULL;
|
||||
_mem_heap = tlsf_create_with_pool((void *)&__psram_heap_start__, __psram_heap_size, 16 * 1024 * 1024);
|
||||
if (!_mem_heap) {
|
||||
return false;
|
||||
}
|
||||
_mem_psram_pool = tlsf_get_pool(_mem_heap);
|
||||
if (!_mem_psram_pool) {
|
||||
return false;
|
||||
}
|
||||
_bInitalized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void *__psram_malloc(size_t size) {
|
||||
if (!__psram_heap_init() || !_mem_heap) {
|
||||
return NULL;
|
||||
}
|
||||
return tlsf_malloc(_mem_heap, size);
|
||||
}
|
||||
|
||||
void __psram_free(void *ptr) {
|
||||
if (!__psram_heap_init() || !_mem_heap) {
|
||||
return;
|
||||
}
|
||||
tlsf_free(_mem_heap, ptr);
|
||||
}
|
||||
|
||||
void *__psram_realloc(void *ptr, size_t size) {
|
||||
if (!__psram_heap_init() || !_mem_heap) {
|
||||
return NULL;
|
||||
}
|
||||
return tlsf_realloc(_mem_heap, ptr, size);
|
||||
}
|
||||
|
||||
void *__psram_calloc(size_t num, size_t size) {
|
||||
if (!__psram_heap_init() || !_mem_heap) {
|
||||
return NULL;
|
||||
}
|
||||
void *ptr = tlsf_malloc(_mem_heap, num * size);
|
||||
if (ptr) {
|
||||
bzero(ptr, num * size);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static bool max_free_walker(void *ptr, size_t size, int used, void *user) {
|
||||
size_t *max_size = (size_t *)user;
|
||||
if (!used && *max_size < size) {
|
||||
*max_size = size;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t __psram_largest_free_block() {
|
||||
if (!__psram_heap_init() || !_mem_heap) {
|
||||
return 0;
|
||||
}
|
||||
size_t max_free = 0;
|
||||
if (_mem_psram_pool) {
|
||||
tlsf_walk_pool(_mem_psram_pool, max_free_walker, &max_free);
|
||||
}
|
||||
return max_free;
|
||||
}
|
||||
|
||||
static bool memory_size_walker(void *ptr, size_t size, int used, void *user) {
|
||||
*((size_t *)user) += size;
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t __psram_total_space() {
|
||||
if (!__psram_heap_init() || !_mem_heap) {
|
||||
return 0;
|
||||
}
|
||||
size_t total_size = 0;
|
||||
if (_mem_psram_pool) {
|
||||
tlsf_walk_pool(_mem_psram_pool, memory_size_walker, &total_size);
|
||||
}
|
||||
return total_size;
|
||||
}
|
||||
|
||||
static bool memory_used_walker(void *ptr, size_t size, int used, void *user) {
|
||||
if (used) {
|
||||
*((size_t *)user) += size;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t __psram_total_used() {
|
||||
if (!__psram_heap_init() || !_mem_heap) {
|
||||
return 0;
|
||||
}
|
||||
size_t total_size = 0;
|
||||
if (_mem_psram_pool) {
|
||||
tlsf_walk_pool(_mem_psram_pool, memory_used_walker, &total_size);
|
||||
}
|
||||
return total_size;
|
||||
}
|
||||
|
||||
#endif // RP2350_PSRAM_CS
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
@file sfe_psram.c
|
||||
|
||||
@brief This file contains a function that is used to detect and initialize PSRAM on
|
||||
SparkFun rp2350 boards.
|
||||
*/
|
||||
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2024 SparkFun Electronics
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions: The
|
||||
above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
|
||||
"AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
||||
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
void psram_reinit_timing();
|
||||
void *__psram_malloc(size_t size);
|
||||
void __psram_free(void *ptr);
|
||||
void *__psram_realloc(void *ptr, size_t size);
|
||||
void *__psram_calloc(size_t num, size_t size);
|
||||
size_t __psram_largest_free_block();
|
||||
size_t __psram_total_space();
|
||||
size_t __psram_total_used();
|
||||
@@ -0,0 +1,383 @@
|
||||
/*
|
||||
* Copyright (c) 2011 ARM Ltd
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the company may not be used to endorse or promote
|
||||
* products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#if defined(PICO_RP2350) && defined(__arm__)
|
||||
/* Prototype: void *memcpy (void *dst, const void *src, size_t count). */
|
||||
/* Use the version of memcpy implemented using LDRD and STRD.
|
||||
This version is tuned for Cortex-A15.
|
||||
This might not be the best for other ARMv7-A CPUs,
|
||||
but there is no predefine to distinguish between
|
||||
different CPUs in the same architecture,
|
||||
and this version is better than the plain memcpy provided in newlib.
|
||||
Therefore, we use this version for all ARMv7-A CPUS. */
|
||||
/* To make the same code compile for both ARM and Thumb instruction
|
||||
sets, switch to unified syntax at the beginning of this function.
|
||||
However, by using the same code, we may be missing optimization
|
||||
opportunities. For instance, in LDRD/STRD instructions, the first
|
||||
destination register must be even and the second consecutive in
|
||||
ARM state, but not in Thumb state. */
|
||||
.syntax unified
|
||||
#if defined (__thumb__)
|
||||
.thumb
|
||||
.thumb_func
|
||||
#endif
|
||||
#ifdef __native_client__
|
||||
#define SFI_BREG(reg) sfi_breg reg,
|
||||
#define IT(insn)
|
||||
#ifdef __thumb__
|
||||
#error "thumb and native_client are not compatible!"
|
||||
#endif
|
||||
.p2align 4
|
||||
#else
|
||||
#define SFI_BREG(reg)
|
||||
#define IT(insn) insn
|
||||
#endif
|
||||
.global __wrap_memcpy
|
||||
.type __wrap_memcpy, %function
|
||||
// .section .time_critical.memcpy // Actually slows down a bit because RAM and program RAM conflict
|
||||
__wrap_memcpy:
|
||||
/* Assumes that n >= 0, and dst, src are valid pointers.
|
||||
If there is at least 8 bytes to copy, use LDRD/STRD.
|
||||
If src and dst are misaligned with different offsets,
|
||||
first copy byte by byte until dst is aligned,
|
||||
and then copy using LDRD/STRD and shift if needed.
|
||||
When less than 8 left, copy a word and then byte by byte. */
|
||||
/* Save registers (r0 holds the return value):
|
||||
optimized push {r0, r4, r5, lr}.
|
||||
To try and improve performance, stack layout changed,
|
||||
i.e., not keeping the stack looking like users expect
|
||||
(highest numbered register at highest address). */
|
||||
push {r0, lr}
|
||||
strd r4, r5, [sp, #-8]!
|
||||
/* TODO: Add debug frame directives.
|
||||
We don't need exception unwind directives, because the code below
|
||||
does not throw any exceptions and does not call any other functions.
|
||||
Generally, newlib functions like this lack debug information for
|
||||
assembler source. */
|
||||
/* Get copying of tiny blocks out of the way first. */
|
||||
/* Is there at least 4 bytes to copy? */
|
||||
subs r2, r2, #4
|
||||
blt copy_less_than_4 /* If n < 4. */
|
||||
/* Check word alignment. */
|
||||
ands ip, r0, #3 /* ip = last 2 bits of dst. */
|
||||
bne dst_not_word_aligned /* If dst is not word-aligned. */
|
||||
/* Get here if dst is word-aligned. */
|
||||
ands ip, r1, #3 /* ip = last 2 bits of src. */
|
||||
bne src_not_word_aligned /* If src is not word-aligned. */
|
||||
word_aligned:
|
||||
/* Get here if source and dst both are word-aligned.
|
||||
The number of bytes remaining to copy is r2+4. */
|
||||
/* Is there is at least 64 bytes to copy? */
|
||||
subs r2, r2, #60
|
||||
blt copy_less_than_64 /* If r2 + 4 < 64. */
|
||||
/* First, align the destination buffer to 8-bytes,
|
||||
to make sure double loads and stores don't cross cache line boundary,
|
||||
as they are then more expensive even if the data is in the cache
|
||||
(require two load/store issue cycles instead of one).
|
||||
If only one of the buffers is not 8-bytes aligned,
|
||||
then it's more important to align dst than src,
|
||||
because there is more penalty for stores
|
||||
than loads that cross cacheline boundary.
|
||||
This check and realignment are only worth doing
|
||||
if there is a lot to copy. */
|
||||
/* Get here if dst is word aligned,
|
||||
i.e., the 2 least significant bits are 0.
|
||||
If dst is not 2w aligned (i.e., the 3rd bit is not set in dst),
|
||||
then copy 1 word (4 bytes). */
|
||||
ands r3, r0, #4
|
||||
beq 11f /* If dst already two-word aligned. */
|
||||
SFI_BREG(r1) \
|
||||
ldr r3, [r1], #4
|
||||
SFI_BREG(r0) \
|
||||
str r3, [r0], #4
|
||||
subs r2, r2, #4
|
||||
blt copy_less_than_64
|
||||
11:
|
||||
/* TODO: Align to cacheline (useful for PLD optimization). */
|
||||
/* Every loop iteration copies 64 bytes. */
|
||||
1:
|
||||
.irp offset, #0, #8, #16, #24, #32, #40, #48, #56
|
||||
SFI_BREG(r1) \
|
||||
ldrd r4, r5, [r1, \offset]
|
||||
SFI_BREG(r0) \
|
||||
strd r4, r5, [r0, \offset]
|
||||
.endr
|
||||
add r0, r0, #64
|
||||
add r1, r1, #64
|
||||
subs r2, r2, #64
|
||||
bge 1b /* If there is more to copy. */
|
||||
copy_less_than_64:
|
||||
/* Get here if less than 64 bytes to copy, -64 <= r2 < 0.
|
||||
Restore the count if there is more than 7 bytes to copy. */
|
||||
adds r2, r2, #56
|
||||
blt copy_less_than_8
|
||||
/* Copy 8 bytes at a time. */
|
||||
2:
|
||||
SFI_BREG(r1) \
|
||||
ldrd r4, r5, [r1], #8
|
||||
SFI_BREG(r0) \
|
||||
strd r4, r5, [r0], #8
|
||||
subs r2, r2, #8
|
||||
bge 2b /* If there is more to copy. */
|
||||
copy_less_than_8:
|
||||
/* Get here if less than 8 bytes to copy, -8 <= r2 < 0.
|
||||
Check if there is more to copy. */
|
||||
cmn r2, #8
|
||||
beq return /* If r2 + 8 == 0. */
|
||||
/* Restore the count if there is more than 3 bytes to copy. */
|
||||
adds r2, r2, #4
|
||||
blt copy_less_than_4
|
||||
/* Copy 4 bytes. */
|
||||
SFI_BREG(r1) \
|
||||
ldr r3, [r1], #4
|
||||
SFI_BREG(r0) \
|
||||
str r3, [r0], #4
|
||||
copy_less_than_4:
|
||||
/* Get here if less than 4 bytes to copy, -4 <= r2 < 0. */
|
||||
/* Restore the count, check if there is more to copy. */
|
||||
adds r2, r2, #4
|
||||
beq return /* If r2 == 0. */
|
||||
/* Get here with r2 is in {1,2,3}={01,10,11}. */
|
||||
/* Logical shift left r2, insert 0s, update flags. */
|
||||
lsls r2, r2, #31
|
||||
/* Copy byte by byte.
|
||||
Condition ne means the last bit of r2 is 0.
|
||||
Condition cs means the second to last bit of r2 is set,
|
||||
i.e., r2 is 1 or 3. */
|
||||
IT(itt ne)
|
||||
SFI_BREG(r1) \
|
||||
ldrbne r3, [r1], #1
|
||||
SFI_BREG(r0) \
|
||||
strbne r3, [r0], #1
|
||||
IT(itttt cs)
|
||||
SFI_BREG(r1) \
|
||||
ldrbcs r4, [r1], #1
|
||||
SFI_BREG(r1) \
|
||||
ldrbcs r5, [r1]
|
||||
SFI_BREG(r0) \
|
||||
strbcs r4, [r0], #1
|
||||
SFI_BREG(r0) \
|
||||
strbcs r5, [r0]
|
||||
return:
|
||||
/* Restore registers: optimized pop {r0, r4, r5, pc} */
|
||||
ldrd r4, r5, [sp], #8
|
||||
#ifdef __native_client__
|
||||
pop {r0, lr}
|
||||
sfi_bx lr
|
||||
#else
|
||||
pop {r0, pc} /* This is the only return point of memcpy. */
|
||||
#endif
|
||||
#ifndef __ARM_FEATURE_UNALIGNED
|
||||
/* The following assembly macro implements misaligned copy in software.
|
||||
Assumes that dst is word aligned, src is at offset "pull" bits from
|
||||
word, push = 32 - pull, and the number of bytes that remain to copy
|
||||
is r2 + 4, r2 >= 0. */
|
||||
/* In the code below, r2 is the number of bytes that remain to be
|
||||
written. The number of bytes read is always larger, because we have
|
||||
partial words in the shift queue. */
|
||||
.macro miscopy pull push shiftleft shiftright
|
||||
/* Align src to the previous word boundary. */
|
||||
bic r1, r1, #3
|
||||
/* Initialize the shift queue. */
|
||||
SFI_BREG(r1) \
|
||||
ldr r5, [r1], #4 /* Load a word from source. */
|
||||
subs r2, r2, #4
|
||||
blt 6f /* Go to misaligned copy of less than 8 bytes. */
|
||||
/* Get here if there is more than 8 bytes to copy.
|
||||
The number of bytes to copy is r2+8, r2 >= 0. */
|
||||
/* Save registers: push { r6, r7 }.
|
||||
We need additional registers for LDRD and STRD, because in ARM state
|
||||
the first destination register must be even and the second
|
||||
consecutive. */
|
||||
strd r6, r7, [sp, #-8]!
|
||||
subs r2, r2, #56
|
||||
blt 4f /* Go to misaligned copy of less than 64 bytes. */
|
||||
3:
|
||||
/* Get here if there is more than 64 bytes to copy.
|
||||
The number of bytes to copy is r2+64, r2 >= 0. */
|
||||
/* Copy 64 bytes in every iteration.
|
||||
Use a partial word from the shift queue. */
|
||||
.irp offset, #0, #8, #16, #24, #32, #40, #48, #56
|
||||
mov r6, r5, \shiftleft #\pull
|
||||
SFI_BREG(r1) \
|
||||
ldrd r4, r5, [r1, \offset]
|
||||
orr r6, r6, r4, \shiftright #\push
|
||||
mov r7, r4, \shiftleft #\pull
|
||||
orr r7, r7, r5, \shiftright #\push
|
||||
SFI_BREG(r0) \
|
||||
strd r6, r7, [r0, \offset]
|
||||
.endr
|
||||
add r1, r1, #64
|
||||
add r0, r0, #64
|
||||
subs r2, r2, #64
|
||||
bge 3b
|
||||
4:
|
||||
/* Get here if there is less than 64 bytes to copy (-64 <= r2 < 0)
|
||||
and they are misaligned. */
|
||||
/* Restore the count if there is more than 7 bytes to copy. */
|
||||
adds r2, r2, #56
|
||||
/* If less than 8 bytes to copy,
|
||||
restore registers saved for this loop: optimized poplt { r6, r7 }. */
|
||||
itt lt
|
||||
ldrdlt r6, r7, [sp], #8
|
||||
blt 6f /* Go to misaligned copy of less than 8 bytes. */
|
||||
5:
|
||||
/* Copy 8 bytes at a time.
|
||||
Use a partial word from the shift queue. */
|
||||
mov r6, r5, \shiftleft #\pull
|
||||
SFI_BREG(r1) \
|
||||
ldrd r4, r5, [r1], #8
|
||||
orr r6, r6, r4, \shiftright #\push
|
||||
mov r7, r4, \shiftleft #\pull
|
||||
orr r7, r7, r5, \shiftright #\push
|
||||
SFI_BREG(r0) \
|
||||
strd r6, r7, [r0], #8
|
||||
subs r2, r2, #8
|
||||
bge 5b /* If there is more to copy. */
|
||||
/* Restore registers saved for this loop: optimized pop { r6, r7 }. */
|
||||
ldrd r6, r7, [sp], #8
|
||||
6:
|
||||
/* Get here if there less than 8 bytes to copy (-8 <= r2 < 0)
|
||||
and they are misaligned. */
|
||||
/* Check if there is more to copy. */
|
||||
cmn r2, #8
|
||||
beq return
|
||||
/* Check if there is less than 4 bytes to copy. */
|
||||
cmn r2, #4
|
||||
itt lt
|
||||
/* Restore src offset from word-align. */
|
||||
sublt r1, r1, #(\push / 8)
|
||||
blt copy_less_than_4
|
||||
/* Use a partial word from the shift queue. */
|
||||
mov r3, r5, \shiftleft #\pull
|
||||
/* Load a word from src, but without writeback
|
||||
(this word is not fully written to dst). */
|
||||
SFI_BREG(r1) \
|
||||
ldr r5, [r1]
|
||||
/* Restore src offset from word-align. */
|
||||
add r1, r1, #(\pull / 8)
|
||||
/* Shift bytes to create one dst word and store it. */
|
||||
orr r3, r3, r5, \shiftright #\push
|
||||
SFI_BREG(r0) \
|
||||
str r3, [r0], #4
|
||||
/* Use single byte copying of the remaining bytes. */
|
||||
b copy_less_than_4
|
||||
.endm
|
||||
#endif /* not __ARM_FEATURE_UNALIGNED */
|
||||
dst_not_word_aligned:
|
||||
/* Get here when dst is not aligned and ip has the last 2 bits of dst,
|
||||
i.e., ip is the offset of dst from word.
|
||||
The number of bytes that remains to copy is r2 + 4,
|
||||
i.e., there are at least 4 bytes to copy.
|
||||
Write a partial word (0 to 3 bytes), such that dst becomes
|
||||
word-aligned. */
|
||||
/* If dst is at ip bytes offset from a word (with 0 < ip < 4),
|
||||
then there are (4 - ip) bytes to fill up to align dst to the next
|
||||
word. */
|
||||
rsb ip, ip, #4 /* ip = #4 - ip. */
|
||||
cmp ip, #2
|
||||
/* Copy byte by byte with conditionals. */
|
||||
IT(itt gt)
|
||||
SFI_BREG(r1) \
|
||||
ldrbgt r3, [r1], #1
|
||||
SFI_BREG(r0) \
|
||||
strbgt r3, [r0], #1
|
||||
IT(itt ge)
|
||||
SFI_BREG(r1) \
|
||||
ldrbge r4, [r1], #1
|
||||
SFI_BREG(r0) \
|
||||
strbge r4, [r0], #1
|
||||
SFI_BREG(r1) \
|
||||
ldrb lr, [r1], #1
|
||||
SFI_BREG(r0) \
|
||||
strb lr, [r0], #1
|
||||
/* Update the count.
|
||||
ip holds the number of bytes we have just copied. */
|
||||
subs r2, r2, ip /* r2 = r2 - ip. */
|
||||
blt copy_less_than_4 /* If r2 < ip. */
|
||||
/* Get here if there are more than 4 bytes to copy.
|
||||
Check if src is aligned. If beforehand src and dst were not word
|
||||
aligned but congruent (same offset), then now they are both
|
||||
word-aligned, and we can copy the rest efficiently (without
|
||||
shifting). */
|
||||
ands ip, r1, #3 /* ip = last 2 bits of src. */
|
||||
beq word_aligned /* If r1 is word-aligned. */
|
||||
src_not_word_aligned:
|
||||
/* Get here when src is not word-aligned, but dst is word-aligned.
|
||||
The number of bytes that remains to copy is r2+4. */
|
||||
#ifdef __ARM_FEATURE_UNALIGNED
|
||||
/* Copy word by word using LDR when alignment can be done in hardware,
|
||||
i.e., SCTLR.A is set, supporting unaligned access in LDR and STR. */
|
||||
subs r2, r2, #60
|
||||
blt 8f
|
||||
7:
|
||||
/* Copy 64 bytes in every loop iteration. */
|
||||
.irp offset, #0, #4, #8, #12, #16, #20, #24, #28, #32, #36, #40, #44, #48, #52, #56, #60
|
||||
SFI_BREG(r1) \
|
||||
ldr r3, [r1, \offset]
|
||||
SFI_BREG(r0) \
|
||||
str r3, [r0, \offset]
|
||||
.endr
|
||||
add r0, r0, #64
|
||||
add r1, r1, #64
|
||||
subs r2, r2, #64
|
||||
bge 7b
|
||||
8:
|
||||
/* Get here if less than 64 bytes to copy, -64 <= r2 < 0.
|
||||
Check if there is more than 3 bytes to copy. */
|
||||
adds r2, r2, #60
|
||||
blt copy_less_than_4
|
||||
9:
|
||||
/* Get here if there is less than 64 but at least 4 bytes to copy,
|
||||
where the number of bytes to copy is r2+4. */
|
||||
SFI_BREG(r1) \
|
||||
ldr r3, [r1], #4
|
||||
SFI_BREG(r0) \
|
||||
str r3, [r0], #4
|
||||
subs r2, r2, #4
|
||||
bge 9b
|
||||
b copy_less_than_4
|
||||
#else /* not __ARM_FEATURE_UNALIGNED */
|
||||
/* ip has last 2 bits of src,
|
||||
i.e., ip is the offset of src from word, and ip > 0.
|
||||
Compute shifts needed to copy from src to dst. */
|
||||
cmp ip, #2
|
||||
beq miscopy_16_16 /* If ip == 2. */
|
||||
bge miscopy_24_8 /* If ip == 3. */
|
||||
/* Get here if ip == 1. */
|
||||
/* Endian independent macros for shifting bytes within registers. */
|
||||
#ifndef __ARMEB__
|
||||
miscopy_8_24: miscopy pull=8 push=24 shiftleft=lsr shiftright=lsl
|
||||
miscopy_16_16: miscopy pull=16 push=16 shiftleft=lsr shiftright=lsl
|
||||
miscopy_24_8: miscopy pull=24 push=8 shiftleft=lsr shiftright=lsl
|
||||
#else /* not __ARMEB__ */
|
||||
miscopy_8_24: miscopy pull=8 push=24 shiftleft=lsl shiftright=lsr
|
||||
miscopy_16_16: miscopy pull=16 push=16 shiftleft=lsl shiftright=lsr
|
||||
miscopy_24_8: miscopy pull=24 push=8 shiftleft=lsl shiftright=lsr
|
||||
#endif /* not __ARMEB__ */
|
||||
#endif /* not __ARM_FEATURE_UNALIGNED */
|
||||
#endif /* memcpy */
|
||||
@@ -49,11 +49,15 @@ static uint32_t pico_flash_bank_get_alignment(void * context) {
|
||||
static void pico_flash_bank_erase(void * context, int bank) {
|
||||
(void)(context);
|
||||
DEBUG_PRINT("erase: bank %d\n", bank);
|
||||
noInterrupts();
|
||||
if (!__isFreeRTOS) {
|
||||
noInterrupts();
|
||||
}
|
||||
rp2040.idleOtherCore();
|
||||
flash_range_erase(PICO_FLASH_BANK_STORAGE_OFFSET + (PICO_FLASH_BANK_SIZE * bank), PICO_FLASH_BANK_SIZE);
|
||||
rp2040.resumeOtherCore();
|
||||
interrupts();
|
||||
if (!__isFreeRTOS) {
|
||||
interrupts();
|
||||
}
|
||||
}
|
||||
|
||||
static void pico_flash_bank_read(void *context, int bank, uint32_t offset, uint8_t *buffer, uint32_t size) {
|
||||
@@ -147,11 +151,15 @@ static void pico_flash_bank_write(void * context, int bank, uint32_t offset, con
|
||||
offset = 0;
|
||||
|
||||
// Now program the entire page
|
||||
noInterrupts();
|
||||
if (!__isFreeRTOS) {
|
||||
noInterrupts();
|
||||
}
|
||||
rp2040.idleOtherCore();
|
||||
flash_range_program(bank_start_pos + (page * FLASH_PAGE_SIZE), page_data, FLASH_PAGE_SIZE);
|
||||
rp2040.resumeOtherCore();
|
||||
interrupts();
|
||||
if (!__isFreeRTOS) {
|
||||
interrupts();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
// Taken from LWIP's inet_chksum.c just to set the -O2 flag
|
||||
|
||||
/*
|
||||
Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
This file is part of the lwIP TCP/IP stack.
|
||||
|
||||
Author: Adam Dunkels <adam@sics.se>
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#include "lwip/inet_chksum.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
|
||||
#pragma GCC optimize ("O2")
|
||||
/**
|
||||
An optimized checksum routine. Basically, it uses loop-unrolling on
|
||||
the checksum loop, treating the head and tail bytes specially, whereas
|
||||
the inner loop acts on 8 bytes at a time.
|
||||
|
||||
@arg start of buffer to be checksummed. May be an odd byte address.
|
||||
@len number of bytes in the buffer to be checksummed.
|
||||
@return host order (!) lwip checksum (non-inverted Internet sum)
|
||||
|
||||
by Curt McDowell, Broadcom Corp. December 8th, 2005
|
||||
*/
|
||||
extern "C" u16_t lwip_standard_chksum(const void *dataptr, int len) {
|
||||
const u8_t *pb = (const u8_t *)dataptr;
|
||||
const u16_t *ps;
|
||||
u16_t t = 0;
|
||||
const u32_t *pl;
|
||||
u32_t sum = 0, tmp;
|
||||
/* starts at odd byte address? */
|
||||
int odd = ((mem_ptr_t)pb & 1);
|
||||
|
||||
if (odd && len > 0) {
|
||||
((u8_t *)&t)[1] = *pb++;
|
||||
len--;
|
||||
}
|
||||
|
||||
ps = (const u16_t *)(const void *)pb;
|
||||
|
||||
if (((mem_ptr_t)ps & 3) && len > 1) {
|
||||
sum += *ps++;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
pl = (const u32_t *)(const void *)ps;
|
||||
|
||||
while (len > 7) {
|
||||
tmp = sum + *pl++; /* ping */
|
||||
if (tmp < sum) {
|
||||
tmp++; /* add back carry */
|
||||
}
|
||||
|
||||
sum = tmp + *pl++; /* pong */
|
||||
if (sum < tmp) {
|
||||
sum++; /* add back carry */
|
||||
}
|
||||
|
||||
len -= 8;
|
||||
}
|
||||
|
||||
/* make room in upper bits */
|
||||
sum = FOLD_U32T(sum);
|
||||
|
||||
ps = (const u16_t *)pl;
|
||||
|
||||
/* 16-bit aligned word remaining? */
|
||||
while (len > 1) {
|
||||
sum += *ps++;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
/* dangling tail byte remaining? */
|
||||
if (len > 0) { /* include odd byte */
|
||||
((u8_t *)&t)[0] = *(const u8_t *)ps;
|
||||
}
|
||||
|
||||
sum += t; /* add end bytes */
|
||||
|
||||
/* Fold 32-bit sum to 16 bits
|
||||
calling this twice is probably faster than if statements... */
|
||||
sum = FOLD_U32T(sum);
|
||||
sum = FOLD_U32T(sum);
|
||||
|
||||
if (odd) {
|
||||
sum = SWAP_BYTES_IN_WORD(sum);
|
||||
}
|
||||
|
||||
return (u16_t)sum;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/times.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#if PICO_ENTER_USB_BOOT_ON_EXIT
|
||||
#include "pico/bootrom.h"
|
||||
#endif
|
||||
#include "pico/time.h"
|
||||
#include "pico/runtime_init.h"
|
||||
|
||||
#if LIB_PICO_PRINTF_PICO
|
||||
#include "pico/printf.h"
|
||||
#else
|
||||
#define weak_raw_printf printf
|
||||
#define weak_raw_vprintf vprintf
|
||||
#endif
|
||||
#if LIB_PICO_STDIO
|
||||
#include "pico/stdio.h"
|
||||
#endif
|
||||
|
||||
#if PICO_ENTER_USB_BOOT_ON_EXIT
|
||||
#include "pico/bootrom.h"
|
||||
#endif
|
||||
|
||||
extern char __StackLimit; /* Set by linker. */
|
||||
|
||||
#define STDIO_HANDLE_STDIN 0
|
||||
#define STDIO_HANDLE_STDOUT 1
|
||||
#define STDIO_HANDLE_STDERR 2
|
||||
|
||||
void __attribute__((noreturn)) __weak _exit(__unused int status) {
|
||||
#if PICO_ENTER_USB_BOOT_ON_EXIT
|
||||
reset_usb_boot(0, 0);
|
||||
#else
|
||||
while (1) {
|
||||
__breakpoint();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
__weak void *_sbrk(int incr) {
|
||||
extern char end; /* Set by linker. */
|
||||
static char *heap_end;
|
||||
char *prev_heap_end;
|
||||
|
||||
if (heap_end == 0) {
|
||||
heap_end = &end;
|
||||
}
|
||||
|
||||
prev_heap_end = heap_end;
|
||||
char *next_heap_end = heap_end + incr;
|
||||
|
||||
if (__builtin_expect(next_heap_end > (&__StackLimit), false)) {
|
||||
#if PICO_USE_OPTIMISTIC_SBRK
|
||||
if (heap_end == &__StackLimit) {
|
||||
// errno = ENOMEM;
|
||||
return (char *) -1;
|
||||
}
|
||||
next_heap_end = &__StackLimit;
|
||||
#else
|
||||
return (char *) -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
heap_end = next_heap_end;
|
||||
return (void *) prev_heap_end;
|
||||
}
|
||||
#if 0
|
||||
static int64_t epoch_time_us_since_boot;
|
||||
|
||||
__weak int _gettimeofday(struct timeval *__restrict tv, __unused void *__restrict tz) {
|
||||
if (tv) {
|
||||
int64_t us_since_epoch = ((int64_t)to_us_since_boot(get_absolute_time())) - epoch_time_us_since_boot;
|
||||
tv->tv_sec = (time_t)(us_since_epoch / 1000000);
|
||||
tv->tv_usec = (suseconds_t)(us_since_epoch % 1000000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
__weak int settimeofday(__unused const struct timeval *tv, __unused const struct timezone *tz) {
|
||||
if (tv) {
|
||||
int64_t us_since_epoch = tv->tv_sec * 1000000 + tv->tv_usec;
|
||||
epoch_time_us_since_boot = (int64_t)to_us_since_boot(get_absolute_time()) - us_since_epoch;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
__weak int _times(struct tms *tms) {
|
||||
#if CLOCKS_PER_SEC >= 1000000
|
||||
tms->tms_utime = (clock_t)(to_us_since_boot(get_absolute_time()) * (CLOCKS_PER_SEC / 1000000));
|
||||
#else
|
||||
tms->tms_utime = (clock_t)(to_us_since_boot(get_absolute_time()) / (1000000 / CLOCKS_PER_SEC));
|
||||
#endif
|
||||
tms->tms_stime = 0;
|
||||
tms->tms_cutime = 0;
|
||||
tms->tms_cstime = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
__weak pid_t _getpid(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
__weak int _kill(__unused pid_t pid, __unused int sig) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int __attribute__((weak)) _read(int handle, char *buffer, int length) {
|
||||
#if LIB_PICO_STDIO
|
||||
if (handle == STDIO_HANDLE_STDIN) {
|
||||
return stdio_get_until(buffer, length, at_the_end_of_time);
|
||||
}
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
int __attribute__((weak)) _write(int handle, char *buffer, int length) {
|
||||
#if LIB_PICO_STDIO
|
||||
if (handle == STDIO_HANDLE_STDOUT || handle == STDIO_HANDLE_STDERR) {
|
||||
stdio_put_string(buffer, length, false, true);
|
||||
return length;
|
||||
}
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
int __attribute__((weak)) _open(__unused const char *fn, __unused int oflag, ...) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int __attribute__((weak)) _close(__unused int fd) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
off_t __attribute__((weak)) _lseek(__unused int fd, __unused off_t pos, __unused int whence) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int __attribute__((weak)) _fstat(__unused int fd, __unused struct stat *buf) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int __attribute__((weak)) _isatty(int fd) {
|
||||
return fd == STDIO_HANDLE_STDIN || fd == STDIO_HANDLE_STDOUT || fd == STDIO_HANDLE_STDERR;
|
||||
}
|
||||
|
||||
// exit is not useful... no desire to pull in __call_exitprocs
|
||||
void exit(int status) {
|
||||
_exit(status);
|
||||
}
|
||||
|
||||
// incorrect warning from GCC 6
|
||||
GCC_Pragma("GCC diagnostic push")
|
||||
GCC_Pragma("GCC diagnostic ignored \"-Wsuggest-attribute=format\"")
|
||||
void __weak __assert_func(const char *file, int line, const char *func, const char *failedexpr) {
|
||||
weak_raw_printf("assertion \"%s\" failed: file \"%s\", line %d%s%s\n",
|
||||
failedexpr, file, line, func ? ", function: " : "",
|
||||
func ? func : "");
|
||||
|
||||
_exit(1);
|
||||
}
|
||||
GCC_Pragma("GCC diagnostic pop")
|
||||
#endif
|
||||
void runtime_init(void) {
|
||||
#ifndef NDEBUG
|
||||
if (__get_current_exception()) {
|
||||
// crap; started in exception handler
|
||||
__breakpoint();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !PICO_RUNTIME_SKIP_INIT_PER_CORE_INSTALL_STACK_GUARD
|
||||
// install core0 stack guard
|
||||
extern char __StackBottom;
|
||||
runtime_init_per_core_install_stack_guard(&__StackBottom);
|
||||
#endif
|
||||
|
||||
// todo maybe we want to do this in the future, but it does stuff like register_tm_clones
|
||||
// which we didn't do in previous SDKs
|
||||
//extern void __libc_init_array(void);
|
||||
//__libc_init_array();
|
||||
|
||||
// ... so instead just do the __preinit_array
|
||||
runtime_run_initializers();
|
||||
// ... and the __init_array
|
||||
extern void (*__init_array_start)(void);
|
||||
extern void (*__init_array_end)(void);
|
||||
for (void (**p)(void) = &__init_array_start; p < &__init_array_end; ++p) {
|
||||
(*p)();
|
||||
}
|
||||
}
|
||||
@@ -6,10 +6,9 @@
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "pico.h"
|
||||
#include "pico/time.h"
|
||||
#include "pico/bootrom.h"
|
||||
#include "pico/binary_info.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
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
Expost absolute mouse HID descriptor and report
|
||||
Taken from @tobozo PR https://github.com/hathach/tinyusb/pull/1363
|
||||
TODO - remove once that PR merged with TinyUSB
|
||||
|
||||
Copyright (c) 2023 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 "tusb.h"
|
||||
#include "class/hid/hid_device.h"
|
||||
|
||||
// Absolute Mouse: same as the Standard (relative) Mouse Report but
|
||||
// with int16_t instead of int8_t for X and Y coordinates.
|
||||
typedef struct TU_ATTR_PACKED {
|
||||
uint8_t buttons; /**< buttons mask for currently pressed buttons in the mouse. */
|
||||
int16_t x; /**< Current x position of the mouse. */
|
||||
int16_t y; /**< Current y position of the mouse. */
|
||||
int8_t wheel; /**< Current delta wheel movement on the mouse. */
|
||||
int8_t pan; // using AC Pan
|
||||
} hid_abs_mouse_report_t;
|
||||
|
||||
|
||||
// Absolute Mouse Report Descriptor Template
|
||||
#define TUD_HID_REPORT_DESC_ABSMOUSE(...) \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_MOUSE ) ,\
|
||||
HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\
|
||||
/* Report ID if any */\
|
||||
__VA_ARGS__ \
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_POINTER ) ,\
|
||||
HID_COLLECTION ( HID_COLLECTION_PHYSICAL ) ,\
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ) ,\
|
||||
HID_USAGE_MIN ( 1 ) ,\
|
||||
HID_USAGE_MAX ( 5 ) ,\
|
||||
HID_LOGICAL_MIN ( 0 ) ,\
|
||||
HID_LOGICAL_MAX ( 1 ) ,\
|
||||
/* Left, Right, Middle, Backward, Forward buttons */ \
|
||||
HID_REPORT_COUNT( 5 ) ,\
|
||||
HID_REPORT_SIZE ( 1 ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
|
||||
/* 3 bit padding */ \
|
||||
HID_REPORT_COUNT( 1 ) ,\
|
||||
HID_REPORT_SIZE ( 3 ) ,\
|
||||
HID_INPUT ( HID_CONSTANT ) ,\
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
|
||||
/* X, Y absolute position [0, 32767] */ \
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_X ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_Y ) ,\
|
||||
HID_LOGICAL_MIN ( 0x00 ) ,\
|
||||
HID_LOGICAL_MAX_N( 0x7FFF, 2 ) ,\
|
||||
HID_REPORT_SIZE ( 16 ) ,\
|
||||
HID_REPORT_COUNT ( 2 ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
|
||||
/* Vertical wheel scroll [-127, 127] */ \
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_WHEEL ) ,\
|
||||
HID_LOGICAL_MIN ( 0x81 ) ,\
|
||||
HID_LOGICAL_MAX ( 0x7f ) ,\
|
||||
HID_REPORT_COUNT( 1 ) ,\
|
||||
HID_REPORT_SIZE ( 8 ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ) ,\
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_CONSUMER ), \
|
||||
/* Horizontal wheel scroll [-127, 127] */ \
|
||||
HID_USAGE_N ( HID_USAGE_CONSUMER_AC_PAN, 2 ), \
|
||||
HID_LOGICAL_MIN ( 0x81 ), \
|
||||
HID_LOGICAL_MAX ( 0x7f ), \
|
||||
HID_REPORT_COUNT( 1 ), \
|
||||
HID_REPORT_SIZE ( 8 ), \
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_RELATIVE ), \
|
||||
HID_COLLECTION_END , \
|
||||
HID_COLLECTION_END \
|
||||
|
||||
|
||||
static inline bool tud_hid_abs_mouse_report(uint8_t report_id,
|
||||
uint8_t buttons, int16_t x, int16_t y, int8_t vertical, int8_t horizontal) {
|
||||
hid_abs_mouse_report_t report = {
|
||||
.buttons = buttons,
|
||||
.x = x,
|
||||
.y = y,
|
||||
.wheel = vertical,
|
||||
.pan = horizontal
|
||||
};
|
||||
|
||||
return tud_hid_n_report(0, report_id, &report, sizeof(report));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
16-bit axis gamepad definition
|
||||
Copyright (c) 2024 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 "tusb.h"
|
||||
#include "class/hid/hid_device.h"
|
||||
|
||||
#define TUD_HID_REPORT_DESC_GAMEPAD16(...) \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_GAMEPAD ) ,\
|
||||
HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\
|
||||
/* Report ID if any */\
|
||||
__VA_ARGS__ \
|
||||
/* 16 bit X, Y, Z, Rz, Rx, Ry (min -32767, max 32767 ) */ \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_X ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_Y ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_Z ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_RZ ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_RX ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_RY ) ,\
|
||||
HID_LOGICAL_MIN_N ( -32767, 2 ) ,\
|
||||
HID_LOGICAL_MAX_N ( 32767, 2 ) ,\
|
||||
HID_REPORT_COUNT ( 6 ) ,\
|
||||
HID_REPORT_SIZE ( 16 ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
|
||||
/* 8 bit DPad/Hat Button Map */ \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_HAT_SWITCH ) ,\
|
||||
HID_LOGICAL_MIN ( 1 ) ,\
|
||||
HID_LOGICAL_MAX ( 8 ) ,\
|
||||
HID_PHYSICAL_MIN ( 0 ) ,\
|
||||
HID_PHYSICAL_MAX_N ( 315, 2 ) ,\
|
||||
HID_REPORT_COUNT ( 1 ) ,\
|
||||
HID_REPORT_SIZE ( 8 ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
|
||||
/* 32 bit Button Map */ \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_BUTTON ) ,\
|
||||
HID_USAGE_MIN ( 1 ) ,\
|
||||
HID_USAGE_MAX ( 32 ) ,\
|
||||
HID_LOGICAL_MIN ( 0 ) ,\
|
||||
HID_LOGICAL_MAX ( 1 ) ,\
|
||||
HID_REPORT_COUNT ( 32 ) ,\
|
||||
HID_REPORT_SIZE ( 1 ) ,\
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
|
||||
HID_COLLECTION_END \
|
||||
|
||||
// HID Gamepad Protocol Report.
|
||||
typedef struct TU_ATTR_PACKED {
|
||||
int16_t x; ///< Delta x movement of left analog-stick
|
||||
int16_t y; ///< Delta y movement of left analog-stick
|
||||
int16_t z; ///< Delta z movement of right analog-joystick
|
||||
int16_t rz; ///< Delta Rz movement of right analog-joystick
|
||||
int16_t rx; ///< Delta Rx movement of analog left trigger
|
||||
int16_t ry; ///< Delta Ry movement of analog right trigger
|
||||
uint8_t hat; ///< Buttons mask for currently pressed buttons in the DPad/hat
|
||||
uint32_t buttons; ///< Buttons mask for currently pressed buttons
|
||||
} hid_gamepad16_report_t;
|
||||
@@ -23,8 +23,8 @@
|
||||
.program tone2
|
||||
.side_set 1 opt
|
||||
|
||||
pull ; TXFIFO -> OSR, or X -> OSR if no new period
|
||||
mov x, osr ; OSR -> X
|
||||
; pull ; TXFIFO -> OSR, or X -> OSR if no new period
|
||||
; mov x, osr ; OSR -> X
|
||||
|
||||
high:
|
||||
pull noblock ; Potentially grab new HALFCYCLECOUNT, OTW copy from backup in X
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// This file is autogenerated by pioasm; do not edit! //
|
||||
// -------------------------------------------------- //
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !PICO_NO_HARDWARE
|
||||
#include "hardware/pio.h"
|
||||
#endif
|
||||
@@ -11,27 +13,30 @@
|
||||
// ----- //
|
||||
|
||||
#define tone2_wrap_target 0
|
||||
#define tone2_wrap 8
|
||||
#define tone2_wrap 6
|
||||
#define tone2_pio_version 0
|
||||
|
||||
static const uint16_t tone2_program_instructions[] = {
|
||||
// .wrap_target
|
||||
0x80a0, // 0: pull block
|
||||
0x8080, // 0: pull noblock
|
||||
0xa027, // 1: mov x, osr
|
||||
0x8080, // 2: pull noblock
|
||||
0xa027, // 3: mov x, osr
|
||||
0xb847, // 4: mov y, osr side 1
|
||||
0xb847, // 2: mov y, osr side 1
|
||||
0x0083, // 3: jmp y--, 3
|
||||
0xb047, // 4: mov y, osr side 0
|
||||
0x0085, // 5: jmp y--, 5
|
||||
0xb047, // 6: mov y, osr side 0
|
||||
0x0087, // 7: jmp y--, 7
|
||||
0x0002, // 8: jmp 2
|
||||
0x0000, // 6: jmp 0
|
||||
// .wrap
|
||||
};
|
||||
|
||||
#if !PICO_NO_HARDWARE
|
||||
static const struct pio_program tone2_program = {
|
||||
.instructions = tone2_program_instructions,
|
||||
.length = 9,
|
||||
.length = 7,
|
||||
.origin = -1,
|
||||
.pio_version = 0,
|
||||
#if PICO_PIO_VERSION > 0
|
||||
.used_gpio_ranges = 0x0
|
||||
#endif
|
||||
};
|
||||
|
||||
static inline pio_sm_config tone2_program_get_default_config(uint offset) {
|
||||
|
||||
@@ -30,7 +30,7 @@ void __clearADCPin(pin_size_t p);
|
||||
|
||||
static uint32_t analogScale = 255;
|
||||
static uint32_t analogFreq = 1000;
|
||||
static uint32_t pwmInitted = 0;
|
||||
static uint64_t pwmInitted = 0;
|
||||
static bool scaleInitted = false;
|
||||
static bool adcInitted = false;
|
||||
static uint16_t analogWritePseudoScale = 1;
|
||||
@@ -79,7 +79,7 @@ extern "C" void analogWriteResolution(int res) {
|
||||
extern "C" void analogWrite(pin_size_t pin, int val) {
|
||||
CoreMutex m(&_dacMutex);
|
||||
|
||||
if ((pin > 29) || !m) {
|
||||
if ((pin >= __GPIOCNT) || !m) {
|
||||
DEBUGCORE("ERROR: Illegal analogWrite pin (%d)\n", pin);
|
||||
return;
|
||||
}
|
||||
@@ -101,12 +101,12 @@ extern "C" void analogWrite(pin_size_t pin, int val) {
|
||||
}
|
||||
scaleInitted = true;
|
||||
}
|
||||
if (!(pwmInitted & (1 << pwm_gpio_to_slice_num(pin)))) {
|
||||
if (!(pwmInitted & (1LL << 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 - 1);
|
||||
pwm_init(pwm_gpio_to_slice_num(pin), &c, true);
|
||||
pwmInitted |= 1 << pwm_gpio_to_slice_num(pin);
|
||||
pwmInitted |= 1LL << pwm_gpio_to_slice_num(pin);
|
||||
}
|
||||
|
||||
val <<= analogWritePseudoScale;
|
||||
@@ -125,17 +125,17 @@ extern "C" void analogWrite(pin_size_t pin, int val) {
|
||||
auto_init_mutex(_adcMutex);
|
||||
static uint8_t _readBits = 10;
|
||||
static uint8_t _lastADCMux = 0;
|
||||
static uint32_t _adcGPIOInit = 0;
|
||||
static uint64_t _adcGPIOInit = 0;
|
||||
|
||||
void __clearADCPin(pin_size_t p) {
|
||||
_adcGPIOInit &= ~(1 << p);
|
||||
_adcGPIOInit &= ~(1LL << p);
|
||||
}
|
||||
|
||||
extern "C" int analogRead(pin_size_t pin) {
|
||||
CoreMutex m(&_adcMutex);
|
||||
|
||||
pin_size_t maxPin = max(A0, A3);
|
||||
pin_size_t minPin = min(A0, A3);
|
||||
pin_size_t maxPin = __GPIOCNT;
|
||||
pin_size_t minPin = __FIRSTANALOGGPIO;
|
||||
|
||||
if ((pin < minPin) || (pin > maxPin) || !m) {
|
||||
DEBUGCORE("ERROR: Illegal analogRead pin (%d)\n", pin);
|
||||
@@ -145,9 +145,9 @@ extern "C" int analogRead(pin_size_t pin) {
|
||||
adc_init();
|
||||
adcInitted = true;
|
||||
}
|
||||
if (!(_adcGPIOInit & (1 << pin))) {
|
||||
if (!(_adcGPIOInit & (1LL << pin))) {
|
||||
adc_gpio_init(pin);
|
||||
_adcGPIOInit |= 1 << pin;
|
||||
_adcGPIOInit |= 1LL << pin;
|
||||
}
|
||||
if (_lastADCMux != pin) {
|
||||
adc_select_input(pin - minPin);
|
||||
@@ -169,7 +169,7 @@ extern "C" float analogReadTemp(float vref) {
|
||||
_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
|
||||
adc_select_input(__GPIOCNT - __FIRSTANALOGGPIO); // Temperature sensor
|
||||
int v = adc_read();
|
||||
adc_set_temp_sensor_enabled(false);
|
||||
float t = 27.0f - ((v * vref / 4096.0f) - 0.706f) / 0.001721f; // From the datasheet
|
||||
|
||||
@@ -23,10 +23,15 @@
|
||||
|
||||
extern void __clearADCPin(pin_size_t p);
|
||||
|
||||
static PinMode _pm[30];
|
||||
static PinMode _pm[__GPIOCNT];
|
||||
|
||||
extern "C" void pinMode(pin_size_t ulPin, PinMode ulMode) __attribute__((weak, alias("__pinMode")));
|
||||
extern "C" void __pinMode(pin_size_t ulPin, PinMode ulMode) {
|
||||
if (ulPin >= __GPIOCNT) {
|
||||
DEBUGCORE("ERROR: Illegal pin in pinMode (%d)\n", ulPin);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ulMode) {
|
||||
case INPUT:
|
||||
gpio_init(ulPin);
|
||||
@@ -72,20 +77,16 @@ extern "C" void __pinMode(pin_size_t ulPin, PinMode ulMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ulPin > 29) {
|
||||
DEBUGCORE("ERROR: Illegal pin in pinMode (%d)\n", ulPin);
|
||||
return;
|
||||
}
|
||||
_pm[ulPin] = ulMode;
|
||||
|
||||
if ((ulPin >= std::min(A0, A3)) && (ulPin <= std::max(A0, A3))) {
|
||||
if (ulPin >= __FIRSTANALOGGPIO) {
|
||||
__clearADCPin(ulPin);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void digitalWrite(pin_size_t ulPin, PinStatus ulVal) __attribute__((weak, alias("__digitalWrite")));
|
||||
extern "C" void __digitalWrite(pin_size_t ulPin, PinStatus ulVal) {
|
||||
if (ulPin > 29) {
|
||||
if (ulPin >= __GPIOCNT) {
|
||||
DEBUGCORE("ERROR: Illegal pin in pinMode (%d)\n", ulPin);
|
||||
return;
|
||||
}
|
||||
@@ -109,7 +110,7 @@ extern "C" void __digitalWrite(pin_size_t ulPin, PinStatus ulVal) {
|
||||
|
||||
extern "C" PinStatus digitalRead(pin_size_t ulPin) __attribute__((weak, alias("__digitalRead")));
|
||||
extern "C" PinStatus __digitalRead(pin_size_t ulPin) {
|
||||
if (ulPin > 29) {
|
||||
if (ulPin >= __GPIOCNT) {
|
||||
DEBUGCORE("ERROR: Illegal pin in digitalRead (%d)\n", ulPin);
|
||||
return LOW;
|
||||
}
|
||||
|
||||
@@ -23,29 +23,40 @@
|
||||
#include <hardware/gpio.h>
|
||||
#include <hardware/sync.h>
|
||||
#include <map>
|
||||
#include "_freertos.h"
|
||||
|
||||
|
||||
// Support nested IRQ disable/re-enable
|
||||
#ifndef maxIRQs
|
||||
#define maxIRQs 15
|
||||
#endif
|
||||
static uint32_t _irqStackTop[2] = { 0, 0 };
|
||||
static uint32_t _irqStack[2][maxIRQs];
|
||||
|
||||
extern "C" void interrupts() {
|
||||
auto core = get_core_num();
|
||||
if (!_irqStackTop[core]) {
|
||||
// ERROR
|
||||
return;
|
||||
if (__freeRTOSinitted) {
|
||||
__freertos_task_exit_critical();
|
||||
} else {
|
||||
auto core = get_core_num();
|
||||
if (!_irqStackTop[core]) {
|
||||
// ERROR
|
||||
return;
|
||||
}
|
||||
restore_interrupts(_irqStack[core][--_irqStackTop[core]]);
|
||||
}
|
||||
restore_interrupts(_irqStack[core][--_irqStackTop[core]]);
|
||||
}
|
||||
|
||||
extern "C" void noInterrupts() {
|
||||
auto core = get_core_num();
|
||||
if (_irqStackTop[core] == maxIRQs) {
|
||||
// ERROR
|
||||
panic("IRQ stack overflow");
|
||||
if (__freeRTOSinitted) {
|
||||
__freertos_task_enter_critical();
|
||||
} else {
|
||||
auto core = get_core_num();
|
||||
if (_irqStackTop[core] == maxIRQs) {
|
||||
// ERROR
|
||||
panic("IRQ stack overflow");
|
||||
}
|
||||
_irqStack[core][_irqStackTop[core]++] = save_and_disable_interrupts();
|
||||
}
|
||||
|
||||
_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
|
||||
@@ -76,15 +87,22 @@ 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, (FromISR | DebugEnable));
|
||||
if (m) {
|
||||
auto irq = _map.find(gpio);
|
||||
if (irq != _map.end()) {
|
||||
auto cb = irq->second;
|
||||
cb.callback();
|
||||
CBInfo *cb;
|
||||
{
|
||||
CoreMutex m(&_irqMutex);
|
||||
if (m) {
|
||||
auto irq = _map.find(gpio);
|
||||
if (irq == _map.end()) {
|
||||
return;
|
||||
}
|
||||
cb = &irq->second;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
cb->callback();
|
||||
}
|
||||
|
||||
// To be called when appropriately protected w/IRQ and mutex protects
|
||||
|
||||
@@ -26,7 +26,7 @@ extern "C" unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeo
|
||||
uint64_t start = time_us_64();
|
||||
uint64_t abort = start + timeout;
|
||||
|
||||
if (pin > 29) {
|
||||
if (pin >= __GPIOCNT) {
|
||||
DEBUGCORE("ERROR: Illegal pin in pulseIn (%d)\n", pin);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -24,11 +24,11 @@
|
||||
extern "C" uint8_t shiftIn(pin_size_t dataPin, pin_size_t clockPin, BitOrder bitOrder) {
|
||||
uint8_t value = 0;
|
||||
uint8_t i;
|
||||
if (dataPin > 29) {
|
||||
if (dataPin >= __GPIOCNT) {
|
||||
DEBUGCORE("ERROR: Illegal dataPin in shiftIn (%d)\n", dataPin);
|
||||
return 0;
|
||||
}
|
||||
if (clockPin > 29) {
|
||||
if (clockPin >= __GPIOCNT) {
|
||||
DEBUGCORE("ERROR: Illegal clockPin in shiftIn (%d)\n", clockPin);
|
||||
return 0;
|
||||
}
|
||||
@@ -46,11 +46,11 @@ extern "C" uint8_t shiftIn(pin_size_t dataPin, pin_size_t clockPin, BitOrder bit
|
||||
|
||||
extern "C" void shiftOut(pin_size_t dataPin, pin_size_t clockPin, BitOrder bitOrder, uint8_t val) {
|
||||
uint8_t i;
|
||||
if (dataPin > 29) {
|
||||
if (dataPin >= __GPIOCNT) {
|
||||
DEBUGCORE("ERROR: Illegal dataPin in shiftOut (%d)\n", dataPin);
|
||||
return;
|
||||
}
|
||||
if (clockPin > 29) {
|
||||
if (clockPin >= __GPIOCNT) {
|
||||
DEBUGCORE("ERROR: Illegal clockPin in shiftOut (%d)\n", clockPin);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -66,10 +66,14 @@ typedef enum {
|
||||
} wl_status_t;
|
||||
|
||||
/* Encryption modes */
|
||||
enum wl_enc_type { /* Values map to 802.11 encryption suites... */
|
||||
enum wl_enc_type { /* Values map to 802.11 Cipher Algorithm Identifier */
|
||||
ENC_TYPE_WEP = 5,
|
||||
ENC_TYPE_TKIP = 2,
|
||||
ENC_TYPE_WPA = ENC_TYPE_TKIP,
|
||||
ENC_TYPE_CCMP = 4,
|
||||
ENC_TYPE_WPA2 = ENC_TYPE_CCMP,
|
||||
ENC_TYPE_GCMP = 6,
|
||||
ENC_TYPE_WPA3 = ENC_TYPE_GCMP,
|
||||
/* ... except these two, 7 and 8 are reserved in 802.11-2007 */
|
||||
ENC_TYPE_NONE = 7,
|
||||
ENC_TYPE_AUTO = 8,
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
Bluetooth Audio (A2DP Source and Sink)
|
||||
======================================
|
||||
|
||||
The PicoW can be used as a Bluetooth Audio sink or source with the ``BluetoothAudio`` class.
|
||||
Operation is generally handled "automatically" in the background so while the audio is
|
||||
playing or streaming the main application can perform other operations (like displaying
|
||||
playback info, polling buttons for controls, etc.)
|
||||
|
||||
.. code :: cpp
|
||||
|
||||
#include <BluetoothAudio.h>
|
||||
...
|
||||
|
||||
**Note about CPU usage:** Bluetooth SBC audio is a compressed format. That means
|
||||
that it takes non-trivial amounts of CPU to compress on send, or decompress on receive.
|
||||
Transmitting precompressed audio from, say, MP3 or AAC, requires first decompressing
|
||||
the source file into raw PCM and then re-compressing them in the SBC format. You may
|
||||
want to consider overclocking in this case to avoid underflow.
|
||||
|
||||
A2DPSink
|
||||
--------
|
||||
|
||||
This class implements slave sink-mode operation with player control (play, pause, etc.) and
|
||||
can play the received and decoded SBC audio to ``PWMAudio``, ``I2S``, or a user-created
|
||||
`BluetoothAudioConsumer`` class.
|
||||
|
||||
The ``A2DPSink.ino`` example demonstrates turning a PicoW into a Bluetooth headset with
|
||||
``PWMAudio``.
|
||||
|
||||
A2DPSource
|
||||
-----------
|
||||
|
||||
This class implements a master source-mode SBC Bluetooth A2DP audio connection which
|
||||
transmits audio using the standard ``Stream`` interface (like ``I2S`` or ``PWMAudio``.
|
||||
The main application connects to a Bluetooth speaker and then writes samples into a buffer
|
||||
that's automatically transmitted behind the scenes.
|
||||
|
||||
The ``A2DPSource.ino`` example shows how to connect to a Bluetooth speaker, transmit
|
||||
data, and respond to commands from the speaker.
|
||||
+2
-2
@@ -12,7 +12,7 @@ need to be periodically sampled to be read by applications, easily, such as:
|
||||
* Light dependent resistors (LDR), etc.
|
||||
|
||||
|
||||
Up to 4 analog samples can be recorded by the hardware (``A0`` ... ``A4``), and all
|
||||
Up to 4 analog samples can be recorded by the hardware (``A0`` ... ``A3``), and all
|
||||
recording is done at 16-bit levels (but be aware that the ADC in the Pico will only
|
||||
ever return values between 0...4095).
|
||||
|
||||
@@ -29,7 +29,7 @@ ADC Input API
|
||||
ADCInput(pin0 [, pin1, pin2, pin3])
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Creates an ADC input object which will record the pins specified in the code.
|
||||
Only pins ``A0`` ... ``A4`` can be used, and they must be specified in increasing
|
||||
Only pins ``A0`` ... ``A3`` can be used, and they must be specified in increasing
|
||||
order (i.e. ``ADCInput(A0, A1);`` is valid, but ``ADCInput(A1, A0)`` is not.
|
||||
|
||||
bool setBuffers(size_t buffers, size_t bufferWords)
|
||||
|
||||
+4
-2
@@ -30,7 +30,7 @@ Analog Outputs
|
||||
--------------
|
||||
The RP2040 does not have any onboard DACs, so analog outputs are
|
||||
simulated using the standard method of using pulse width modulation
|
||||
(PWM) using the RP20400's hardware PWM units.
|
||||
(PWM) using the RP2040's hardware PWM units.
|
||||
|
||||
While up to 16 PWM channels can be generated, they are not independent
|
||||
and there are significant restrictions as to allowed pins in parallel.
|
||||
@@ -40,7 +40,9 @@ Analog Output Restrictions
|
||||
--------------------------
|
||||
|
||||
The PWM generator source clock restricts the legal combinations of
|
||||
frequency and ranges. For example, at 1MHz only about 6 bits of range
|
||||
frequency and ranges.
|
||||
At a CPU frequency of 133MHz, the 16 bit maximum range decreases by 1 bit for every doubling of the default PWM frequency of 1 kHz.
|
||||
For example, at 1MHz only about 6 bits of range
|
||||
are possible. When you define an ``analogWriteFreq`` and ``analogWriteRange``
|
||||
that can't be fulfilled by the hardware, the frequency will be preserved
|
||||
but the accuracy (range) will be reduced automatically. Your code will
|
||||
|
||||
@@ -120,7 +120,7 @@ Valid values for min and max are `BR_TLS10`, `BR_TLS11`, `BR_TLS12`. Min and ma
|
||||
|
||||
|
||||
ESP32 Compatibility
|
||||
===================
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
Simple ESP32 ``WiFiClientSecure`` compatibility is built-in, allow for some sketches to run without any modification.
|
||||
The following methods are implemented:
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ Similar to the `BearSSL::WiFiClientSecure` method, sets the receive and transmit
|
||||
Setting Server Certificates
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
TLS servers require a certificate identifying itself and containing its public key, and a private key they will use to encrypt information with. The application author is responsible for generating this certificate and key, either using a self-signed generator or using a commercial certification authority. **Do not re-use the certificates included in the examples provided.**
|
||||
TLS servers require a certificate identifying itself and containing its public key, and a private key they will use to encrypt information with. The application author is responsible for generating this certificate and key, either using a self-signed generator or using a commercial certification authority. **Do not reuse the certificates included in the examples provided.**
|
||||
|
||||
This example command will generate a RSA 2048-bit key and certificate:
|
||||
|
||||
|
||||
+7
-5
@@ -2,9 +2,6 @@ Bluetooth on PicoW Support
|
||||
==========================
|
||||
|
||||
As of the Pico-SDK version 1.5.0, the PicoW has **BETA** Bluetooth support.
|
||||
So, since this core builds off the SDK the best that can be suggested it
|
||||
that we have **ALPHA** Bluetooth support. As such, bug reports are welcome,
|
||||
but Pull Requests fixing problems you find are seriously appreciated.
|
||||
|
||||
Enabling Bluetooth
|
||||
------------------
|
||||
@@ -24,6 +21,11 @@ Bluetooth Low Energy (BLE) HID device using the same API as their USB versions.
|
||||
The ``SerialBT`` library implements a very simple SPP (Serial Port Profile)
|
||||
Serial-compatible port.
|
||||
|
||||
Connect and use Bluetooth peripherals with the PicoW using the
|
||||
``BluetoothHIDMaster`` library.
|
||||
|
||||
``BluetoothAudio`` (A2DP) is also supported, both sink and source.
|
||||
|
||||
Writing Custom Bluetooth Applications
|
||||
-------------------------------------
|
||||
You may also write full applications using the ``BTStack`` standard callback
|
||||
@@ -40,8 +42,8 @@ For many BTStack examples, you simply need call the included
|
||||
called afterwards to start processing (in the background).
|
||||
|
||||
You will also need to acquire the BT ``async_context`` system lock before
|
||||
calling any BTStack APIs. See the ``libraries/PicoBluetoothHID`` helper
|
||||
class for an example of how to do this.
|
||||
calling any BTStack APIs. ``__lockBluetooth`` and ``unlockBluetooth`` are
|
||||
provided in the PicoW variant code.
|
||||
|
||||
Note that if you need to modify the system ``btstack_config.h`` file, do so
|
||||
in the ``tools/libpico`` directory and rebuild the Pico SDK static library.
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
BOOTSEL Button
|
||||
==============
|
||||
|
||||
The BOOTSEL button on the Pico is not connected to a standard GPIO, so
|
||||
it cannot be read using the usual ``digitalRead`` function. It **can**,
|
||||
however, be read using a special (relatively slow) method.
|
||||
|
||||
The ``BOOTSEL`` object implements a simple way of reading the BOOTSEL
|
||||
button. Simply use the object ``BOOTSEL`` as a boolean (as a conditional
|
||||
in an ``if`` or ``while``, or assigning to a ``bool``):
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
// Print "BEEP" if the BOOTSEL button is pressed
|
||||
if (BOOTSEL) {
|
||||
Serial.println("BEEP!");
|
||||
// Wait until BOOTSEL is released
|
||||
while (BOOTSEL) {
|
||||
delay(1);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -54,9 +54,9 @@ author = u'Earle F. Philhower, III'
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = u'3.2.0'
|
||||
version = u'4.2.0'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = u'3.2.0'
|
||||
release = u'4.2.0'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
||||
+41
-2
@@ -10,7 +10,8 @@ Contributing to the Core (Pull Requests)
|
||||
----------------------------------------
|
||||
|
||||
We use the standard GitHub Pull Request model. If you're unfamiliar with it,
|
||||
this `guide <https://www.freecodecamp.org/news/how-to-make-your-first-pull-request-on-github-3/>` gives a simple overview of the process.
|
||||
this `guide <https://www.freecodecamp.org/news/how-to-make-your-first-pull-request-on-github-3/>`__
|
||||
gives a simple overview of the process.
|
||||
|
||||
All pull requests have to pass a set of Continuous Integration (CI) checks
|
||||
which help make sure the code compiles under different configurations and has
|
||||
@@ -84,10 +85,47 @@ code that only runs on this core, use the following define.
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
#if defined(ARDUINO_ARCH_RP2040)
|
||||
#if defined(ARDUINO_ARCH_RP2040) && !defined(__MBED__)
|
||||
~~~ your changes ~~~
|
||||
#endif
|
||||
|
||||
Identifying RP2040, RP2530A, or RP2350B
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To check if a board is an original RP2040
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
#if defined(PICO_RP2040)
|
||||
...OG Pico code...
|
||||
#endif
|
||||
|
||||
For RP2350(A or B):
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
#if defined(PICO_RP2350)
|
||||
...Pico 2 code...
|
||||
#endif
|
||||
|
||||
For only RP2350A variants (using the compile options, not the onboard ID register):
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
#if defined(PICO_RP2350) && !defined(PICO_RP2350B)
|
||||
...RP2350A only code...
|
||||
#endif
|
||||
|
||||
For only RP2350B variants (again, at compile time as identified by the selected board
|
||||
and not the chip ID register):
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
#if defined(PICO_RP2350B)
|
||||
...48-GPIO version code here
|
||||
#endif
|
||||
|
||||
|
||||
Library Architectures
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -97,3 +135,4 @@ not know your new code is compatible here.
|
||||
|
||||
Add ``rp2040`` to ``architectures`` (in ``library.properties``) and
|
||||
``"rp2040"`` to ``platforms[]`` (in ``library.json``) to let the tools know.
|
||||
Note that even the RP2350 is identified as ``rp2040`` for this purpose.
|
||||
|
||||
@@ -6,6 +6,10 @@ Board-Specific Pins
|
||||
The Raspberry Pi Pico RP2040 chip supports up to 30 digital I/O pins,
|
||||
however not all boards provide access to all pins.
|
||||
|
||||
Pin Notation
|
||||
------------
|
||||
When using Analog or Digital I/Os, if you supply an integer it specifies the RP2040 GPIO pin to use. Using Dx or Ax notation (for example, D4 or A3) may be necessary on boards without a direct PCB pin to GPIO mapping.
|
||||
|
||||
Input Modes
|
||||
-----------
|
||||
The Raspberry Pi Pico has 3 Input modes settings for use with `pinMode`: `INPUT`, `INPUT_PULLUP` and `INPUT_PULLDOWN`
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
EthernetLWIP (Wired Ethernet) Support
|
||||
=====================================
|
||||
|
||||
Wired Ethernet interfaces are supported for all the internal networking
|
||||
libraries (``WiFiClient``, ``WiFiClientSecure``, ``WiFiServer``,
|
||||
``WiFiServerSecure``, ``WiFiUDP``, ``WebServer``, ``Updater``,
|
||||
``HTTPClient``, etc.).
|
||||
|
||||
Using these wired interfaces is very similar to using the Pico-W WiFi
|
||||
so most examples in the core only require minor modifications to use
|
||||
a wired interface.
|
||||
|
||||
Supported Wired Ethernet Modules
|
||||
--------------------------------
|
||||
|
||||
* Wiznet W5100(s)
|
||||
|
||||
* Wiznet W5500
|
||||
|
||||
* ENC28J60
|
||||
|
||||
|
||||
Enabling Wired Ethernet
|
||||
-----------------------
|
||||
|
||||
Simply replace the WiFi include at the top with:
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
#include <W5500lwIP.h> // Or W5100lwIP.h or ENC28J60.h
|
||||
|
||||
|
||||
And add a global Ethernet object of the same type:
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
Wiznet5500lwIP eth(1); // Parameter is the Chip Select pin
|
||||
|
||||
In your ``setup()`` you may adjust the SPI pins you're using to
|
||||
match your hardware (be sure they are legal for the RP2040!), or
|
||||
skip this if you're using the default ones:
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
void setup() {
|
||||
SPI.setRX(0);
|
||||
SPI.setCS(1);
|
||||
SPI.setSCK(2);
|
||||
SPI.setTX(3);
|
||||
....
|
||||
}
|
||||
|
||||
And finally replace the ``WiFi.begin()`` and ``WiFi.connected()``
|
||||
calls with ``eth.begin()`` and ``eth.connected()``:
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
void setup() {
|
||||
....
|
||||
// WiFi.begin(SSID, PASS)
|
||||
eth.begin();
|
||||
|
||||
//while (!WiFi.connected()) {
|
||||
while (!eth.connected()) {
|
||||
Serial.print(".");
|
||||
}
|
||||
|
||||
Serial.print("IP address: ");
|
||||
//Serial.println(WiFi.localIP());
|
||||
Serial.println(eth.localIP());
|
||||
|
||||
....
|
||||
}
|
||||
|
||||
Adjusting LWIP Polling
|
||||
----------------------
|
||||
|
||||
LWIP operates in a polling mode for the wired Ethernet devices. By default it will run
|
||||
every 20ms, meaning that on average it will take half that time (10ms) before a packet
|
||||
received in the Ethernet module is received and operated upon by the Pico. This gives
|
||||
very low CPU utilization but in some cases this latency can affect performance.
|
||||
|
||||
Adding a call to ``lwipPollingPeriod(XXX)`` (where ``XXXX`` is the polling period in
|
||||
milliseconds) can adjust this setting on the fly. Note that if you set it too low, the
|
||||
Pico may not have enough time to service the Ethernet port before the timer fires again,
|
||||
leading to a lock up and hang.
|
||||
|
||||
|
||||
Using Interrupt-Driven Handling
|
||||
-------------------------------
|
||||
|
||||
The WizNet and ENC28J60 devices support generating an interrupt when a packet is received,
|
||||
removing the need for polling and decreasing latency. Simply specify the SPI object to use and the
|
||||
interrupt pin when instantiating the Ethernet object:
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
#include <W5100lwIP.h>
|
||||
Wiznet5100lwIP eth(SS /* Chip Select*/, SPI /* SPI interface */, 17 /* Interrupt GPIO */ );
|
||||
|
||||
|
||||
Adjusting SPI Speed
|
||||
-------------------
|
||||
|
||||
By default a 4MHz clock will be used to clock data into and out of the Ethernet module.
|
||||
Depending on the module and your wiring, a higher SPI clock may increase performance (but
|
||||
too high of a clock will cause communications problems or hangs).
|
||||
|
||||
This value may be adjusted using the ``eth.setSPISpeed(hz)`` call **before** starting the
|
||||
device. (You may also use custom ``SPISettings`` instead via ``eth.setSPISettings(spis)```)
|
||||
|
||||
For example, to set the W5500 to use a 30MHZ clock:
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
#include <W5500lwIP.h>
|
||||
Wiznet5500lwIP eth(1);
|
||||
|
||||
void setup() {
|
||||
eth.setSPISpeed(30000000);
|
||||
lwipPollingPeriod(3);
|
||||
...
|
||||
eth.begin();
|
||||
...
|
||||
}
|
||||
|
||||
Using the WIZnet W5100S-EVB-Pico
|
||||
--------------------------------
|
||||
|
||||
You can use the onboard Ethernet chip with these drivers, in interrupt mode, by utilizing the following options:
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
#include <W5100lwIP.h>
|
||||
Wiznet5100lwIP eth(17, SPI, 21); // Note chip select is **17**
|
||||
|
||||
void setup() {
|
||||
// Set SPI to the onboard Wiznet chip
|
||||
SPI.setRX(16);
|
||||
SPI.setCS(17);
|
||||
SPI.setSCK(18);
|
||||
SPI.setTX(19);
|
||||
...
|
||||
eth.begin();
|
||||
...
|
||||
}
|
||||
|
||||
Example Code
|
||||
------------
|
||||
|
||||
The following examples allow switching between WiFi and Ethernet:
|
||||
|
||||
* ``WebServer/AdvancedWebServer``
|
||||
|
||||
* ``HTTPClient/BasicHTTPSClient``
|
||||
|
||||
Caveats
|
||||
-------
|
||||
|
||||
The same restrictions for ``WiFi`` apply to these Ethernet classes, namely:
|
||||
|
||||
* Only core 0 may run any networking related code.
|
||||
|
||||
* In FreeRTOS, only the ``setup`` and ``loop`` task can call networking libraries, not any tasks.
|
||||
|
||||
Special Thanks
|
||||
--------------
|
||||
|
||||
* LWIPEthernet classes come from the ESP8266 Arduino team
|
||||
|
||||
* Individual Ethernet drivers were written by Nicholas Humfrey
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
FatFSUSB
|
||||
========
|
||||
|
||||
When the onboard flash memory is used as a ``FatFS`` filesystem, the
|
||||
``FatFSUSB`` can be used to allow exporting it to a PC as a standard
|
||||
memory stick. The PC can then access, add, and remove files as if the
|
||||
Pico was a USB memory stick, and upon ejection the Pico can access
|
||||
any new files just as if it made them itself.
|
||||
|
||||
(Note, if you are using LittleFS then you need to use ``SingleFileDrive``
|
||||
to export a single file, not this class, because the PC does not
|
||||
understand the LittleFS disk format.)
|
||||
|
||||
Callbacks, Interrupt Safety, and File Operations
|
||||
------------------------------------------------
|
||||
|
||||
The ``FatFSUSB`` library allows your application to get a callback
|
||||
when a PC attempts to mount or unmount the Pico as a FAT drive.
|
||||
|
||||
When the drive is being used by the Pico (i.e. any ``File`` is open for
|
||||
read or write, the ``FatFS`` is not ``end()`` -ed and still mounted,
|
||||
etc.) the host may not access it. Conversely, while the host PC is
|
||||
connected to the drive no ``FatFS`` access by the Pico is allowed.
|
||||
|
||||
Your ``driveReady`` callback will be called when the PC attempts to mount
|
||||
the drive. If you have any files open, then this callback can report back
|
||||
that the drive is not yet ready. When you complete file processing, the PC
|
||||
can re-attempt to mount the drive and your callback can return ``true`` .
|
||||
|
||||
The ``onPlug`` callback will generally ``FatFS.end()`` and set a
|
||||
global flag letting your application know not to touch the filesystem until
|
||||
the flag is cleared by the ``onUnplug`` callback (which will also do a
|
||||
``FatFS.begin()`` call).
|
||||
|
||||
Failing to close all files **and** ``FatFS.end()`` before granting the
|
||||
PC access to flash memory will result in corruption. FAT does not allow multiple
|
||||
writers to access the same drive. Even mounting and only reading files from
|
||||
the PC may cause hidden writes (things like access time, etc.) which would
|
||||
also cause corruption.
|
||||
|
||||
See the included ``Listfiles-USB`` sketch for an example of working with
|
||||
these limitations.
|
||||
+131
-55
@@ -18,12 +18,12 @@ The following diagram shows the flash layout used in Arduino-Pico:
|
||||
|
||||
::
|
||||
|
||||
|---------------------|-------------|----|
|
||||
^ ^ ^
|
||||
Sketch File system EEPROM
|
||||
|----|---------------------|-------------|----|
|
||||
^ ^ ^ ^
|
||||
OTA Sketch File system EEPROM
|
||||
|
||||
The file system size is configurable via the IDE menus, rom 64k up to 15MB
|
||||
(assuming you have an RP2040 boad with that much flash)
|
||||
The file system size is configurable via the IDE menus, from 64k up to 15MB
|
||||
(assuming you have an RP2040 board with that much flash)
|
||||
|
||||
**Note:** to use any of file system functions in the sketch, add the
|
||||
following include to the sketch:
|
||||
@@ -33,31 +33,68 @@ following include to the sketch:
|
||||
#include "LittleFS.h" // LittleFS is declared
|
||||
// #include <SDFS.h>
|
||||
// #include <SD.h>
|
||||
// #include <FatFS.h>
|
||||
|
||||
|
||||
Compatible Filesystem APIs
|
||||
--------------------------
|
||||
|
||||
LittleFS is an onboard filesystem that sets asidesome program flash for
|
||||
LittleFS is an onboard filesystem that sets aside some program flash for
|
||||
use as a filesystem without requiring any external hardware.
|
||||
|
||||
SDFS is a filesystem for SD cards, based on [SdFat 2.0](https://github.com/earlephilhower/ESP8266SdFat).
|
||||
It supports FAT16 and FAT32 formatted cards, and requires an external
|
||||
SD card reader.
|
||||
|
||||
SD is the Arduino supported, somewhat old and limited SD card filesystem.
|
||||
SD is the Arduino-supported, somewhat old and limited SD card filesystem.
|
||||
It is recommended to use SDFS for new applications instead of SD.
|
||||
|
||||
All three of these filesystems can open and manipulate ``File`` and ``Dir``
|
||||
FatFS implements a wear-leveled, FTL-backed FAT filesystem in the onboard
|
||||
flash which can be easily accessed over USB as a standard memory stick
|
||||
via FatFSUSB.
|
||||
|
||||
All of these filesystems can open and manipulate ``File`` and ``Dir``
|
||||
objects with the same code because the implement a common end-user
|
||||
filesystem API.
|
||||
|
||||
FatFS File System Caveats and Warnings
|
||||
--------------------------------------
|
||||
|
||||
The FAT filesystem is ubiquitous, but it is also around 50 years old and ill
|
||||
suited to SPI flash memory due to having "hot spots" like the FAT copies that
|
||||
are rewritten many times over. SPI flash allows a high, but limited, number
|
||||
of writes before losing the ability to write safely. Applications like
|
||||
data loggers where many writes occur could end up wearing out the SPI flash
|
||||
sector that holds the FAT **years** before coming close to the write limits of
|
||||
the data sectors.
|
||||
|
||||
To circumvent this issue, the FatFS implementation here uses a flash translation
|
||||
layer (FTL) developed for SPI flash on embedded systems. This allows for the
|
||||
same LBA to be written over and over by the FAT filesystem, but use different
|
||||
flash locations. For more information see
|
||||
[SPIFTL](https://github.com/earlephilhower/SPIFTL). In this mode the Pico
|
||||
flash appears as a normal, 512-byte sector drive to the FAT.
|
||||
|
||||
What this means, practically, is that about 5KB of RAM per megabyte of flash
|
||||
is required for housekeeping. Writes can also become very slow if most of the
|
||||
flash LBA range is used (i.e. if the FAT drive is 99% full) due to the need
|
||||
for garbage collection processes to move data around and preserve the flash
|
||||
lifetime.
|
||||
|
||||
Alternatively, if an FTL is not desired or memory is tight, FatFS can use the
|
||||
raw flash directly. In this mode sectors are 4K in size and flash is mapped
|
||||
1:1 to sectors, so things like the FAT table updates will all use the same
|
||||
physical flash bits. For low-utilization operations this may be fine, but if
|
||||
significant writes are done (from the Pico or the PC host) this may wear out
|
||||
portions of flash very quickly , rendering it unusable.
|
||||
|
||||
LittleFS File System Limitations
|
||||
--------------------------------
|
||||
|
||||
The LittleFS implementation for the RP2040 supports filenames of up
|
||||
to 31 characters + terminating zero (i.e. ``char filename[32]``), and
|
||||
as many subdirectories as space permits.
|
||||
to 254 characters + terminating zero (i.e. ``char filename[255]`` or
|
||||
better ``char filename[LFS_NAME_MAX]`` ), and as many subdirectories
|
||||
as space permits.
|
||||
|
||||
Filenames are assumed to be in the root directory if no initial "/" is
|
||||
present.
|
||||
@@ -75,22 +112,28 @@ Uploading Files to the LittleFS File System
|
||||
menu item to **Tools** menu for uploading the contents of sketch data
|
||||
directory into a new LittleFS flash file system.
|
||||
|
||||
**IDE 1.x**
|
||||
|
||||
- Download the tool: https://github.com/earlephilhower/arduino-pico-littlefs-plugin/releases
|
||||
- In your Arduino sketchbook directory, create ``tools`` directory if
|
||||
it doesn't exist yet.
|
||||
- Unpack the tool into ``tools`` directory (the path will look like
|
||||
``<home_dir>/Arduino/tools/PicoLittleFS/tool/picolittlefs.jar``)
|
||||
- In your Arduino sketchbook directory, create ``tools`` directory if it doesn't exist yet.
|
||||
- Unpack the tool into ``tools`` directory (the path will look like ``<home_dir>/Arduino/tools/PicoLittleFS/tool/picolittlefs.jar``)
|
||||
If upgrading, overwrite the existing JAR file with the newer version.
|
||||
- Restart Arduino IDE.
|
||||
- Open a sketch (or create a new one and save it).
|
||||
- Go to sketch directory (choose Sketch > Show Sketch Folder).
|
||||
- Create a directory named ``data`` and any files you want in the file
|
||||
system there.
|
||||
- Create a directory named ``data`` and any files you want in the file system there.
|
||||
- Make sure you have selected a board, port, and closed Serial Monitor.
|
||||
- Double check theSerial Monitor is closed. Uploads will fail if the Serial
|
||||
Monitor has control of the serial port.
|
||||
- Select ``Tools > Pico LittleFS Data Upload``. This should start
|
||||
uploading the files into the flash file system.
|
||||
- Double check the Serial Monitor is closed. Uploads will fail if the Serial Monitor has control of the serial port.
|
||||
- Select ``Tools > Pico LittleFS Data Upload``. This should start uploading the files into the flash file system.
|
||||
|
||||
**IDE 2.x**
|
||||
|
||||
- Download the new tool: https://github.com/earlephilhower/arduino-littlefs-upload/releases
|
||||
- Exit the IDE, if running
|
||||
- Copy the VSIX file manually to (Linux/Mac) ``~/.arduinoIDE/plugins/`` (you may need to make this directory yourself beforehand) or to (Windows) ``C:\Users\<username>\.arduinoIDE\``
|
||||
- Restart the IDE
|
||||
- Double check the Serial Monitor is closed. Uploads will fail if the Serial Monitor has control of the serial port.
|
||||
- Enter ``[Ctrl]`` + ``[Shift]`` + ``[P]`` to bring up the command palette, then select/type ``Upload LittleFS to Pico/ESP8266``
|
||||
|
||||
SD Library Information
|
||||
----------------------
|
||||
@@ -109,8 +152,50 @@ second SPI port, ``SPI1``. Just use the following call in place of
|
||||
SD.begin(cspin, SPI1);
|
||||
|
||||
|
||||
File system object (LittleFS/SD/SDFS)
|
||||
-------------------------------------
|
||||
Using VFS (Virtual File System) for POSIX support
|
||||
-------------------------------------------------
|
||||
The ``VFS`` library enables sketches to use standard POSIX file I/O operations using
|
||||
standard ``FILE *`` operations. Include the ``VFS`` library in your application and
|
||||
add a call to map the ``VFS.root()`` to your filesystem. I.e.:
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
#include <VFS.h>
|
||||
#include <LittleFS.h>
|
||||
|
||||
void setup() {
|
||||
LittleFS.begin();
|
||||
VFS.root(LittleFS);
|
||||
FILE *fp = fopen("/thisfilelivesonflash.txt", "w");
|
||||
fprintf(fp, "Hello!\n");
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
Multiple filesystems can be ``VFS.map()`` into the VFS namespace under different directory
|
||||
names. For example, the following will make files on ``/sd`` reside on an external\
|
||||
SD card and files on ``/lfs`` live in internal flash.
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
#include <VFS.h>
|
||||
#include <LittleFS.h>
|
||||
#include <SDFS.h>
|
||||
|
||||
void setup() {
|
||||
LittleFS.begin();
|
||||
SDFS.begin();
|
||||
VFS.map("/lfs", LittleFS);
|
||||
VFS.map("/sd", SDFS);
|
||||
FILE *onSD = fopen("/sd/thislivesonsd.txt", "wb");
|
||||
....
|
||||
}
|
||||
|
||||
See the examples in the ``VFS`` library for more information.
|
||||
|
||||
|
||||
|
||||
File system object (LittleFS/SD/SDFS/FatFS)
|
||||
-------------------------------------------
|
||||
|
||||
setConfig
|
||||
~~~~~~~~~
|
||||
@@ -125,14 +210,22 @@ setConfig
|
||||
c2.setCSPin(12);
|
||||
SDFS.setConfig(c2);
|
||||
|
||||
FatFSConfig c3;
|
||||
c3.setUseFTL(false); // Directly access flash memory
|
||||
c3.setDirEntries(256); // We need 256 root directory entries on a format()
|
||||
c3.setFATCopies(1); // Only 1 FAT to save 4K of space and extra writes
|
||||
FatFS.setConfig(c3);
|
||||
FatFS.format(); // Format using these settings, erasing everything
|
||||
|
||||
This method allows you to configure the parameters of a filesystem
|
||||
before mounting. All filesystems have their own ``*Config`` (i.e.
|
||||
``SDFSConfig`` or ``LittleFSConfig`` with their custom set of options.
|
||||
All filesystems allow explicitly enabling/disabling formatting when
|
||||
mounts fail. If you do not call this ``setConfig`` method before
|
||||
perforing ``begin()``, you will get the filesystem's default
|
||||
behavior and configuration. By default, SPIFFS will autoformat the
|
||||
filesystem if it cannot mount it, while SDFS will not.
|
||||
behavior and configuration. By default, LittleFS and FatFS will autoformat the
|
||||
filesystem if it cannot mount it, while SDFS will not. FatFS will also use
|
||||
the built-in FTL to support 512 byte sectors and higher write lifetime.
|
||||
|
||||
begin
|
||||
~~~~~
|
||||
@@ -144,11 +237,10 @@ begin
|
||||
|
||||
This method mounts file system. It must be called before any
|
||||
other FS APIs are used. Returns *true* if file system was mounted
|
||||
successfully, false otherwise. With no options it will format SPIFFS
|
||||
if it is unable to mount it on the first try.
|
||||
successfully, false otherwise.
|
||||
|
||||
Note that LittleFS will automatically format the filesystem
|
||||
if one is not detected. This is configurable via ``setConfig``
|
||||
if one is not detected. This is configurable via ``setConfig``.
|
||||
|
||||
end
|
||||
~~~
|
||||
@@ -181,8 +273,8 @@ open
|
||||
|
||||
Opens a file. ``path`` should be an absolute path starting with a slash
|
||||
(e.g. ``/dir/filename.txt``). ``mode`` is a string specifying access
|
||||
mode. It can be one of "r", "w", "a", "r+", "w+", "a+". Meaning of these
|
||||
modes is the same as for ``fopen`` C function.
|
||||
mode. It can be one of "r", "w", "a", "r+", "w+", "a+". The meaning of these
|
||||
modes is the same as for the ``fopen`` C function.
|
||||
|
||||
::
|
||||
|
||||
@@ -258,8 +350,6 @@ openDir
|
||||
or LittleFS.openDir(path)
|
||||
|
||||
Opens a directory given its absolute path. Returns a *Dir* object.
|
||||
Please note the previous discussion on the difference in behavior between
|
||||
LittleFS and SPIFFS for this call.
|
||||
|
||||
remove
|
||||
~~~~~~
|
||||
@@ -283,8 +373,8 @@ rename
|
||||
Renames file from ``pathFrom`` to ``pathTo``. Paths must be absolute.
|
||||
Returns *true* if file was renamed successfully.
|
||||
|
||||
info **DEPRECATED**
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
info
|
||||
~~~~
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
@@ -293,9 +383,8 @@ info **DEPRECATED**
|
||||
|
||||
Fills `FSInfo structure <#filesystem-information-structure>`__ with
|
||||
information about the file system. Returns ``true`` if successful,
|
||||
``false`` otherwise. Because this cannot report information about
|
||||
filesystemd greater than 4MB, don't use it in new code. Use ``info64``
|
||||
instead which uses 64-bit fields for filesystem sizes.
|
||||
``false`` otherwise. ``ìnfo()`` has been updated to support filesystems
|
||||
greater than 4GB and ``FSInfo64`` and ``info64()`` have been discarded.
|
||||
|
||||
Filesystem information structure
|
||||
--------------------------------
|
||||
@@ -303,8 +392,8 @@ Filesystem information structure
|
||||
.. code:: cpp
|
||||
|
||||
struct FSInfo {
|
||||
size_t totalBytes;
|
||||
size_t usedBytes;
|
||||
uint64_t totalBytes;
|
||||
uint64_t usedBytes;
|
||||
size_t blockSize;
|
||||
size_t pageSize;
|
||||
size_t maxOpenFiles;
|
||||
@@ -319,19 +408,6 @@ block size - ``pageSize`` — filesystem logical page size - ``maxOpenFiles``
|
||||
``maxPathLength`` — max file name length (including one byte for zero
|
||||
termination)
|
||||
|
||||
info64
|
||||
~~~~~~
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
FSInfo64 fsinfo;
|
||||
SDFS.info(fsinfo);
|
||||
or LittleFS(fsinfo);
|
||||
|
||||
Performs the same operation as ``info`` but allows for reporting greater than
|
||||
4GB for filesystem size/used/etc. Should be used with the SD and SDFS
|
||||
filesystems since most SD cards today are greater than 4GB in size.
|
||||
|
||||
setTimeCallback(time_t (\*cb)(void))
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -550,8 +626,8 @@ close
|
||||
Close the file. No other operations should be performed on *File* object
|
||||
after ``close`` function was called.
|
||||
|
||||
openNextFile (compatibiity method, not recommended for new code)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
openNextFile (compatibility method, not recommended for new code)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
@@ -562,8 +638,8 @@ openNextFile (compatibiity method, not recommended for new code)
|
||||
Opens the next file in the directory pointed to by the File. Only valid
|
||||
when ``File.isDirectory() == true``.
|
||||
|
||||
rewindDirectory (compatibiity method, not recommended for new code)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
rewindDirectory (compatibility method, not recommended for new code)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
Bluetooth HID Master
|
||||
====================
|
||||
|
||||
The PicoW can connect to a Bluetooth Classic or Bluetooth BLE keyboard,
|
||||
mouse, or joystick and receive input events from it. As opposed to
|
||||
the ``Keyboard``, ``Mouse``, and ``Joystick`` libraries, which make
|
||||
the PicoW into a peripheral others can use, this lets the PicoW use the
|
||||
same kinds of peripherals in a master rols.
|
||||
|
||||
BTDeviceInfo Class
|
||||
------------------
|
||||
|
||||
The ``BluetoothHCI`` class implements a scanning function for classic
|
||||
and BLE devices and can return a ``std::vector`` of discovered devices to an application.
|
||||
Iterate over the list using any of the STL iteration methods (i.e. ``for (auto e : list)``).
|
||||
The elements of this list are ``BTDeviceInfo`` objects which have the following
|
||||
member functions:
|
||||
|
||||
``BTDeviceInfo::deviceClass()`` returns the Bluetooth BLE UUID or the Blustooth device
|
||||
class for the device. This specifies the general class of the device (keyboard, mouse,
|
||||
etc.).
|
||||
|
||||
``BTDeviceInfo::address()`` and ``BTDeviceInfo::addressString()`` return the
|
||||
Bluetooth address as a binary array or a string that can be used to ``print``.
|
||||
|
||||
``BTDeviceInfo::addressType()`` returns whether the BLE address is random or not, and
|
||||
is not generally needed by a user application.
|
||||
|
||||
``BTDeviceInfo::rssi()`` returns an approximate dB level for the device. Less
|
||||
negative is stronger signal.
|
||||
|
||||
``BTDeviceInfo::name()`` returns the advertised name of the device, if present. Some
|
||||
devices or scans do not return names for valid devices.
|
||||
|
||||
|
||||
BluetoothHCI Class
|
||||
------------------
|
||||
|
||||
The ``BluetoothHCI`` class is responsible for scanning for devices and the lower-level
|
||||
housekeeping for a master-mode Bluetooth application. Most applications will not need
|
||||
to access it directly, but it can be used to discover nearby BT devices. As
|
||||
part of the application Bluetooth setup, call ``BluetoothHCI::install()`` and then
|
||||
``BluetoothHCI::begin()`` to start BT processing. Your application is still responsible
|
||||
for all the non-default HCI initialization and customization. See the ``BluetoothScanner.ino``
|
||||
example for more info.
|
||||
|
||||
|
||||
BluetoothHIDMaster Operation
|
||||
----------------------------
|
||||
|
||||
Most applications will use the ``BluetoothHIDMaster`` class and, after connecting, receive
|
||||
callbacks from the Bluetooth stack when input events (key presses, mouse moves, button
|
||||
mashes) occur.
|
||||
|
||||
Application flow will generally be:
|
||||
1. Install the appropriate callbacks using the ``BluetoothHIDMaster::onXXX`` methods
|
||||
2. Start the Bluetooth processing with ``BluetoothHIDMaster::begin()`` or ``BluetoothHIDMaster::beginBLE()``
|
||||
3. Connect to the first device found with ``BluetoothHIDMaster::connectXXX()`` and start receiving callbacks.
|
||||
4. Callbacks will come at interrupt time and set global state variables, which the main ``loop()`` will process
|
||||
|
||||
Callback Event Handlers
|
||||
-----------------------
|
||||
The main application is informed of new inputs via a standard callback mechanism. These callbacks run at
|
||||
interrupt time and should not do significant work, ``delay()``, or allocate or free memory. The most common
|
||||
way of handling this is setting global ``volatile`` flags and variables that the main ``loop()`` will poll
|
||||
and process.
|
||||
|
||||
Mouse Callbacks
|
||||
~~~~~~~~~~~~~~~
|
||||
The ``BluetoothHIDMaster::onMouseMove`` callback gets the delta X, Y, and wheel reported by the device.
|
||||
The ``BluetoothHIDMaster::onMouseButton`` gets a button number and state (up or down) and will be called
|
||||
each time an individual button is reported changed by the mouse.
|
||||
|
||||
.. code :: cpp
|
||||
|
||||
void mouseMoveCB(void *cbdata, int dx, int dy, int dw) {
|
||||
// Process the deltas, adjust global mouse state
|
||||
}
|
||||
|
||||
void mouseButtonCB(void *cbdata, int butt, bool down) {
|
||||
// Set the global button array with this new info
|
||||
}
|
||||
|
||||
|
||||
Meyboard Callbacks
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
The `BluetoothHIDMaster::onKeyDown`` callback receives the raw HID key (**NOT ASCII**) sent by the device on a key press
|
||||
while `BluetoothHIDMaster::onKeyUp`` gets the same when a key is released. Note that up to 6 keys can be pressed at any
|
||||
one time. For media keys ("consumer keys" in the USB HID documentation) the ``BluetoothHIDMaster::onConsumerKeyDown`` and
|
||||
``BluetoothHIDMaster::onConsumerKeyUp`` perform the same function (and receive the consumer key IDs defined by the
|
||||
USB HID spec and not ASCII).
|
||||
|
||||
To convert the key press and release (including SHIFT handling), use a ``HIDKeyStream`` object. Simply write the raw
|
||||
HID key and the up/down state to the stream and read back the ASCII for use in an application.
|
||||
|
||||
.. code :: cpp
|
||||
|
||||
HIDKeyStream keystream;
|
||||
|
||||
void keyDownCB(void *cbdata, int key) {
|
||||
keystream.write((uint8_t )key);
|
||||
keystream.write((uint8_t) true); // Keystream now has 1 ASCII character to read out and use
|
||||
char ascii = keystream.read();
|
||||
// ....
|
||||
}
|
||||
|
||||
void keyUpCB(void *cbdata, int key) {
|
||||
// Normally don't do anything on this, the character was read in the keyDownCB
|
||||
}
|
||||
|
||||
void consumerKeyDownCB(void *cbdata, int key) {
|
||||
// switch(key) and use cases from the USB Consumer Key page
|
||||
}
|
||||
|
||||
void consumerKeyUpCB(void *cbdata, int key) {
|
||||
// switch(key) and use cases from the USB Consumer Key page
|
||||
}
|
||||
|
||||
|
||||
Joystick Callbacks
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
A single ``BluetoothHIDMaster::onJoystick`` callback gets activated every time a report from a joystick is processed.
|
||||
It receives (potentially, if supported by the device) 4 analog axes, one 8-way digital hat switch position, and up
|
||||
to 32 button states at a time.
|
||||
|
||||
.. code :: cpp
|
||||
|
||||
void joystickCB(void *cbdata, int x, int y, int z, int rz, uint8_t hat, uint32_t buttons) {
|
||||
// HAT 0 = UP and continues clockwise. If no hat direction it is set to 0x0f.
|
||||
// Use "buttons & (1 << buttonNumber)" to look at the individual button states
|
||||
// ...
|
||||
}
|
||||
|
||||
PianoKeyboard Example
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
See the ``PianoKeyboard.ino`` and ``PianoKeyboardBLE.ino`` examples for more information on callback operation.
|
||||
|
||||
|
||||
BluetoothHIDMaster::onXXX Callback Installers
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code :: cpp
|
||||
|
||||
void BluetoothHIDMaster::onMouseMove(void (*)(void *, int, int, int), void *cbData = nullptr);
|
||||
void BluetoothHIDMaster::onMouseButton(void (*)(void *, int, bool), void *cbData = nullptr);
|
||||
void BluetoothHIDMaster::onKeyDown(void (*)(void *, int), void *cbData = nullptr);
|
||||
void BluetoothHIDMaster::onKeyUp(void (*)(void *, int), void *cbData = nullptr);
|
||||
void BluetoothHIDMaster::onConsumerKeyDown(void (*)(void *, int), void *cbData = nullptr);
|
||||
void BluetoothHIDMaster::onConsumerKeyUp(void (*)(void *, int), void *cbData = nullptr);
|
||||
void BluetoothHIDMaster::onJoystick(void (*)(void *, int, int, int, int, uint8_t, uint32_t), void *cbData = nullptr);
|
||||
|
||||
BluetoothHIDMaster Class
|
||||
------------------------
|
||||
|
||||
bool BluetoothHIDMaster::begin()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Installs and configures the Bluetooth Classic stack and starts processing events. No connections are made at this point.
|
||||
When running in Classic mode, no BLE devices can be detected or used.
|
||||
|
||||
|
||||
bool BluetoothHIDMaster::begin(const char *BLEName)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Installs and configures the Bluetooth BLE stack and starts processing events. No connections are made at this point.
|
||||
When running in BLE mode, no Classic devices can be detected or used.
|
||||
|
||||
bool BluetoothHIDMaster::connected()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Returns if the Bluetooth stack is up and running and a connection to a device is currently active.
|
||||
|
||||
void BluetoothHIDMaster::end()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Disables the Bluetooth stack. Note that with the current Bluetooth implementation restarting the stack (i.e. calling ``begin()`` after ``end()``) is not stable and will not work. Consider storing state and rebooting completely if this is necessary.
|
||||
|
||||
bool BluetoothHIDMaster::running()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Returns if the Bluetooth stack is running at all. Does not indicate if there is an active connection or not.
|
||||
|
||||
bool BluetoothHIDMaster::hciRunning()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Returns if the Bluetooth stack has passed the initial HCI start up phase. Until this returns ``true`` no Bluetooth operations can be performed.
|
||||
|
||||
std::vector<BTDeviceInfo> BluetoothHIDMaster::scan(uint32_t mask, int scanTimeSec, bool async)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Passes through the ``BluetoothHCI::scan()`` function to manually scan for a list of nearby devices. If you want to connect to the first found device, this is not needed.
|
||||
|
||||
bool BluetoothHIDMaster::connect(const uint8_t *addr)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Start the connection process to the Bluetooth Classic device with the given MAC. Note that this returns immediately, but it may take several seconds until ``connected()`` reports that the connection has been established.
|
||||
|
||||
bool BluetoothHIDMaster::connectKeyboard(), connectMouse(), connectJoystick(), connectAny()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Connect to the first found specified Bluetooth Classic device type (or any HID device) in pairing mode. No need to call ``scan()`` or have an address.
|
||||
|
||||
bool BluetoothHIDMaster::connectBLE(const uint8_t *addr, int addrType)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Start the connection process to the Bluetooth BLE device with the given MAC. Note that this returns immediately, but it may take several seconds until ``connected()`` reports that the connection has been established.
|
||||
|
||||
bool BluetoothHIDMaster::connectBLE()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Connect to the first found BLE device that has a HID service UUID (keyboard, mouse, or joystick)
|
||||
|
||||
bool BluetoothHIDMaster::disconnect()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Shuts down the connection to the currently connected device.
|
||||
|
||||
void BluetoothHIDMaster::clearPairing()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Erases all Bluetooth keys from memory. This effectively "forgets" all pairing between devices and can help avoid issues with the beta Bluetooth stack in the SDK.
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
HTTPClient Library
|
||||
==================
|
||||
|
||||
A simple HTTP requestor that can handle both HTTP and HTTP requests is
|
||||
A simple HTTP requester that can handle both HTTP and HTTPS requests is
|
||||
included as the ``HTTPClient`` library.
|
||||
|
||||
Check the examples for use under HTTP and HTTPS configurations. In general,
|
||||
|
||||
+32
-1
@@ -40,6 +40,16 @@ bool setDATA(pin_size_t pin)
|
||||
Sets the DOUT or DIN pin of the I2S device. Any pin may be used.
|
||||
Call before ``I2S::begin()``
|
||||
|
||||
bool setMCLK(pin_size_t pin)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Sets the MCLK pin of the I2S device and enables MCLK output. Any pin may be used.
|
||||
Call before ``I2S::begin()``
|
||||
|
||||
bool setMCLKmult(int mult)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Sets the sample rate to MCLK multiplier value. Only multiples of 64 are valid.
|
||||
Call before ``I2S::begin()``
|
||||
|
||||
bool setBitsPerSample(int bits)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Specify how many bits per audio sample to read or write. Note that
|
||||
@@ -58,12 +68,28 @@ Sets the word clock frequency, but does not start the I2S device if not
|
||||
already running. May be called after ``I2S::begin()`` to change the
|
||||
sample rate on-the-fly.
|
||||
|
||||
bool setSysClk(int samplerate)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Changes the PICO system clock to optimise for the desired samplerate.
|
||||
The clock changes to 147.6 MHz for samplerates that are a multiple of 8 kHz, and 135.6 MHz for multiples of 11.025 kHz.
|
||||
Note that using ``setSysClk()`` may affect the timing of other sysclk-dependent functions.
|
||||
Should be called before any I2S functions and any other sysclk dependent initialisations.
|
||||
|
||||
bool setLSBJFormat()
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
Enables LSB-J format for I2S output. In this mode the MSB comes out at the
|
||||
same time as the LRCLK changes, and not the normal 1-cycle delay. Useful for
|
||||
DAC chips like the PT8211.
|
||||
|
||||
bool setTDMFormat()
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
Enabled TDM formatted multi-channel output. Be sure to set the number of channels to
|
||||
the expected value (8 normally) and the bits per sample to 32.
|
||||
|
||||
bool setTDMChannels(int channels)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Sets the number of TDM channels between frame syncs. Generally should be set to 8.
|
||||
|
||||
bool swapClocks()
|
||||
~~~~~~~~~~~~~~~~~
|
||||
Certain boards are hardwired with the WCLK before the BCLK, instead of the normal
|
||||
@@ -84,6 +110,11 @@ void flush()
|
||||
~~~~~~~~~~~~
|
||||
Waits until all the I2S buffers have been output.
|
||||
|
||||
void getOverUnderflow()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Returns a flag indicating if the I2S system ran our of data to send on output,
|
||||
or had to throw away data on input.
|
||||
|
||||
size_t write(uint8_t/int8_t/int16_t/int32_t)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Writes a single sample of ``bitsPerSample`` to the buffer. It is up to the
|
||||
@@ -112,7 +143,7 @@ many bytes were actually written.
|
||||
|
||||
int availableForWrite()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Returns the number of L/R samples that can be written without
|
||||
Returns the amount of bytes that can be written without
|
||||
potentially blocking.
|
||||
|
||||
int read()
|
||||
|
||||
+3
-7
@@ -1,15 +1,11 @@
|
||||
IDE Menus
|
||||
=========
|
||||
|
||||
Model
|
||||
Board
|
||||
-----
|
||||
Use the boards menu to select your model of RP2040 board. There will be two
|
||||
options: `Boardname` and `Boardname (Picoprobe)`. If you want to use a
|
||||
Picoprobe to upload your sketches and not the default automatic UF2 upload,
|
||||
use the `(Picoprobe)` option, otherwise use the normal name. No functional
|
||||
or code changes are done because of this.
|
||||
Use the boards menu to select your model of RP2040 board.
|
||||
|
||||
There is also a `Generic` board which allows you to individually select
|
||||
There is also a `Generic RP2040` board which allows you to individually select
|
||||
things such as flash size or boot2 flash type. Use this if your board isn't
|
||||
yet fully supported and isn't working with the normal `Raspberry Pi Pico`
|
||||
option.
|
||||
|
||||
+16
-7
@@ -2,12 +2,12 @@ Arduino-Pico
|
||||
============
|
||||
|
||||
This is the documentation for the Raspberry Pi Pico Arduino core,
|
||||
Arduino-Pico. Arduino-Pico is a community port of the RP2040
|
||||
(Raspberry Pi Pico processor) to the Arduino ecosystem, intended
|
||||
to make it easier and more fun to use and program the Raspberry Pi
|
||||
Pico / RP2040 based boards.
|
||||
Arduino-Pico. Arduino-Pico is a community port of Arduino to the
|
||||
RP2040 (Raspberry Pi Pico processor) and RP2350 (Raspberry Pi Pico 2
|
||||
processor), intended to make it easier and more fun to use and
|
||||
program the Raspberry Pi Pico / RP2040 / RP2350 based boards.
|
||||
|
||||
This Arduino core uses a custom toolset with GCC 10.3 and Newlib 4.0.0
|
||||
This Arduino core uses a custom toolset with GCC 14.2 and Newlib 4.3
|
||||
and doesn't require any system-installed prerequisites.
|
||||
|
||||
For the latest version, always check https://github.com/earlephilhower/arduino-pico
|
||||
@@ -26,10 +26,11 @@ For the latest version, always check https://github.com/earlephilhower/arduino-p
|
||||
|
||||
Pin (Re)Assignment <pins>
|
||||
|
||||
RP2040 Helper <rp2040>
|
||||
RP2040/RP2350 Helper <rp2040>
|
||||
|
||||
Analog I/O <analog>
|
||||
Digital I/O <digital>
|
||||
BOOTSEL Button <bootsel>
|
||||
EEPROM <eeprom>
|
||||
I2S Audio <i2s>
|
||||
PWM Audio <pwm>
|
||||
@@ -43,13 +44,20 @@ For the latest version, always check https://github.com/earlephilhower/arduino-p
|
||||
USB (Arduino and Adafruit_TinyUSB) <usb>
|
||||
Multicore Processing <multicore>
|
||||
|
||||
Bluetooth (Alpha/Beta) <bluetooth>
|
||||
RP2350 Specific Notes <rp2350>
|
||||
RP2350 PSRAM <psram>
|
||||
|
||||
Bluetooth <bluetooth>
|
||||
Bluetooth HID Master <hidmaster>
|
||||
Bluetooth Audio (A2DP) <a2dp>
|
||||
|
||||
Single File USB Drive <singlefile>
|
||||
FatFSUSB - full FS access over USB <fatfsusb>
|
||||
|
||||
FreeRTOS SMP (multicore) <freertos>
|
||||
|
||||
WiFi (Pico-W Support) <wifi>
|
||||
Ethernet (Wired) <ethernet>
|
||||
WiFiClient <wificlient>
|
||||
WiFiServer <wifiserver>
|
||||
WiFiUDP <wifiudp>
|
||||
@@ -65,4 +73,5 @@ For the latest version, always check https://github.com/earlephilhower/arduino-p
|
||||
Ported/Optimized Libraries <libraries>
|
||||
Using Pico-SDK <sdk>
|
||||
|
||||
|
||||
Licenses <license>
|
||||
|
||||
+27
-21
@@ -26,9 +26,7 @@ Arduino IDE Installation Warning
|
||||
the actual Arduino application because it has issues detecting attached Pico
|
||||
boards. Use the "Windows ZIP" or plain "Windows" executable (EXE) download
|
||||
direct from https://arduino.cc. and allow it to install any device drivers
|
||||
it suggests. Otherwise the Pico board may not be detected. Also, if trying
|
||||
out the 2.0 beta Arduino please install the release 1.8 version beforehand
|
||||
to ensure needed device drivers are present.
|
||||
it suggests. Otherwise the Pico board may not be detected.
|
||||
|
||||
**Note for Linux Users**: If you installed the Arduino IDE using Flatpak, which
|
||||
is common in Pop!_OS, Fedora, and Mint, among others, you may need to configure
|
||||
@@ -38,6 +36,22 @@ prevent the Arduino IDE from accessing. For Arduino IDE V2, override the filesys
|
||||
restriction using ``flatpak override --user --filesystem=host cc.arduino.IDE2`` . For
|
||||
For Arduino IDE < V2, use ``flatpak override --user --filesystem=host cc.arduino.arduinoide``.
|
||||
|
||||
Installing via Arduino CLI
|
||||
--------------------------
|
||||
To install using the Arduino command line tool (arduino-cli):
|
||||
|
||||
.. code:: bash
|
||||
|
||||
arduino-cli config add board_manager.additional_urls https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
|
||||
arduino-cli core update-index
|
||||
arduino-cli core install rp2040:rp2040
|
||||
|
||||
To list the supported boards:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
arduino-cli board listall | grep rp2040
|
||||
|
||||
Installing via GIT
|
||||
------------------
|
||||
To install via GIT (for latest and greatest versions):
|
||||
@@ -125,11 +139,13 @@ Uploading Filesystem Images
|
||||
---------------------------
|
||||
The onboard flash filesystem for the Pico, LittleFS, lets you upload a filesystem image from the sketch directory for your sketch to use. Download the needed plugin from
|
||||
|
||||
* https://github.com/earlephilhower/arduino-pico-littlefs-plugin/releases
|
||||
* `IDE 1.x`: https://github.com/earlephilhower/arduino-pico-littlefs-plugin/releases
|
||||
* `IDE 2.x`: https://github.com/earlephilhower/arduino-littlefs-upload/releases
|
||||
|
||||
To install, follow the directions in
|
||||
|
||||
* https://github.com/earlephilhower/arduino-pico-littlefs-plugin/blob/master/README.md
|
||||
* `IDE 1.x`: https://github.com/earlephilhower/arduino-pico-littlefs-plugin/blob/master/README.md
|
||||
* `IDE 2.x`: https://github.com/earlephilhower/arduino-littlefs-upload/blob/main/README.md
|
||||
|
||||
For detailed usage information, please check the repo documentation available at
|
||||
|
||||
@@ -143,12 +159,6 @@ So for the first sketch you will need to rebuild (with the ``Upload Method->Pico
|
||||
|
||||
After the initial upload, as long as the running binary was built using the ``Picotool`` upload method, then the normal upload process should work.
|
||||
|
||||
Under MacOS, it may be necessary to install the USB support libraries from a command terminal before the ``Picotool`` upload method can be used:
|
||||
|
||||
.. code::
|
||||
|
||||
brew install libusb
|
||||
|
||||
For Ubuntu and other Linux operating systems you may need to add the following lines to a new `udev` config file(``99-picotool.rules``) to allow normal users to access the special USB device the Pico exports:
|
||||
|
||||
.. code::
|
||||
@@ -174,11 +184,9 @@ The first line creates a file with the USB vendor and ID of the Picoprobe and te
|
||||
|
||||
Once Picoprobe permissions are set up properly, then select the board "Raspberry Pi Pico (Picoprobe)" in the Tools menu and upload as normal.
|
||||
|
||||
Uploading Sketches with pico-debug
|
||||
----------------------------------
|
||||
pico-debug differs from Picoprobe in that pico-debug is a virtual debug pod that runs side-by-side on the same RP2040 that you run your code on; so, you only need one RP2040 board instead of two. pico-debug also differs from Picoprobe in that pico-debug is standards-based; it uses the CMSIS-DAP protocol, which means even software not specially written for the Raspberry Pi Pico can support it. pico-debug uses OpenOCD to handle your sketch uploads, and debugging can be accomplished with CMSIS-DAP capable debuggers including GDB.
|
||||
|
||||
Under Windows and macOS, any user should be able to access pico-debug automatically, but under Linux `udev` must be told about the device and to allow normal users access.
|
||||
Uploading Sketches with OpenOCD
|
||||
-------------------------------
|
||||
Under Windows and macOS, any user should be able to access OpenOCD automatically, but under Linux `udev` must be told about the device and to allow normal users access.
|
||||
|
||||
To set up user-level access to all CMSIS-DAP adapters on Ubuntu (and other OSes which use `udev`):
|
||||
|
||||
@@ -189,10 +197,8 @@ To set up user-level access to all CMSIS-DAP adapters on Ubuntu (and other OSes
|
||||
|
||||
The first line creates a file that recognizes all CMSIS-DAP adapters and tells UDEV to give users full access to it. The second causes `udev` to load this new rule. Note that you will need to unplug and re-plug in your device the first time you create this file, to allow udev to make the device node properly.
|
||||
|
||||
Once CMSIS-DAP permissions are set up properly, then select the board "Raspberry Pi Pico (pico-debug)" in the Tools menu.
|
||||
Once CMSIS-DAP permissions are set up properly, then select the Upload Method "Picoprobe/Debugprobe (CMSIS-DAP)" in the Tools menu.
|
||||
|
||||
When first connecting the USB port to your PC, you must copy pico-debug-gimmecache.uf2 to the Pi Pico to load pico-debug into RAM; after this, upload as normal.
|
||||
|
||||
Debugging with Picoprobe/pico-debug, OpenOCD, and GDB
|
||||
Debugging with Picoprobe/Debugprobe, OpenOCD, and GDB
|
||||
-----------------------------------------------------
|
||||
The installed tools include a version of OpenOCD (in the pqt-openocd directory) and GDB (in the pqt-gcc directory). These may be used to run GDB in an interactive window as documented in the Pico Getting Started manuals from the Raspberry Pi Foundation. For pico-debug, replace the raspberrypi-swd and picoprobe example OpenOCD arguments of "-f interface/raspberrypi-swd.cfg -f target/rp2040.cfg" or "-f interface/picoprobe.cfg -f target/rp2040.cfg" respectively in the Pico Getting Started manual with "-f board/pico-debug.cfg".
|
||||
The installed tools include a version of OpenOCD (in the pqt-openocd directory) and GDB (in the pqt-gcc directory). These may be used to run GDB in an interactive window as documented in the Pico Getting Started manuals from the Raspberry Pi Foundation.
|
||||
|
||||
+1
-1
@@ -10,5 +10,5 @@ In addition, it contains code from additional open source projects:
|
||||
* The `Pico-SDK <https://github.com/raspberrypi/pico-sdk>`_ and `Pico-Extras <https://github.com/raspberrypi/pico-extras>`_ are by Raspberry Pi (Trading) Ltd. and licensed under the BSD 3-Clause license.
|
||||
* `Arduino-Pico <https://github.com/earlephilhower/arduino-pico>`_ core files are licenses under the LGPL.
|
||||
* `LittleFS <https://github.com/ARMmbed/littlefs>`_ library written by ARM Limited and released under the `BSD 3-clause license <https://github.com/ARMmbed/littlefs/blob/master/LICENSE.md>`_ .
|
||||
* `UF2CONV.PY <https://github.com/microsoft/uf2>`_ is by Microsoft Corporatio and licensed under the MIT license.
|
||||
* `UF2CONV.PY <https://github.com/microsoft/uf2>`_ is by Microsoft Corporation and licensed under the MIT license.
|
||||
* Some filesystem code taken from the `ESP8266 Arduino Core <https://github.com/esp8266/Arduino>`_ and licensed under the LGPL.
|
||||
|
||||
+28
-2
@@ -16,11 +16,32 @@ not necessarily simultaneously!).
|
||||
See the ``Multicore.ino`` example in the ``rp2040`` example directory for a
|
||||
quick introduction.
|
||||
|
||||
Stack Sizes
|
||||
-----------
|
||||
|
||||
When the Pico is running in single core mode, core 0 has the full 8KB of stack
|
||||
space available to it. When using multicore ``setup1``/``loop1`` the 8KB is split
|
||||
into two 4K stacks, one per core. It is possible for core 0's stack to overwrite
|
||||
core 1's stack in this case, if you go beyond the 4K limitation.
|
||||
|
||||
To allocate a separate 8K stack for core 1, resulting in 8K stacks being available
|
||||
for both cores, simply define the following variable in your sketch and set it
|
||||
to ``true``:
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
bool core1_separate_stack = true;
|
||||
|
||||
Pausing Cores
|
||||
-------------
|
||||
|
||||
Sometimes an application needs to pause the other core on chip (i.e. it is
|
||||
writing to flash or needs to stop processing while some other event occurs).
|
||||
In most cases, however, these calls are **SHOULD NOT BE USED**. To synchronize
|
||||
cross-core operations use normal multiprocessor methods such as circular buffers,
|
||||
global ``volatile`` flags, mutexes, and the like. Stopping a core has massive
|
||||
implications and can kill networking and USB communications if done too long or
|
||||
too frequently.
|
||||
|
||||
void rp2040.idleOtherCore()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -53,7 +74,12 @@ Communicating Between Cores
|
||||
The RP2040 provides a hardware FIFO for communicating between cores, but it
|
||||
is used exclusively for the idle/resume calls described above. Instead, please
|
||||
use the following functions to access a software-managed, multicore safe
|
||||
FIFO.
|
||||
FIFO. There are two FIFOs, one written to by core 0 and read by core 1, and
|
||||
the other written to by core 1 and read by core 0.
|
||||
|
||||
You can (and probably should) use shared memory (such as ``volatile`` globals)
|
||||
or other normal multiprocessor communication algorithms to transfer data or
|
||||
work between cores, but for simple tasks these FIFO routines can suffice.
|
||||
|
||||
void rp2040.fifo.push(uint32_t)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -80,4 +106,4 @@ Reads a value from this core's FIFO and places it in dest. Will return
|
||||
int rp2040.fifo.available()
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Returns the number of values available in this core's FIFO.
|
||||
Returns the number of values available to read in this core's FIFO.
|
||||
|
||||
+14
-15
@@ -1,7 +1,6 @@
|
||||
OTA Updates
|
||||
===========
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
@@ -12,7 +11,7 @@ OTA may be done using:
|
||||
- `Arduino IDE <#arduino-ide>`__
|
||||
- `Web Browser <#web-browser>`__
|
||||
- `HTTP Server <#http-server>`__
|
||||
- Any other method (ZModen receive over a UART port, etc.) by using the ``Updater`` object in your sketch
|
||||
- Any other method (ZModem receive over a UART port, etc.) by using the ``Updater`` object in your sketch
|
||||
|
||||
The Arduino IDE option is intended primarily for the software development phase. The other two options would be more useful after deployment, to provide the module with application updates either manually with a web browser, or automatically using an HTTP server.
|
||||
|
||||
@@ -90,7 +89,7 @@ Signing requires the generation of an RSA-2048 key (other bit lengths are suppor
|
||||
Automatic Signing
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
The simplest way of implementing signing is to use the automatic mode, which presently is only possible on Linux and Mac due to some of the tools not being available for Windows. This mode uses the IDE to configure the source code to enable sigining verification with a given public key, and signs binaries as part of the standard build process using a given public key.
|
||||
The simplest way of implementing signing is to use the automatic mode, which presently is only possible on Linux and Mac due to some of the tools not being available for Windows. This mode uses the IDE to configure the source code to enable signing verification with a given public key, and signs binaries as part of the standard build process using a given public key.
|
||||
|
||||
To enable this mode, just include `private.key` and `public.key` in the sketch `.ino` directory. The IDE will call a helper script (`tools/signing.py`) before the build begins to create a header to enable key validation using the given public key, and to actually do the signing after the build process, generating a `sketch.bin.signed` file. When OTA is enabled (ArduinoOTA, Web, or HTTP), the binary will automatically only accept signed updates.
|
||||
|
||||
@@ -140,11 +139,11 @@ Compile the sketch normally and, once a `.bin` file is available, sign it using
|
||||
Compression
|
||||
-----------
|
||||
|
||||
The eboot bootloader incorporates a GZIP decompressor, built for very low code requirements. For applications, this optional decompression is completely transparent. For uploading compressed filesystems, the application must be built with `ATOMIC_FS_UPDATE` defined because, otherwise, eboot will not be involved in writing the filesystem.
|
||||
The bootloader incorporates a GZIP decompressor, built for very low code requirements. For applications, this optional decompression is completely transparent.
|
||||
|
||||
No changes to the application are required. The `Updater` class and `eboot` bootloader (which performs actual application overwriting on update) automatically search for the `gzip` header in the uploaded binary, and if found, handle it.
|
||||
No changes to the application are required. The `Updater` class and bootloader (which performs actual application overwriting on update) automatically search for the `gzip` header in the uploaded binary, and if found, handle it.
|
||||
|
||||
Compress an application `.bin` file or filesystem package using any `gzip` available, at any desired compression level (`gzip -9` is recommended because it provides the maximum compression and uncompresses as fast as any other compressino level). For example:
|
||||
Compress an application `.bin` file or filesystem package using any `gzip` available, at any desired compression level (`gzip -9` is recommended because it provides the maximum compression and uncompresses as fast as any other compression level). For example:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
@@ -185,11 +184,11 @@ Uploading modules wirelessly from Arduino IDE is intended for the following typi
|
||||
|
||||
- Only if modules are accessible on the same network as the computer with the Arduino IDE.
|
||||
|
||||
- For all IDE uploads,m the Pico W and the computer must be connected to the same network.
|
||||
- For all IDE uploads, the Pico W and the computer must be connected to the same network.
|
||||
|
||||
To upload wirelessly from the IDE:
|
||||
|
||||
1. Build a sketch starts ``WiFi`` and includes the appropriare calls to ``ArduinoOTA`` (see the examples for reference). These include the ``ArduinoOTA.begin()`` call in ``setup()`` and periodically calling ``ArduinoOTA.handle();`` from the ``loop()``
|
||||
1. Build a sketch that starts ``WiFi`` and includes the appropriate calls to ``ArduinoOTA`` (see the examples for reference). These include the ``ArduinoOTA.begin()`` call in ``setup()`` and periodically calling ``ArduinoOTA.handle();`` from the ``loop()``
|
||||
|
||||
2. Upload using standard USB connection the first time.
|
||||
|
||||
@@ -200,7 +199,7 @@ To upload wirelessly from the IDE:
|
||||
Password Protection
|
||||
-------------------
|
||||
|
||||
Protecting your OTA uploads with password is really straightforward. All you need to do, is to include the following statement in your code:
|
||||
Protecting your OTA uploads with a password is really straightforward. All you need to do, is to include the following statement in your code:
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
@@ -208,13 +207,13 @@ Protecting your OTA uploads with password is really straightforward. All you nee
|
||||
|
||||
Where ``123`` is a sample password that you should replace with your own.
|
||||
|
||||
Before implementing it in your sketch, it is a good idea to check how it works using *BasicOTA.ino* sketch available under *File > Examples > ArduinoOTA*. Go ahead, open *BasicOTA.ino*, uncomment the above statement that is already there, and upload the sketch. To make troubleshooting easier, do not modify example sketch besides what is absolutely required. This is including original simple ``123`` OTA password. Then attempt to upload sketch again (using OTA). After compilation is complete, once upload is about to begin, you should see prompt for password.
|
||||
Before implementing it in your sketch, it is a good idea to check how it works using *BasicOTA.ino* sketch available under *File > Examples > ArduinoOTA*. Go ahead, open *BasicOTA.ino*, uncomment the above statement that is already there, and upload the sketch. To make troubleshooting easier, do not modify example sketch besides what is absolutely required. This includes the original simple ``123`` OTA password. Then attempt to upload a sketch again (using OTA). After compilation is complete, once upload is about to begin, you should see a prompt for password.
|
||||
|
||||
Enter the password and upload should be initiated as usual with the only difference being ``Authenticating...OK`` message visible in upload log.
|
||||
Enter the password and upload should be initiated as usual with the only difference being ``Authenticating...OK`` message visible in the upload log.
|
||||
|
||||
You will not be prompted for a reentering the same password next time. Arduino IDE will remember it for you. You will see prompt for password only after reopening IDE, or if you change it in your sketch, upload the sketch and then try to upload it again.
|
||||
You will not be prompted for a reentering the same password next time. Arduino IDE will remember it for you. You will see a prompt for password only after reopening the IDE, or if you change it in your sketch, upload the sketch and then try to upload it again.
|
||||
|
||||
Please note, it is possible to reveal password entered previously in Arduino IDE, if IDE has not been closed since last upload. This can be done by enabling *Show verbose output during: upload* in *File > Preferences* and attempting to upload the module.
|
||||
Please note, it is possible to reveal password entered previously in Arduino IDE, if the IDE has not been closed since last upload. This can be done by enabling *Show verbose output during: upload* in *File > Preferences* and attempting to upload the module.
|
||||
|
||||
|
||||
|
||||
@@ -289,7 +288,7 @@ Simple updater downloads the file every time the function is called.
|
||||
Advanced updater
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
Its possible to point the update function to a script on the server. If a version string argument is given, it will be sent to the server. The server side script can use this string to check whether an update should be performed.
|
||||
It's possible to point the update function to a script on the server. If a version string argument is given, it will be sent to the server. The server side script can use this string to check whether an update should be performed.
|
||||
|
||||
The server-side script can respond as follows: - response code 200, and send the firmware image, - or response code 304 to notify Pico that no update is required.
|
||||
|
||||
@@ -305,7 +304,7 @@ The server-side script can respond as follows: - response code 200, and send the
|
||||
Serial.println("[update] Update no Update.");
|
||||
break;
|
||||
case HTTP_UPDATE_OK:
|
||||
Serial.println("[update] Update ok."); // may not be called since we reboot the RP2040
|
||||
Serial.println("[update] Update ok.");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
+7
-1
@@ -15,6 +15,7 @@ To instantiate only a serial transmit or receive unit, pass in
|
||||
``SerialPIO::NOPIN`` as the ``txpin`` or ``rxpin``.
|
||||
|
||||
For example, to make a transmit-only port on GP16
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
SerialPIO transmitter( 16, SerialPIO::NOPIN );
|
||||
@@ -22,6 +23,12 @@ For example, to make a transmit-only port on GP16
|
||||
For detailed information about the Serial ports, see the
|
||||
Arduino `Serial Reference <https://www.arduino.cc/reference/en/language/functions/communication/serial/>`_ .
|
||||
|
||||
Inversion
|
||||
---------
|
||||
|
||||
``SoftwareSerial`` and ``SerialPIO`` can both support inverted input and/or outputs via the methods
|
||||
``setInvertRX(bool invert)`` and ``setInvertTX(bool invert)``.
|
||||
|
||||
|
||||
SoftwareSerial Emulation
|
||||
========================
|
||||
@@ -30,7 +37,6 @@ with the Arduino `Software Serial <https://docs.arduino.cc/learn/built-in-librar
|
||||
library. Use the normal ``#include <SoftwareSerial.h>`` to include it. The following
|
||||
differences from the Arduino standard are present:
|
||||
|
||||
* Inverted mode is not supported
|
||||
* All ports are always listening
|
||||
* ``listen`` call is a no-op
|
||||
* ``isListening()`` always returns ``true``
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user