Raspberry Pi Pico in Rust Proj Template with RTIC USB-Serial and UF2

A template for my Rust projects with Raspberry Pi Pico.

Description

Hi, this is my starting project template for my developments in Embedded Rust with the Raspberry Pi Pico (rp2040 micro-controller).

It is a example of a program developed with:

  • The RTIC operating system or scheduler for ARM Micro-controllers.
  • The USB-Serial emulation of a serial port, it can emulate other types of USB devices.
  • Uf2 method of programming the Pico, but probe-run can also be used by uncommenting one line.
  • It's an example of using shared and local state in RTIC.
  • It's an example of using interrupts in RTIC.
  • It's an example on processing the input from serial and sending a menu to serial terminal, printing long test, and format text with variables to serial terminal.
  • It's an example of doing direct register access in Rust with PAC.
  • It's an example of using the rp2040-hal.
  • It's an example of using the rp-pico bsp abstraction layer.

I developed and tested this project in Linux Ubuntu 20.04, but it probably will compile and run in any computer (Linux, Windows, Mac and Raspberry Pi) connected to a Raspberry Pi Pico. This project feeds from several other projects.

This project was made after studying all Rust Pico examples and the RTIC book. By starting with the Project template for rp2040-hal configuring it to UF2 and changing it to suit my needs. I then added all the dependency libs for it to work with many of the examples of rp-pico board in the rp-hal and the examples in rp2040-hal in the rp-hal. Then I started with the code from example pico_rtic.rs and mixed it with the example pico_usb_serial.rs and pico_usb_serial_interrupt.rs but I couldn't make it all compile in RTIC. Then searched online for clues and arrived at Matrix chat room for the rp-hal https://matrix.to/#/#rp-rs:matrix.org. There I found a very warm and helpful community, that gave me links to examples of working USB in RTIC with Pico. Using this information I come up with this cool and useful (at least to me) project template. I extensively used the example that Paul Daniel Faria gave me - Nashenas88 - dactyl-manuform-kb2040-rs https://github.com/Nashenas88/dactyl-manuform-kb2040-rs.

RP-Pico Pinout

rp-pico pinout

Specifications RP-Pico Board:

  • Low cost
  • Dual core ARM Cortex M0 at 133 MHz that some people made it working at 420 MHZ
  • 3.3V operating voltage
  • 12MHz system crystal
  • DMA controller
  • JTAG/SWD header
  • 2 MByte external Fash, 264 KByte SRAM
  • 2x SPI, 2x USART, 2x I2C
  • 16x PWM
  • 30 GPIO Pins only at 3.3V (not 5V-tolerant)
  • 1x USB 1.1 controller and PHY, with host and device support
  • 1x ADC (12-bit / 5-channel / one temperature sensor)
  • 30 GPIO pins, 4 of which can be used as analogue inputs
  • 8x PIO - Programmable Input Output Controllers
  • 3.3V LDO voltage regulator, max current 150mA
  • Micro USB for power and data
  • Onboard user LED (GPIO 25)
  • 1x button for bootloader selection
  • You can install a Reset button glued and soldered to the top of rp-pico board.
  • 2x20 side pins + 1x3 SWD pins
  • Note: Space to install a Reset button.
  • See the datasheet for more accurate specs.

RP-HAL development environment installation steps

  1. Install Rust on your computer.
    Follow the Rust site steps.
    https://www.rust-lang.org/

  2. Install the packages specific to Embedded development and / or specific to Raspberry Pico.
    Read the README.md page in
    rp-hal - https://github.com/rp-rs/rp-hal

$ rustup self update
$ rustup update stable
$ rustup target add thumbv6m-none-eabi

# Useful to creating UF2 images for the RP2040 USB Bootloader
$ cargo install elf2uf2-rs --locked

# Useful for flashing over the SWD pins using a supported JTAG probe
$ cargo install probe-run

# Useful to detect stack overflow in your developed firmware.
$ cargo install flip-link

Configure your permissions to the USB-Serial port of your computer by your user.

# Connect the Pico and see the USB_Serial current connections 
$ ls -l /dev/ttyUSB* /dev/ttyACM*

# Give permissions to the user to use the Serial port
$ usermod -a -G dialout $USER

  1. Install a Serial Terminal program like

    1. GTKTerminal
      From the Ubuntu App install.

    2. or Install CuteCom
      $ sudo apt install cutecom

    3. or this one, that is the one that I end up using more.
      CoolTerm
      Because it has a line mode, a better GUI and works in Linux, Windows and Mac.
      https://freeware.the-meiers.org/
      On the executable do chmod +x CoolTerm

  2. Install a Serial Plot GUI
    Very useful to easily monitor ADC plots.
    SerialPlot - Realtime Plotting Software
    https://hackaday.io/project/5334-serialplot-realtime-plotting-software
    On the executable do chmod +x SerialPlot

  3. Download the latest version of rp-hal github repo to a directory and unzip it.
    rp-hal - Rust support for the "Raspberry Silicon" family of micro-controllers
    https://github.com/rp-rs/rp-hal

  4. Download this project repository and unzip it to the some directory where you put the root of the previous rp-hal. Because we will be using it for the new version 4.0.0 of the rp2040-hal in our dependencies.
    Raspberry Pi Pico in Rust Proj Template with RTIC USB-Serial and UF2

  5. Change the project directory name from the unzip name to rp2040-project-template-main .

  6. Compile it and upload the firmware to the Raspberry Pico.
    Remove the USB cable and press the white bootload button, while pressing, connect the cable again. It will enter in the USB - UF2 bootload mode that you can use to program the Pico by copyng the file (Cargo run does this automatically). Later you can install a Reset button in the Pico that will simplify this process.

# To Clean do:
$ cargo clean
$ clear

# To Compile and upload the firmware do:
$ cargo run --release
  1. Open CoolTerm.
    Then Menu -> Connection -> Options and select /dev/tttyACM0 115200 bps 8 N 1 (8 data bits, Parity None, Stop Bits 1). And in the Terminal choose "Line Mode" so that it will only send data when you press enter.
    Then press "M" and the menu will appear. Then try the different options.

  2. Play with the code and understand it. See it, as an example of RTIC development with USB-Serial and UF2 programming and then change it (use it as a template) into your project. The only thing that you have to make is to change the root directory name into your project name and change the Cargo.toml file project name in the field name = "rp2040-project-template". This file and your project name as to match, use only lower case letter and "-" or "_".

Note_1: UF2 - Make sure your .cargo/config.toml contains the following (it should by default if you are working in this repository for uf2 method):

[target.thumbv6m-none-eabi]
runner = "elf2uf2-rs -d"

Note_2: Compile and Run with probe-run and another Pico as a external debugger.

Note_3: For this project template you don't need the Rust nightly version but if you need you can change between stable and nightly versions by doing the following.

# To go to Rust nightly version 
$ rustup default nightly

# The add the architecture support for the nightly
$ rustup target add thumbv6m-none-eabi

# To go back to Rust stable version do
$ rustup default stable

This project can also be programmed with other Raspberry Pi Pico as the programmer.

I tested the probe program firmware that should be loaded into a second Pico, the programmer. That allows you to program the first Pico. Rpi Pico-Probe from korken89 that implements a CMSIS DAP V1 and V2 Probe and it works well. Currently Pico-Probe is still under heavy development so many new features should appear but currently it already works well to program the Pico.

To program follow the instructions in the README.md in the above link. You have to connect the two Pico’s. You have to compile the Pico-Probe, upload it as a UF2 and after that you can use it to program the target Pico.

# Don’t forget to change the .cargo/config.toml in my template project,

# comment the runner line for UF2 programming type
runner = "elf2uf2-rs -d" 

# and uncomment the line
runner = "probe-run --chip RP2040" 

# then do
$ cargo clean
$ cargo run --release
 
# to exit CMSIS DAP terminal do a ctrl + C

The connection diagram that I used (but you can change the pins in the Pico-Probe code setup.rs) was:

Pin on programmer Pico Description Pin on target Pico
GPIO13 nRESET Run Pin
GPIO14 SWDIO SWDIO in 3 pin header
GPIO15 SWCLK SWCLK in 3 pin header
VSYS Power VSYS
GND Ground GND
GND Ground GND in 3 pin header

Good Pico in Rust References

  1. Book - Get Started with MicroPython on Raspberry Pi Pico
    https://hackspace.raspberrypi.com/books/micropython-pico

  2. Video - An Overview of the Embedded Rust Ecosystem
    https://www.youtube.com/watch?v=vLYit_HHPaY

  3. rp-hal - Rust support for the "Raspberry Silicon" family of micro-controllers
    Your primary source of information for Rust developments with Raspberry Pico.
    https://github.com/rp-rs/rp-hal

  4. Crate rp2040_hal - Docs
    Your primary source of doc information on the HAL - Hardware Abstraction Layer.
    https://docs.rs/rp2040-hal/latest/rp2040_hal/

  5. Raspberry Pi Pico Board - Rust Code Examples
    Study them all!
    https://github.com/rp-rs/rp-hal/tree/main/boards/rp-pico/examples

  6. Examples for the HAL - Hardware Abstraction Layer
    rp-hal - rp2040-hal - examples
    https://github.com/rp-rs/rp-hal/tree/main/rp2040-hal/examples

  7. Github rp2040-hal
    https://github.com/rp-rs/rp-hal/tree/main/rp2040-hal

  8. Getting Started with Rust on a Raspberry Pi Pico (Part 1)
    https://reltech.substack.com/p/getting-started-with-rust-on-a-raspberry

  9. Getting Started with Rust on a Raspberry Pi Pico (Part 2)
    https://reltech.substack.com/p/getting-started-with-raspberry-pi

  10. Getting Started with Rust on a Raspberry Pi Pico (Part 3)
    https://reltech.substack.com/p/getting-started-with-rust-on-a-raspberry-a88

  11. Multilingual blink for Raspberry Pi Pico - Alasdair Allan
    https://www.raspberrypi.com/news/multilingual-blink-for-raspberry-pi-pico/

  12. Video - How can we write the best device driver for a Hal in Rust?
    https://www.youtube.com/watch?v=z9z74VpqO9A

  13. 258 drivers para Embedded-HAL
    https://crates.io/search?q=embedded-hal%20driver

  14. Video - RTIC - Real Time Interrupt driven Concurrency
    RTIC is a RTOS - Real Time Operating System.
    https://www.youtube.com/watch?v=saNdh0m_qHc

  15. RTIC Book
    Real-Time Interrupt-driven Concurrency.
    A very efficient preemptive multitasking framework that supports task prioritization and dead lock free execution.
    https://rtic.rs/1/book/en/

  16. Github - rtic-rs - cortex-m-rtic
    https://github.com/rtic-rs/cortex-m-rtic

  17. Video - Grepit about the Rust RTIC framework
    https://www.youtube.com/watch?v=sSJ-Md8nwIM

  18. Good example 1 of advanced Pico with RTIC to Study
    Paul Daniel Faria
    Nashenas88 - dactyl-manuform-kb2040-rs
    Dactyl Manuform firmware for Adafruit kb2040 in Rust
    https://github.com/Nashenas88/dactyl-manuform-kb2040-rs

  19. Good example 2 of advanced Pico with RTIC to Study
    korken89
    korken89 - pico-probe
    https://github.com/korken89/pico-probe

  20. Good example 3 of advanced Pico with RTIC to Study
    Mathias
    mgottschlag - rp2040-usb-sound-card
    https://github.com/mgottschlag/rp2040-usb-sound-card

  21. Good example 4 of advanced Pico with RTIC to Study
    kalkyl - Playground for RTIC on RP2040
    3 good examples
    https://github.com/kalkyl/rp-rtic

  22. Project template for rp2040-hal
    The starting point for the project that you are current reading.
    https://github.com/rp-rs/rp2040-project-template

  23. pio-rs - Support for the Raspberry Silicon RP2040's PIO State Machines
    https://github.com/rp-rs/pio-rs

  24. embedded-hal
    Use this if you are writing code that should run on any micro-controller
    https://github.com/rust-embedded/embedded-hal

  25. raspberrypi picotool - Not really neaded in Rust
    https://github.com/raspberrypi/picotool

  26. usb-device - Experimental device-side USB stack for embedded devices
    https://crates.io/crates/usb-device

  27. probe-rs - A modern, embedded debugging toolkit, written in Rust
    https://probe.rs/

  28. GitHub probe-rs
    https://github.com/probe-rs/probe-rs

  29. Video - probe-rs: Your Embedded Tome
    https://www.youtube.com/watch?v=esNPoXbhHkU

  30. rust-embedded - cortex-m-quickstart
    https://github.com/rust-embedded/cortex-m-quickstart

  31. STM32 - Discovery - Book
    https://docs.rust-embedded.org/discovery/

  32. The Embedded Rust Book
    https://docs.rust-embedded.org/book/

  33. The Embedonomicon Book
    Deep dive into the inner workings.
    https://docs.rust-embedded.org/embedonomicon/

  34. More gdb commands cheat-sheet
    https://darkdust.net/files/GDB%20Cheat%20Sheet.pdf

  35. Video - Getting Started with Debugging using GDB
    Find Bugs in Your Code with A Couple Easy Commands
    https://www.youtube.com/watch?v=Dq8l1_-QgAc

  36. Play List - Embedded Rust BluePill - Vers Binarii
    https://www.youtube.com/playlist?list=PLP_X41VhYn5X6Wwjnm0bRwI3n2pdaszxU

  37. Play List - Embedded Rust course - JaJakub - 2022
    https://www.youtube.com/playlist?list=PLL2SCPK5xSRWBPj-nKOVYIhxRw7C4kYeI

  38. joaocarvalhoopen - stm32_bluepill_in_rust__Template
    https://github.com/joaocarvalhoopen/stm32_bluepill_in_rust__Template

  39. Awesome Embedded Rust
    https://github.com/rust-embedded/awesome-embedded-rust

  40. How to learn modern Rust
    https://github.com/joaocarvalhoopen/How_to_learn_modern_Rust

Datasheets and other specific info for the RP2040 micro-controller

  1. Raspberry Pi Pico Site
    https://www.raspberrypi.com/products/raspberry-pi-pico/

  2. Pico RP2040 documentation
    https://www.raspberrypi.com/documentation/microcontrollers/

  3. RP2040 Micro-controller - Datasheet - PDF
    https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf

  4. Pico board Datasheet - PDF
    https://datasheets.raspberrypi.com/pico/pico-datasheet.pdf

  5. Pico C/C++ SDK - Libraries and Tools - PDF
    https://datasheets.raspberrypi.com/pico/raspberry-pi-pico-c-sdk.pdf

  6. Pico Python SDK - PDF
    https://datasheets.raspberrypi.com/pico/raspberry-pi-pico-python-sdk.pdf

  7. Pico FAQ - PDF
    https://datasheets.raspberrypi.com/pico/raspberry-pi-pico-faq.pdf

  8. Raspberry Pi Pico Overclocking, beware there is a catch! - Part 1
    The part 2 will resolve the flash issue.
    https://www.youtube.com/watch?v=G2BuoFNLoDM

  9. Pico Overclock Part 2. Fixing the catch with the flash. - Part 2
    https://www.youtube.com/watch?v=rU381A-b79c

  10. Play List - Raspberry Pi Pico - Low Level Learning
    https://www.youtube.com/playlist?list=PLc7W4b0WHTAV6EYRVayb9c9dEsq-NeXAt

  11. Play List - Intro to Raspberry Pi Pico and RP2040 - DigiKey
    https://www.youtube.com/playlist?list=PLEBQazB0HUyQO6rJxKr2umPCgmfAU-cqR

  12. Video - In-depth: Raspberry Pi Pico's PIO - programmable I/O
    https://www.youtube.com/watch?v=yYnQYF_Xa8g

  13. Raspberry Pi Pico 200Khz Digital Oscilloscope
    https://www.instructables.com/Raspberry-Pi-Pico-200Khz-Digital-Oscilloscope/

  14. The Pico ADC
    Integral Non-Linearity (INL) and Differential Non-Linearity (DNL) are used to measure the error of the quantization of the incoming signal that the ADC generates
    Pag. 589 e Pag. 590 do Pico Datasheet
    https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf

  15. Characterizing the Raspberry Pi Pico ADC - markomo
    https://pico-adc.markomo.me/

  16. Pico ADC - Power Supply Noise and Spectrum Testing
    https://pico-adc.markomo.me/PSU-Noise/

  17. Using a HD44780 LCD display with MicroPython on the Raspberry Pi Pico
    https://raphaelkabo.com/blog/pi-pico-hd44780/

  18. How to connect a piezo speaker to a microcontroller?
    https://www.eevblog.com/forum/projects/how-to-connect-a-piezo-speaker-to-a-microcontroller/

  19. Electrical Symbols & Electronic Symbols
    https://www.rapidtables.com/electric/electrical_symbols.html

How to install a Raspberry Pi Pico Reset Button

Solder a push button between the GND and Run pin's and then glue it over RP-Pico board empty space.

Pico Reset Button soldered and glued over the RP-Pico Board

The Reset process to enter UF2 programming mode, instead of doing:
1. Remove USB Cable.
3. Press Bootload Button.
4. While pressing re-insert the USB cable.
5. Upload the C/C++ or Rust firmware

You will do:
1. Press the reset button.
2. Press the Bootload Button.
1. Release the reset button.
2. Release the Bootload Button.
5. Upload the C/C++ or Rust firmware
  1. Video - Pico Quick Reset Button
    https://www.youtube.com/watch?v=OVM_spenILE

Order in which you should study the Rust examples for the RP2040 Micro-Controller and the RP-Pico Board

Use the following documentation while studying the examples:

The examples:

1.  - pico_blinky.rs
2.  - pico_gpio_in_out.rs
3.  - pico_rtic.rs
4.  - pico_countdown_blinky.rs
5.  - pico_pwm_blink.rs
6.  - pico_usb_serial.rs
7.  - pico_usb_serial_interrupt.rs
8.  - pico_usb_twitchy_mouse.rs
9.  - pico_uart_irq_buffer.rs
10. - pico_uart_irq_echo.rs
11. - pico_i2c_oled_display_ssd1306.rs
12. - pico_i2c_pio.rs
13. - pico_spi_sd_card.rs
14. - pico_ws2812_led.rs
1.  - blinky.rs
2.  - gpio_in_out.rs

3.  - multicore_fifo_blink.rs
4.  - adc.rs

5.  - lcd_display.rs
6.  - watchdog.rs

7.  - pwm_blink.rs

8.  - rom_funcs.rs

9.  - dht11.rs
11. - i2c.rs
12. - spi.rs
13. - uart.rs

14. - pio_blink.rs
15. - pio_proc_blink.rs
16. - pio_side_set.rs

Then study My example Template.

Then the following RTIC examples with USB.

How to program the Pico in Rust?

First if possible try to use RTIC framework for concurrency. It’s like a small and lightweight operating system that simplifies the development process.
Then you should use BSP (Board level support package) features where available.
Then use rp2040-hal (Hardware Abstraction Layer) features for the majority of development and if you need something that is not yet supported by the HAL or if you need a more fine grained control over the hardware, you should use rp2040-pac (Peripheral Access Crate) direct access through the registers and consult the rp2040 datasheet to discover each register name, what each register do and how to use them.

// Example
use rp_pico::hal;
use rp_pico::pac;
let led_status_reg = unsafe { (*pac::IO_BANK0::ptr()).gpio[25].gpio_status.read().bits() };
let sio_pin_value  = unsafe { (*pac::SIO::ptr()).gpio_out.read().bits() };

let (led_bool, led_str) = if ((led_status_reg & 1 << 8) >> 8) == 1_u32 {
        (true, "ON")
    } else {
        (false, "OFF")
    };

License

The contents of this repository are dual-licensed under the MIT OR Apache 2.0 License. That means you can chose either the MIT licence or the Apache-2.0 licence when you re-use this code. See MIT or APACHE2.0 for more information on each specific licence.

Have fun!

Best regards,
João Nuno Carvalho