Compare commits

...
79 Commits
Author SHA1 Message Date
Earle F. Philhower, III 31786cdc24 Update version 2025-02-18 12:55:03 -08:00
Earle F. Philhower, III 3d17a56ecf Fix Wire/Wire1 definitions for Xaio RP2350 (#2811)
Fixes #2808
2025-02-18 10:28:12 -08:00
Earle F. Philhower, III 3cb5c315f3 Correct Seeed XAIO RP2350 config (#2803)
Fixes #2801
2025-02-15 16:15:29 -08:00
Earle F. Philhower, III 0148b1469c Update README.md 2025-02-09 09:53:46 -08:00
Stefan NürnbergerandStefan Nuernberger 96a4059f09 added I2C TwoWire::busIdle to be checked by writeReadAsync (#2798)
---------
Co-authored-by: Stefan Nuernberger <stefan@elexir.eu>
2025-02-09 09:52:45 -08:00
Limor "Ladyada" Fried c3d15931a4 Add new RP2350 Metro! (#2795) 2025-02-09 09:16:45 -08:00
Earle F. Philhower, III c79e543c41 Move to Arduino API 10501 (#2797)
* Move to Arduino API 10501

Track upstream Arduino API headers

* IPAddress V4/V6 compatiblity restored

* Fix WiFiUDP includes

* String differences in example

* HardwareSerial using exported
2025-02-08 22:45:10 -08:00
Stefan NürnbergerandStefan Nuernberger 3c556e6729 fixed: Wire::writeReadAsync not setting _dmaSendBufferLen, therefore allocating the DMA buffer anew on every call (#2796)
Co-authored-by: Stefan Nuernberger <stefan@elexir.eu>
2025-02-08 14:15:18 -08:00
Earle F. Philhower, III 5e2fbf324b Update version 2025-02-04 14:34:53 -08:00
Maximilian Gerhardt fb82f16704 Document PSRAM and Boot2 better (#2792) 2025-02-04 12:01:54 -08:00
Earle F. Philhower, III 79568a3e63 OTA Updater better error codes on OOS (#2793)
Fixes #2785.  Thanks @donmsmall!
2025-02-04 11:54:12 -08:00
Earle F. Philhower, III b506c010f7 Fix I2C on Adafruit Feather RP2350 HSTX (#2784)
Fixes #2783
2025-01-30 12:08:24 -08:00
Earle F. Philhower, III 8c3170596f Deduplicate SPI and SoftwareSPI routines (#2779) 2025-01-28 12:47:13 -08:00
Earle F. Philhower, III acf81f426c Add PIO-based SoftwareSPI enabling SPI on any pins (#2778)
* Add PIO-based SoftwareSPI enabling SPI on any pins

The Raspberry Pi team has a working PIO-based SPI interface.  Wrap it
to work like a hardware SPI interface, allowing SPI on any pin
combination.

Tested reading and writing an SD card using unmodified SD library.

* Add W5500 example

Good for testing, shows non-contiguous pin outs.
2025-01-27 13:59:52 -08:00
Cooper Dalrymple a426fbf51d Add buffer read to AudioBufferManager and I2S (#2777)
* Added buffer read to `AudioBufferManager` and `I2S`. Example and documentation included.
* Update type of words to unsigned in example.
* Improve buffered loopback example.
* Remove const from read buffer.
2025-01-26 10:03:44 -08:00
Cooper Dalrymple e133147192 Bi-directional I2S support (#2775)
* Initial bi-directional I2S support.

* Formatting update on pioasm file.

* Added loopback example.

* Updated documentation.

* Fix `getOverUnderflow` naming.

* Revert `getOverUnderflow` naming changes.

* Remove python cache file.

* Remove `availableForRead`.

* Updated naming convention of OverUnderflow methods.

* Update constructor to prevent conflicts with existing code.

* Avoid ambiguous `setDATA` in bi-directional mode.

* Use only input buffer manager in `available`.

* Fix input checks in `read` and `peek`.

* Fix erroneous comment.

* Update pio_i2s.pio to pio v1.

* Change pio_i2s.pio back to pio v0.
2025-01-23 16:30:53 -08:00
Earle F. Philhower, III 84826935a9 Don't set SDFAT_FILE_TYPE, default is OK (#2773)
* Don't set SDFAT_FILE_TYPE, default is OK

Fixes #2772

No need to set SDFAT_FILE_TYPE=3 as that is the defaulr value with upstream
SdFat.  Remove it from platform.txt and platform.io build.

* Codespell got all techy
2025-01-22 10:08:28 -08:00
Earle F. Philhower, III 9480c2a55d Update version 2025-01-21 10:15:08 -08:00
Markus Gyger b3d0ccc7e3 Change duty cycle of PIO Tone to 50% (#2770) 2025-01-21 10:03:31 -08:00
Dryw Wade 5a34395f46 PIOProgram: Replace __pioHighGPIO with pio_get_gpio_base() (#2769)
Fixes #2768
2025-01-21 09:33:04 -08:00
Earle F. Philhower, III e20c973bf5 SDIO doesn't take a clock speed parameter (#2766)
It's fixed by the PIO program and GPIO slew rates encoded in the SdFAT
driver.  Remove the parameter from the SD/SDFS begins.
2025-01-18 09:19:39 -08:00
Earle F. Philhower, III 452ef17174 Replace ESP8266SdFat w/SdFat 2.3.0, SDIO, ExFAT (#2764)
* Replace ESP8266SdFat w/SdFat 2.3.0, add SDIO and ExFAT support

Remove ESP8266SdFat fork and replaces with upstream SdFat to simplify
maintenance.

This 2.3.0 version adds SDIO support and enables exFAT support.
Also upgraded FAT filename support to 256 chars, identical to  LittleFS.

* Add SDIO support to SD and SDFS, documentation, and examples

* Update SD examples to all support SPI0, SPI1, or SDIO
2025-01-17 15:22:39 -08:00
Earle F. Philhower, III 4785c16243 Update to LittleFS v2.10.1 (#2762)
Minor behavior changes WRT path handling with trailing slashes, but
should not affect anything on the Arduino side.
2025-01-17 10:18:32 -08:00
Earle F. Philhower, III 2506b8e1d1 Update to Adafruit TinyUSB 3.4.2 (#2761)
Should be no change, just keeping in pace with upstream.
2025-01-17 10:03:22 -08:00
Earle F. Philhower, III 7bfe25b8aa Remove SDK C++ new/delete, duplicated objects (#2760)
* Remove Pico-SDK C++ exception-override new/delete

We support exceptions on and off, but the cxx_options file in the
SDK implemented a single override to new/delete.

Remove it so we will use GCC's build-in operator new/delete
which will be correct for either option (2 different libstdc++
versions are shipped as part of the toolchain).

* Remove duplicated SDK files

The SDK will link in the same compilation unit in the LWIP builds.
Remove them to shrink the repo size by ~28MB.
2025-01-16 15:02:01 -08:00
SomebodyOdd 2348051026 A2DPSink: Remove stubs, fix volume and connect callbacks (#2757)
* A2DPSink: Remove Stream implementation and onTransmit
* A2DPSink: Fix onConnect and onVolume callbacks
* A2DPSink: Remove transmit callback field
2025-01-16 09:37:22 -08:00
Dryw WadeandKirk Benell b4001bfb0e Add SparkFun IoT Node LoRaWAN (#2745)
* added files to support the SparkFun IoT Node LoRaWAN board

* added rp2053 to our lorawan board defs

* adding updates/new files generated for the iot node board

* Add SPI swap

* Remove incorrect comment from IoT Node LoRawAN

* Replace missing line in boards.txt

* Re-run makeboards.py for IoT Node LoRaWAN

---------

Co-authored-by: Kirk Benell <kirk.benell@sparkfun.com>
2025-01-15 09:47:55 -08:00
Earle F. Philhower, III 0655b7d5b6 Fix ADCInput clocks for multiple inputs (#2755)
When multiple inputs were active, the frequency was being scaled two
times resulting in incorrect sampling speed.  Correct to only scale
the calculation and not the stored value (which is used in `begin`).

Fixes #2754
2025-01-14 15:58:45 -08:00
Earle F. Philhower, III 83b8d122d7 Restore Bluetooth TLV on Pico2/RPiWiFi boards (#2753) 2025-01-13 17:38:51 -08:00
timw01 8caa590f5c Correct return from NTP.waitSet() (#2736)
Fixes #2735
2025-01-04 17:06:26 -08:00
Earle F. Philhower, III ec528d34f8 Remove unneeded SDK files from libpico/etc. (#2733)
Pico-SDK changed the output extension of their compilation from "x.c.obj"
to "x.c.o" meaning the removed Newlib and STDIO SDK wrappers were still
being linked in certain situations.  Update make-libpico Cmakefile to
remove the new names.

Fixes debug `printf` output.
2025-01-03 10:42:47 -08:00
Earle F. Philhower, III 5296241949 Update version 2024-12-31 10:35:02 -08:00
Earle F. Philhower, III d84ff02f03 Allow setting PWMAudio frequency before begin (#2726)
I2S allows setting freq before ::begin, so allow same for PWMAudio.
2024-12-30 10:57:40 -08:00
Earle F. Philhower, III cc2581afd6 Properly wrap AudioBufferManager block writes (#2725)
The memcpy-version of the ABM::write updated the destination and count
but neglected to move the source forward.  If a block write crossed a
frame boundary then the 2nd frame would repeat the data from the first
half of the buffer.

Fix by incrementing the source pointer by the same amount as was written.
2024-12-29 16:26:23 -08:00
Earle F. Philhower, III bb682bbb33 Use the distributed ARM ar in libpico, not system (#2721)
Fixes #508
2024-12-29 10:29:42 -08:00
Earle F. Philhower, III 809beffc8b Add AudioOutputBase keyword 2024-12-27 10:15:05 -08:00
Earle F. Philhower, III fa22c6c627 RTD has its own key for PDF generation 2024-12-27 08:48:39 -08:00
Earle F. Philhower, III 0788a42477 RTD doesn't do formats:PDF, revert 2024-12-27 08:44:58 -08:00
Earle F. Philhower, III d732ac82ba Precalculate common PWMAudio dividers, avoid noise (#2714)
Calculating the DMA clock divider for PWMAudio can take a very long time
because there are 65K floating point divisions required.  But most audio
will be one of a dozen sample rates, so it is possible to precalculate
the rates on the host and use a small lookup table to avoid any math at
all.  Removes occasional scratching in PWMAudio when the BackgroundAudio
library changes sample rates.
2024-12-22 14:05:44 -08:00
Earle F. Philhower, III 5fb5e16be8 Add real block write for AudioRequestBuffer (#2712)
Optimize AudioRequestBuffer writing when large blocks are available (i.e.
I2S writes of full MP3 or AAC frames in BackgroundAudio).  Update I2S to use
the new call.  Reduces 1152 calls to arb::write() to a single call/return
and optimized memcpy in that case.
2024-12-21 14:15:40 -08:00
Earle F. Philhower, III 45c0b3a1b4 Move MacX86 runner up to new minimum spec (#2711)
The MacOS12 runner is dead, so move up to the lowest version still available for CI.
2024-12-21 10:27:44 -08:00
Markus Gyger 7961d2943d Overclock to 153.6 MHz (instead of 147.6 MHz) for I²S 48 kHz sample rate (#2708) 2024-12-21 07:36:57 -08:00
Kjell Braden 4d03edc7d5 Don't go through runtime initializers when there is no OTA command (#2697)
Leave that to the main app instead, so we don't reset peripherals twice.
* ota: fix copy error for riscv headers
* ota: initialize bootrom bit ops and add explanation
2024-12-19 10:05:46 -08:00
CIncinnatus d5a6888cac Fix issue with undefined LED_BUILTIN on Seeed Xiao RP2350 (#2704)
* Modify the pin definitions for XIAO RP2350

* Fix issue with undefined LED_BUILTIN
2024-12-19 09:02:32 -08:00
Earle F. Philhower, III a13d236afd Update fs.rst 2024-12-19 07:00:59 -08:00
Earle F. Philhower, III 2f99b0ae2f Update version 2024-12-18 17:51:11 -08:00
Tristan Rowley 681a4c5482 Add Pimoroni Plasma 2350, fix Plasma 2040 I2C (#2698)
* my attempt at adding plasma_2040 support.. cant seem to get it working to test yet though?

* Tracked+replaced files, this now works it seems!

* correct serial count

* Update pins_arduino.h

* Rudimentary Pimoroni Plasma2350 support.

* include correct files + changes needed for proper support.

also!! fixes pin definitions for the i2c on Pimoroni Plasma 2350 (tested, working) and (presumably, untested) on the Plasma RP2040 too by swapping the i2c numbers.  i2c now works!!

* use correct USB PID for Plasma 2350
2024-12-18 17:49:07 -08:00
Earle F. Philhower, III eecbcdf59a Derive playback devices from common AudioOutputBase (#2703)
The audio output objects all have the same general necessary configuration
calls.  Abstract them out to a generic AudioOutputBase interface class that
they will inherit from.  Simplifies letting applications use different
output channels.

Should be backwards compatible with existing code.
2024-12-18 12:19:40 -08:00
Earle F. Philhower, III f1b965f704 Allow I2S constructor to set pins, like PWMAudio (#2702)
Pins are a physical connection, makes sense to define them at construction.
2024-12-18 10:06:54 -08:00
Earle F. Philhower, III 66af359578 Remove unused variable from AudioBufferManager class (#2701) 2024-12-18 07:06:40 -08:00
Earle F. Philhower, III d65b030644 Add PDF output to readthedocs.yaml (#2700) 2024-12-18 06:48:47 -08:00
Earle F. Philhower, III 33b126836f Support setting channel for SoftAP (#2695)
Fixes #2694
2024-12-17 08:34:14 -08:00
Earle F. Philhower, III def00bac66 Fix ordering of boards in menus (#2696)
Been a little cruft in the order of boards, rearrange alphabetically.
2024-12-16 19:45:30 -08:00
mr.chaiwat chainvong 06e3ef9556 Add MyMakers RP2040 board (#2692) 2024-12-16 19:28:03 -08:00
Heng Teng YiandHTY2003 dc0dc50e36 Modify EVN Alpha board (#2690)
Co-authored-by: HTY2003 <randumbperson@gmail.com>
2024-12-15 16:39:31 -08:00
Earle F. Philhower, III 21a767e7e4 Semihosting part of core, RISC-V support (#2685)
Semihosting is handy for debugging, so allow the core to use `SerialSemi` as the
::printf port.  Add menu item to the IDE to allow selection.

Add RISC-V implementation of semihost call
2024-12-14 09:42:45 -08:00
Earle F. Philhower, III a02e188fc7 PWMAudio setFrequency optimization (#2683)
If we set the frequency to the same one running, no need to do anything.
2024-12-13 08:04:50 -08:00
Earle F. Philhower, III e56a295e34 Add MDNS.addServiceTxt() to SimpleMDNS (#2679)
* Add MDNS.addServiceTxt() to SimpleMDNS

Fixes #2678

A simple mapping allows for basic service text addition even when using
SimpleMDNS and ArduinoOTA.

* Protection against duplicate services addition
2024-12-12 11:55:14 -08:00
Earle F. Philhower, III 5b4dff9a77 Add optional callback parameters for I2S/PWMAudio (#2677)
Like GPIO interrupts, allow the user to pass in a callback data pointer.
2024-12-11 14:53:54 -08:00
Kirk D. Benell abc07ef4e5 Add build.mcu to board definitions (#2673)
* added logic so that the build.mcu value is written to a board defintion in boards.txt. This is needed for Arduino libs that use precompiled/archive libs

* move the setting for the build.mcu as recommended - to manage the different archs available on the rp2340
2024-12-06 10:38:08 -08:00
Earle F. Philhower, III 0061d3f97f Enable gprof onboard profiling (#2669)
Adds a menu item to enable onboard profiling.  This requires significant
RAM and really only makes sense on devices with PSRAM to store the state.

When the menu item is selected, allocates RAM and tracks function calls and
periodically samples the PC to generate a histogram of application usage.
The onboard gmon.out file can be written over Semihosting or
some other way to transfer to a PC for analysis.

Adds a profiling example with command lines.
2024-12-05 17:30:45 -08:00
Earle F. Philhower, III 48bc91af36 Update semihosting.rst typo 2024-12-04 16:33:46 -08:00
Earle F. Philhower, III 1725e2109f Add semihosting support (SerialSemi and SemiFS) (#2670)
Enable ARM-only semihosting mode.  This mode allows applications on the
Pico to write to the OpenOCD console and read and write files on the
host system (i.e. debugging dump information, etc.)

It is not very fast because of the way it uses breakpoints on the Pico
to communicate, but it is useful in cases when you want to get a single
file off of the Pico while debugging.

Note that this **requires** a connected OpenOCD and GDB or else the
semihosting will cause a system panic.
2024-12-04 16:07:46 -08:00
Earle F. Philhower, III f2d30abb1c Add -O0 optimization mode to menus (#2667)
GCC will still do several optimizations in -Og mode which can make it hard
to see local temporary variables.
2024-12-03 16:11:56 -08:00
Earle F. Philhower, III f2fc68f55e GDB + mklittlefs can expand on-device filesystems (#2666) 2024-12-03 16:01:18 -08:00
Earle F. Philhower, III 34e02aaeb5 Update version 2024-12-02 11:39:24 -08:00
Earle F. Philhower, III 6024e9a7e8 Increase LWIP timeouts to avoid MDNS panics (#2653)
Bump up the LWIP_ARP setting to increase the LWIP timeout pool to
avoid a panic when using SimpleMDNS and TCP clients.

Fixes #2650
2024-11-30 10:43:19 -08:00
Earle F. Philhower, III 633faa18ac Update to Adafruit TinyUSB 3.4.1 (#2647) 2024-11-27 13:04:36 -08:00
Earle F. Philhower, III 90d4841be7 Fix LED pin for Pico 2W (#2646)
Fixes #2644
2024-11-27 12:40:09 -08:00
Linar Yusupov e16c459598 Fix for cyw43_wrappers.h build with C code (#2639) 2024-11-26 00:48:34 -08:00
Earle F. Philhower, III 33b0fd57a0 Fix pinMode for RP2040 PicoW (#2638)
Enable WL_DYNAMIC on the RP2040 lib builds.

Fixes #2637
2024-11-26 00:31:41 -08:00
Earle F. Philhower, III 7add6250e0 Update version 2024-11-25 10:44:58 -08:00
Earle F. Philhower, III 4068601b01 Update to SDK 2.1.0, add Pico 2W (#2629)
Update to Pico SDK 2.1.0, remove XIP and PSRAM workarounds.

Add Pico2W board.
2024-11-25 10:43:55 -08:00
Earle F. Philhower, III 9cea4708c8 Update README.md 2024-11-21 15:31:40 -08:00
Jeff Eplerandladyada 1a41be1eb0 Add Adafruit Floppsy board (#2628)
Co-authored-by: ladyada <limor@ladyada.net>
2024-11-21 15:30:59 -08:00
Earle F. Philhower, III 996c3bfab9 Clean up unused parameter warnings (#2624) 2024-11-19 13:55:00 -08:00
Earle F. Philhower, III 322a1af6da Avoid memory (de)allocation in GPIO ISR handler (#2623)
Replace std::map, which can `new` and `delete` elements of the tree,
with a statically allocated array and housekeeping.

Fixes #2622
2024-11-19 12:26:47 -08:00
Earle F. Philhower, III e25d382732 Support WiFi/BT/BLT with RP2350 CYW43 boards (#2616)
Using pico-sdk develop branch, add in support for CYW43-based
WiFi/BT/BLE boards on the RP2350 such as the
SparkFun Thing Plus RP2350 or the Pimoroni Pico Plus 2W.

Fixes #2608

Rolls in dynamic SPI divider #2600

* Support LED digitalWrite on RP2350+CYW

Also move "special GPIO" to 64 since the Pimoroni Pico 2W uses the
RP2350B with 48 GPIOs.

* Enable CYW43_PIN_WL_DYNAMIC in IDE and P.IO

Allows calling `cyw43_set_pins_wl(cyw43_pin_array);` to redefine the
CYW43 hookup in the variant initialization.
2024-11-19 10:28:12 -08:00
Earle F. Philhower, III bda12cd7e7 WiFiUDP only emit a packet on flush if not ended (#2618)
A flush() on a packet that's already been sent should be a no-op, not
send a 0-byte UDP packet.  Track when an outgoing packet is dirty and
only endPacket()/transmit it when so.

Fixes #2617
2024-11-17 08:58:44 -08:00
201 changed files with 9027 additions and 1259 deletions
-6
View File
@@ -29,12 +29,6 @@ jobs:
# add to PATH
echo "$GITHUB_WORKSPACE/system/riscv32-unknown-elf/bin" >> "$GITHUB_PATH"
echo "$GITHUB_WORKSPACE/system/arm-none-eabi/bin" >> "$GITHUB_PATH"
# Needed until we switch to Pico-SDK 2.0.1.
- name: Patch Pico-SDK (Fix Assembly for newer GCC)
run: |
cd pico-sdk
wget https://patch-diff.githubusercontent.com/raw/raspberrypi/pico-sdk/pull/2000.patch
patch -p1 < 2000.patch
- name: Build libpico
run: |
cd tools/libpico
+2 -2
View File
@@ -20,7 +20,7 @@ jobs:
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
ignore_words_list: ser,dout,shiftIn,acount,froms
- name: Get submodules for following tests
run: git submodule update --init
- name: Check package references
@@ -196,7 +196,7 @@ jobs:
name: Mac
strategy:
matrix:
os: [macOS-12, macOS-14]
os: [macOS-13, macOS-14]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
+2
View File
@@ -3,5 +3,7 @@ system
tools/dist
docs/_build
ota/build
ota/build-rp2350
ota/build-rp2350-riscv
tools/libpico/build
platform.local.txt
+3 -3
View File
@@ -10,9 +10,6 @@
[submodule "libraries/LittleFS/lib/littlefs"]
path = libraries/LittleFS/lib/littlefs
url = https://github.com/littlefs-project/littlefs.git
[submodule "libraries/SdFat"]
path = libraries/ESP8266SdFat
url = https://github.com/earlephilhower/ESP8266SdFat.git
[submodule "libraries/Keyboard"]
path = libraries/HID_Keyboard
url = https://github.com/earlephilhower/Keyboard.git
@@ -49,3 +46,6 @@
[submodule "libraries/ESPHost"]
path = libraries/ESPHost
url = https://github.com/Networking-for-Arduino/ESPHost.git
[submodule "libraries/SdFat"]
path = libraries/SdFat
url = https://github.com/greiman/SdFat.git
+2 -2
View File
@@ -29,8 +29,8 @@ sphinx:
# fail_on_warning: true
# Optionally build your docs in additional formats such as PDF and ePub
# formats:
# - pdf
formats:
- pdf
# - epub
# Optional but recommended, declare the Python requirements required
+10 -2
View File
@@ -16,13 +16,16 @@ Read the [Contributing Guide](https://github.com/earlephilhower/arduino-pico/blo
* Raspberry Pi Pico
* Raspberry Pi Pico W
* Raspberry Pi Pico 2
* Raspberry Pi Pico 2W
* 0xCB Helios
* Adafruit Feather RP2040
* Adafruit Feather RP2040 SCORPIO
* Adafruit Floppsy RP2040
* Adafruit ItsyBitsy RP2040
* Adafruit KB2040
* Adafruit Macropad RP2040
* Adafruit Metro RP2040
* Adafruit Metro RP2350
* Adafruit QTPy RP2040
* Adafruit STEMMA Friend RP2040
* Adafruit Trinkey RP2040 QT
@@ -66,13 +69,16 @@ Read the [Contributing Guide](https://github.com/earlephilhower/arduino-pico/blo
* Melopero Cookie RP2040
* Melopero Shake RP2040
* METE HOCA Akana R1
* MyMakers RP2040
* Neko Systems BL2040 Mini
* Olimex RP2040-Pico30
* Newsan Archi
* nullbits Bit-C PRO
* Olimex RP2040-Pico30
* Pimoroni PGA2040
* Pimoroni Pico Plus 2
* Pimoroni Pico Plus 2W
* Pimoroni Plasma2040
* Pimoroni Plasma2350
* Pimoroni Tiny2040
* Pimoroni Tiny2350
* Pintronix PinMax
@@ -134,6 +140,8 @@ Read the [Contributing Guide](https://github.com/earlephilhower/arduino-pico/blo
* 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
* Semihosted serial and file system access
* GPROF profiling support
The RP2040 PIO state machines (SMs) are used to generate jitter-free:
* Servos
@@ -141,7 +149,7 @@ The RP2040 PIO state machines (SMs) are used to generate jitter-free:
* I2S Input
* I2S Output
* Software UARTs (Serial ports)
* Software SPIs
# Installing via Arduino Boards Manager
## Windows-specific Notes
+3551 -369
View File
File diff suppressed because it is too large Load Diff
+6 -1
View File
@@ -110,7 +110,7 @@ extern bool __isFreeRTOS;
#endif
#ifndef PGM_VOID_P
#define PGM_VOID_P void *
#define PGM_VOID_P const void *
#endif
#ifdef __cplusplus
@@ -126,6 +126,7 @@ extern const String emptyString;
#endif
#include "SerialUART.h"
#include "SerialSemi.h"
#include "RP2040Support.h"
#include "SerialPIO.h"
#include "Bootsel.h"
@@ -158,3 +159,7 @@ constexpr uint64_t __bitset(const int (&a)[N], size_t i = 0U) {
#define __GPIOCNT 30
#define __FIRSTANALOGGPIO 26
#endif
#ifdef __cplusplus
using namespace arduino;
#endif
+21
View File
@@ -0,0 +1,21 @@
// Abstract class for audio output devices to allow easy swapping between output devices
#pragma once
#include <Print.h>
class AudioOutputBase : public Print {
public:
virtual ~AudioOutputBase() { }
virtual bool setBuffers(size_t buffers, size_t bufferWords, int32_t silenceSample = 0) = 0;
virtual bool setBitsPerSample(int bps) = 0;
virtual bool setFrequency(int freq) = 0;
virtual bool setStereo(bool stereo = true) = 0;
virtual bool begin() = 0;
virtual bool end() = 0;
virtual bool getUnderflow() = 0;
virtual void onTransmit(void(*)(void *), void *) = 0;
// From Print
virtual size_t write(const uint8_t *buffer, size_t size) = 0;
virtual int availableForWrite() = 0;
};
+7 -9
View File
@@ -33,7 +33,6 @@
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) {
@@ -64,16 +63,16 @@ bool PIOProgram::prepare(PIO *pio, int *sm, int *offset, int start, int cnt) {
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);
uint gpioBaseNeeded = ((start + cnt) >= 32) ? 16 : 0;
DEBUGV("PIOProgram %p: Searching for base=%d, pins %d-%d\n", _pgm, gpioBaseNeeded, 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)) {
if ((p != __pioMap[o].end()) && (pio_get_gpio_base(pio_get_instance(o)) == gpioBaseNeeded)) {
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);
DEBUGV("PIOProgram %p: Reusing IMEM ON PIO %p(base=%d) for pins %d-%d\n", _pgm, pi[o], pio_get_gpio_base(pio_get_instance(o)), start, start + cnt - 1);
_pio = pi[o];
_sm = idx;
*pio = pi[o];
@@ -86,12 +85,12 @@ bool PIOProgram::prepare(PIO *pio, int *sm, int *offset, int start, int cnt) {
// Not in any PIO IRAM, so try and add
for (int o = 0; o < PIOCNT; o++) {
if (__pioAllocated[o] && (__pioHighGPIO[o] == needsHigh)) {
if (__pioAllocated[o] && (pio_get_gpio_base(pio_get_instance(o)) == gpioBaseNeeded)) {
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);
DEBUGV("PIOProgram %p: Adding IMEM ON PIO %p(base=%d) for pins %d-%d\n", _pgm, pi[o], pio_get_gpio_base(pio_get_instance(o)), start, start + cnt - 1);
int off = pio_add_program(pi[o], _pgm);
__pioMap[o].insert({_pgm, off});
_pio = pi[o];
@@ -123,8 +122,7 @@ bool PIOProgram::prepare(PIO *pio, int *sm, int *offset, int start, int cnt) {
}
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);
DEBUGV("PIOProgram %p: Allocating new PIO %p(base=%d) for pins %d-%d\n", _pgm, pi[o], pio_get_gpio_base(pio_get_instance(o)), start, start + cnt - 1);
__pioMap[o].insert({_pgm, off});
_pio = pi[o];
_sm = idx;
+17 -1
View File
@@ -18,9 +18,11 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <Arduino.h>
#include <pico/runtime.h>
#ifdef PICO_RP2040
#include <Arduino.h>
#include <hardware/structs/psm.h>
extern "C" void boot_double_tap_check();
@@ -35,3 +37,17 @@ void RP2040::enableDoubleResetBootloader() {
}
#endif
#ifdef __PROFILE
Stream *__profileFile;
int __writeProfileCB(const void *data, int len) {
return __profileFile->write((const char *)data, len);
}
#ifdef __PROFILE
extern "C" void runtime_init_setup_profiling();
#define PICO_RUNTIME_INIT_PROFILING "11011" // Towards the end, after PSRAM
PICO_RUNTIME_INIT_FUNC_RUNTIME(runtime_init_setup_profiling, PICO_RUNTIME_INIT_PROFILING);
#endif
#endif
+31 -7
View File
@@ -18,6 +18,8 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include <hardware/clocks.h>
#include <hardware/irq.h>
#include <hardware/pio.h>
@@ -45,6 +47,13 @@
extern "C" volatile bool __otherCoreIdled;
extern "C" {
#ifdef __PROFILE
typedef int (*profileWriteCB)(const void *data, int len);
extern void _writeProfile(profileWriteCB writeCB);
#endif
}
class _MFIFO {
public:
_MFIFO() { /* noop */ };
@@ -180,7 +189,7 @@ public:
void begin() {
_epoch = 0;
#if !defined(__riscv)
#if !defined(__riscv) && !defined(__PROFILE)
if (!__isFreeRTOS) {
// Enable SYSTICK exception
exception_set_exclusive_handler(SYSTICK_EXCEPTION, _SystickHandler);
@@ -193,7 +202,7 @@ public:
_ccountPgm->prepare(&_pio, &_sm, &off);
ccount_program_init(_pio, _sm, off);
pio_sm_set_enabled(_pio, _sm, true);
#if !defined(__riscv)
#if !defined(__riscv) && !defined(__PROFILE)
}
#endif
}
@@ -217,7 +226,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 !defined(__riscv) && !defined(__PROFILE)
if (!__isFreeRTOS) {
uint32_t epoch;
uint32_t ctr;
@@ -229,13 +238,13 @@ public:
} else {
#endif
return ccount_read(_pio, _sm);
#if !defined(__riscv)
#if !defined(__riscv) && !defined(__PROFILE)
}
#endif
}
inline uint64_t getCycleCount64() {
#if !defined(__riscv)
#if !defined(__riscv) && !defined(__PROFILE)
if (!__isFreeRTOS) {
uint64_t epoch;
uint64_t ctr;
@@ -247,7 +256,7 @@ public:
} else {
#endif
return ccount_read(_pio, _sm);
#if !defined(__riscv)
#if !defined(__riscv) && !defined(__PROFILE)
}
#endif
}
@@ -465,7 +474,7 @@ public:
}
bool isPicoW() {
#if !defined(ARDUINO_RASPBERRY_PI_PICO_W)
#if !defined(PICO_CYW43_SUPPORTED)
return false;
#else
extern bool __isPicoW;
@@ -473,6 +482,21 @@ public:
#endif
}
#ifdef __PROFILE
void writeProfiling(Stream *f) {
extern Stream *__profileFile;
extern int __writeProfileCB(const void *data, int len);
__profileFile = f;
_writeProfile(__writeProfileCB);
}
size_t getProfileMemoryUsage() {
extern int __profileMemSize;
return (size_t) __profileMemSize;
}
#endif
private:
static void _SystickHandler() {
+3 -3
View File
@@ -1,5 +1,5 @@
#pragma once
#define ARDUINO_PICO_MAJOR 4
#define ARDUINO_PICO_MINOR 2
#define ARDUINO_PICO_REVISION 1
#define ARDUINO_PICO_VERSION_STR "4.2.1"
#define ARDUINO_PICO_MINOR 4
#define ARDUINO_PICO_REVISION 4
#define ARDUINO_PICO_VERSION_STR "4.4.4"
+297
View File
@@ -0,0 +1,297 @@
/*
SemiFS.h - File system wrapper for Semihosting ARM
Copyright (c) 2024 Earle F. Philhower, III. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include "Semihosting.h"
#include "FS.h"
#include "FSImpl.h"
using namespace fs;
namespace semifs {
class SemiFSFileImpl;
class SemiFSConfig : public FSConfig {
public:
static constexpr uint32_t FSId = 0x53454d49;
SemiFSConfig() : FSConfig(FSId, false) { }
};
class SemiFSFileImpl : public FileImpl {
public:
SemiFSFileImpl(int fd, const char *name, bool writable)
: _fd(fd), _opened(true), _writable(writable) {
_name = std::shared_ptr<char>(new char[strlen(name) + 1], std::default_delete<char[]>());
strcpy(_name.get(), name);
}
~SemiFSFileImpl() override {
flush();
close();
}
int availableForWrite() override {
return 1; // TODO - not implemented? _opened ? _fd->availableSpaceForWrite() : 0;
}
size_t write(const uint8_t *buf, size_t size) override {
if (_opened) {
uint32_t a[3];
a[0] = _fd;
a[1] = (uint32_t)buf;
a[2] = size;
return 0 == Semihost(SEMIHOST_SYS_WRITE, a) ? size : -1;
}
return -1; // some kind of error
}
int read(uint8_t* buf, size_t size) override {
if (_opened) {
uint32_t a[3];
a[0] = _fd;
a[1] = (uint32_t)buf;
a[2] = size;
int ret = Semihost(SEMIHOST_SYS_READ, a);
if (ret == 0) {
return size;
} else if (ret == (int)size) {
return -1;
} else {
return ret;
}
}
return -1;
}
void flush() override {
/* noop */
}
bool seek(uint32_t pos, SeekMode mode) override {
if (!_opened || (mode != SeekSet)) {
// No seek cur/end in semihost
return false;
}
uint32_t a[2];
a[0] = _fd;
a[1] = pos;
return !Semihost(SEMIHOST_SYS_SEEK, a);
}
size_t position() const override {
return 0; // Not available semihost
}
size_t size() const override {
if (!_opened) {
return 0;
}
uint32_t a;
a = _fd;
int ret = Semihost(SEMIHOST_SYS_FLEN, &a);
if (ret < 0) {
return 0;
}
return ret;
}
bool truncate(uint32_t size) override {
return false; // Not allowed
}
void close() override {
if (_opened) {
uint32_t a = _fd;
Semihost(SEMIHOST_SYS_CLOSE, &a);
_opened = false;
}
}
const char* name() const override {
if (!_opened) {
DEBUGV("SemiFSFileImpl::name: file not opened\n");
return nullptr;
} else {
const char *p = _name.get();
const char *slash = strrchr(p, '/');
// For names w/o any path elements, return directly
// If there are slashes, return name after the last slash
// (note that strrchr will return the address of the slash,
// so need to increment to ckip it)
return (slash && slash[1]) ? slash + 1 : p;
}
}
const char* fullName() const override {
return _opened ? _name.get() : nullptr;
}
bool isFile() const override {
return _opened; // Could look at ISTTY but that's not the sense here. Just differentiating between dirs and files
}
bool isDirectory() const override {
return false;
}
time_t getLastWrite() override {
return getCreationTime(); // TODO - FatFS doesn't seem to report both filetimes
}
time_t getCreationTime() override {
time_t ftime = 0;
return ftime;
}
protected:
int _fd;
std::shared_ptr<char> _name;
bool _opened;
bool _writable;
};
class SemiFSImpl : public FSImpl {
public:
SemiFSImpl() {
/* noop */
}
FileImplPtr open(const char* path, OpenMode openMode, AccessMode accessMode) override {
if (!path || !path[0]) {
DEBUGV("SemiFSImpl::open() called with invalid filename\n");
return FileImplPtr();
}
// Mode conversion https://developer.arm.com/documentation/dui0471/m/what-is-semihosting-/sys-open--0x01-?lang=en
int mode = 1; // "rb"
if (accessMode == AM_READ) {
mode = 1; // "rb"
} else if (accessMode == AM_WRITE) {
if (openMode & OM_APPEND) {
mode = 9; // "ab";
} else {
mode = 5; // "wb";
}
} else {
if (openMode & OM_TRUNCATE) {
mode = 7; // "w+b";
} else if (openMode & OM_APPEND) {
mode = 3; // "r+b"
} else {
mode = 11; // "a+b";
}
}
uint32_t a[3];
a[0] = (uint32_t)path;
a[1] = mode;
a[2] = strlen(path);
int handle = Semihost(SEMIHOST_SYS_OPEN, a);
if (handle < 0) {
return FileImplPtr();
}
return std::make_shared<SemiFSFileImpl>(handle, path, (accessMode & AM_WRITE) ? true : false);
}
bool exists(const char* path) override {
File f = open(path, OM_DEFAULT, AM_READ);
return f ? true : false;
}
DirImplPtr openDir(const char* path) override {
// No directories
return DirImplPtr();
}
bool rename(const char* pathFrom, const char* pathTo) override {
uint32_t a[4];
a[0] = (uint32_t)pathFrom;
a[1] = strlen(pathFrom);
a[2] = (uint32_t)pathTo;
a[3] = strlen(pathTo);
return !Semihost(SEMIHOST_SYS_RENAME, a);
}
bool info(FSInfo& info) override {
// Not available
return false;
}
bool remove(const char* path) override {
uint32_t a[2];
a[0] = (uint32_t)path;
a[1] = strlen(path);
return !Semihost(SEMIHOST_SYS_REMOVE, a);
}
bool mkdir(const char* path) override {
// No mkdir
return false;
}
bool rmdir(const char* path) override {
// No rmdir
return false;
}
bool stat(const char *path, FSStat *st) override {
if (!path || !path[0]) {
return false;
}
uint32_t a[3];
a[0] = (uint32_t)path;
a[1] = 0; // READ
a[2] = strlen(path);
int fn = Semihost(SEMIHOST_SYS_OPEN, a);
if (fn < 0) {
return false;
}
bzero(st, sizeof(*st));
a[0] = fn;
st->size = Semihost(SEMIHOST_SYS_FLEN, a);
a[0] = fn;
Semihost(SEMIHOST_SYS_CLOSE, a);
return true;
}
bool setConfig(const FSConfig &cfg) override {
return true;
}
bool begin() override {
/* noop */
return true;
}
void end() override {
/* noop */
}
bool format() override {
return false;
}
};
}; // namespace sdfs
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SEMIFS)
extern FS SemiFS;
using semifs::SemiFSConfig;
#endif
+6
View File
@@ -0,0 +1,6 @@
#include "Semihosting.h"
#include "SerialSemi.h"
#include "SemiFS.h"
SerialSemiClass SerialSemi;
FS SemiFS = FS(FSImplPtr(new semifs::SemiFSImpl()));
+99
View File
@@ -0,0 +1,99 @@
/*
Semihosting.h - Semihosting for Serial and FS access via GDB
Copyright (c) 2024 Earle F. Philhower, III. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
// Be sure to only use this library with GDB and to enable the ARM semihosting support
// (gdb) monitor arm semihosting enable
// Input/output will be handled by OpenOCD
// From https://developer.arm.com/documentation/dui0471/g/Semihosting/Semihosting-operations?lang=en
typedef enum {
SEMIHOST_SYS_CLOSE = 0x02,
SEMIHOST_SYS_CLOCK = 0x10,
SEMIHOST_SYS_ELAPSED = 0x30,
SEMIHOST_SYS_ERRNO = 0x13,
SEMIHOST_SYS_FLEN = 0x0C,
SEMIHOST_SYS_GET_CMDLINE = 0x15,
SEMIHOST_SYS_HEAPINFO = 0x16,
SEMIHOST_SYS_ISERROR = 0x08,
SEMIHOST_SYS_ISTTY = 0x09,
SEMIHOST_SYS_OPEN = 0x01,
SEMIHOST_SYS_READ = 0x06,
SEMIHOST_SYS_READC = 0x07,
SEMIHOST_SYS_REMOVE = 0x0E,
SEMIHOST_SYS_RENAME = 0x0F,
SEMIHOST_SYS_SEEK = 0x0A,
SEMIHOST_SYS_SYSTEM = 0x12,
SEMIHOST_SYS_TICKFREQ = 0x31,
SEMIHOST_SYS_TIME = 0x11,
SEMIHOST_SYS_TMPNAM = 0x0D,
SEMIHOST_SYS_WRITE = 0x05,
SEMIHOST_SYS_WRITEC = 0x03,
SEMIHOST_SYS_WRITE0 = 0x04
} SEMIHOST_OPCODES;
#ifdef __arm__
// From https://github.com/ErichStyger/mcuoneclipse/blob/master/Examples/MCUXpresso/FRDM-K22F/FRDM-K22F_Semihosting/source/McuSemihost.c
static inline int __attribute__((always_inline)) Semihost(int reason, void *arg) {
int value;
__asm volatile(
"mov r0, %[rsn] \n" /* place semihost operation code into R0 */
"mov r1, %[arg] \n" /* R1 points to the argument array */
"bkpt 0xAB \n" /* call debugger */
"mov %[val], r0 \n" /* debugger has stored result code in R0 */
: [val] "=r"(value) /* outputs */
: [rsn] "r"(reason), [arg] "r"(arg) /* inputs */
: "r0", "r1", "r2", "r3", "ip", "lr", "memory", "cc" /* clobber */
);
return value; /* return result code, stored in R0 */
}
#else
// https://groups.google.com/a/groups.riscv.org/g/sw-dev/c/n-5VQ9PHZ4w/m/KbzH5t9MBgAJ
static inline int __attribute__((always_inline)) Semihost(int reason, void *argPack) {
register int value asm("a0") = reason;
register void *ptr asm("a1") = argPack;
asm volatile(
// Force 16-byte alignment to make sure that the 3 instructions fall
// within the same virtual page.
" .balign 16 \n"
" .option push \n"
// Force non-compressed RISC-V instructions
" .option norvc \n"
// semihosting e-break sequence
" slli x0, x0, 0x1f \n" // # Entry NOP
" ebreak \n" // # Break to debugger
" srai x0, x0, 0x7 \n" // # NOP encoding the semihosting call number 7
" .option pop \n"
/*mark (value) as an output operand*/
: "=r"(value) /* Outputs */
// The semihosting call number is passed in a0, and the argument in a1.
: "0"(value), "r"(ptr) /* Inputs */
// The "memory" clobber makes GCC assume that any memory may be arbitrarily read or written by the asm block,
// so will prevent the compiler from reordering loads or stores across it, or from caching memory values in registers across it.
// The "memory" clobber also prevents the compiler from removing the asm block as dead code.
: "memory" /* Clobbers */
);
return value;
}
#endif
+1 -1
View File
@@ -29,7 +29,7 @@
extern "C" typedef struct uart_inst uart_inst_t;
class SerialPIO : public HardwareSerial {
class SerialPIO : public arduino::HardwareSerial {
public:
static const pin_size_t NOPIN = 0xff; // Use in constructor to disable RX or TX unit
SerialPIO(pin_size_t tx, pin_size_t rx, size_t fifoSize = 32);
+98
View File
@@ -0,0 +1,98 @@
/*
SerialSemi.h - Serial port over Semihosting for ARM
Copyright (c) 2024 Earle F. Philhower, III. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include "Semihosting.h"
#include "Arduino.h"
#include "api/HardwareSerial.h"
class SerialSemiClass : public arduino::HardwareSerial {
public:
SerialSemiClass() {
/* noop */
}
~SerialSemiClass() {
/* noop */
}
void begin(unsigned long baudIgnored = 115200) override {
(void)baudIgnored;
}
void begin(unsigned long baudIgnored, uint16_t configIgnored) override {
(void)baudIgnored;
(void)configIgnored;
}
void end() override {
/* noop */
}
virtual int peek() override {
// Can't really peek on SH, so fake it best we can
if (!_peeked) {
_peekedChar = read();
_peeked = true;
}
return _peekedChar;
}
virtual int read() override {
if (_peeked) {
_peeked = false;
return _peekedChar;
}
return Semihost(SEMIHOST_SYS_READC, nullptr);
}
virtual int available() override {
// Can't really tell with SH, so always true. Buyer beware
return 1;
}
virtual int availableForWrite() override {
// Can't really tell with SH, so always true. Buyer beware
return 1;
}
virtual void flush() override {
/* noop */
}
virtual size_t write(uint8_t c) override {
int32_t param = c;
Semihost(SEMIHOST_SYS_WRITEC, &param);
return 1;
}
using Print::write;
operator bool() override {
return true;
}
private:
bool _peeked = false;
uint8_t _peekedChar;
};
extern SerialSemiClass SerialSemi;
+1 -1
View File
@@ -29,7 +29,7 @@
extern "C" typedef struct uart_inst uart_inst_t;
#define UART_PIN_NOT_DEFINED (255u)
class SerialUART : public HardwareSerial {
class SerialUART : public arduino::HardwareSerial {
public:
SerialUART(uart_inst_t *uart, pin_size_t tx, pin_size_t rx, pin_size_t rts = UART_PIN_NOT_DEFINED, pin_size_t cts = UART_PIN_NOT_DEFINED);
+1 -1
View File
@@ -24,7 +24,7 @@
#include "api/HardwareSerial.h"
#include <stdarg.h>
class SerialUSB : public HardwareSerial {
class SerialUSB : public arduino::HardwareSerial {
public:
SerialUSB() { }
void begin(unsigned long baud = 115200) override;
+2 -5
View File
@@ -71,10 +71,7 @@ void tone(uint8_t pin, unsigned int frequency, unsigned long duration) {
return; // Weird deadlock case
}
int us = 1'000'000 / frequency / 2;
if (us < 5) {
us = 5;
}
unsigned int delay = (RP2040::f_cpu() + frequency) / (frequency * 2) - 3; // rounded
auto entry = _toneMap.find(pin);
Tone *newTone;
if (entry == _toneMap.end()) {
@@ -99,7 +96,7 @@ void tone(uint8_t pin, unsigned int frequency, unsigned long duration) {
tone2_program_init(newTone->pio, newTone->sm, newTone->off, pin);
}
pio_sm_clear_fifos(newTone->pio, newTone->sm); // Remove any old updates that haven't yet taken effect
pio_sm_put_blocking(newTone->pio, newTone->sm, RP2040::usToPIOCycles(us));
pio_sm_put_blocking(newTone->pio, newTone->sm, delay);
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);
+23 -19
View File
@@ -30,32 +30,36 @@ extern bool __isFreeRTOS;
// FreeRTOS has been set up
extern volatile bool __freeRTOSinitted;
#ifdef __cplusplus
extern "C" {
struct QueueDefinition; /* Using old naming convention so as not to break kernel aware debuggers. */
typedef struct QueueDefinition * QueueHandle_t;
typedef QueueHandle_t SemaphoreHandle_t;
typedef int32_t BaseType_t;
#endif // __cplusplus
struct QueueDefinition; /* Using old naming convention so as not to break kernel aware debuggers. */
typedef struct QueueDefinition * QueueHandle_t;
typedef QueueHandle_t SemaphoreHandle_t;
typedef int32_t BaseType_t;
extern bool __freertos_check_if_in_isr() __attribute__((weak));
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 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(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, BaseType_t* pxHigherPriorityTaskWoken) __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, 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));
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));
extern void __freertos_idle_other_core() __attribute__((weak));
extern void __freertos_resume_other_core() __attribute__((weak));
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 void __freertos_task_exit_critical() __attribute__((weak));
extern void __freertos_task_enter_critical() __attribute__((weak));
#ifdef __cplusplus
}
extern SemaphoreHandle_t __get_freertos_mutex_for_ptr(mutex_t *m, bool recursive = false);
#endif // __cplusplus
+103 -1
View File
@@ -17,7 +17,7 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
#if defined(PICO_CYW43_SUPPORTED)
#include <lwip/netif.h>
extern "C" {
@@ -25,6 +25,12 @@ extern "C" {
#include <cyw43_stats.h>
}
#include <pico/cyw43_arch.h>
#include <pico/cyw43_driver.h>
#include <pico/lwip_nosys.h>
#include <hardware/resets.h>
#include <hardware/gpio.h>
#include <hardware/adc.h>
#include <hardware/clocks.h>
#include <Arduino.h>
// From cyw43_ctrl.c
@@ -101,4 +107,100 @@ extern "C" void __wrap_cyw43_cb_tcpip_deinit(cyw43_t *self, int itf) {
(void) itf;
}
#ifndef WIFICC
#define WIFICC CYW43_COUNTRY_WORLDWIDE
#endif
// Taken from https://datasheets.raspberrypi.com/picow/connecting-to-the-internet-with-pico-w.pdf
// also discussion in https://github.com/earlephilhower/arduino-pico/issues/849
static bool CheckPicoW() {
#ifdef PICO_RP2040
adc_init();
auto dir = gpio_get_dir(29);
auto fnc = gpio_get_function(29);
adc_gpio_init(29);
adc_select_input(3);
auto adc29 = adc_read();
gpio_set_function(29, fnc);
gpio_set_dir(29, dir);
dir = gpio_get_dir(25);
fnc = gpio_get_function(25);
gpio_init(25);
gpio_set_dir(25, GPIO_IN);
auto gp25 = gpio_get(25);
gpio_set_function(25, fnc);
gpio_set_dir(25, dir);
if (gp25) {
return true; // Can't tell, so assume yes
} else if (adc29 < 200) {
return true; // PicoW
} else {
return false;
}
#else
return true;
#endif
}
bool __isPicoW = true;
extern "C" void init_cyw43_wifi() {
__isPicoW = CheckPicoW();
if (__isPicoW) {
// Fix for overclocked CPU: SPI communication breaks down with default "div by 2" speed
// So, divide clock by 4 for anything including and above 250MHz CPU frequency.
if (clock_get_hz(clk_sys) >= 250000000) {
cyw43_set_pio_clock_divisor(4, 0); // div by 4.0
}
cyw43_arch_init_with_country(WIFICC);
}
}
extern "C" void __lockBluetooth() {
async_context_acquire_lock_blocking(cyw43_arch_async_context());
}
extern "C" void __unlockBluetooth() {
async_context_release_lock(cyw43_arch_async_context());
}
extern "C" void __pinMode(pin_size_t pin, PinMode mode);
extern "C" void __digitalWrite(pin_size_t pin, PinStatus val);
extern "C" PinStatus __digitalRead(pin_size_t pin);
extern "C" void cyw43_pinMode(pin_size_t pin, PinMode mode) {
if (!__isPicoW && (pin == PIN_LED)) {
pin = 25; // Silently swap in the Pico's LED
}
if (pin < 64) {
__pinMode(pin, mode);
} else {
// TBD - There is no GPIO direction control in the driver
}
}
extern "C" void cyw43_digitalWrite(pin_size_t pin, PinStatus val) {
if (!__isPicoW && (pin == PIN_LED)) {
pin = 25; // Silently swap in the Pico's LED
}
if (pin < 64) {
__digitalWrite(pin, val);
} else {
cyw43_arch_gpio_put(pin - 64, val == HIGH ? 1 : 0);
}
}
extern "C" PinStatus cyw43_digitalRead(pin_size_t pin) {
if (!__isPicoW && (pin == PIN_LED)) {
pin = 25; // Silently swap in the Pico's LED
}
if (pin < 64) {
return __digitalRead(pin);
} else {
return cyw43_arch_gpio_get(pin - 64) ? HIGH : LOW;
}
}
#endif
+37
View File
@@ -0,0 +1,37 @@
/*
CYW43 TCP/Ethernet wrappers
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 <Arduino.h>
#include <pico/cyw43_driver.h>
extern bool __isPicoW;
#ifdef __cplusplus
extern "C" {
#endif
void init_cyw43_wifi();
void __lockBluetooth();
void __unlockBluetooth();
void cyw43_pinMode(pin_size_t pin, PinMode mode);
void cyw43_digitalWrite(pin_size_t pin, PinStatus val);
PinStatus cyw43_digitalRead(pin_size_t pin);
#ifdef __cplusplus
}
#endif
-95
View File
@@ -1,95 +0,0 @@
/*
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
}
};
+470
View File
@@ -0,0 +1,470 @@
/* -
Copyright (c) 1983, 1992, 1993
The Regents of the University of California. 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.
4. Neither the name of the University nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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 code is built as a C file because otherwise G++ would add profiling
// code to the preamble of these functions as well, leading to an infinite
// loop in the mcount routine. Because the Arduino IDE can't (easily)
// apply different compile parameters to different files, we set all C++
// files to "-pg" but leave all C files uninstrumented.
// Original code and organization taken from https://mcuoneclipse.com/2015/08/23/tutorial-using-gnu-profiling-gprof-with-arm-cortex-m/
#include <Arduino.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
// Frequency of sampling PC
#ifndef GMON_HZ
#define GMON_HZ 10000
#endif
// Fraction of text space to allocate for histogram counters here, 1/2
#ifndef HISTFRACTION
#ifdef PICO_RP2350
#define HISTFRACTION 4 // Every 8 bytes of .text
#else
#define HISTFRACTION 8 // Every 16 bytes of .text
#endif
#endif
// Fraction of text space to allocate for from hash buckets.
// The value of HASHFRACTION is based on the minimum number of bytes
// of separation between two subroutine call points in the object code.
// Given MIN_SUBR_SEPARATION bytes of separation the value of
// HASHFRACTION is calculated as:
//
// HASHFRACTION = MIN_SUBR_SEPARATION / (2 * sizeof(short) - 1);
//
// For example, on the VAX, the shortest two call sequence is:
//
// calls $0,(r0)
// calls $0,(r0)
//
// which is separated by only three bytes, thus HASHFRACTION is
// calculated as:
//
// HASHFRACTION = 3 / (2 * 2 - 1) = 1
//
// Note that the division above rounds down, thus if MIN_SUBR_FRACTION
// is less than three, this algorithm will not work!
//
// In practice, however, call instructions are rarely at a minimal
// distance. Hence, we will define HASHFRACTION to be 2 across all
// architectures. This saves a reasonable amount of space for
// profiling data structures without (in practice) sacrificing
// any granularity.
#ifndef HASHFRACTION
#define HASHFRACTION 2
#endif
// Percent of text space to allocate for tostructs with a minimum.
#ifndef ARCDENSITY
#define ARCDENSITY 2 // This is in percentage, relative to text size!
#endif
#define MINARCS 50
#define MAXARCS ((1 << (8 * sizeof(HISTCOUNTER))) - 2)
// Histogram counters are unsigned shorts (according to the kernel)
typedef uint16_t HISTCOUNTER; //#define HISTCOUNTER unsigned short
// In the original profiler code selfpc and count are full 32 bits each
// so the structure actually comes to 12 bytes due to padding (with 2
// bytes wasted per entry). We don't have that much to spare on the Picos,
// so limit the recorded address to 16MB (which is the flash address
// window, anyway) and the counts to 16M (saturating). This saves 4 bytes
// (33%) per entry at the cost of some logic to expand/pack it.
struct tostruct {
uint8_t selfpc[3]; // Callee address/program counter. The caller address is in froms[] array which points to tos[] array
uint8_t count[3]; // How many times it has been called
uint16_t link; // Link to next entry in hash table. For tos[0] this points to the last used entry
};
typedef enum { PROFILE_NOT_INIT = 0, PROFILE_ON, PROFILE_OFF } PROFILE_State;
struct profinfo {
PROFILE_State state; // Profiling state
uint16_t *counter; // Profiling counters
size_t lowpc, highpc; // Range to be profiled
uint32_t scale; // Scale value of bins
};
// Global profinfo for profil() call
static struct profinfo prof = { PROFILE_NOT_INIT, 0, 0, 0, 0 };
// Possible states of profiling
typedef enum { GMON_PROF_ON = 0, GMON_PROF_BUSY, GMON_PROF_ERROR, GMON_PROF_OFF } GMON_State;
// The profiling data structures are housed in this structure.
struct gmonparam {
int state;
uint16_t *kcount; // Histogram PC sample array
size_t kcountsize; // Size of kcount[] array in bytes
uint16_t *froms; // Array of hashed 'from' addresses. The 16bit value is an index into the tos[] array
size_t fromssize; // Size of froms[] array in bytes
struct tostruct *tos; // to struct, contains histogram counter
size_t tossize; // Size of tos[] array in bytes
long tolimit;
size_t lowpc; // Low program counter of area
size_t highpc; // High program counter
size_t textsize; // Code size
};
static struct gmonparam _gmonparam = { GMON_PROF_OFF, NULL, 0, NULL, 0, NULL, 0, 0L, 0, 0, 0};
static bool already_setup = false; // Flag to indicate if we need to init
static bool _perf_in_setup = false; // Are we currently trying to initialize? (avoid infinite recursion)
int __profileMemSize = 0; // Memory allocated by the profiler to store tables
static int s_scale = 0;
#define SCALE_1_TO_1 0x10000L
// Convert an addr to an index
static inline __attribute__((always_inline)) size_t profidx(size_t pc, size_t base, size_t scale) {
size_t i = (pc - base) / 2;
return (unsigned long long int) i * scale / 65536;
}
// Sample the current program counter periodically
#if defined(__riscv)
// TODO - systick-like handler
#else
static void __no_inline_not_in_flash_func(_SystickHandler)(void) {
static size_t pc, idx; // Ensure in heap, not on stack
extern volatile bool __otherCoreIdled;
if (!__otherCoreIdled && (prof.state == PROFILE_ON)) {
pc = ((uint32_t*)(__builtin_frame_address(0)))[14]; // Get SP and use it to get the return address from stack
if ((pc >= prof.lowpc) && (pc < prof.highpc)) {
idx = profidx(pc, prof.lowpc, prof.scale);
prof.counter[idx]++;
}
}
}
#endif
// Convert an index into an address
static inline __attribute__((always_inline)) size_t profaddr(size_t idx, size_t base, size_t scale) {
return base + ((((unsigned long long)(idx) << 16) / (unsigned long long)(scale)) << 1);
}
// Start or stop profiling
// Profiling goes into the SAMPLES buffer of size SIZE (which is treated as an array of uint16_ts of size size/2).
// Each bin represents a range of pc addresses from OFFSET. The number of pc addresses in a bin depends on SCALE.
// (A scale of 65536 maps each bin to two addresses, A scale of 32768 maps each bin to 4 addresses, a scale of
// 1 maps each bin to 128k address). Scale may be 1 - 65536, or zero to turn off profiling
static int __no_inline_not_in_flash_func(profile_ctl)(char *samples, size_t size, size_t offset, uint32_t scale) {
size_t maxbin;
if (scale > 65536) {
return -1;
}
prof.state = PROFILE_OFF;
if (scale) {
bzero(samples, size);
bzero(&prof, sizeof(prof));
maxbin = size >> 1;
prof.counter = (uint16_t*)samples;
prof.lowpc = offset;
prof.highpc = profaddr(maxbin, offset, scale);
prof.scale = scale;
prof.state = PROFILE_ON;
}
return 0;
}
// Control profiling. Profiling is what mcount checks to see if all the data structures are ready.
static void __no_inline_not_in_flash_func(moncontrol)(int mode) {
if (mode) { // Start
profile_ctl((char *)_gmonparam.kcount, _gmonparam.kcountsize, _gmonparam.lowpc, s_scale);
_gmonparam.state = GMON_PROF_ON;
} else { // Stop
profile_ctl((char *)NULL, 0, 0, 0);
_gmonparam.state = GMON_PROF_OFF;
}
}
// General rounding functions
static inline __attribute__((always_inline)) size_t rounddown(size_t x, size_t y) {
return (x / y) * y;
}
static inline __attribute__((always_inline)) size_t roundup(size_t x, size_t y) {
return ((x + y - 1) / y) * y;
}
// Allocate memory and set boundaries before any sampling is performed
void __no_inline_not_in_flash_func(monstartup)(size_t lowpc, size_t highpc) {
register size_t o;
char *cp;
struct gmonparam *p = &_gmonparam;
// Round lowpc and highpc to multiples of the density we're using so the rest of the scaling (here and in gprof) stays in ints.
p->lowpc = rounddown(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
p->highpc = roundup(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
p->textsize = p->highpc - p->lowpc;
p->kcountsize = p->textsize / HISTFRACTION;
p->fromssize = p->textsize / HASHFRACTION;
p->tolimit = p->textsize * ARCDENSITY / 100;
if (p->tolimit < MINARCS) {
p->tolimit = MINARCS;
} else if (p->tolimit > MAXARCS) {
p->tolimit = MAXARCS;
}
p->tossize = p->tolimit * sizeof(struct tostruct);
__profileMemSize = p->kcountsize + p->fromssize + p->tossize;
#ifdef RP2350_PSRAM_CS
cp = pmalloc(__profileMemSize);
#else
cp = malloc(__profileMemSize);
#endif
if (cp == NULL) {
// OOM
already_setup = false;
return;
}
// Zero out cp as value will be added there
bzero(cp, p->kcountsize + p->fromssize + p->tossize);
p->tos = (struct tostruct *)cp;
cp += p->tossize;
p->kcount = (uint16_t *)cp;
cp += p->kcountsize;
p->froms = (uint16_t *)cp;
p->tos[0].link = 0;
o = p->highpc - p->lowpc;
if (p->kcountsize < o) {
s_scale = ((float)p->kcountsize / o) * SCALE_1_TO_1;
} else {
s_scale = SCALE_1_TO_1;
}
moncontrol(1); // Start
}
// Accessors for the selfpc and count fields
static inline __attribute__((always_inline)) void setselfpc(struct tostruct *x, size_t d) {
x->selfpc[0] = d & 0xff;
x->selfpc[1] = (d >> 8) & 0xff;
x->selfpc[2] = (d >> 16) & 0xff;
}
static inline __attribute__((always_inline))void setcount(struct tostruct *x, size_t d) {
x->count[0] = d & 0xff;
x->count[1] = (d >> 8) & 0xff;
x->count[2] = (d >> 16) & 0xff;
}
static inline __attribute__((always_inline)) uint32_t getselfpc(const struct tostruct *x) {
return 0x10000000 | ((uint32_t)x->selfpc[0]) | (((uint32_t)x->selfpc[1]) << 8) | (((uint32_t)x->selfpc[2]) << 16);
}
static inline __attribute__((always_inline)) uint32_t getcount(const struct tostruct *x) {
return ((uint32_t)x->count[0]) | (((uint32_t)x->count[1]) << 8) | (((uint32_t)x->count[2]) << 16);
}
// Called by the GCC function shim (gprof_shim.S) on function entry to record an arc hit
void __no_inline_not_in_flash_func(_mcount_internal)(uint32_t *frompcindex, uint32_t *selfpc) {
register struct tostruct *top;
register struct tostruct *prevtop;
register long toindex;
struct gmonparam *p = &_gmonparam;
if (_perf_in_setup) {
// Avoid infinite recursion
return;
}
if (!already_setup) {
extern char __flash_binary_start; // Start of flash
extern char __etext; // End of .text
already_setup = true;
_perf_in_setup = true;
monstartup((uint32_t)&__flash_binary_start, (uint32_t)&__etext);
_perf_in_setup = false;
}
// Check that we are profiling and that we aren't recursively invoked.
if (p->state != GMON_PROF_ON) {
return;
}
p->state++;
// Check that frompcindex is a reasonable pc value.
frompcindex = (uint32_t*)((long)frompcindex - (long)p->lowpc);
if ((unsigned long)frompcindex > p->textsize) {
goto done;
}
frompcindex = (uint32_t*)&p->froms[((long)frompcindex) / (HASHFRACTION * sizeof(*p->froms))];
toindex = *((uint16_t*)frompcindex); // Get froms[] value
if (toindex == 0) {
// First time traversing this arc
toindex = ++p->tos[0].link; // The link of tos[0] points to the last used record in the array
if (toindex >= p->tolimit) { // More tos[] entries than we can handle!
goto overflow;
}
*((uint16_t*)frompcindex) = (uint16_t)toindex; // Store new 'to' value into froms[]
top = &p->tos[toindex];
setselfpc(top, (uint32_t)selfpc);
setcount(top, 1);
top->link = 0;
goto done;
}
top = &p->tos[toindex];
if (getselfpc(top) == (size_t)selfpc) {
// Arc at front of chain; usual case.
uint32_t cnt = getcount(top) + 1;
if (cnt >= 1 << 24) {
cnt = (1 << 24) - 1;
}
setcount(top, cnt);
goto done;
}
// Have to go looking down chain for it. top points to what we are looking at, prevtop points to previous top. We know it is not at the head of the chain.
for (; /* goto done */;) {
if (top->link == 0) {
// top is end of the chain and none of the chain had top->selfpc == selfpc, so we allocate a new tostruct and link it to the head of the chain.
toindex = ++p->tos[0].link;
if (toindex >= p->tolimit) {
goto overflow;
}
top = &p->tos[toindex];
setselfpc(top, (uint32_t)selfpc);
setcount(top, 1);
top->link = *((uint16_t*)frompcindex);
*(uint16_t*)frompcindex = (uint16_t)toindex;
goto done;
}
// Otherwise, check the next arc on the chain.
prevtop = top;
top = &p->tos[top->link];
if (getselfpc(top) == (size_t)selfpc) {
// Increment its count, move it to the head of the chain.
uint32_t cnt = getcount(top) + 1;
if (cnt >= 1 << 24) {
cnt = (1 << 24) - 1;
}
setcount(top, cnt);
toindex = prevtop->link;
prevtop->link = top->link;
top->link = *((uint16_t*)frompcindex);
*((uint16_t*)frompcindex) = (uint16_t)toindex;
goto done;
}
}
done:
p->state--;
return;
overflow:
p->state++; // Halt further profiling
return;
}
// Write out the GMON.OUT file using internal state
void _writeProfile(int (*writeCB)(const void *data, int len)) {
struct gmonhdr { // GMON.OUT header
size_t lpc; // base pc address of sample buffer
size_t hpc; // max pc address of sampled buffer
int ncnt; // size of sample buffer (plus this header)
int version; // version number
int profrate; // profiling clock rate
int spare[3]; // reserved
};
const unsigned int GMONVERSION = 0x00051879;
struct rawarc { // Per-arc on-disk data format
size_t raw_frompc;
size_t raw_selfpc;
long raw_count;
};
int fromindex;
int endfrom;
size_t frompc;
int toindex;
struct rawarc rawarc;
const int BS = 64;
struct rawarc rawarcbuff[BS];
int rawarcbuffptr = 0;
struct gmonparam *p = &_gmonparam;
struct gmonhdr hdr;
moncontrol(0); // Stop
hdr.lpc = p->lowpc;
hdr.hpc = p->highpc;
hdr.ncnt = p->kcountsize + sizeof(hdr);
hdr.version = GMONVERSION;
hdr.profrate = GMON_HZ;
writeCB((void *)&hdr, sizeof(hdr));
writeCB((void *)p->kcount, p->kcountsize);
endfrom = p->fromssize / sizeof(*p->froms);
for (fromindex = 0; fromindex < endfrom; fromindex++) {
if (p->froms[fromindex] == 0) {
continue;
}
frompc = p->lowpc;
frompc += fromindex * HASHFRACTION * sizeof(*p->froms);
for (toindex = p->froms[fromindex]; toindex != 0; toindex = p->tos[toindex].link) {
rawarc.raw_frompc = frompc;
rawarc.raw_selfpc = getselfpc(&p->tos[toindex]);
rawarc.raw_count = getcount(&p->tos[toindex]);
// Buffer up writes because Semihosting is really slow per write call
rawarcbuff[rawarcbuffptr++] = rawarc;
if (rawarcbuffptr == BS) {
writeCB((void *)rawarcbuff, BS * sizeof(struct rawarc));
rawarcbuffptr = 0;
}
}
}
// Write any remaining bits
if (rawarcbuffptr) {
writeCB((void *)rawarcbuff, rawarcbuffptr * sizeof(struct rawarc));
}
}
// These are referenced by RP2040Support.cpp and called by the runtime init SDK
// Install a periodic PC sampler at the specified frequency
#if defined(__riscv)
void runtime_init_setup_profiling() {
// TODO - is there an equivalent? Or do we need to build a timer IRQ here?
}
#else
#include <hardware/exception.h>
#include <hardware/structs/systick.h>
void runtime_init_setup_profiling() {
exception_set_exclusive_handler(SYSTICK_EXCEPTION, _SystickHandler);
systick_hw->csr = 0x7;
systick_hw->rvr = (F_CPU / GMON_HZ) - 1;
}
#endif
+58
View File
@@ -0,0 +1,58 @@
#if defined(__riscv)
// Originally from https://github.com/sbzpro/riscv-gprof
# define RSIZE 4
.section .text
.align 2
.globl _mcount
_mcount:
addi sp,sp,-4*RSIZE
sw ra, 3*RSIZE(sp)
mv a1,ra
call _mcount_internal; //jal _mcount_internal
lw ra, 3*RSIZE(sp)
addi sp,sp,4*RSIZE
ret
#else
/*
* profiler.S
* Implements the gprof profiler arc counting function.
* Created on: 06.08.2015
* Author: Erich Styger
* Modified for RP2040/RP2350 on Dec 3 2024 by Earle F. Philhower, III.
*/
.syntax unified
.arch armv7-m
.cpu cortex-m0plus
.text
.thumb
.thumb_func
.align 2
.globl __gnu_mcount_nc
.type __gnu_mcount_nc, %function
.section .time_critical
__gnu_mcount_nc:
// LR = to return to
// SP = to-replace-LR with
push {r0, r1, r2, r3}
push {lr}
// Swap 24/0
ldr r0, [sp, #20]
ldr r1, [sp, #0]
str r0, [sp, #0]
str r1, [sp, #20]
mov r1, lr
ldr r0, [sp, #0] /* caller - at the top of the stack */
bl _mcount_internal /* when __gnu_mcount_nc is called */
pop {r0}
mov lr, r0
pop {r0, r1, r2, r3}
pop {pc}
.end __gnu_mcount_nc
#endif
+3 -5
View File
@@ -26,9 +26,7 @@
#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"
@@ -46,7 +44,7 @@ public:
if (ethernet_arch_lwip_gpio_mask) {
ethernet_arch_lwip_gpio_mask();
}
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
#if defined(PICO_CYW43_SUPPORTED)
if (rp2040.isPicoW()) {
cyw43_arch_lwip_begin();
return;
@@ -60,7 +58,7 @@ public:
}
~LWIPMutex() {
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
#if defined(PICO_CYW43_SUPPORTED)
if (rp2040.isPicoW()) {
cyw43_arch_lwip_end();
} else {
@@ -70,7 +68,7 @@ public:
} else {
recursive_mutex_exit(&__lwipMutex);
}
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
#if defined(PICO_CYW43_SUPPORTED)
}
#endif
if (ethernet_arch_lwip_gpio_unmask) {
+3
View File
@@ -76,10 +76,13 @@ extern "C" void *pcalloc(size_t count, size_t size) {
#else
// No PSRAM, always fail
extern "C" void *pmalloc(size_t size) {
(void) size;
return nullptr;
}
extern "C" void *pcalloc(size_t count, size_t size) {
(void) count;
(void) size;
return nullptr;
}
#endif
+1
View File
@@ -23,6 +23,7 @@
#include <errno.h>
#include <_syslist.h>
#include <sys/times.h>
#include <sys/unistd.h>
#include <pico/stdlib.h>
#include <pico/multicore.h>
@@ -4,7 +4,7 @@
SPDX-License-Identifier: BSD-3-Clause
*/
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
#if defined(PICO_CYW43_SUPPORTED)
#include <btstack.h>
#include <pico/btstack_flash_bank.h>
#include <hardware/flash.h>
+5 -4
View File
@@ -18,7 +18,7 @@
; Side-set pin 0 is used for Tone output
; OSR == Halfcycle count
; OSR == Halfcycle count - 3
.program tone2
.side_set 1 opt
@@ -26,10 +26,11 @@
; pull ; TXFIFO -> OSR, or X -> OSR if no new period
; mov x, osr ; OSR -> X
.wrap_target
high:
pull noblock ; Potentially grab new HALFCYCLECOUNT, OTW copy from backup in X
mov x, osr ; OSR -> X
mov y, osr side 1 ; HALFCYCLECOUNT -> Y
mov x, osr side 1 ; OSR -> X
mov y, osr ; HALFCYCLECOUNT -> Y
highloop:
jmp y-- highloop ; while (y--) { /* noop delay */ }
@@ -38,7 +39,7 @@ low:
lowloop:
jmp y-- lowloop ; while (y--) { /* noop delay */ }
jmp high ; GOTO high
.wrap ; GOTO high
% c-sdk {
static inline void tone2_program_init(PIO pio, uint sm, uint offset, uint pin) {
+7 -8
View File
@@ -13,27 +13,26 @@
// ----- //
#define tone2_wrap_target 0
#define tone2_wrap 6
#define tone2_wrap 5
#define tone2_pio_version 0
static const uint16_t tone2_program_instructions[] = {
// .wrap_target
// .wrap_target
0x8080, // 0: pull noblock
0xa027, // 1: mov x, osr
0xb847, // 2: mov y, osr side 1
0xb827, // 1: mov x, osr side 1
0xa047, // 2: mov y, osr
0x0083, // 3: jmp y--, 3
0xb047, // 4: mov y, osr side 0
0x0085, // 5: jmp y--, 5
0x0000, // 6: jmp 0
// .wrap
// .wrap
};
#if !PICO_NO_HARDWARE
static const struct pio_program tone2_program = {
.instructions = tone2_program_instructions,
.length = 7,
.length = 6,
.origin = -1,
.pio_version = 0,
.pio_version = tone2_pio_version,
#if PICO_PIO_VERSION > 0
.used_gpio_ranges = 0x0
#endif
+25 -47
View File
@@ -22,7 +22,6 @@
#include <CoreMutex.h>
#include <hardware/gpio.h>
#include <hardware/sync.h>
#include <map>
#include "_freertos.h"
@@ -59,58 +58,34 @@ extern "C" void noInterrupts() {
}
}
auto_init_mutex(_irqMutex);
static uint64_t _gpioIrqEnabled = 0; // Sized to work with RP2350B, 48 GPIOs
static uint64_t _gpioIrqUseParam;
void *_gpioIrqCB[__GPIOCNT];
void *_gpioIrqCBParam[__GPIOCNT];
// Only 1 GPIO IRQ callback for all pins, so we need to look at the pin it's for and
// dispatch to the real callback manually
auto_init_mutex(_irqMutex);
class CBInfo {
public:
CBInfo(voidFuncPtr cb) : _cb(cb), _useParam(false), _param(nullptr) { };
CBInfo(voidFuncPtrParam cbParam, void *param) : _cbParam(cbParam), _useParam(true), _param(param) { };
void callback() {
if (_useParam && _cbParam) {
_cbParam(_param);
} else if (_cb) {
_cb();
}
}
private:
union {
voidFuncPtr _cb;
voidFuncPtrParam _cbParam;
};
bool _useParam;
void *_param;
};
static std::map<pin_size_t, CBInfo> _map;
void _gpioInterruptDispatcher(uint gpio, uint32_t events) {
(void) events;
// Only need to lock around the std::map check, not the whole IRQ callback
CBInfo *cb;
{
CoreMutex m(&_irqMutex);
if (m) {
auto irq = _map.find(gpio);
if (irq == _map.end()) {
return;
}
cb = &irq->second;
uint64_t mask = 1LL << gpio;
if (_gpioIrqEnabled & mask) {
if (_gpioIrqUseParam & mask) {
voidFuncPtr cb = (voidFuncPtr)_gpioIrqCB[gpio];
cb();
} else {
return;
voidFuncPtrParam cb = (voidFuncPtrParam)_gpioIrqCB[gpio];
cb(_gpioIrqCBParam[gpio]);
}
}
cb->callback();
}
// To be called when appropriately protected w/IRQ and mutex protects
static void _detachInterruptInternal(pin_size_t pin) {
auto irq = _map.find(pin);
if (irq != _map.end()) {
uint64_t mask = 1LL << pin;
if (_gpioIrqEnabled & mask) {
gpio_set_irq_enabled(pin, 0x0f /* all */, false);
_map.erase(pin);
_gpioIrqEnabled &= ~mask;
}
}
@@ -119,7 +94,7 @@ extern "C" void attachInterrupt(pin_size_t pin, voidFuncPtr callback, PinStatus
if (!m) {
return;
}
uint64_t mask = 1LL << pin;
uint32_t events;
switch (mode) {
case LOW: events = 1; break;
@@ -131,8 +106,9 @@ extern "C" void attachInterrupt(pin_size_t pin, voidFuncPtr callback, PinStatus
}
noInterrupts();
_detachInterruptInternal(pin);
CBInfo cb(callback);
_map.insert({pin, cb});
_gpioIrqEnabled |= mask;
_gpioIrqUseParam &= ~mask; // No parameter
_gpioIrqCB[pin] = (void *)callback;
gpio_set_irq_enabled_with_callback(pin, events, true, _gpioInterruptDispatcher);
interrupts();
}
@@ -142,7 +118,7 @@ void attachInterruptParam(pin_size_t pin, voidFuncPtrParam callback, PinStatus m
if (!m) {
return;
}
uint64_t mask = 1LL << pin;
uint32_t events;
switch (mode) {
case LOW: events = 1; break;
@@ -154,8 +130,10 @@ void attachInterruptParam(pin_size_t pin, voidFuncPtrParam callback, PinStatus m
}
noInterrupts();
_detachInterruptInternal(pin);
CBInfo cb(callback, param);
_map.insert({pin, cb});
_gpioIrqEnabled |= mask;
_gpioIrqUseParam &= ~mask; // No parameter
_gpioIrqCB[pin] = (void *)callback;
_gpioIrqCBParam[pin] = param;
gpio_set_irq_enabled_with_callback(pin, events, true, _gpioInterruptDispatcher);
interrupts();
}
+2 -2
View File
@@ -56,9 +56,9 @@ extern "C" void shiftOut(pin_size_t dataPin, pin_size_t clockPin, BitOrder bitOr
}
for (i = 0; i < 8; i++) {
if (bitOrder == LSBFIRST) {
digitalWrite(dataPin, !!(val & (1 << i)));
digitalWrite(dataPin, !!(val & (1 << i)) ? HIGH : LOW);
} else {
digitalWrite(dataPin, !!(val & (1 << (7 - i))));
digitalWrite(dataPin, !!(val & (1 << (7 - i))) ? HIGH : LOW);
}
digitalWrite(clockPin, HIGH);
+2 -2
View File
@@ -54,9 +54,9 @@ author = u'Earle F. Philhower, III'
# built documents.
#
# The short X.Y version.
version = u'4.2.1'
version = u'4.4.4'
# The full version, including alpha/beta/rc tags.
release = u'4.2.1'
release = u'4.4.4'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
+40
View File
@@ -135,6 +135,29 @@ directory into a new LittleFS flash file system.
- 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``
Downloading Files from a LittleFS System
----------------------------------------
Using ``gdb`` it is possible to dump the flash data making up the filesystem and then extract
it using the ``mklittlefs`` tool. A working ``OpenOCD`` setup, DebugProbe, and ``gdb`` are required.
To download the raw filesystem, from within ``GDB`` run:
.. code::
^C (break)
(gdb) dump binary memory littlefs.bin &_FS_start &_FS_end
It may take a few seconds as ``GDB`` reads out the flash to the file. Once the raw file is downloaded it can be extracted using the ``mklittlefs`` tool from the BASH/Powershell/command line
.. code::
$ <path-to-mklittlefs>/mklittlefs -u output-dir littlefs.bin
Directory <output-dir> does not exists. Try to create it.
gmon.out > <output-dir>/gmon.out size: 24518 Bytes
gmon.bak > <output-dir>/gmon.bak size: 1 Bytes
The defaults built into ``mklittlefs`` should be appropriate for normal LittleFS filesystems built on the device or using the upload tool.
SD Library Information
----------------------
The included ``SD`` library is the Arduino standard one. Please refer to
@@ -151,6 +174,23 @@ second SPI port, ``SPI1``. Just use the following call in place of
SD.begin(cspin, SPI1);
Enabling SDIO operation for SD
------------------------------
SDIO support is available thanks to SdFat implementing a PIO-based SDIO controller.
This mode can significantly increase IO performance to SD cards but it requires that
all 4 DAT0..DAT3 lines to be wired to the Pico (most SD breakout boards only provide
1-but SPI mode of operation).
To enable SDIO mode, simply specify the SD_CLK, SD_CMD, and SD_DAT0 GPIO pins. The clock
and command pins can be any GPIO (not limited to legal SPI pins). The DAT0 pin can be any
GPIO with remaining DAT1...3 pins consecutively connected.
..code:: cpp
SD.begin(RP_CLK_GPIO, RP_CMD_GPIO, RP_DAT0_GPIO);
No other changes are required in the application to take advantage of this high
performance mode.
Using VFS (Virtual File System) for POSIX support
-------------------------------------------------
+35 -3
View File
@@ -30,6 +30,12 @@ I2S(INPUT)
Creates an I2S input port. Needs to be connected up to the
desired pins (see below) and started before any input can happen.
I2S(INPUT_PULLUP)
~~~~~~~~~~~~~~~~~
Creates a bi-directional I2S input and output port. Needs to be
connected up to the desired pins (see below) and started before
any input or output can happen.
bool setBCLK(pin_size_t pin)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the BCLK pin of the I2S device. The LRCLK/word clock will be ``pin + 1``
@@ -37,7 +43,18 @@ due to limitations of the PIO state machines. Call this before ``I2S::begin()``
bool setDATA(pin_size_t pin)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the DOUT or DIN pin of the I2S device. Any pin may be used.
Sets the DOUT or DIN pin of the I2S device. Any pin may be used. In bi-directional
operation, must use ``I2S::setDOUT()`` and ``I2S::setDIN`` instead.
Call before ``I2S::begin()``
bool setDOUT(pin_size_t pin)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the DOUT pin of the I2S device. Any pin may be used.
Call before ``I2S::begin()``
bool setDIN(pin_size_t pin)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the DIN pin of the I2S device. Any pin may be used.
Call before ``I2S::begin()``
bool setMCLK(pin_size_t pin)
@@ -71,7 +88,7 @@ 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.
The clock changes to 153.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.
@@ -115,6 +132,14 @@ 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.
void getOverflow()
~~~~~~~~~~~~~~~~~~~~~~~
Returns a flag indicating if the I2S system had to throw away data on input.
void getUnderflow()
~~~~~~~~~~~~~~~~~~~~~~~
Returns a flag indicating if the I2S system ran our of data to send on output.
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
@@ -139,7 +164,7 @@ size_t write(const uint8_t \*buffer, size_t size)
Transfers number of bytes from an application buffer to the I2S output buffer.
Be aware that ``size`` is in *bytes** and not samples. Size must be a multiple
of **4 bytes**. Will not block, so check the return value to find out how
many bytes were actually written.
many 32-bit words were actually written.
int availableForWrite()
~~~~~~~~~~~~~~~~~~~~~~~
@@ -156,6 +181,13 @@ int peek()
Returns the next sample to be read from the I2S buffer (without actually
removing it).
size_t read(uint8_t \*buffer, size_t size)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Transfers number of bytes from the I2S input buffer to an application buffer.
Be aware that ``size`` is in *bytes** and not samples. Size must be a multiple
of **4 bytes**. Will not block, so check the return value to find out how
many 32-bit words were actually read.
void onTransmit(void (\*fn)(void))
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets a callback to be called when an I2S DMA buffer is fully transmitted.
+2
View File
@@ -43,6 +43,8 @@ For the latest version, always check https://github.com/earlephilhower/arduino-p
File Systems (SD, SDFS, LittleFS) <fs>
USB (Arduino and Adafruit_TinyUSB) <usb>
Multicore Processing <multicore>
Semihosting <semihosting>
Profiling (GPROF) <profiling>
RP2350 Specific Notes <rp2350>
RP2350 PSRAM <psram>
+31
View File
@@ -172,6 +172,37 @@ To learn more about PSRAM usage, see: :doc:`RP2350 PSRAM Support <psram>`
; PSRAM size: 4MB
board_upload.psram_length = 4194304
PSRAM chip select (CS)
----------------------
For RP2350 based boards, this controls what chip-select (also called: slave-select / SS) pin to use when wanting to talk to the PSRAM chip.
Note that it's not needed to set this with a board that is known to have a PSRAM chip on-board, such as a "Sparkfun Thing Plus 2350". The ``pins_arduino.h`` of that variant already has the correct definition.
To learn more about PSRAM usage, see: :doc:`RP2350 PSRAM Support <psram>`
.. code:: ini
; PSRAM CS is at GP47
build_flags =
-DRP2350_PSRAM_CS=47
Boot2 Source
------------
Boot2 is the second stage bootloader and predominantly used on the RP2040.
Its main purpose is to configure the communication with the Flash at the highest, safest speed it can.
All known boards have their correct value already configured. However, when choosing ``board = generic``,
you can freely configure the Boot2 to be for a different flash.
For possible Boot2 filenames, `please see here <https://github.com/earlephilhower/arduino-pico/tree/master/boot2/rp2040>`__.
.. code:: ini
; expect an ISSI IS25LP080 flash, SPI frequency = CPU frequency divided by 2
board_build.arduino.earlephilhower.boot2_source = boot2_is25lp080_2_padded_checksum.S
CPU Speed
---------
+76
View File
@@ -0,0 +1,76 @@
Profiling Applications with GPROF
=================================
Applications running on the Pico can be profiled using GNU GPROF to show where the CPU is using its time
on the device and how often certain functions are called. It does this by recompiling the application
and adding a small preamble to each function built to identify what functions call what others (and
how frequently). It also uses the ``SYSTICK`` exception timer to sample and record the PC 10,000 times
per second. When an application is complete, the recorded date can be dumped to the host PC as a
``gmon.,out`` file which can be processed by ``arm-none-eabi-gprof`` into useful date.
s histogram of PCs and tally of function caller/callees can take a significant amount of RAM, from 100KB
to 10000KB depending on the size of the application. As such, while the RP2040 **may** be able to
profile small applications, this is only really recommended on the RP2350 with external PSRAM. The
profiler will automatically use PSRAM when available. Call ``rp2040.getProfileMemoryUsage()`` to get the
memory allocated at runtime.
Profiling also adds processing overhead in terms of the periodic sampling and the function preambles.
In most cases there is no reason to enable (and many reasons to disable) profiling when an application
is deployed to the field.
To transfer the ``GMON.OUT`` data from the Pico to the host HP can be done by having the application
write it out to an SD card or a LittleFS filesystem which is then manually dumped, but for ease of use
semihosting can be used to allow the Pico (under the control of OpenOCD and GDB) to write the
``gmon.out`` file directly on the host PC, ready for use.
**NOTE** Semihosting only works when connected to an OpenOCD + GDB debug session. Running an application
compiled for Semihosting without the debugger will cause a panic and hang the chip.
As of now, only ARM has support for Semihosting or GPROF.
Enabling Profiling in an Application
------------------------------------
The ``Tools->Profiling->Enabled`` menu needs to be selected to enable profiling support in GCC. This will
add the necessary preamble to every function compiled (**Note** that the ``libpico`` and ``libc`` will not
be instrumented because they are pre-built so calls from them will not be fully instrumented. However,
PC data will still be grabbed and decoded from them at runtime.)
The application will automatically start collecting profiling data even before ``setup`` starts in this
mode. It will continue collecting data until you stop and write out the profiling data using
``rp2040.writeProfiling()`` to dump to the host, a file, serial port, etc.
For example, an application which does all its processing in ``setup()`` might look like:
.. code:: cpp
#include <SemiFS.h>
void setup() {
SerialSemi.printf("BEGIN\n");
do_some_work_that_takes_a_long_time_with_many_function_calls();
// Do lots of other work...
// Now all done...
SerialSemi.printf("Writing GMON.OUT\n");
SemiFS.begin();
File gmon = SemiFS.open("gmon.out", "w");
rp2040.writeProfiling(&gmon);
gmon.close();
SerialSemi.printf("END\n");
}
void loop() {}
Collecting and Analyzing Profile Data
-------------------------------------
Running this application under `semihosting <semihosting>`_ GDB and OpenOCD generates a ``gmon.out`` file
in the OpenOCD current working directory. This file, combined with the ``ELF`` binary build in the
IDE and loaded through GDB, can produce profiler output using
.. code::
$ /path/to/arm-none-eabi/bin/arm-none-eabi-gprof /path/to/sketch.ino.elf /path/to/gmon.out
See the ``rp2040/Profiling.ino`` example for more details.
+59
View File
@@ -0,0 +1,59 @@
Semihosting Support
===================
Using special debugger breakpoints and commands, the Pico can read and write to the debugging console as well
as read and write files on a development PC. The ``Semihosting`` library allows applications to use the
semihosting support as a normal filesystem or serial port.
**NOTE** Semihosting only works when connected to an OpenOCD + GDB debug session. Running an application
compiled for Semihosting without the debugger will cause a panic and hang the chip.
As of now, only ARM has support for Semihosting.
Running Semihosting on the Development Host
-------------------------------------------
Start OpenOCD normally from inside a directory that you can read and write files within (i.e. do not run from
``C:\\Program Files\\..`` on Windows where general users aren't allowed to write). The starting
directory will be where the Pico will read and write files using the ``SemiFS`` class.
Be sure to keep the terminal window you ran OpenOCD in open, because all ``SerialSemi`` input and output
will go to **that** terminal and not ``gdb``'s.
Start GDB normally and connect to the OpenOCD debugger and enable semihosting support
.. code::
(gdb) target extended-remote localhost:3333
(gdb) monitor arm semihosting enable
At this point load and run your ``ELF`` application as normal. Again, all ``SerialSemi`` output will go
to the **OpenOCD** window, not GDB.
See the ``hellosemi`` example in the ``Semihosting`` library.
SerialSemi - Serial over Semihosting
------------------------------------
Simply include ``<Semihosting.h>`` in your application and use ``SerialSemi`` as you would any other
``Serial`` port with the following limitations:
* Baud rate, bit width, etc. are all ignored
* Input is limited because ``read`` may hang indefinitely in the host and ``available`` is not part of the spec
``SerialSemi`` can also be selected as the debug output port in the IDE, in which case ``::printf`` will write
to the debugger directly.
SemiFS - Host filesystem access through Semihosting
---------------------------------------------------
Use ``SemiFS`` the same way as any other file system. Note that only file creation and renaming are supported, with
no provision for iterating over directories or listing files. In most cases simply opening a ``File`` and writing out
a debug dump is all that's needed:
.. code::
SemiFS.begin();
File f = SemiFS.open("debug.dmp", "w");
f.write(buffer, size);
f.close();
SerialSemi.printf("Debug dump now available on host.\n");
+13
View File
@@ -28,6 +28,19 @@ pin itself, as is the standard way in Arduino.
* The interrupt calls (``attachInterrupt``, and ``detachInterrpt``) are not implemented.
Software SPI (Master Only)
==========================
Similar to ``SoftwareSerial``, ``SoftwareSPI`` creates a PIO based SPI interface that
can be used in the same manner as the hardware SPI devices. The constructor takes the
pins desired, which can be any GPIO pins with the rule that if hardware CS is used then
it must be on pin ``SCK + 1``. Construct a ``SoftwareSPI`` object in your code as
follows and use it as needed (i.e. pass it into ``SD.begin(_CS, softwareSPI);``
.. code:: cpp
#include <SoftwareSPI.h>
SoftwareSPI softSPI(_sck, _miso, _mosi); // no HW CS support, any selection of pins can be used
SPI Slave (SPISlave)
====================
+1 -2
View File
@@ -29,9 +29,8 @@ extern unsigned long __lwip_rand(void);
#define MEM_SIZE (__LWIP_MEMMULT * 16384)
#define MEMP_NUM_TCP_SEG (32)
#define MEMP_NUM_ARP_QUEUE (10)
//#define MEMP_NUM_SYS_TIMEOUT (LWIP_NUM_SYS_TIMEOUT_INTERNAL + 4)
#define PBUF_POOL_SIZE (__LWIP_MEMMULT > 1 ? 32 : 24)
#define LWIP_ARP 5
#define LWIP_ARP 7
#define LWIP_ETHERNET 1
#define LWIP_ICMP 1
#define LWIP_RAW 1
+2 -2
View File
@@ -12,8 +12,8 @@
#define _PICO_VERSION_H
#define PICO_SDK_VERSION_MAJOR 2
#define PICO_SDK_VERSION_MINOR 0
#define PICO_SDK_VERSION_MINOR 1
#define PICO_SDK_VERSION_REVISION 0
#define PICO_SDK_VERSION_STRING "2.0.0"
#define PICO_SDK_VERSION_STRING "2.1.0"
#endif
+2 -2
View File
@@ -12,8 +12,8 @@
#define _PICO_VERSION_H
#define PICO_SDK_VERSION_MAJOR 2
#define PICO_SDK_VERSION_MINOR 0
#define PICO_SDK_VERSION_MINOR 1
#define PICO_SDK_VERSION_REVISION 0
#define PICO_SDK_VERSION_STRING "2.0.0"
#define PICO_SDK_VERSION_STRING "2.1.0"
#endif
+7
View File
@@ -14,6 +14,7 @@ File KEYWORD1
timeval KEYWORD1
time_t KEYWORD1
SoftwareSerial KEYWORD1
AudioOutputBase KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
@@ -65,6 +66,9 @@ getUsedPSRAMHeap KEYWORD2
getTotalPSRAMHeap KEYWORD2
getTotalPSRAM KEYWORD2
getProfileMemoryUsage KEYWORD2
writeProfiling KEYWORD2
getChipID KEYWORD2
hwrand32 KEYWORD2
@@ -83,6 +87,9 @@ digitalReadFast KEYWORD2
enableDoubleResetBootloader KEYWORD2
SerialSemi KEYWORD2
SemiFS KEYWORD2
openDir KEYWORD2
next KEYWORD2
getLastWrite KEYWORD2
+2
View File
@@ -15,6 +15,7 @@
-iwithprefixbefore/pico-sdk/src/common/pico_util/include
-iwithprefixbefore/pico-sdk/src/common/pico_stdlib_headers/include
-iwithprefixbefore/pico-sdk/src/common/pico_usb_reset_interface_headers/include
-iwithprefixbefore/pico-sdk/src/rp2_common/boot_bootrom_headers/include
-iwithprefixbefore/pico-sdk/src/rp2_common/cmsis/include
-iwithprefixbefore/pico-sdk/src/rp2_common/cmsis/stub/CMSIS/Core/Include
-iwithprefixbefore/pico-sdk/src/rp2_common/hardware_adc/include
@@ -47,6 +48,7 @@
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_bootrom/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_double/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_fix/rp2040_usb_device_enumeration/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_flash/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_float/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_int64_ops/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_lwip/include
-5
View File
@@ -67,8 +67,3 @@
-Wl,--wrap=cyw43_tcpip_link_status
-Wl,--wrap=cyw43_cb_tcpip_init
-Wl,--wrap=cyw43_cb_tcpip_deinit
-Wl,--wrap=flash_range_erase
-Wl,--wrap=flash_range_program
-Wl,--wrap=flash_get_unique_id
-Wl,--wrap=flash_do_cmd
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
+1
View File
@@ -1,5 +1,6 @@
-DPICO_CYW43_ARCH_THREADSAFE_BACKGROUND=1
-DCYW43_LWIP=1
-DCYW43_PIO_CLOCK_DIV_DYNAMIC=1
-DCFG_TUSB_MCU=OPT_MCU_RP2040
-DARM_MATH_CM0_FAMILY
-DARM_MATH_CM0_PLUS
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+3
View File
@@ -0,0 +1,3 @@
source [find interface/cmsis-dap.cfg]
adapter speed 5000
source [find target/rp2350-riscv.cfg]
+3
View File
@@ -1,3 +1,6 @@
-DPICO_CYW43_ARCH_THREADSAFE_BACKGROUND=1
-DCYW43_LWIP=1
-DCYW43_PIO_CLOCK_DIV_DYNAMIC=1
-DCFG_TUSB_MCU=OPT_MCU_RP2040
-DCFG_TUSB_OS=OPT_OS_PICO
-DLIB_BOOT_STAGE2_HEADERS=1
+8
View File
@@ -8,3 +8,11 @@
-iwithprefixbefore/pico-sdk/src/rp2_common/hardware_hazard3/include
-iwithprefixbefore/pico-sdk/src/rp2_common/hardware_sha256/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_sha256/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_btstack/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_cyw43_arch/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_cyw43_driver/include
-iwithprefixbefore/pico-sdk/lib/cyw43-driver/src
-iwithprefixbefore/pico-sdk/lib/btstack/src
-iwithprefixbefore/pico-sdk/lib/btstack/3rd-party/bluedroid/decoder/include
-iwithprefixbefore/pico-sdk/lib/btstack/3rd-party/bluedroid/encoder/include
-iwithprefixbefore/pico-sdk/lib/btstack/platform/embedded
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
+3
View File
@@ -1,3 +1,6 @@
-DPICO_CYW43_ARCH_THREADSAFE_BACKGROUND=1
-DCYW43_LWIP=1
-DCYW43_PIO_CLOCK_DIV_DYNAMIC=1
-DCFG_TUSB_MCU=OPT_MCU_RP2040
-DCFG_TUSB_OS=OPT_OS_PICO
-DLIB_BOOT_STAGE2_HEADERS=1
+8
View File
@@ -6,3 +6,11 @@
-iwithprefixbefore/pico-sdk/src/rp2_common/cmsis/stub/CMSIS/Device/RP2350/Include
-iwithprefixbefore/pico-sdk/src/rp2_common/hardware_sha256/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_sha256/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_btstack/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_cyw43_arch/include
-iwithprefixbefore/pico-sdk/src/rp2_common/pico_cyw43_driver/include
-iwithprefixbefore/pico-sdk/lib/cyw43-driver/src
-iwithprefixbefore/pico-sdk/lib/btstack/src
-iwithprefixbefore/pico-sdk/lib/btstack/3rd-party/bluedroid/decoder/include
-iwithprefixbefore/pico-sdk/lib/btstack/3rd-party/bluedroid/encoder/include
-iwithprefixbefore/pico-sdk/lib/btstack/platform/embedded
+3 -2
View File
@@ -77,8 +77,9 @@ bool ADCInput::setPins(pin_size_t pin0, pin_size_t pin1, pin_size_t pin2, pin_si
}
bool ADCInput::setFrequency(int newFreq) {
_freq = newFreq * __builtin_popcount(_pinMask); // Want to sample all channels at given frequency
adc_set_clkdiv(48000000.0f / _freq - 1.0f);
_freq = newFreq;
int scaledFreq = newFreq * __builtin_popcount(_pinMask); // Want to sample all channels at given frequency
adc_set_clkdiv(48000000.0f / scaledFreq - 1.0f);
return true;
}
@@ -42,6 +42,8 @@ AudioBufferManager::AudioBufferManager(size_t bufferCount, size_t bufferWords, i
_dmaSize = dmaSize;
_overunderflow = false;
_callback = nullptr;
_callbackCB = nullptr;
_useData = false;
_userOff = 0;
// Create the silence buffer, fill with appropriate value
@@ -101,11 +103,16 @@ AudioBufferManager::~AudioBufferManager() {
void AudioBufferManager::setCallback(void (*fn)()) {
_callback = fn;
_useData = false;
}
void AudioBufferManager::setCallback(void (*fn)(void *), void *cbData) {
_callbackCB = fn;
_callbackData = cbData;
_useData = true;
}
bool AudioBufferManager::begin(int dreq, volatile void *pioFIFOAddr) {
_running = true;
// Get ping and pong DMA channels
for (auto i = 0; i < 2; i++) {
_channelDMA[i] = dma_claim_unused_channel(false);
@@ -117,6 +124,8 @@ bool AudioBufferManager::begin(int dreq, volatile void *pioFIFOAddr) {
}
}
_running = true;
// Need to know both channels to set up ping-pong, so do in 2 stages
for (auto i = 0; i < 2; i++) {
dma_channel_config c = dma_channel_get_default_config(_channelDMA[i]);
@@ -179,6 +188,38 @@ bool AudioBufferManager::write(uint32_t v, bool sync) {
return true;
}
size_t AudioBufferManager::write(const uint32_t *v, size_t words, bool sync) {
size_t written = 0;
if (!_running || !_isOutput) {
return 0;
}
while (words) {
AudioBuffer ** volatile p = (AudioBuffer ** volatile)&_empty;
if (!*p) {
if (!sync) {
return written;
} else {
while (!*p) {
/* noop busy wait */
}
}
}
size_t availToWriteThisBuff = _wordsPerBuffer - _userOff;
size_t toWrite = std::min(availToWriteThisBuff, words);
memcpy(&((*p)->buff[_userOff]), v, toWrite * sizeof(uint32_t));
v += toWrite;
written += toWrite;
_userOff += toWrite;
words -= toWrite;
if (_userOff == _wordsPerBuffer) {
_addToList(&_filled, _takeFromList(p));
_userOff = 0;
}
}
return written;
}
bool AudioBufferManager::read(uint32_t *v, bool sync) {
if (!_running || _isOutput) {
return false;
@@ -203,6 +244,38 @@ bool AudioBufferManager::read(uint32_t *v, bool sync) {
return true;
}
size_t AudioBufferManager::read(uint32_t *v, size_t words, bool sync) {
size_t read = 0;
if (!_running || _isOutput) {
return 0;
}
while (words) {
AudioBuffer ** volatile p = (AudioBuffer ** volatile)&_filled;
if (!*p) {
if (!sync) {
return read;
} else {
while (!*p) {
/* noop busy wait */
}
}
}
size_t availToReadThisBuff = _wordsPerBuffer - _userOff;
size_t toRead = std::min(availToReadThisBuff, words);
memcpy((void *)v, &((*p)->buff[_userOff]), toRead * sizeof(uint32_t));
v += toRead;
read += toRead;
_userOff += toRead;
words -= toRead;
if (_userOff == _wordsPerBuffer) {
_addToList(&_empty, _takeFromList(p));
_userOff = 0;
}
}
return read;
}
bool AudioBufferManager::getOverUnderflow() {
bool hold = _overunderflow;
_overunderflow = false;
@@ -265,7 +338,9 @@ void __not_in_flash_func(AudioBufferManager::_dmaIRQ)(int channel) {
}
dma_channel_set_trans_count(channel, _wordsPerBuffer * (_dmaSize == DMA_SIZE_16 ? 2 : 1), false);
dma_channel_acknowledge_irq0(channel);
if (_callback) {
if (_callbackCB) {
_callbackCB(_callbackData);
} else if (_callback) {
_callback();
}
}
@@ -29,11 +29,14 @@ public:
~AudioBufferManager();
void setCallback(void (*fn)());
void setCallback(void (*fn)(void *), void *cbData);
bool begin(int dreq, volatile void *pioFIFOAddr);
bool write(uint32_t v, bool sync = true);
size_t write(const uint32_t *v, size_t words, bool sync = true);
bool read(uint32_t *v, bool sync = true);
size_t read(uint32_t *v, size_t words, bool sync = true);
void flush();
bool getOverUnderflow();
@@ -86,14 +89,17 @@ private:
delete ab;
}
int _bitsPerSample;
size_t _wordsPerBuffer;
size_t _bufferCount;
enum dma_channel_transfer_size _dmaSize;
bool _isOutput;
int _channelDMA[2];
bool _useData;
void (*_callback)();
void (*_callbackCB)(void *);
void *_callbackData;
bool _overunderflow;
@@ -82,7 +82,7 @@ void deviceDisconnectedCallback(BLEDevice * device) {
@text In BTstack, the Read Callback is first called to query the size of the
Characteristic Value, before it is called to provide the data.
Both times, the size has to be returned. The data is only stored in the provided
buffer, if the buffer argeument is not NULL.
buffer, if the buffer argument is not NULL.
If more than one dynamic Characteristics is used, the value handle is used
to distinguish them.
*/
+8 -4
View File
@@ -676,6 +676,9 @@ void A2DPSink::avrcp_target_packet_handler(uint8_t packet_type, uint16_t channel
volume_percentage = volume * 100 / 127;
DEBUGV("AVRCP Target : Volume set to %d%% (%d)\n", volume_percentage, volume);
_consumer->setVolume(volume);
if (_volumeCB) {
_volumeCB(_volumeData, volume);
}
break;
case AVRCP_SUBEVENT_OPERATION:
@@ -773,6 +776,11 @@ void A2DPSink::a2dp_sink_packet_handler(uint8_t packet_type, uint16_t channel, u
DEBUGV("A2DP Sink : Streaming connection is established, address %s, cid 0x%02x, local seid %d\n",
bd_addr_to_str(a2dp_conn->addr), a2dp_conn->a2dp_cid, a2dp_conn->a2dp_local_seid);
memcpy(_sourceAddress, a2dp_conn->addr, sizeof(_sourceAddress));
_connected = true;
if (_connectCB) {
_connectCB(_connectData, true);
}
break;
case A2DP_SUBEVENT_STREAM_STARTED:
@@ -784,10 +792,6 @@ void A2DPSink::a2dp_sink_packet_handler(uint8_t packet_type, uint16_t channel, u
// prepare media processing
media_processing_init(&a2dp_conn->sbc_configuration);
// audio stream is started when buffer reaches minimal level
_connected = true;
if (_connectCB) {
_connectCB(_connectData, true);
}
break;
case A2DP_SUBEVENT_STREAM_SUSPENDED:
+1 -35
View File
@@ -30,7 +30,7 @@
#include "btstack_resample.h"
#include "btstack_ring_buffer.h"
class A2DPSink : public Stream {
class A2DPSink {
public:
A2DPSink() {
_title[0] = 0;
@@ -38,33 +38,6 @@ public:
_album[0] = 0;
_genre[0] = 0;
}
virtual int available() override {
return 0; // Unreadable, this is output only
}
virtual int read() override {
return 0;
}
virtual int peek() override {
return 0;
}
virtual void flush() override {
}
virtual size_t write(const uint8_t *buffer, size_t size) override {
(void) buffer;
(void) size;
return 0;
}
virtual int availableForWrite() override {
return 0;
}
virtual size_t write(uint8_t s) override {
(void) s;
return 0;
}
bool setName(const char *name) {
if (_running) {
@@ -75,11 +48,6 @@ public:
return true;
}
void onTransmit(void (*cb)(void *), void *cbData = nullptr) {
_transmitCB = cb;
_transmitData = cbData;
}
void onAVRCP(void (*cb)(void *, avrcp_operation_id_t, int), void *cbData = nullptr) {
_avrcpCB = cb;
_avrcpData = cbData;
@@ -237,8 +205,6 @@ private:
bool _connected = false;
// Callbacks
void (*_transmitCB)(void *) = nullptr;
void *_transmitData;
void (*_avrcpCB)(void *, avrcp_operation_id_t, int) = nullptr;
void *_avrcpData;
void (*_batteryCB)(void *, avrcp_battery_status_t) = nullptr;
@@ -220,6 +220,8 @@ void A2DPSource::clearPairing() {
size_t A2DPSource::write(const uint8_t *buffer, size_t size) {
BluetoothLock b;
size = std::min((size_t)availableForWrite(), size);
size_t count = 0;
size /= 2;
@@ -260,6 +262,7 @@ int A2DPSource::availableForWrite() {
} else {
avail = _pcmBufferSize - _pcmWriter + _pcmReader - 1;
}
avail /= sizeof(uint32_t); // availableForWrite always 32b sample pairs in this core...
return avail;
}
+22 -5
View File
@@ -24,17 +24,20 @@
#include <BluetoothHCI.h>
#include <BluetoothLock.h>
#include "BluetoothMediaConfigurationSBC.h"
#include <AudioOutputBase.h>
#include <functional>
#include <list>
#include <memory>
class A2DPSource : public Stream {
class A2DPSource : public Stream, public AudioOutputBase {
public:
A2DPSource() {
}
bool setFrequency(uint32_t rate) {
virtual ~A2DPSource() { }
virtual bool setFrequency(int rate) override {
if (_running || ((rate != 44100) && (rate != 48000))) {
return false;
}
@@ -51,7 +54,14 @@ public:
return true;
}
void onTransmit(void (*cb)(void *), void *cbData = nullptr) {
virtual bool setBitsPerSample(int bps) override {
return bps == 16;
}
virtual bool setStereo(bool stereo = true) override {
return stereo;
}
virtual void onTransmit(void (*cb)(void *), void *cbData = nullptr) override {
_transmitCB = cb;
_transmitData = cbData;
}
@@ -84,7 +94,11 @@ public:
return true;
}
bool getUnderflow() {
virtual bool setBuffers(size_t buffers, size_t bufferWords, int32_t silenceSample = 0) override {
return setBufferSize(buffers * bufferWords * sizeof(int32_t));
}
virtual bool getUnderflow() override {
BluetoothLock b;
if (!_running) {
return false;
@@ -102,7 +116,10 @@ public:
}
}
bool begin();
virtual bool begin() override;
virtual bool end() override {
return false; // We can't actually stop bluetooth on this device
}
std::vector<BTDeviceInfo> scan(uint32_t mask = BluetoothHCI::speaker_cod, int scanTimeSec = 5, bool async = false) {
return _hci.scan(mask, scanTimeSec, async);
@@ -53,7 +53,7 @@ void setup() {
TaskHandle_t blinkTask;
Serial.begin(115200);
xTaskCreate(blink, "BLINK", 256, nullptr, 1, &blinkTask);
#ifdef ARDUINO_RASPBERRY_PI_PICO_W
#if defined(PICO_CYW43_SUPPORTED)
// The PicoW WiFi chip controls the LED, and only core 0 can make calls to it safely
vTaskCoreAffinitySet(blinkTask, 1 << 0);
#endif
@@ -47,12 +47,12 @@ void setup() {
xSemaphore = xSemaphoreCreateMutexStatic( &xMutexBuffer );
ledOnTask = xTaskCreateStatic(led_ON, "led_ON", STACK_SIZE, NULL, configMAX_PRIORITIES - 1, xStack_A, &xTaskBuffer_A);
#ifdef ARDUINO_RASPBERRY_PI_PICO_W
#if defined(PICO_CYW43_SUPPORTED)
// The PicoW WiFi chip controls the LED, and only core 0 can make calls to it safely
vTaskCoreAffinitySet(ledOnTask, 1 << 0);
#endif
ledOffTask = xTaskCreateStatic(led_OFF, "led_OFF", STACK_SIZE, NULL, configMAX_PRIORITIES - 1, xStack_B, &xTaskBuffer_B);
#ifdef ARDUINO_RASPBERRY_PI_PICO_W
#if defined(PICO_CYW43_SUPPORTED)
// The PicoW WiFi chip controls the LED, and only core 0 can make calls to it safely
vTaskCoreAffinitySet(ledOffTask, 1 << 0);
#endif
@@ -0,0 +1,36 @@
/*
I2S bi-directional input and output loopback example
Released to the Public Domain by Cooper Dalrymple
*/
#include <I2S.h>
I2S i2s(INPUT_PULLUP);
void setup() {
Serial.begin(115200);
i2s.setDOUT(0);
i2s.setDIN(1);
i2s.setBCLK(2); // Note: LRCLK = BCLK + 1
i2s.setBitsPerSample(16);
i2s.setFrequency(22050);
// NOTE: The following values are known to work with the Adafruit microphone:
// i2s.setBitsPerSample(32);
// i2s.setFrequency(16000);
i2s.begin();
while (1) {
int16_t l, r;
i2s.read16(&l, &r);
i2s.write16(l, r);
// NOTE: Adafruit microphone word size needs to match the BPS above.
// int32_t l, r;
// i2s.read32(&l, &r);
// i2s.write32(l, r);
}
}
void loop() {
/* Nothing here */
}
@@ -0,0 +1,39 @@
/*
I2S bi-directional input and output buffered loopback example
Released to the Public Domain by Cooper Dalrymple
*/
#include <I2S.h>
I2S i2s(INPUT_PULLUP);
#define SIZE 256
int16_t buffer[SIZE];
void setup() {
Serial.begin(115200);
i2s.setDOUT(0);
i2s.setDIN(1);
i2s.setBCLK(2); // Note: LRCLK = BCLK + 1
i2s.setBitsPerSample(16);
i2s.setFrequency(22050);
i2s.setBuffers(6, SIZE * sizeof(int16_t) / sizeof(uint32_t));
i2s.begin();
size_t count, index;
while (1) {
count = i2s.read((uint8_t *)&buffer, SIZE * sizeof(int16_t)) * sizeof(uint32_t) / sizeof(int16_t);
index = 0;
while (index < count) {
// Reduce volume by half
buffer[index++] >>= 1; // right
buffer[index++] >>= 1; // left
}
i2s.write((const uint8_t *)&buffer, count * sizeof(int16_t));
}
}
void loop() {
/* Nothing here */
}

Some files were not shown because too many files have changed in this diff Show More