Sming Raspberry Pi Pico Architecture
Support building Sming for the Raspberry Pi Pico-series Microcontrollers. At time of writing this includes both RP2040 and RP2350 devices.
Testing has been limited to the Rasperry Pi Pico development boards, but there are lots of others available.
Configure this using the PICO_BOARD setting.
The default is pico (or pico_w if networking is enabled).
Support for the new pico2 boards is provided using SMING_SOC=rp2350.
You can find the full list here.
Special mention to the arduino-pico project https://github.com/earlephilhower/arduino-pico. Lots of helpful stuff in there!
Features
The following features are tested and working:
CPU frequency adjustment
system_get_cpu_freq(),system_update_cpu_freq()Timers working: hardware, software and CPU cycle counter
Hardware serial ports (UART driver)
Task queue (also supports queuing tasks from code running on core #1)
Flash memory routines
os_random()andos_get_random()implemented using ring oscillator. This is the best the hardware is capable of, but not crypto grade.Heap is standard newlib implementation,
system_get_free_heap_size()provided.Software watchdog implemented, timeout is 8 seconds
A disassembly and symbol file are generated for this architecture.
SDK declares flash memory size in the board header files. This is checked at compile time against the value declared in the partition table.
Reset information
system_get_rst_info()indicates watchdog or manual resets. Exception information not yet implemented.System functions
system_get_chip_id(),system_get_sdk_version().Partitions and file systems (except SD cards and FAT)
SPIClass tested with Radio_nRF24L01 sample only
WiFi networking support for the Pico-W
Standard analogue I/O via analogRead. More advanced hardware capabilities require use of the SDK directly.
USB supported using the USB library, both host and device modes.
HardwareSPI via HardwareSPI for fully asynchronous SPI communications (host mode only).
Limited or no support is provided for the following items. In many cases best use of the hardware is made using the Pico SDK API directly.
- PWM
Hardware can drive up to 16 outputs and measure input frequency/duty cycle. The native API is quite straightforward to use and makes best use of the hardware.
- I2C
Has hardware support
- RTC
Can wake from deep sleep but requires an external clock (e.g. 32kHz crystal) and appropriate API. (Setting and reading the time is implemented.) Note that the RP2350 does not have an RTC. Sming uses the Always-On timer api to support both devices.
- Low-power modes
Deep sleep / suspend / power-saving
- PIO (Programmable I/O)
A killer feature for the RP2 series. Uses range from simple glue logic to I2S, etc.
- Crash/exception handling & serial debugging
RP2 devices support JTAG debugging but requires extra hardware. Serial debugging is often enough and easier to set up. Requires GDB stub plus implementing crash handler callbacks, etc.
- Bluetooth
The SDK supports bluetooth for the CYW43439 BT/WiFi SoC which the Pico-W boards (and other) use. This has not yet been integrated into Sming.
- RISCV (RP2350)
Sming builds ARM code but these devices also support RISCV. This will require an additional toolchain and compile options.
Installation
The easiest way to get started is with the Sming installer - see Getting Started.
Linux and MacOS:
Tools/install.sh rp2040.Windows:
Tools\install rp2040.
See PICO_TOOLCHAIN_PATH for details of the toolchains.
Note that you can use the toolchains provided in your GNU/Linux distribution. These are not extensively tested though.
Ubuntu
sudo apt install gcc-arm-none-eabi gdb-multiarchTo use gdb-multiarch you’ll need to do this:
make gdb GDB=gdb-multiarch
Fedora
sudo dnf install arm-none-eabi-gcc-cs-c++ arm-none-eabi-newlibThe standard GDB appears to work OK.
Setup and programming
Serial support requires a 3.3v USB adapter connected to the appropriate pins:
UART0: TX = 0, RX = 1
UART1: TX = 4, RX = 5
To program your device, unplug the USB cable (i.e. remove power from the device)
then hold down the BOOTSEL button whilst plugging it back in again.
You can then run:
make flash
as usual and the device will be programmed.
Once Sming is running on the device, reprogramming is simpler and only requires pressing
the BOOTSEL button (no power cycle).
If the firmware has crashed or stalled the watchdog timer should reboot the system after 8 seconds, at which point BOOTSEL should be detected. So just hold the button down until this happens.
If all else fails, go through the initial power-cycle process.
This behaviour can be disabled using the ENABLE_BOOTSEL setting.
Boot process
Unlike the Espressif parts, the RP2040 is not programmed via the serial port, but written to the device when configured as a Mass Storage device (removable flash drive).
Data to be flashed must be in UF2 format and sent as a single file. See UF2 Support.
Once the file has finished sending the RP2040 reboots itself into normal operating mode (assuming BOOTSEL has been released).
The RP2040 can also be programmed via JTAG debugging but this requires additional hardware and setup.
Commands such as make readmap use Picotool and require the device to be in BOOT mode.
Dual-core support
Sming is a strictly non-threaded framework, and all code runs on core #0. The SDK multicore API may still be used to run code on core #1, but this requires some care to ensure smooth operation.
The task queue (System::queueTask(), etc.) may be used to send messages to Sming from Core #1 code.
Passing messages the other way, from Sming code to core #1, could be done using a separate SDK task queue.
Flash access
Core 1 code may run directly from flash memory (via XIP) without any special considerations. However, during flash erase/write operations (e.g. file writes) XIP is disabled. If core 1 code attempts to access flash during these periods the system will hard fault.
Note
Floating-point support requires use of routines in flash memory. Integer operations should all be safe to use.
If unexplained crashes are occurring then check the build output files (in out/Rp2040/debug/build) or use a debugger to identify any errant code running from flash.
A typical use for core #1 might be to perform processing of some kind, such as processing data sampled via analogue inputs. If all code is run from RAM then it can continue uninterrupted even during filing system operations.
Alternatively some kind of synchronisation mechanism may be used to ensure that core 1 is suspended or running from RAM during any flash erase/write operations.
Multi-boot / OTA updates
If you run make map you’ll see there is no bootloader.
The second-stage bootloader is part of the application firmware image, called directly from the boot ROM.
The RP2350 chip (as used in Pico2 boards) introduced a boot ROM with partition support. Sming can take advantage of this to support A/B application images and OTA updates.
Note
The RP2040 bootrom has no partition table support. Implementations such as the Pico typically have only 2MByte flash which is quite restrictive for more than one application image. It is also necessary to compile images at different addresses as there is no windowed XIP (eXecute In Place) capability. See Flash In-Place library for a basic method of OTA.
Multi-boot support requires the following:
A valid RP2350 binary partition table located in the first flash sector. See Binary partition table.
Build system support to generate the binary image
RP2350 support in the OTA library.
The espressif chips (esp8266 with rBoot, esp32 with IDF) use a separate stage 2 bootloader partition, plus a reserved partition which stores information about which image to boot.
The RP2350 approach is different in that there is no separate place to indicate which is the bootable partition. Instead, a metadata block (IMAGE_DEF) embedded within each image is used to determine boot behaviour.
Note: After building, this metadata can be inspected via make imageinfo. Use make flashid to read from a device.
The IMAGE_DEF identifies the version number for the image.
Optionally, this can be manually set in MAJOR.MINOR format, e.g. make APP_VERSION=1.5.
For OTA updating two partitions are required, configured as an A/B pair. This is handled by Sming where two partitions are defined of type app/ota_0 and app/ota_1. Of these, the image with the higher version number is selected for boot by ROM code.
There is a try-before-you-buy mode which can be used for temporary booting. This requires the image to have a TBYB bit set in the IMAGE_DEF.
Note
If manually setting APP_VERSION or PICO_TBYB, please run make rp2040-clean
before building to ensure the metadata is updated.
Use make imageinfo to check that the version number is as expected.
Normally, the boot ROM launches the OTA application image with the highest version number.
To run a different application image, use OtaManager::setBootPartition:
// Find the partition to boot
auto partition = Storage::findPartition(...);
bool save = false
OtaManager::setBootPartition(partition, save);
// System doesn't restart until explicitly told to
System.restart();
When save = false, the TBYB bit is set in the application image with a FLASH_UPDATE reboot.
Note that if the TBYB bit is not set in this reboot mode, ROM code will invalidate the alternate application image by wiping its first sector. This means it cannot be later selected for booting.
When save = true, the image version is checked to ensure it is the highest of the OTA images.
If not, it will be adjusted to the next minor release.
Note
The Try-Before-You-Buy feature is discussed in the RP2360 datasheet, section 5.1.17. It states that when an image is booted with this flag, it is “entered under a watchdog timer, and has 16.7 seconds to mark itself OK via the explicit_buy() function”.
Firstly, the watchdog timer is reset by the main Sming task loop, so will only reset if that crashes.
Applications may incorporate their own runtime checks and call System::restart() to revert to the previous application image.
To confirm the image, use the setBootPartition call above.
At time of writing, calling rom_explicit_buy() fails as discussed in https://github.com/raspberrypi/pico-sdk/issues/2639. Whilst there are workarounds, this is less useful as it results in invalidation of the alternative OTA image. This is why the OTA manager uses version numbering to manage boots.
Networking
The Pico-W variant includes an Infineon CYW43439 bluetooth/WiFi SoC. Raspberry Pi makes use of the CYW43xx WiFi/BT SoC driver driver under special license. The SDK also includes an LWIP2 implementation.
The physical interface is SPI using a custom (PIO) implementation.
This requires the use of several GPIO pins which can no longer be
controlled via standard digitalWrite() calls.
The user LED, for example, is connected to a GPIO on the CYW43 chip WL_GPIO0.
Those pins are controlled using a separate API which is far more involved.
The CYW43 chip is initialised (via cyw43_ensure_up()) when application code
makes the first call into the networking API, for example by enabling station
or AP access. Part of the hardware configuration here is to download firmware
to the CYW43 chip (about 240KB) plus the CLM BLOB (< 1KB).
Sming contains patches which compresses this data (based on https://github.com/raspberrypi/pico-sdk/issues/909)
to about 145KB.
By default, it is linked into the application image, but can also be read from a separate partition.
See LINK_CYW43_FIRMWARE.
Source code
The RP2040 is a very capable SOC, similar to Espressif offerings but without integrated WiFi. A massive advantage is that the platform is fully open-source. Even the bootrom is published!
Here’s a summary of the various Github repositories the Raspberry Pi Foundation have made available:
- https://github.com/raspberrypi/pico-sdk
The core SDK for the RP2040 SOC. Sming includes this as a submodule.
- https://github.com/raspberrypi/picotool
This is a tool for inspecting RP2040 binaries, and interacting with RP2040 devices when they are in BOOTSEL mode. It does this by talking to a custom USB device implemented in the RP2040 bootrom.
Getting this to build is a bit fiddly. So far I’ve managed without it, but there is a
picotoolcomponent in the framework which can be used to try building it.- https://github.com/raspberrypi/pico-bootrom
Contents of the RP2040 boot rom. Very handy to be able to see this.
- https://github.com/raspberrypi/pico-examples
Examples using the pico SDK directly.
- https://github.com/raspberrypi/picoprobe
An RP2040 board can be used as a low-cost JTAG adapter using this firmware. Takes some setting up to use though. See [Getting Started PDF](https://datasheets.raspberrypi.org/pico/getting-started-with-pico.pdf) for details.
- https://github.com/raspberrypi/pico-extras
Some additional libraries which may or may not end up in the SDK.
- https://github.com/raspberrypi/pico-playground
Further examples using the pico-extras libraries.
Configuration Variables
- PICO_TOOLCHAIN_PATH
This contains the base directory for the toolchain used to build the framework.
The RP2040 contains two ARM Cortex-M0+ cores. Pre-compiled toolchains can be downloaded from the ARM Developer website.
These can be unzipped to a suitable location and
PICO_TOOLCHAIN_PATHset accordingly. The Sming installer scripts use/opt/rp2040orc:\tools\rp2040.