+# Generated by Cargo
+# will have compiled files and executables
+debug/
+target/
+
+# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
+# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
+Cargo.lock
+
+# These are backup files generated by rustfmt
+**/*.rs.bk
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## Unreleased
+
+## 0.7.0 - 2023-02-18
+
+### Changed
+
+- Update to rp2040-hal 0.8.0
+- Update to ws2812-pio 0.6.0
+- Update to i2c-pio 0.6.0
+- Update to embedded-sdmmc 0.4.0
+
+## 0.6.0 - 2022-12-11
+
+### Changed
+
+- Update to rp2040-hal 0.7.0
+- Update to ws2812-pio 0.5.0
+- Update to i2c-pio 0.5.0
+
+## 0.5.0 - 2022-08-26
+
+### Added
+
+- `rp2040-e5` feature enabling the workaround for errata 5 on the USB device peripheral.
+- Support for critical-section 1.0.0 in the examples.
+- Example for the interpolator
+
+### Changed
+
+- Use `rp2040-hal`'s entry function.
+- Migrate from `embedded-time` to `fugit`
+- Bump `ws2812-pio` to 0.4.0
+- Bump `i2c-pio` to 0.4.0
+- Update to rp2040-hal 0.6.0
+
+### Removed
+
+- Unused dependencies
+
+## 0.4.0 - 2022-06-13
+
+### Changed
+
+- Update to rp2040-hal 0.5.0
+
+## 0.3.0 - 2022-03-11
+
+### Changed
+
+- Update to rp-hal 0.4.0
+
+## 0.2.0 - 2021-12-23
+
+### Added
+
+- Lots of things!
+
+### Changed
+
+- Basically re-written.
+
+## 0.1.3 - 2021-02-03
+
+- Last release outside the [rp-rs] organisation by [@jannic].
+
+[@jannic]: https://github.com/jannic
+[rp-rs]: https://github.com/rp-rs
+[package]
+name = "doa-hallonbrod"
+version = "0.7.0"
+authors = ["Chip <bytex64@bytex64.net>", "The Dominion of Awesome"]
+edition = "2018"
+homepage = "https://dominionofawesome.com/vca/hallonbrod/"
+description = "Board Support Package for the DoA Hallonbröd interface board"
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/bytex64/doa-hallonbrod.git"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+cortex-m = "0.7.2"
+rp2040-boot2 = { version = "0.2.0", optional = true }
+rp2040-hal = { version = "0.8.0" }
+cortex-m-rt = { version = "0.7", optional = true }
+fugit = "0.3.5"
+usb-device= "0.2.9"
+
+[dev-dependencies]
+rp2040-hal = { version = "0.8.0", features = [ "defmt" ] }
+panic-halt= "0.2.0"
+embedded-hal ="0.2.5"
+cortex-m-rtic = "1.1.2"
+nb = "1.0"
+i2c-pio = "0.6.0"
+heapless = "0.7.9"
+embedded-sdmmc = "0.5.0"
+smart-leds = "0.3.0"
+ws2812-pio = "0.6.0"
+ssd1306 = "0.7.0"
+embedded-graphics = "0.7.1"
+hd44780-driver = "0.4.0"
+pio = "0.2.0"
+pio-proc = "0.2.1"
+critical-section = "1.0.0"
+usbd-serial = "0.1.1"
+usbd-hid = "0.5.1"
+
+defmt = "0.3.0"
+defmt-rtt = "0.4.0"
+
+[features]
+# This is the set of features we enable by default
+default = ["boot2", "rt", "critical-section-impl", "rom-func-cache"]
+
+# critical section that is safe for multicore use
+critical-section-impl = ["rp2040-hal/critical-section-impl"]
+
+# 2nd stage bootloaders for rp2040
+boot2 = ["rp2040-boot2"]
+
+# Minimal startup / runtime for Cortex-M microcontrollers
+rt = ["cortex-m-rt","rp2040-hal/rt"]
+
+# This enables a fix for USB errata 5: USB device fails to exit RESET state on busy USB bus.
+# Only required for RP2040 B0 and RP2040 B1, but it also works for RP2040 B2 and above
+rp2040-e5 = ["rp2040-hal/rp2040-e5"]
+
+# Memoize(cache) ROM function pointers on first use to improve performance
+rom-func-cache = ["rp2040-hal/rom-func-cache"]
+
+# Disable automatic mapping of language features (like floating point math) to ROM functions
+disable-intrinsics = ["rp2040-hal/disable-intrinsics"]
+
+# This enables ROM functions for f64 math that were not present in the earliest RP2040s
+rom-v2-intrinsics = ["rp2040-hal/rom-v2-intrinsics"]
+
+[[example]]
+name = "pico_rtic_monotonic"
+required-features = ["rp2040-hal/rtic-monotonic"]
+# [rp-pico] - Board Support for the [Raspberry Pi Pico]
+
+You should include this crate if you are writing code that you want to run on
+a [Raspberry Pi Pico] - the original launch PCB for the RP2040 chip.
+
+This crate includes the [rp2040-hal], but also configures each pin of the
+RP2040 chip according to how it is connected up on the Pico.
+
+[Raspberry Pi Pico]: https://www.raspberrypi.org/products/raspberry-pi-pico/
+[rp-pico]: https://github.com/rp-rs/rp-hal-boards/tree/main/boards/rp-pico
+[rp2040-hal]: https://github.com/rp-rs/rp-hal/tree/main/rp2040-hal
+[Raspberry Silicon RP2040]: https://www.raspberrypi.org/products/rp2040/
+
+## Using
+
+To use this crate, your `Cargo.toml` file should contain:
+
+```toml
+rp-pico = "0.7.0"
+```
+
+In your program, you will need to call `rp_pico::Pins::new` to create
+a new `Pins` structure. This will set up all the GPIOs for any on-board
+devices. See the [examples](./examples) folder for more details.
+
+## Examples
+
+### General Instructions
+
+To compile an example, clone the _rp-hal-boards_ repository and run:
+
+```console
+rp-hal-boards/boards/rp-pico $ cargo build --release --example <name>
+```
+
+You will get an ELF file called
+`./target/thumbv6m-none-eabi/release/examples/<name>`, where the `target`
+folder is located at the top of the _rp-hal-boards_ repository checkout. Normally
+you would also need to specify `--target=thumbv6m-none-eabi` but when
+building examples from this git repository, that is set as the default.
+
+If you want to convert the ELF file to a UF2 and automatically copy it to the
+USB drive exported by the RP2040 bootloader, simply boot your board into
+bootloader mode and run:
+
+```console
+rp-hal-boards/boards/rp-pico $ cargo run --release --example <name>
+```
+
+If you get an error about not being able to find `elf2uf2-rs`, try:
+
+```console
+$ cargo install elf2uf2-rs
+```
+then try repeating the `cargo run` command above.
+
+### From Scratch
+
+To start a basic project from scratch, create a project using `cargo new project-name`. Within the
+project directory, run `cargo add rp-pico`, `cargo add cortex-m-rt`, and `cargo add panic-halt`. The
+first command will this HAL (Hardware Abstraction Layer), the second is required for the `#[entry]` macro, and _panic-halt_ creates a simple panic function, which just halts.
+
+You'll also need to copy the cargo config file from the [repo](https://github.com/rp-rs/rp-hal-boards/blob/main/.cargo/config). It specifies the target and optimizing flags to the linker. You'll also need to copy [_memory.x_](https://github.com/rp-rs/rp-hal-boards/blob/main/memory.x) to your project root. This file tells the linker the flash and RAM layout, so it won't clobber the bootloader or write to an out of bounds memory address.
+
+The simplest working example, which does nothing except loop forever, is:
+
+```ignore
+#![no_std]
+#![no_main]
+use rp_pico::entry;
+use panic_halt as _;
+#[entry]
+fn see_doesnt_have_to_be_called_main() -> ! {
+ loop {}
+}
+```
+
+It can be placed in _/src/main.rs_.
+
+You can use `cargo run` to compile and install it.
+**Note**: You won't see any activity since this program does nothing. You can use the examples provided
+to add more functionality.
+### [pico_blinky](./examples/pico_blinky.rs)
+
+Flashes the Pico's on-board LED on and off.
+
+### [pico_gpio_in_out](./examples/pico_gpio_in_out.rs)
+
+Reads a push button attached to GPIO 15 and drives the on-board LED to match it (i.e. on when pressed, off when not pressed).
+
+### [pico_rtic](./examples/pico_rtic.rs)
+
+Demonstrates the use of the [Real-Time Interrupt-driven Concurrency Framework] on the Raspberry Pi Pico.
+
+[Real-Time Interrupt-driven Concurrency Framework]: https://rtic.rs
+
+### [pico_countdown_blinky](./examples/pico_countdown_blinky.rs)
+
+Another LED blinking example, but using a Timer in count-down mode.
+
+### [pico_pwm_blink](./examples/pico_pwm_blink.rs)
+
+Puts out an analog 'triangle wave' on GPIO 25, using the PWM hardware.
+
+### [pico_pwm_servo](./examples/pico_pwm_servo.rs)
+
+Demonstrates handling a micro servo, using the PWM hardware.
+
+### [pico_usb_serial](./examples/pico_usb_serial.rs)
+
+Creates a USB Serial device on a Pico board.
+
+The USB Serial device will print `HelloWorld` on start-up, and then echo any
+incoming characters - except that any lower-case ASCII characters are
+converted to the upper-case equivalent.
+
+### [pico_usb_serial_interrupt](./examples/pico_usb_serial_interrupt.rs)
+
+Creates a USB Serial device on a Pico board, but demonstrating handling
+interrupts when USB data arrives.
+
+### [pico_usb_twitchy_mouse](./examples/pico_usb_twitchy_mouse.rs)
+
+Demonstrates emulating a USB Human Input Device (HID) Mouse. The mouse
+cursor will jiggle up and down.
+
+### [pico_spi_sd_card](./examples/pico_spi_sd_card.rs)
+
+Example that shows how to use the
+[embedded_sdmmc crate](https://github.com/rust-embedded-community/embedded-sdmmc-rs)
+with the Raspberry Pi Pico.
+
+## Contributing
+
+Contributions are what make the open source community such an amazing place to
+be learn, inspire, and create. Any contributions you make are **greatly
+appreciated**.
+
+The steps are:
+
+1. Fork the Project by clicking the 'Fork' button at the top of the page.
+2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
+3. Make some changes to the code or documentation.
+4. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
+5. Push to the Feature Branch (`git push origin feature/AmazingFeature`)
+6. Create a [New Pull Request](https://github.com/rp-rs/rp-hal-boards/pulls)
+7. An admin will review the Pull Request and discuss any changes that may be required.
+8. Once everyone is happy, the Pull Request can be merged by an admin, and your work is part of our project!
+
+## Code of Conduct
+
+Contribution to this crate is organized under the terms of the [Rust Code of
+Conduct][CoC], and the maintainer of this crate, the [rp-rs team], promises
+to intervene to uphold that code of conduct.
+
+[CoC]: CODE_OF_CONDUCT.md
+[rp-rs team]: https://github.com/orgs/rp-rs/teams/rp-rs
+
+## License
+
+The contents of this repository are dual-licensed under the _MIT OR Apache
+2.0_ License. That means you can choose either the MIT license or the
+Apache-2.0 license when you re-use this code. See `MIT` or `APACHE2.0` for more
+information on each specific license.
+
+Any submissions to this project (e.g. as Pull Requests) must be made available
+under these terms.
+//! This build script makes sure the linker flag -Tdefmt.x is added
+//! for the examples.
+
+fn main() {
+ println!("cargo:rustc-link-arg-examples=-Tdefmt.x");
+}
+//! # Pico Blinky Example
+//!
+//! Blinks the LED on a Pico board.
+//!
+//! This will blink an LED attached to GP25, which is the pin the Pico uses for
+//! the on-board LED.
+//!
+//! See the `Cargo.toml` file for Copyright and license details.
+
+#![no_std]
+#![no_main]
+
+// The macro for our start-up function
+use doa_hallonbrod::entry;
+
+// GPIO traits
+use embedded_hal::digital::v2::OutputPin;
+
+// Ensure we halt the program on panic (if we don't mention this crate it won't
+// be linked)
+use panic_halt as _;
+
+// Pull in any important traits
+use doa_hallonbrod::hal::prelude::*;
+
+// A shorter alias for the Peripheral Access Crate, which provides low-level
+// register access
+use doa_hallonbrod::hal::pac;
+
+// A shorter alias for the Hardware Abstraction Layer, which provides
+// higher-level drivers.
+use doa_hallonbrod::hal;
+
+/// Entry point to our bare-metal application.
+///
+/// The `#[entry]` macro ensures the Cortex-M start-up code calls this function
+/// as soon as all global variables are initialised.
+///
+/// The function configures the RP2040 peripherals, then blinks the LED in an
+/// infinite loop.
+#[entry]
+fn main() -> ! {
+ // Grab our singleton objects
+ let mut pac = pac::Peripherals::take().unwrap();
+ let core = pac::CorePeripherals::take().unwrap();
+
+ // Set up the watchdog driver - needed by the clock setup code
+ let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);
+
+ // Configure the clocks
+ //
+ // The default is to generate a 125 MHz system clock
+ let clocks = hal::clocks::init_clocks_and_plls(
+ doa_hallonbrod::XOSC_CRYSTAL_FREQ,
+ pac.XOSC,
+ pac.CLOCKS,
+ pac.PLL_SYS,
+ pac.PLL_USB,
+ &mut pac.RESETS,
+ &mut watchdog,
+ )
+ .ok()
+ .unwrap();
+
+ // The delay object lets us wait for specified amounts of time (in
+ // milliseconds)
+ let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz());
+
+ // The single-cycle I/O block controls our GPIO pins
+ let sio = hal::Sio::new(pac.SIO);
+
+ // Set the pins up according to their function on this particular board
+ let pins = doa_hallonbrod::Pins::new(
+ pac.IO_BANK0,
+ pac.PADS_BANK0,
+ sio.gpio_bank0,
+ &mut pac.RESETS,
+ );
+
+ // Set the LED to be an output
+ let mut led_pin = pins.led.into_push_pull_output();
+
+ // Blink the LED at 1 Hz
+ loop {
+ led_pin.set_high().unwrap();
+ delay.delay_ms(500);
+ led_pin.set_low().unwrap();
+ delay.delay_ms(500);
+ }
+}
+
+// End of file
+//! # Pico Countdown Blinky Example
+//!
+//! Blinks the LED on a Pico board, using an RP2040 Timer in Count-down mode.
+//!
+//! This will blink an LED attached to GP25, which is the pin the Pico uses for
+//! the on-board LED.
+//!
+//! See the `Cargo.toml` file for Copyright and license details.
+
+#![no_std]
+#![no_main]
+
+// The macro for our start-up function
+use rp_pico::entry;
+
+use cortex_m::prelude::*;
+
+// GPIO traits
+use embedded_hal::digital::v2::OutputPin;
+
+// Traits for converting integers to amounts of time
+use fugit::ExtU32;
+
+// Ensure we halt the program on panic (if we don't mention this crate it won't
+// be linked)
+use panic_halt as _;
+
+// A shorter alias for the Peripheral Access Crate, which provides low-level
+// register access
+use rp_pico::hal::pac;
+
+// A shorter alias for the Hardware Abstraction Layer, which provides
+// higher-level drivers.
+use rp_pico::hal;
+
+#[entry]
+fn main() -> ! {
+ // Grab our singleton objects
+ let mut pac = pac::Peripherals::take().unwrap();
+
+ // Set up the watchdog driver - needed by the clock setup code
+ let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);
+
+ // Configure the clocks
+ //
+ // The default is to generate a 125 MHz system clock
+ let _clocks = hal::clocks::init_clocks_and_plls(
+ rp_pico::XOSC_CRYSTAL_FREQ,
+ pac.XOSC,
+ pac.CLOCKS,
+ pac.PLL_SYS,
+ pac.PLL_USB,
+ &mut pac.RESETS,
+ &mut watchdog,
+ )
+ .ok()
+ .unwrap();
+
+ // Configure the Timer peripheral in count-down mode
+ let timer = hal::Timer::new(pac.TIMER, &mut pac.RESETS);
+ let mut count_down = timer.count_down();
+
+ // The single-cycle I/O block controls our GPIO pins
+ let sio = hal::Sio::new(pac.SIO);
+
+ // Set the pins up according to their function on this particular board
+ let pins = rp_pico::Pins::new(
+ pac.IO_BANK0,
+ pac.PADS_BANK0,
+ sio.gpio_bank0,
+ &mut pac.RESETS,
+ );
+
+ let mut led_pin = pins.led.into_push_pull_output();
+
+ // Blink the LED at 1 Hz
+ loop {
+ // LED on, and wait for 500ms
+ led_pin.set_high().unwrap();
+ count_down.start(500.millis());
+ let _ = nb::block!(count_down.wait());
+
+ // LED off, and wait for 500ms
+ led_pin.set_low().unwrap();
+ count_down.start(500.millis());
+ let _ = nb::block!(count_down.wait());
+ }
+}
+//! # Pico GPIO In/Out Example
+//!
+//! Toggles the LED based on GPIO input.
+//!
+//! This will control an LED on GP25 based on a button hooked up to GP15. The
+//! button should cause the line to be grounded, as the input pin is pulled high
+//! internally by this example. When the button is pressed, the LED will turn
+//! off.
+//!
+//! See the `Cargo.toml` file for Copyright and license details.
+
+#![no_std]
+#![no_main]
+
+// The macro for our start-up function
+use rp_pico::entry;
+
+// GPIO traits
+use embedded_hal::digital::v2::{InputPin, OutputPin};
+
+// Ensure we halt the program on panic (if we don't mention this crate it won't
+// be linked)
+use panic_halt as _;
+
+// A shorter alias for the Peripheral Access Crate, which provides low-level
+// register access
+use rp_pico::hal::pac;
+
+// A shorter alias for the Hardware Abstraction Layer, which provides
+// higher-level drivers.
+use rp_pico::hal;
+
+/// Entry point to our bare-metal application.
+///
+/// The `#[entry]` macro ensures the Cortex-M start-up code calls this function
+/// as soon as all global variables are initialised.
+///
+/// The function configures the RP2040 peripherals, then just reads the button
+/// and sets the LED appropriately.
+#[entry]
+fn main() -> ! {
+ // Grab our singleton objects
+ let mut pac = pac::Peripherals::take().unwrap();
+
+ // Note - we don't do any clock set-up in this example. The RP2040 will run
+ // at it's default clock speed.
+
+ // The single-cycle I/O block controls our GPIO pins
+ let sio = hal::Sio::new(pac.SIO);
+
+ // Set the pins up according to their function on this particular board
+ let pins = rp_pico::Pins::new(
+ pac.IO_BANK0,
+ pac.PADS_BANK0,
+ sio.gpio_bank0,
+ &mut pac.RESETS,
+ );
+
+ // Our LED output
+ let mut led_pin = pins.led.into_push_pull_output();
+
+ // Our button input
+ let button_pin = pins.gpio15.into_pull_up_input();
+
+ // Run forever, setting the LED according to the button
+ loop {
+ if button_pin.is_low().unwrap() {
+ led_pin.set_high().unwrap();
+ } else {
+ led_pin.set_low().unwrap();
+ }
+ }
+}
+
+// End of file
+//! # LCD Display Example
+//!
+//! In this example, the RP2040 is configured to drive a small two-line
+//! alphanumeric LCD using the
+//! [HD44780](https://crates.io/crates/hd44780-driver) driver.
+//!
+//! This example drives the LCD by pushing data out of six GPIO pins, writing
+//! the data four bits at a time. A faster alternative can be created using
+//! HD44780::new_8bit() but requiring an additional four GPIO pins.
+//!
+//! See the `Cargo.toml` file for Copyright and license details.
+//!
+//! ```text
+//! /--------------------------------------\
+//! ____________ | /-------------------------\ |
+//! | 1 GND|-------+---\ | _|USB|_ | |
+//! | 2 VDD|-------+---+----/ |1 R 40|-VBUS-o v
+//! | 3 VS|-------/ | |2 P 39| ||POT||
+//! | 4 RS|--\ o-----------GND-|3 38|-GND----------o
+//! | 5 RW|--+--------/ /------GP2-|4 P 37|
+//! | 6 EN|--+-\ /--+------GP3-|5 I 36|
+//! | 7 | | | /--+--+------GP4-|6 C |
+//! | 8 | | | /--+--+--+------GP5-|7 O |
+//! | 9 | | \--+--+--+--+---\ |8 |
+//! | 10 | \----+--+--+--+-\ \-GP6-|9 |
+//! | 11 D4|-------/ | | | \---GP7-|10 |
+//! | 12 D5|----------/ | | .........
+//! | 13 D6|-------------/ | |20 21|
+//! | 14 D7|----------------/ """""""
+//! ..............
+//! Symbols:
+//! - (+) crossing lines, not connected
+//! - (o) connected lines
+//! ```
+//!
+//! See the `Cargo.toml` file for Copyright and license details.
+
+#![no_std]
+#![no_main]
+
+// Ensure we halt the program on panic (if we don't mention this crate it won't
+// be linked)
+use panic_halt as _;
+
+// Pull in any important traits
+use rp_pico::hal::prelude::*;
+
+// GPIO traits
+use embedded_hal::digital::v2::OutputPin;
+
+// For LCD display
+use hd44780_driver::HD44780;
+
+/// Entry point to our bare-metal application.
+///
+/// The `#[rp_pico::entry]` macro ensures the Cortex-M start-up code calls this function
+/// as soon as all global variables and the spinlock are initialised.
+#[rp_pico::entry]
+fn main() -> ! {
+ // Grab our singleton objects
+ let mut pac = rp_pico::hal::pac::Peripherals::take().unwrap();
+ let core = rp_pico::hal::pac::CorePeripherals::take().unwrap();
+
+ // Set up the watchdog driver - needed by the clock setup code
+ let mut watchdog = rp_pico::hal::Watchdog::new(pac.WATCHDOG);
+
+ // Configure the clocks
+ // The default is to generate a 125 MHz system clock
+ let clocks = rp_pico::hal::clocks::init_clocks_and_plls(
+ rp_pico::XOSC_CRYSTAL_FREQ,
+ pac.XOSC,
+ pac.CLOCKS,
+ pac.PLL_SYS,
+ pac.PLL_USB,
+ &mut pac.RESETS,
+ &mut watchdog,
+ )
+ .ok()
+ .unwrap();
+
+ // The single-cycle I/O block controls our GPIO pins
+ let sio = rp_pico::hal::Sio::new(pac.SIO);
+
+ // Set the pins up according to their function on this particular board
+ let pins = rp_pico::Pins::new(
+ pac.IO_BANK0,
+ pac.PADS_BANK0,
+ sio.gpio_bank0,
+ &mut pac.RESETS,
+ );
+
+ let mut led_pin = pins.led.into_push_pull_output();
+
+ // The delay object lets us wait for specified amounts of time
+ let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz());
+
+ // Init pins
+ let rs = pins.gpio7.into_push_pull_output();
+ let en = pins.gpio6.into_push_pull_output();
+ let d4 = pins.gpio5.into_push_pull_output();
+ let d5 = pins.gpio4.into_push_pull_output();
+ let d6 = pins.gpio3.into_push_pull_output();
+ let d7 = pins.gpio2.into_push_pull_output();
+
+ // LCD Init
+ let mut lcd = HD44780::new_4bit(rs, en, d4, d5, d6, d7, &mut delay).unwrap();
+
+ loop {
+ // Clear the screen
+ lcd.reset(&mut delay).unwrap();
+ lcd.clear(&mut delay).unwrap();
+
+ // Write to the top line
+ lcd.write_str("rp-hal on", &mut delay).unwrap();
+
+ // Move the cursor
+ lcd.set_cursor_pos(40, &mut delay).unwrap();
+
+ // Write more more text
+ lcd.write_str("HD44780! ", &mut delay).unwrap();
+ let mut char_count = 9;
+ for ch in "move along!.. ".chars() {
+ if char_count > 15 {
+ // Switch autoscroll on
+ lcd.set_autoscroll(true, &mut delay).unwrap();
+ }
+ led_pin.set_high().unwrap();
+ lcd.write_char(ch, &mut delay).unwrap();
+ char_count += 1;
+ delay.delay_us(400_000); //0.4s
+ led_pin.set_low().unwrap();
+ delay.delay_us(100_000); //0.1s
+ }
+ lcd.set_autoscroll(false, &mut delay).unwrap();
+ }
+}
+//! # Raspberry Pi Pico (monochome) 128x64 OLED Display with SSD1306 Driver Example
+//!
+//! This example assumes you got an 128x64 OLED Display with an SSD1306 driver
+//! connected to your Raspberry Pi Pico. The +3.3V voltage source of the
+//! Raspberry Pi Pico will be used, and the output pins 21 and 22 of the board
+//! (on the lower right).
+//!
+//! It will demonstrate how to get an I2C device and use it with the ssd1306 crate.
+//! Additionally you can also see how to format a number into a string using
+//! [core::fmt].
+//!
+//! The following diagram will show how things should be connected.
+//! These displays usually can take 3.3V up to 5V.
+//!
+//! ```text
+//! VCC SCL
+//! /------------\ /----------\
+//! | GND \ / SDA |
+//! _|USB|_ | /-----\ | | /--------+--\
+//! |1 R 40| | / __|__|__|__|___ | |
+//! |2 P 39| | / | ____________ | | |
+//! |3 38|- GND --+-/ | |Hello worl| | | |
+//! |4 P 37| | | |Hello Rust| | | |
+//! |5 I 36|-+3.3V -/ | |counter: 1| | | |
+//! |6 C | | | | | | |
+//! |7 O | | """""""""""" | | |
+//! | | """"""""""""""" | |
+//! | | (SSD1306 128x64 OLED Display) | |
+//! ......... / /
+//! | | / /
+//! | 22|-GP17 I2C0 SCL---------------------/ /
+//! |20 21|-GP16 I2C0 SDA-----------------------/
+//! """""""
+//! Symbols:
+//! - (+) crossing lines, not connected
+//! - (o) connected lines
+//! ```
+//!
+//! See the `Cargo.toml` file for Copyright and license details.
+
+#![no_std]
+#![no_main]
+
+// For string formatting.
+use core::fmt::Write;
+
+// The macro for our start-up function
+use rp_pico::entry;
+
+// Time handling traits:
+use fugit::{ExtU32, RateExtU32};
+
+// CountDown timer for the counter on the display:
+use embedded_hal::timer::CountDown;
+
+// Ensure we halt the program on panic (if we don't mention this crate it won't
+// be linked)
+use panic_halt as _;
+
+// A shorter alias for the Peripheral Access Crate, which provides low-level
+// register access
+use rp_pico::hal::pac;
+
+// A shorter alias for the Hardware Abstraction Layer, which provides
+// higher-level drivers.
+use rp_pico::hal;
+
+// For in the graphics drawing utilities like the font
+// and the drawing routines:
+use embedded_graphics::{
+ mono_font::{ascii::FONT_9X18_BOLD, MonoTextStyleBuilder},
+ pixelcolor::BinaryColor,
+ prelude::*,
+ text::{Baseline, Text},
+};
+
+// The display driver:
+use ssd1306::{prelude::*, Ssd1306};
+
+/// Entry point to our bare-metal application.
+///
+/// The `#[entry]` macro ensures the Cortex-M start-up code calls this function
+/// as soon as all global variables are initialised.
+///
+/// The function configures the RP2040 peripherals,
+/// gets a handle on the I2C peripheral,
+/// initializes the SSD1306 driver, initializes the text builder
+/// and then draws some text on the display.
+#[entry]
+fn main() -> ! {
+ // Grab our singleton objects
+ let mut pac = pac::Peripherals::take().unwrap();
+
+ // Set up the watchdog driver - needed by the clock setup code
+ let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);
+
+ // Configure the clocks
+ //
+ // The default is to generate a 125 MHz system clock
+ let clocks = hal::clocks::init_clocks_and_plls(
+ rp_pico::XOSC_CRYSTAL_FREQ,
+ pac.XOSC,
+ pac.CLOCKS,
+ pac.PLL_SYS,
+ pac.PLL_USB,
+ &mut pac.RESETS,
+ &mut watchdog,
+ )
+ .ok()
+ .unwrap();
+
+ // The single-cycle I/O block controls our GPIO pins
+ let sio = hal::Sio::new(pac.SIO);
+
+ // Set the pins up according to their function on this particular board
+ let pins = rp_pico::Pins::new(
+ pac.IO_BANK0,
+ pac.PADS_BANK0,
+ sio.gpio_bank0,
+ &mut pac.RESETS,
+ );
+
+ // Configure two pins as being I²C, not GPIO
+ let sda_pin = pins.gpio16.into_mode::<hal::gpio::FunctionI2C>();
+ let scl_pin = pins.gpio17.into_mode::<hal::gpio::FunctionI2C>();
+
+ // Create the I²C driver, using the two pre-configured pins. This will fail
+ // at compile time if the pins are in the wrong mode, or if this I²C
+ // peripheral isn't available on these pins!
+ let i2c = hal::I2C::i2c0(
+ pac.I2C0,
+ sda_pin,
+ scl_pin,
+ 400.kHz(),
+ &mut pac.RESETS,
+ &clocks.peripheral_clock,
+ );
+
+ // Create the I²C display interface:
+ let interface = ssd1306::I2CDisplayInterface::new(i2c);
+
+ // Create a driver instance and initialize:
+ let mut display = Ssd1306::new(interface, DisplaySize128x64, DisplayRotation::Rotate0)
+ .into_buffered_graphics_mode();
+ display.init().unwrap();
+
+ // Create a text style for drawing the font:
+ let text_style = MonoTextStyleBuilder::new()
+ .font(&FONT_9X18_BOLD)
+ .text_color(BinaryColor::On)
+ .build();
+
+ let timer = hal::Timer::new(pac.TIMER, &mut pac.RESETS);
+ let mut delay = timer.count_down();
+
+ let mut count = 0;
+
+ let mut buf = FmtBuf::new();
+ loop {
+ buf.reset();
+ // Format some text into a static buffer:
+ write!(&mut buf, "counter: {}", count).unwrap();
+ count += 1;
+
+ // Empty the display:
+ display.clear();
+
+ // Draw 3 lines of text:
+ Text::with_baseline("Hello world!", Point::zero(), text_style, Baseline::Top)
+ .draw(&mut display)
+ .unwrap();
+
+ Text::with_baseline("Hello Rust!", Point::new(0, 16), text_style, Baseline::Top)
+ .draw(&mut display)
+ .unwrap();
+
+ Text::with_baseline(buf.as_str(), Point::new(0, 32), text_style, Baseline::Top)
+ .draw(&mut display)
+ .unwrap();
+
+ display.flush().unwrap();
+
+ // Wait a bit:
+ delay.start(500.millis());
+ let _ = nb::block!(delay.wait());
+ }
+}
+
+/// This is a very simple buffer to pre format a short line of text
+/// limited arbitrarily to 64 bytes.
+struct FmtBuf {
+ buf: [u8; 64],
+ ptr: usize,
+}
+
+impl FmtBuf {
+ fn new() -> Self {
+ Self {
+ buf: [0; 64],
+ ptr: 0,
+ }
+ }
+
+ fn reset(&mut self) {
+ self.ptr = 0;
+ }
+
+ fn as_str(&self) -> &str {
+ core::str::from_utf8(&self.buf[0..self.ptr]).unwrap()
+ }
+}
+
+impl core::fmt::Write for FmtBuf {
+ fn write_str(&mut self, s: &str) -> core::fmt::Result {
+ let rest_len = self.buf.len() - self.ptr;
+ let len = if rest_len < s.len() {
+ rest_len
+ } else {
+ s.len()
+ };
+ self.buf[self.ptr..(self.ptr + len)].copy_from_slice(&s.as_bytes()[0..len]);
+ self.ptr += len;
+ Ok(())
+ }
+}
+
+// End of file
+//! # Pico I2C PIO Example
+//!
+//! Reads the temperature from an LM75B
+//!
+//! This read over I2C the temerature from an LM75B temperature sensor wired on pins 20 and 21
+//! using the PIO peripheral as an I2C bus controller.
+//! The pins used for the I2C can be remapped to any other pin available to the PIO0 peripheral.
+//!
+//! See the `Cargo.toml` file for Copyright and license details.
+
+#![no_std]
+#![no_main]
+
+// The trait used by formatting macros like write! and writeln!
+use core::fmt::Write as FmtWrite;
+
+// The macro for our start-up function
+use rp_pico::entry;
+
+// I2C HAL traits & Types.
+use embedded_hal::blocking::i2c::{Operation, Read, Transactional, Write};
+
+// Time handling traits
+use fugit::RateExtU32;
+
+// Ensure we halt the program on panic (if we don't mention this crate it won't
+// be linked)
+use panic_halt as _;
+
+// Pull in any important traits
+use rp_pico::hal::prelude::*;
+
+// A shorter alias for the Peripheral Access Crate, which provides low-level
+// register access
+use rp_pico::hal::pac;
+
+// A shorter alias for the Hardware Abstraction Layer, which provides
+// higher-level drivers.
+use rp_pico::hal;
+
+// UART related types
+use hal::uart::{DataBits, StopBits, UartConfig};
+
+/// Prints the temperature received from the sensor
+fn print_temperature(serial: &mut impl FmtWrite, temp: [u8; 2]) {
+ let temp_i16 = i16::from_be_bytes(temp) >> 5;
+ let temp_f32 = f32::from(temp_i16) * 0.125;
+
+ // Write formatted output but ignore any error.
+ let _ = writeln!(serial, "Temperature: {:0.2}°C", temp_f32);
+}
+
+/// Entry point to our bare-metal application.
+///
+/// The `#[entry]` macro ensures the Cortex-M start-up code calls this function
+/// as soon as all global variables are initialised.
+///
+/// The function configures the RP2040 peripherals, reads the temperature from
+/// the attached LM75B using PIO0.
+#[entry]
+fn main() -> ! {
+ // Grab our singleton objects
+ let mut pac = pac::Peripherals::take().unwrap();
+
+ // Set up the watchdog driver - needed by the clock setup code
+ let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);
+
+ // Configure the clocks
+ //
+ // The default is to generate a 125 MHz system clock
+ let clocks = hal::clocks::init_clocks_and_plls(
+ rp_pico::XOSC_CRYSTAL_FREQ,
+ pac.XOSC,
+ pac.CLOCKS,
+ pac.PLL_SYS,
+ pac.PLL_USB,
+ &mut pac.RESETS,
+ &mut watchdog,
+ )
+ .ok()
+ .unwrap();
+
+ // The single-cycle I/O block controls our GPIO pins
+ let sio = hal::Sio::new(pac.SIO);
+
+ // Set the pins up according to their function on this particular board
+ let pins = rp_pico::Pins::new(
+ pac.IO_BANK0,
+ pac.PADS_BANK0,
+ sio.gpio_bank0,
+ &mut pac.RESETS,
+ );
+
+ let uart_pins = (
+ // UART TX (characters sent from RP2040) on pin 1 (GPIO0)
+ pins.gpio0.into_mode::<hal::gpio::FunctionUart>(),
+ // UART RX (characters received by RP2040) on pin 2 (GPIO1)
+ pins.gpio1.into_mode::<hal::gpio::FunctionUart>(),
+ );
+
+ let mut uart = hal::uart::UartPeripheral::new(pac.UART0, uart_pins, &mut pac.RESETS)
+ .enable(
+ UartConfig::new(115_200.Hz(), DataBits::Eight, None, StopBits::One),
+ clocks.peripheral_clock.freq(),
+ )
+ .unwrap();
+
+ let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS);
+
+ let mut i2c_pio = i2c_pio::I2C::new(
+ &mut pio,
+ pins.gpio20,
+ pins.gpio21,
+ sm0,
+ 100.kHz(),
+ clocks.system_clock.freq(),
+ );
+
+ let mut temp = [0; 2];
+ i2c_pio
+ .read(0x48u8, &mut temp)
+ .expect("Failed to read from the peripheral");
+ print_temperature(&mut uart, temp);
+
+ i2c_pio
+ .write(0x48u8, &[0])
+ .expect("Failed to write to the peripheral");
+
+ let mut temp = [0; 2];
+ i2c_pio
+ .read(0x48u8, &mut temp)
+ .expect("Failed to read from the peripheral");
+ print_temperature(&mut uart, temp);
+
+ let mut config = [0];
+ let mut thyst = [0; 2];
+ let mut tos = [0; 2];
+ let mut temp = [0; 2];
+ let mut operations = [
+ Operation::Write(&[1]),
+ Operation::Read(&mut config),
+ Operation::Write(&[2]),
+ Operation::Read(&mut thyst),
+ Operation::Write(&[3]),
+ Operation::Read(&mut tos),
+ Operation::Write(&[0]),
+ Operation::Read(&mut temp),
+ ];
+ i2c_pio
+ .exec(0x48u8, &mut operations)
+ .expect("Failed to run all operations");
+ print_temperature(&mut uart, temp);
+
+ loop {
+ cortex_m::asm::wfi();
+ }
+}
+
+// End of file
+//! # Pico Interpolator Example
+//!
+//! Example demonstrating the usage of the hardware interpolator.
+//!
+//! Runs several test programs, outputs the result on LEDs.
+//! Green led for successful test connects to GPIO3.
+//! Red led for unsuccessful test connects to GPIO4.
+//! In case of failure, the system LED blinks the number of the test.
+//! In case of success, the system LED stays lit.
+//!
+//! See the `Cargo.toml` file for Copyright and license details.
+
+#![no_std]
+#![no_main]
+
+// The macro for our start-up function
+use rp_pico::entry;
+
+// GPIO traits
+use embedded_hal::digital::v2::OutputPin;
+
+// Ensure we halt the program on panic (if we don't mention this crate it won't
+// be linked)
+use panic_halt as _;
+
+// A shorter alias for the Peripheral Access Crate, which provides low-level
+// register access
+use rp_pico::hal::pac;
+
+// A shorter alias for the Hardware Abstraction Layer, which provides
+// higher-level drivers.
+use rp_pico::hal;
+
+// Pull in any important traits
+use rp_pico::hal::prelude::*;
+
+use rp_pico::hal::sio::{Interp, Interp0, Interp1, Lane, LaneCtrl};
+
+/// Entry point to our bare-metal application.
+///
+/// The `#[entry]` macro ensures the Cortex-M start-up code calls this function
+/// as soon as all global variables are initialised.
+///
+/// The function configures the RP2040 peripherals, then just reads the button
+/// and sets the LED appropriately.
+#[entry]
+fn main() -> ! {
+ // Grab our singleton objects
+ let mut pac = pac::Peripherals::take().unwrap();
+ let core = pac::CorePeripherals::take().unwrap();
+
+ // Set up the watchdog driver - needed by the clock setup code
+ let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);
+
+ // Configure the clocks
+ //
+ // The default is to generate a 125 MHz system clock
+ let clocks = hal::clocks::init_clocks_and_plls(
+ rp_pico::XOSC_CRYSTAL_FREQ,
+ pac.XOSC,
+ pac.CLOCKS,
+ pac.PLL_SYS,
+ pac.PLL_USB,
+ &mut pac.RESETS,
+ &mut watchdog,
+ )
+ .ok()
+ .unwrap();
+
+ // The delay object lets us wait for specified amounts of time (in
+ // milliseconds)
+ let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz());
+
+ // The single-cycle I/O block controls our GPIO pins
+ let mut sio = hal::Sio::new(pac.SIO);
+
+ // Set the pins up according to their function on this particular board
+ let pins = rp_pico::Pins::new(
+ pac.IO_BANK0,
+ pac.PADS_BANK0,
+ sio.gpio_bank0,
+ &mut pac.RESETS,
+ );
+
+ // Our LED outputs
+ let mut system_led_pin = pins.led.into_push_pull_output();
+ let mut green_led_pin = pins.gpio3.into_push_pull_output();
+ let mut red_led_pin = pins.gpio4.into_push_pull_output();
+
+ system_led_pin.set_low().unwrap();
+ green_led_pin.set_low().unwrap();
+ red_led_pin.set_low().unwrap();
+
+ let mut choose_led = |index: u32, result: bool| {
+ if result {
+ // blink the green led once to indicate success
+ green_led_pin.set_high().unwrap();
+ delay.delay_ms(500);
+ green_led_pin.set_low().unwrap();
+ delay.delay_ms(500);
+ } else {
+ // turn the red led on to indicate failure
+ // and blink the on board led to indicate which test failed, looping forever
+ red_led_pin.set_high().unwrap();
+ loop {
+ for _ in 0..index {
+ system_led_pin.set_high().unwrap();
+ delay.delay_ms(200);
+ system_led_pin.set_low().unwrap();
+ delay.delay_ms(200);
+ }
+ delay.delay_ms(1000);
+ }
+ }
+ };
+
+ // Run forever, setting the LED according to the button
+
+ choose_led(1, multiplication_table(&mut sio.interp0));
+ choose_led(2, moving_mask(&mut sio.interp0));
+ choose_led(3, cross_lanes(&mut sio.interp0));
+ choose_led(4, simple_blend1(&mut sio.interp0));
+ choose_led(5, simple_blend2(&mut sio.interp0));
+ choose_led(6, clamp(&mut sio.interp1));
+ choose_led(7, texture_mapping(&mut sio.interp0));
+
+ // turn the on board led on to indicate testing is done
+ system_led_pin.set_high().unwrap();
+ loop {
+ delay.delay_ms(1000);
+ }
+}
+
+fn multiplication_table(interp: &mut Interp0) -> bool {
+ //get the default configuration that just keep adding base into accum
+ let config = LaneCtrl::new();
+
+ //write the configuration to the hardware.
+ interp.get_lane0().set_ctrl(config.encode());
+
+ //set the accumulator to 0 and the base to 9
+ interp.get_lane0().set_accum(0);
+ interp.get_lane0().set_base(9);
+
+ //the expected output for comparison
+ let expected = [9, 18, 27, 36, 45, 54, 63, 72, 81, 90];
+
+ for i in expected {
+ //returns the value of accum + base and sets accum to the same value
+ let value = interp.get_lane0().pop();
+
+ if value != i {
+ return false; //inform that the interpolator did not return the expected value
+ }
+ }
+ true
+}
+
+fn moving_mask(interp: &mut Interp0) -> bool {
+ //get the default configuration that just keep adding base into accum
+ let mut config = LaneCtrl::new();
+
+ interp.get_lane0().set_accum(0x1234ABCD);
+
+ let expected = [
+ 0x0000_000D,
+ 0x0000_00C0,
+ 0x0000_0B00,
+ 0x0000_A000,
+ 0x0004_0000,
+ 0x0030_0000,
+ 0x0200_0000,
+ 0x1000_0000,
+ ];
+ for i in 0..8 {
+ // LSB, then MSB. These are inclusive, so 0,31 means "the entire 32 bit register"
+ config.mask_lsb = i * 4;
+ config.mask_msb = i * 4 + 3;
+ interp.get_lane0().set_ctrl(config.encode());
+
+ // Reading read_raw() returns the lane data
+ // after shifting, masking and sign extending, without adding base
+ if interp.get_lane0().read_raw() != expected[i as usize] {
+ return false;
+ }
+ }
+
+ let signed_expected = [
+ 0xFFFF_FFFD,
+ 0xFFFF_FFC0,
+ 0xFFFF_FB00,
+ 0xFFFF_A000,
+ 0x0004_0000,
+ 0x0030_0000,
+ 0x0200_0000,
+ 0x1000_0000,
+ ];
+
+ config.signed = true;
+ for i in 0..8 {
+ config.mask_lsb = i * 4;
+ config.mask_msb = i * 4 + 3;
+ interp.get_lane0().set_ctrl(config.encode());
+
+ if interp.get_lane0().read_raw() != signed_expected[i as usize] {
+ return false;
+ }
+ }
+ true
+}
+
+fn cross_lanes(interp: &mut Interp0) -> bool {
+ // this configuration will at the time of pop()
+ // when applied to lane0 : set lane0 accumulator to the result from lane1
+ // when applied to lane1 : set lane1 accumulator to the result from lane0
+ let config = LaneCtrl {
+ cross_result: true,
+ ..LaneCtrl::new()
+ };
+ let encoded_config = config.encode();
+
+ // each lane is used through an accessor,
+ // as lanes mutate each other, they can not be borrowed at the same time
+ interp.get_lane0().set_ctrl(encoded_config);
+ interp.get_lane1().set_ctrl(encoded_config);
+
+ interp.get_lane0().set_accum(123);
+ interp.get_lane1().set_accum(456);
+
+ // lane0 will add 1 to its result, lane1 will add nothing
+ interp.get_lane0().set_base(1);
+ interp.get_lane1().set_base(0);
+
+ let expected = [
+ (124, 456),
+ (457, 124),
+ (125, 457),
+ (458, 125),
+ (126, 458),
+ (459, 126),
+ (127, 459),
+ (460, 127),
+ (128, 460),
+ (461, 128),
+ ];
+
+ for i in expected {
+ if i != (interp.get_lane0().peek(), interp.get_lane1().pop()) {
+ return false;
+ }
+ }
+ true
+}
+
+fn simple_blend1(interp: &mut Interp0) -> bool {
+ let config = LaneCtrl {
+ blend: true,
+ ..LaneCtrl::new()
+ };
+
+ //enable blend mode
+ interp.get_lane0().set_ctrl(config.encode());
+ //make sure the default configuration is in lane1 as the value may be shifted and masked.
+ interp.get_lane1().set_ctrl(LaneCtrl::new().encode());
+
+ //set the minimum value for interp.get_lane0().set_accum(0) 0/256
+ interp.get_lane0().set_base(500);
+ //set the maximum value which is inaccessible
+ // as the blend is done between 0/256 and 255/256
+ interp.get_lane1().set_base(1000);
+
+ let expected = [500, 582, 666, 748, 832, 914, 998];
+ for i in 0..=6 {
+ interp.get_lane1().set_accum(255 * i / 6);
+ if expected[i as usize] != interp.get_lane1().peek() {
+ return false;
+ }
+ }
+ true
+}
+
+fn simple_blend2(interp: &mut Interp0) -> bool {
+ let config = LaneCtrl {
+ blend: true,
+ ..LaneCtrl::new()
+ };
+ //enable blend mode
+ interp.get_lane0().set_ctrl(config.encode());
+
+ interp.get_lane0().set_base((-1000i32) as u32);
+ interp.get_lane1().set_base(1000);
+
+ let mut config1 = LaneCtrl {
+ signed: true,
+ ..LaneCtrl::new()
+ };
+ interp.get_lane1().set_ctrl(config1.encode());
+ let expected_signed = [-1000, -672, -336, -8, 328, 656, 992];
+ for i in 0..=6 {
+ // write a value between 0 and 256 (exclusive)
+ interp.get_lane1().set_accum(255 * i / 6);
+ // reads it as a value between -1000 and 1000 (exclusive)
+ if interp.get_lane1().peek() as i32 != expected_signed[i as usize] {
+ return false;
+ }
+ }
+ config1.signed = false;
+ interp.get_lane1().set_ctrl(config1.encode());
+ let expected_unsigned = [
+ 0xfffffc18, 0xd5fffd60, 0xaafffeb0, 0x80fffff8, 0x56000148, 0x2c000290, 0x010003e0,
+ ];
+ for i in 0..=6 {
+ interp.get_lane1().set_accum(255 * i / 6);
+ // reads a value between 4294966296 and 1000
+ if interp.get_lane1().peek() != expected_unsigned[i as usize] {
+ return false;
+ }
+ }
+ true
+}
+
+///Divides by 4 and clamp the value between 0 and 255 inclusive
+fn clamp(interp: &mut Interp1) -> bool {
+ // Enables Clamp ONLY AVAILABLE ON Interp1
+ // shift two bits to the right and mask the two most significant bits
+ // because sign extension is made after the mask
+ let config = LaneCtrl {
+ clamp: true,
+ shift: 2,
+ mask_lsb: 0,
+ mask_msb: 29,
+ signed: true,
+ ..LaneCtrl::new()
+ };
+ interp.get_lane0().set_ctrl(config.encode());
+ //set minimum value of result
+ interp.get_lane0().set_base(0);
+ //set maximum value of result
+ interp.get_lane1().set_base(255);
+ let values: [(i32, i32); 9] = [
+ (-1024, 0),
+ (-768, 0),
+ (-512, 0),
+ (-256, 0),
+ (0, 0),
+ (256, 64),
+ (512, 128),
+ (768, 192),
+ (1024, 255),
+ ];
+ for (arg, result) in values {
+ interp.get_lane0().set_accum(arg as u32);
+ if result != interp.get_lane0().peek() as i32 {
+ return false;
+ }
+ }
+ true
+}
+
+fn texture_mapping(interp: &mut Interp0) -> bool {
+ #[rustfmt::skip]
+ let texture: [u8;16] = [
+ 0x00, 0x01, 0x02, 0x03,
+ 0x10, 0x11, 0x12, 0x13,
+ 0x20, 0x21, 0x22, 0x23,
+ 0x30, 0x31, 0x32, 0x33,
+ ];
+
+ // the position will be given in fixed point with 16 bits
+ // fractional part
+ let uv_fractional_bits = 16;
+ let texture_width_bits = 2;
+ let texture_height_bits = 2;
+
+ // bits
+ // 3322222222221111 1111110000000000
+ // 1098765432109876 5432109876543210
+ // accum0 u axis coordinate xx xxxxxxxxxxxxxxxx 18 bits
+ // after shift and mask xx
+ // accum1 v axis xx xxxxxxxxxxxxxxxx 18 bits
+ // after shift and mask xx
+
+ // add_raw make the interpolator increment the accumulator
+ // with the base value without masking or shifting
+ let config0 = LaneCtrl {
+ add_raw: true,
+ shift: uv_fractional_bits,
+ mask_lsb: 0,
+ mask_msb: texture_width_bits - 1,
+ ..LaneCtrl::new()
+ };
+ interp.get_lane0().set_ctrl(config0.encode());
+ let config1 = LaneCtrl {
+ add_raw: true,
+ shift: uv_fractional_bits - texture_width_bits,
+ mask_lsb: texture_width_bits,
+ mask_msb: texture_width_bits + texture_height_bits - 1,
+ ..LaneCtrl::new()
+ };
+ interp.get_lane1().set_ctrl(config1.encode());
+
+ interp.set_base(0);
+
+ // set starting position to 0x0
+ // will move 1/2 a pixel horizontally
+ // and 1/3 a pixel vertically per call to pop()
+ interp.get_lane0().set_accum(0);
+ interp.get_lane0().set_base(65536 / 2);
+ interp.get_lane1().set_accum(0);
+ interp.get_lane1().set_base(65536 / 3);
+
+ let expected = [
+ 0x00, 0x00, 0x01, 0x01, 0x12, 0x12, 0x13, 0x23, 0x20, 0x20, 0x31, 0x31,
+ ];
+
+ for i in expected {
+ if i != texture[interp.pop() as usize] {
+ return false;
+ }
+ }
+
+ // reset the starting position
+ interp.get_lane0().set_accum(0);
+ interp.get_lane1().set_accum(0);
+ interp.set_base(texture.as_ptr() as u32);
+
+ for i in expected {
+ // This is unsafe and should be done extremely carefully
+ // remember to follow memory alignment,
+ // reading or writing an unaligned address will crash
+ if i != unsafe { *(interp.pop() as *const u8) } {
+ return false;
+ }
+ }
+
+ true
+}
+// End of file
+//! # Pico PIO PWM Blink Example
+//!
+//! Fades the LED on a Pico board using the PIO peripheral with an pwm program.
+//!
+//! This will fade in the LED attached to GP25, which is the pin the Pico
+//! uses for the on-board LED.
+//!
+//! This example uses a few advance pio tricks such as side setting pins and instruction injection.
+//!
+//! See the `Cargo.toml` file for Copyright and license details. Except for the pio program which is subject to a different license.
+
+#![no_std]
+#![no_main]
+
+use defmt::info;
+use defmt_rtt as _;
+// The macro for our start-up function
+use rp_pico::entry;
+
+// Ensure we halt the program on panic (if we don't mention this crate it won't
+// be linked)
+use panic_halt as _;
+
+// Pull in any important traits
+use rp_pico::hal::prelude::*;
+
+// A shorter alias for the Peripheral Access Crate, which provides low-level
+// register access
+use rp_pico::hal::pac;
+
+// A shorter alias for the Hardware Abstraction Layer, which provides
+// higher-level drivers.
+use rp_pico::hal;
+
+// Import pio crates
+use hal::pio::{PIOBuilder, Running, StateMachine, Tx, ValidStateMachine, SM0};
+use pio::{Instruction, InstructionOperands, OutDestination};
+use pio_proc::pio_file;
+
+/// Set pio pwm period
+///
+/// This uses a sneaky trick to set a second value besides the duty cycle.
+/// We first write a value to the tx fifo. But instead of the normal instructions we
+/// have stopped the state machine and inject our own instructions that move the written value to the ISR.
+fn pio_pwm_set_period<T: ValidStateMachine>(
+ sm: StateMachine<(hal::pac::PIO0, SM0), Running>,
+ tx: &mut Tx<T>,
+ period: u32,
+) -> StateMachine<(hal::pac::PIO0, SM0), Running> {
+ // To make sure the inserted instructions actually use our newly written value
+ // We first busy loop to empty the queue. (Which typically should be the case)
+ while !tx.is_empty() {}
+
+ let mut sm = sm.stop();
+ tx.write(period);
+ sm.exec_instruction(Instruction {
+ operands: InstructionOperands::PULL {
+ if_empty: false,
+ block: false,
+ },
+ delay: 0,
+ side_set: None,
+ });
+ sm.exec_instruction(Instruction {
+ operands: InstructionOperands::OUT {
+ destination: OutDestination::ISR,
+ bit_count: 32,
+ },
+ delay: 0,
+ side_set: None,
+ });
+ sm.start()
+}
+
+/// Set pio pwm duty cycle
+///
+/// The value written to the TX FIFO is used directly by the normal pio program
+fn pio_pwm_set_level<T: ValidStateMachine>(tx: &mut Tx<T>, level: u32) {
+ // Write duty cycle to TX Fifo
+ tx.write(level);
+}
+
+/// Entry point to our bare-metal application.
+///
+/// The `#[entry]` macro ensures the Cortex-M start-up code calls this function
+/// as soon as all global variables are initialised.
+///
+/// The function configures the RP2040 peripherals, then fades the LED in an
+/// infinite loop.
+#[entry]
+fn main() -> ! {
+ // Grab our singleton objects
+ let mut pac = pac::Peripherals::take().unwrap();
+ let core = pac::CorePeripherals::take().unwrap();
+
+ // Set up the watchdog driver - needed by the clock setup code
+ let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);
+
+ // Configure the clocks
+ //
+ // The default is to generate a 125 MHz system clock
+ let clocks = hal::clocks::init_clocks_and_plls(
+ rp_pico::XOSC_CRYSTAL_FREQ,
+ pac.XOSC,
+ pac.CLOCKS,
+ pac.PLL_SYS,
+ pac.PLL_USB,
+ &mut pac.RESETS,
+ &mut watchdog,
+ )
+ .ok()
+ .unwrap();
+
+ // The single-cycle I/O block controls our GPIO pins
+ let sio = hal::Sio::new(pac.SIO);
+
+ // Set the pins up according to their function on this particular board
+ let pins = rp_pico::Pins::new(
+ pac.IO_BANK0,
+ pac.PADS_BANK0,
+ sio.gpio_bank0,
+ &mut pac.RESETS,
+ );
+
+ // The delay object lets us wait for specified amounts of time (in
+ // milliseconds)
+ let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz());
+
+ let (mut pio0, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS);
+
+ // Create a pio program
+ let program = pio_file!("./examples/pwm.pio", select_program("pwm"),);
+ let installed = pio0.install(&program.program).unwrap();
+
+ // Set gpio25 to pio
+ let _led: hal::gpio::Pin<_, hal::gpio::FunctionPio0> = pins.led.into_mode();
+ let led_pin_id = 25;
+
+ // Build the pio program and set pin both for set and side set!
+ // We are running with the default divider which is 1 (max speed)
+ let (mut sm, _, mut tx) = PIOBuilder::from_program(installed)
+ .set_pins(led_pin_id, 1)
+ .side_set_pin_base(led_pin_id)
+ .build(sm0);
+
+ // Set pio pindir for gpio25
+ sm.set_pindirs([(led_pin_id, hal::pio::PinDir::Output)]);
+
+ // Start state machine
+ let sm = sm.start();
+
+ // Set period
+ pio_pwm_set_period(sm, &mut tx, u16::MAX as u32 - 1);
+
+ // Loop forever and adjust duty cycle to make te led brighter
+ let mut level = 0;
+ loop {
+ info!("Level = {}", level);
+ pio_pwm_set_level(&mut tx, level * level);
+ level = (level + 1) % 256;
+ delay.delay_ms(10);
+ }
+}
+
+// End of file
+//! # Pico PWM Blink Example
+//!
+//! Fades the LED on a Pico board using the PWM peripheral.
+//!
+//! This will fade in/out the LED attached to GP25, which is the pin the Pico
+//! uses for the on-board LED.
+//!
+//! See the `Cargo.toml` file for Copyright and license details.
+
+#![no_std]
+#![no_main]
+
+// The macro for our start-up function
+use rp_pico::entry;
+
+// GPIO traits
+use embedded_hal::PwmPin;
+
+// Ensure we halt the program on panic (if we don't mention this crate it won't
+// be linked)
+use panic_halt as _;
+
+// Pull in any important traits
+use rp_pico::hal::prelude::*;
+
+// A shorter alias for the Peripheral Access Crate, which provides low-level
+// register access
+use rp_pico::hal::pac;
+
+// A shorter alias for the Hardware Abstraction Layer, which provides
+// higher-level drivers.
+use rp_pico::hal;
+
+// The minimum PWM value (i.e. LED brightness) we want
+const LOW: u16 = 0;
+
+// The maximum PWM value (i.e. LED brightness) we want
+const HIGH: u16 = 25000;
+
+/// Entry point to our bare-metal application.
+///
+/// The `#[entry]` macro ensures the Cortex-M start-up code calls this function
+/// as soon as all global variables are initialised.
+///
+/// The function configures the RP2040 peripherals, then fades the LED in an
+/// infinite loop.
+#[entry]
+fn main() -> ! {
+ // Grab our singleton objects
+ let mut pac = pac::Peripherals::take().unwrap();
+ let core = pac::CorePeripherals::take().unwrap();
+
+ // Set up the watchdog driver - needed by the clock setup code
+ let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);
+
+ // Configure the clocks
+ //
+ // The default is to generate a 125 MHz system clock
+ let clocks = hal::clocks::init_clocks_and_plls(
+ rp_pico::XOSC_CRYSTAL_FREQ,
+ pac.XOSC,
+ pac.CLOCKS,
+ pac.PLL_SYS,
+ pac.PLL_USB,
+ &mut pac.RESETS,
+ &mut watchdog,
+ )
+ .ok()
+ .unwrap();
+
+ // The single-cycle I/O block controls our GPIO pins
+ let sio = hal::Sio::new(pac.SIO);
+
+ // Set the pins up according to their function on this particular board
+ let pins = rp_pico::Pins::new(
+ pac.IO_BANK0,
+ pac.PADS_BANK0,
+ sio.gpio_bank0,
+ &mut pac.RESETS,
+ );
+
+ // The delay object lets us wait for specified amounts of time (in
+ // milliseconds)
+ let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz());
+
+ // Init PWMs
+ let mut pwm_slices = hal::pwm::Slices::new(pac.PWM, &mut pac.RESETS);
+
+ // Configure PWM4
+ let pwm = &mut pwm_slices.pwm4;
+ pwm.set_ph_correct();
+ pwm.enable();
+
+ // Output channel B on PWM4 to the LED pin
+ let channel = &mut pwm.channel_b;
+ channel.output_to(pins.led);
+
+ // Infinite loop, fading LED up and down
+ loop {
+ // Ramp brightness up
+ for i in (LOW..=HIGH).skip(100) {
+ delay.delay_us(8);
+ channel.set_duty(i);
+ }
+
+ // Ramp brightness down
+ for i in (LOW..=HIGH).rev().skip(100) {
+ delay.delay_us(8);
+ channel.set_duty(i);
+ }
+
+ delay.delay_ms(500);
+ }
+}
+
+// End of file
+//! # Pico PWM Micro Servo Example
+//!
+//! Moves the micro servo on a Pico board using the PWM peripheral.
+//!
+//! This will move in different positions the motor attached to GP1.
+//!
+//! See the `Cargo.toml` file for Copyright and license details.
+
+#![no_std]
+#![no_main]
+
+use cortex_m::prelude::*;
+
+// GPIO traits
+use embedded_hal::PwmPin;
+
+// Traits for converting integers to amounts of time
+use fugit::ExtU32;
+
+// Ensure we halt the program on panic (if we don't mention this crate it won't
+// be linked)
+use panic_halt as _;
+
+// A shorter alias for the Peripheral Access Crate, which provides low-level
+// register access
+use rp_pico::hal::pac;
+
+// A shorter alias for the Hardware Abstraction Layer, which provides
+// higher-level drivers.
+use rp_pico::hal;
+
+/// Entry point to our bare-metal application.
+///
+/// The `#[rp2040_hal::entry]` macro ensures the Cortex-M start-up code calls this function
+/// as soon as all global variables and the spinlock are initialised.
+///
+/// The function configures the RP2040 peripherals, then fades the LED in an
+/// infinite loop.
+#[rp2040_hal::entry]
+fn main() -> ! {
+ // Grab our singleton objects
+ let mut pac = pac::Peripherals::take().unwrap();
+
+ // Set up the watchdog driver - needed by the clock setup code
+ let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);
+
+ // Configure the clocks
+ //
+ // The default is to generate a 125 MHz system clock
+ let _clocks = hal::clocks::init_clocks_and_plls(
+ rp_pico::XOSC_CRYSTAL_FREQ,
+ pac.XOSC,
+ pac.CLOCKS,
+ pac.PLL_SYS,
+ pac.PLL_USB,
+ &mut pac.RESETS,
+ &mut watchdog,
+ )
+ .ok()
+ .unwrap();
+
+ // Configure the Timer peripheral in count-down mode
+ let timer = hal::Timer::new(pac.TIMER, &mut pac.RESETS);
+ let mut count_down = timer.count_down();
+
+ // The single-cycle I/O block controls our GPIO pins
+ let sio = hal::Sio::new(pac.SIO);
+
+ // Set the pins up according to their function on this particular board
+ let pins = rp_pico::Pins::new(
+ pac.IO_BANK0,
+ pac.PADS_BANK0,
+ sio.gpio_bank0,
+ &mut pac.RESETS,
+ );
+
+ // Init PWMs
+ let mut pwm_slices = hal::pwm::Slices::new(pac.PWM, &mut pac.RESETS);
+
+ // Configure PWM0
+ let pwm = &mut pwm_slices.pwm0;
+ pwm.set_ph_correct();
+ pwm.set_div_int(20u8); // 50 hz
+ pwm.enable();
+
+ // Output channel B on PWM0 to the GPIO1 pin
+ let channel = &mut pwm.channel_b;
+ channel.output_to(pins.gpio1);
+
+ // Infinite loop, moving micro servo from one position to another.
+ // You may need to adjust the pulse width since several servos from
+ // different manufacturers respond differently.
+ loop {
+ // move to 0°
+ channel.set_duty(2500);
+ count_down.start(400.millis());
+ let _ = nb::block!(count_down.wait());
+
+ // 0° to 90°
+ channel.set_duty(3930);
+ count_down.start(400.millis());
+ let _ = nb::block!(count_down.wait());
+
+ // 90° to 180°
+ channel.set_duty(7860);
+ count_down.start(400.millis());
+ let _ = nb::block!(count_down.wait());
+
+ // 180° to 90°
+ channel.set_duty(3930);
+ count_down.start(400.millis());
+ let _ = nb::block!(count_down.wait());
+ }
+}
+
+// End of file
+#![no_std]
+#![no_main]
+
+use panic_halt as _;
+
+#[rtic::app(device = rp_pico::hal::pac, peripherals = true)]
+mod app {
+
+ use embedded_hal::digital::v2::OutputPin;
+ use fugit::MicrosDurationU32;
+ use rp_pico::{
+ hal::{self, clocks::init_clocks_and_plls, timer::Alarm, watchdog::Watchdog, Sio},
+ XOSC_CRYSTAL_FREQ,
+ };
+
+ const SCAN_TIME_US: MicrosDurationU32 = MicrosDurationU32::secs(1);
+
+ #[shared]
+ struct Shared {
+ timer: hal::Timer,
+ alarm: hal::timer::Alarm0,
+ led: hal::gpio::Pin<hal::gpio::pin::bank0::Gpio25, hal::gpio::PushPullOutput>,
+ }
+
+ #[local]
+ struct Local {}
+
+ #[init]
+ fn init(c: init::Context) -> (Shared, Local, init::Monotonics) {
+ // Soft-reset does not release the hardware spinlocks
+ // Release them now to avoid a deadlock after debug or watchdog reset
+ unsafe {
+ hal::sio::spinlock_reset();
+ }
+ let mut resets = c.device.RESETS;
+ let mut watchdog = Watchdog::new(c.device.WATCHDOG);
+ let _clocks = init_clocks_and_plls(
+ XOSC_CRYSTAL_FREQ,
+ c.device.XOSC,
+ c.device.CLOCKS,
+ c.device.PLL_SYS,
+ c.device.PLL_USB,
+ &mut resets,
+ &mut watchdog,
+ )
+ .ok()
+ .unwrap();
+
+ let sio = Sio::new(c.device.SIO);
+ let pins = rp_pico::Pins::new(
+ c.device.IO_BANK0,
+ c.device.PADS_BANK0,
+ sio.gpio_bank0,
+ &mut resets,
+ );
+ let mut led = pins.led.into_push_pull_output();
+ led.set_low().unwrap();
+
+ let mut timer = hal::Timer::new(c.device.TIMER, &mut resets);
+ let mut alarm = timer.alarm_0().unwrap();
+ let _ = alarm.schedule(SCAN_TIME_US);
+ alarm.enable_interrupt();
+
+ (Shared { timer, alarm, led }, Local {}, init::Monotonics())
+ }
+
+ #[task(
+ binds = TIMER_IRQ_0,
+ priority = 1,
+ shared = [timer, alarm, led],
+ local = [tog: bool = true],
+ )]
+ fn timer_irq(mut c: timer_irq::Context) {
+ if *c.local.tog {
+ c.shared.led.lock(|l| l.set_high().unwrap());
+ } else {
+ c.shared.led.lock(|l| l.set_low().unwrap());
+ }
+ *c.local.tog = !*c.local.tog;
+
+ let mut alarm = c.shared.alarm;
+ (alarm).lock(|a| {
+ a.clear_interrupt();
+ let _ = a.schedule(SCAN_TIME_US);
+ });
+ }
+}
+#![no_std]
+#![no_main]
+
+use panic_halt as _;
+
+#[rtic::app(device = rp_pico::hal::pac, peripherals = true, dispatchers = [I2C0_IRQ])]
+mod app {
+
+ use embedded_hal::digital::v2::OutputPin;
+ use fugit::ExtU64;
+ use rp_pico::{
+ hal::{
+ self,
+ clocks::init_clocks_and_plls,
+ timer::{monotonic::Monotonic, Alarm0},
+ watchdog::Watchdog,
+ Sio,
+ },
+ XOSC_CRYSTAL_FREQ,
+ };
+
+ #[shared]
+ struct Shared {
+ led: hal::gpio::Pin<hal::gpio::pin::bank0::Gpio25, hal::gpio::PushPullOutput>,
+ }
+
+ #[monotonic(binds = TIMER_IRQ_0, default = true)]
+ type MyMono = Monotonic<Alarm0>;
+
+ #[local]
+ struct Local {}
+
+ #[init]
+ fn init(c: init::Context) -> (Shared, Local, init::Monotonics) {
+ // Soft-reset does not release the hardware spinlocks
+ // Release them now to avoid a deadlock after debug or watchdog reset
+ unsafe {
+ hal::sio::spinlock_reset();
+ }
+ let mut resets = c.device.RESETS;
+ let mut watchdog = Watchdog::new(c.device.WATCHDOG);
+ let _clocks = init_clocks_and_plls(
+ XOSC_CRYSTAL_FREQ,
+ c.device.XOSC,
+ c.device.CLOCKS,
+ c.device.PLL_SYS,
+ c.device.PLL_USB,
+ &mut resets,
+ &mut watchdog,
+ )
+ .ok()
+ .unwrap();
+
+ let sio = Sio::new(c.device.SIO);
+ let pins = rp_pico::Pins::new(
+ c.device.IO_BANK0,
+ c.device.PADS_BANK0,
+ sio.gpio_bank0,
+ &mut resets,
+ );
+ let mut led = pins.led.into_push_pull_output();
+ led.set_low().unwrap();
+
+ let mut timer = hal::Timer::new(c.device.TIMER, &mut resets);
+ let alarm = timer.alarm_0().unwrap();
+ blink_led::spawn_after(500.millis()).unwrap();
+
+ (
+ Shared { led },
+ Local {},
+ init::Monotonics(Monotonic::new(timer, alarm)),
+ )
+ }
+
+ #[task(
+ shared = [led],
+ local = [tog: bool = true],
+ )]
+ fn blink_led(mut c: blink_led::Context) {
+ if *c.local.tog {
+ c.shared.led.lock(|l| l.set_high().unwrap());
+ } else {
+ c.shared.led.lock(|l| l.set_low().unwrap());
+ }
+ *c.local.tog = !*c.local.tog;
+
+ blink_led::spawn_after(500.millis()).unwrap();
+ }
+}
+//! # Pico SD Card Example
+//!
+//! Reads and writes a file from/to the SD Card that is formatted in FAT32.
+//! This example uses the SPI0 device of the Raspberry Pi Pico on the
+//! pins 4,5,6 and 7. If you don't use an external 3.3V power source,
+//! you can connect the +3.3V output on pin 36 to the SD card.
+//!
+//! SD Cards up to 2TB are supported by the `embedded_sdmmc` crate.
+//! I've tested this with a 64GB micro SD card.
+//!
+//! You need to format the card with an regular old FAT32 filesystem
+//! and also make sure the first partition has the right type. This is how your
+//! `fdisk` output should look like:
+//!
+//! ```text
+//! fdisk /dev/sdj
+//!
+//! Welcome to fdisk (util-linux 2.34).
+//! Changes will remain in memory only, until you decide to write them.
+//! Be careful before using the write command.
+//!
+//! Command (m for help): Disk /dev/sdj:
+//! 59,49 GiB, 63864569856 bytes, 124735488 sectors
+//! Disk model: SD/MMC/MS/MSPRO
+//! Units: sectors of 1 * 512 = 512 bytes
+//! Sector size (logical/physical): 512 bytes / 512 bytes
+//! I/O size (minimum/optimal): 512 bytes / 512 bytes
+//! Disklabel type: dos
+//! Disk identifier: 0x00000000
+//!
+//! Device Boot Start End Sectors Size Id Type
+//! /dev/sdj1 2048 124735487 124733440 59,5G c W95 FAT32 (LBA)
+//! ```
+//!
+//! The important bit here is the _Type_ with `W95 FAT32 (LBA)`, other types
+//! are rejected by the `embedded_sdmmc` filesystem implementation.
+//!
+//! Formatting the partition can be done using `mkfs.fat`:
+//!
+//! $ mkfs.fat /dev/sdj1
+//!
+//! In the following ASCII art the SD card is also connected to 5 strong pull up
+//! resistors. I've found varying values for these, from 50kOhm, 10kOhm
+//! down to 5kOhm.
+//! Stronger pull up resistors will eat more amperes, but also allow faster
+//! data rates.
+//!
+//! ```text
+//! +3.3V
+//! Pull Ups ->||||
+//! 4x[5kOhm]
+//! ||| \
+//! _______________ ||| \
+//! | DAT2/NC 9\---o|| \ _|USB|_
+//! | S DAT3/CS 1|---o+----+------SS--\ |1 R 40|
+//! | D CMD/DI 2|----o----+-----MOSI-+-\ |2 P 39|
+//! | VSS1 3|-- GND | | | GND-|3 38|- GND
+//! | C VDD 4|-- +3.3V | /--SCK--+-+----SPI0 SCK-|4 P 37|
+//! | A CLK/SCK 5|---------+-/ | \----SPI0 TX--|5 I 36|- +3.3V
+//! | R VSS2 6|-- GND | /--MISO-+------SPI0 RX--|6 C |
+//! | D DAT0/DO 7|---------o-/ \------SPI0 CSn-|7 O |
+//! | DAT1/IRQ 8|-[5k]- +3.3V | |
+//! """""""""""""""" | |
+//! | |
+//! .........
+//! |20 21|
+//! """""""
+//! Symbols:
+//! - (+) crossing lines, not connected
+//! - (o) connected lines
+//! ```
+//!
+//! The example can either be used with a probe to receive debug output
+//! and also the LED is used as status output. There are different blinking
+//! patterns.
+//!
+//! For every successful stage in the example the LED will blink long once.
+//! If everything is successful (9 long blink signals), the example will go
+//! into a loop and either blink in a _"short long"_ or _"short short long"_ pattern.
+//!
+//! If there are 4 different error patterns, all with short blinking pulses:
+//!
+//! - **3 short blink (in a loop)**: Card size could not be retrieved.
+//! - **4 short blink (in a loop)**: Error getting volume/partition 0.
+//! - **5 short blink (in a loop)**: Error opening root directory.
+//! - **6 short blink (in a loop)**: Could not open file 'O.TST'.
+//!
+//! See the `Cargo.toml` file for Copyright and license details.
+
+#![no_std]
+#![no_main]
+
+use core::cell::RefCell;
+
+// The macro for our start-up function
+use rp_pico::entry;
+
+// info!() and error!() macros for printing information to the debug output
+use defmt::*;
+use defmt_rtt as _;
+
+// Ensure we halt the program on panic (if we don't mention this crate it won't
+// be linked)
+use panic_halt as _;
+
+// Pull in any important traits
+use rp_pico::hal::prelude::*;
+
+// Embed the `Hz` function/trait:
+use fugit::RateExtU32;
+
+// A shorter alias for the Peripheral Access Crate, which provides low-level
+// register access
+use rp_pico::hal::pac;
+
+// Import the SPI abstraction:
+use rp_pico::hal::spi;
+
+// Import the GPIO abstraction:
+use rp_pico::hal::gpio;
+
+// A shorter alias for the Hardware Abstraction Layer, which provides
+// higher-level drivers.
+use rp_pico::hal;
+
+// Link in the embedded_sdmmc crate.
+// The `SdMmcSpi` is used for block level access to the card.
+// And the `VolumeManager` gives access to the FAT filesystem functions.
+use embedded_sdmmc::{SdCard, TimeSource, Timestamp, VolumeIdx, VolumeManager};
+
+// Get the file open mode enum:
+use embedded_sdmmc::filesystem::Mode;
+
+use embedded_hal::blocking::delay::DelayMs;
+use embedded_hal::blocking::delay::DelayUs;
+
+/// A dummy timesource, which is mostly important for creating files.
+#[derive(Default)]
+pub struct DummyTimesource();
+
+impl TimeSource for DummyTimesource {
+ // In theory you could use the RTC of the rp2040 here, if you had
+ // any external time synchronizing device.
+ fn get_timestamp(&self) -> Timestamp {
+ Timestamp {
+ year_since_1970: 0,
+ zero_indexed_month: 0,
+ zero_indexed_day: 0,
+ hours: 0,
+ minutes: 0,
+ seconds: 0,
+ }
+ }
+}
+
+// Setup some blinking codes:
+const BLINK_OK_LONG: [u8; 1] = [8u8];
+const BLINK_OK_SHORT_LONG: [u8; 4] = [1u8, 0u8, 6u8, 0u8];
+const BLINK_OK_SHORT_SHORT_LONG: [u8; 6] = [1u8, 0u8, 1u8, 0u8, 6u8, 0u8];
+const BLINK_ERR_3_SHORT: [u8; 6] = [1u8, 0u8, 1u8, 0u8, 1u8, 0u8];
+const BLINK_ERR_4_SHORT: [u8; 8] = [1u8, 0u8, 1u8, 0u8, 1u8, 0u8, 1u8, 0u8];
+const BLINK_ERR_5_SHORT: [u8; 10] = [1u8, 0u8, 1u8, 0u8, 1u8, 0u8, 1u8, 0u8, 1u8, 0u8];
+const BLINK_ERR_6_SHORT: [u8; 12] = [1u8, 0u8, 1u8, 0u8, 1u8, 0u8, 1u8, 0u8, 1u8, 0u8, 1u8, 0u8];
+
+fn blink_signals(
+ pin: &mut dyn embedded_hal::digital::v2::OutputPin<Error = core::convert::Infallible>,
+ delay: &mut dyn DelayMs<u32>,
+ sig: &[u8],
+) {
+ for bit in sig {
+ if *bit != 0 {
+ pin.set_high().unwrap();
+ } else {
+ pin.set_low().unwrap();
+ }
+
+ let length = if *bit > 0 { *bit } else { 1 };
+
+ for _ in 0..length {
+ delay.delay_ms(100);
+ }
+ }
+
+ pin.set_low().unwrap();
+
+ delay.delay_ms(500);
+}
+
+fn blink_signals_loop(
+ pin: &mut dyn embedded_hal::digital::v2::OutputPin<Error = core::convert::Infallible>,
+ delay: &mut dyn DelayMs<u32>,
+ sig: &[u8],
+) -> ! {
+ loop {
+ blink_signals(pin, delay, sig);
+ delay.delay_ms(1000);
+ }
+}
+
+#[entry]
+fn main() -> ! {
+ info!("Program start");
+
+ // Grab our singleton objects
+ let mut pac = pac::Peripherals::take().unwrap();
+ let core = pac::CorePeripherals::take().unwrap();
+
+ // Set up the watchdog driver - needed by the clock setup code
+ let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);
+
+ // Configure the clocks
+ //
+ // The default is to generate a 125 MHz system clock
+ let clocks = hal::clocks::init_clocks_and_plls(
+ rp_pico::XOSC_CRYSTAL_FREQ,
+ pac.XOSC,
+ pac.CLOCKS,
+ pac.PLL_SYS,
+ pac.PLL_USB,
+ &mut pac.RESETS,
+ &mut watchdog,
+ )
+ .ok()
+ .unwrap();
+
+ // The single-cycle I/O block controls our GPIO pins
+ let sio = hal::Sio::new(pac.SIO);
+
+ // Set the pins up according to their function on this particular board
+ let pins = rp_pico::Pins::new(
+ pac.IO_BANK0,
+ pac.PADS_BANK0,
+ sio.gpio_bank0,
+ &mut pac.RESETS,
+ );
+
+ // Set the LED to be an output
+ let mut led_pin = pins.led.into_push_pull_output();
+
+ // These are implicitly used by the spi driver if they are in the correct mode
+ let _spi_sclk = pins.gpio2.into_mode::<gpio::FunctionSpi>();
+ let _spi_mosi = pins.gpio3.into_mode::<gpio::FunctionSpi>();
+ let _spi_miso = pins.gpio4.into_mode::<gpio::FunctionSpi>();
+ let spi_cs = pins.gpio5.into_push_pull_output();
+
+ // Create an SPI driver instance for the SPI0 device
+ let spi = spi::Spi::<_, _, 8>::new(pac.SPI0);
+
+ // Exchange the uninitialised SPI driver for an initialised one
+ let spi = spi.init(
+ &mut pac.RESETS,
+ clocks.peripheral_clock.freq(),
+ 400.kHz(), // card initialization happens at low baud rate
+ &embedded_hal::spi::MODE_0,
+ );
+
+ // We need a delay implementation that can be passed to SdCard and still be used
+ // for the blink signals.
+ let mut delay = &SharedDelay::new(cortex_m::delay::Delay::new(
+ core.SYST,
+ clocks.system_clock.freq().to_Hz(),
+ ));
+
+ info!("Initialize SPI SD/MMC data structures...");
+ let sdcard = SdCard::new(spi, spi_cs, delay);
+ let mut volume_mgr = VolumeManager::new(sdcard, DummyTimesource::default());
+
+ blink_signals(&mut led_pin, &mut delay, &BLINK_OK_LONG);
+
+ info!("Init SD card controller and retrieve card size...");
+ match volume_mgr.device().num_bytes() {
+ Ok(size) => info!("card size is {} bytes", size),
+ Err(e) => {
+ error!("Error retrieving card size: {}", defmt::Debug2Format(&e));
+ blink_signals_loop(&mut led_pin, &mut delay, &BLINK_ERR_3_SHORT);
+ }
+ }
+
+ blink_signals(&mut led_pin, &mut delay, &BLINK_OK_LONG);
+
+ // Now that the card is initialized, clock can go faster
+ volume_mgr
+ .device()
+ .spi(|spi| spi.set_baudrate(clocks.peripheral_clock.freq(), 16.MHz()));
+
+ info!("Getting Volume 0...");
+ let mut volume = match volume_mgr.get_volume(VolumeIdx(0)) {
+ Ok(v) => v,
+ Err(e) => {
+ error!("Error getting volume 0: {}", defmt::Debug2Format(&e));
+ blink_signals_loop(&mut led_pin, &mut delay, &BLINK_ERR_4_SHORT);
+ }
+ };
+
+ blink_signals(&mut led_pin, &mut delay, &BLINK_OK_LONG);
+
+ // After we have the volume (partition) of the drive we got to open the
+ // root directory:
+ let dir = match volume_mgr.open_root_dir(&volume) {
+ Ok(dir) => dir,
+ Err(e) => {
+ error!("Error opening root dir: {}", defmt::Debug2Format(&e));
+ blink_signals_loop(&mut led_pin, &mut delay, &BLINK_ERR_5_SHORT);
+ }
+ };
+
+ info!("Root directory opened!");
+ blink_signals(&mut led_pin, &mut delay, &BLINK_OK_LONG);
+
+ // This shows how to iterate through the directory and how
+ // to get the file names (and print them in hope they are UTF-8 compatible):
+ volume_mgr
+ .iterate_dir(&volume, &dir, |ent| {
+ info!(
+ "/{}.{}",
+ core::str::from_utf8(ent.name.base_name()).unwrap(),
+ core::str::from_utf8(ent.name.extension()).unwrap()
+ );
+ })
+ .unwrap();
+
+ blink_signals(&mut led_pin, &mut delay, &BLINK_OK_LONG);
+
+ let mut successful_read = false;
+
+ // Next we going to read a file from the SD card:
+ if let Ok(mut file) = volume_mgr.open_file_in_dir(&mut volume, &dir, "O.TST", Mode::ReadOnly) {
+ let mut buf = [0u8; 32];
+ let read_count = volume_mgr.read(&volume, &mut file, &mut buf).unwrap();
+ volume_mgr.close_file(&volume, file).unwrap();
+
+ if read_count >= 2 {
+ info!("READ {} bytes: {}", read_count, buf);
+
+ // If we read what we wrote before the last reset,
+ // we set a flag so that the success blinking at the end
+ // changes it's pattern.
+ if buf[0] == 0x42 && buf[1] == 0x1E {
+ successful_read = true;
+ }
+ }
+ }
+
+ blink_signals(&mut led_pin, &mut delay, &BLINK_OK_LONG);
+
+ match volume_mgr.open_file_in_dir(&mut volume, &dir, "O.TST", Mode::ReadWriteCreateOrTruncate) {
+ Ok(mut file) => {
+ volume_mgr
+ .write(&mut volume, &mut file, b"\x42\x1E")
+ .unwrap();
+ volume_mgr.close_file(&volume, file).unwrap();
+ }
+ Err(e) => {
+ error!("Error opening file 'O.TST': {}", defmt::Debug2Format(&e));
+ blink_signals_loop(&mut led_pin, &mut delay, &BLINK_ERR_6_SHORT);
+ }
+ }
+
+ volume_mgr.free();
+
+ blink_signals(&mut led_pin, &mut delay, &BLINK_OK_LONG);
+
+ if successful_read {
+ info!("Successfully read previously written file 'O.TST'");
+ } else {
+ info!("Could not read file, which is ok for the first run.");
+ info!("Reboot the pico!");
+ }
+
+ loop {
+ if successful_read {
+ blink_signals(&mut led_pin, &mut delay, &BLINK_OK_SHORT_SHORT_LONG);
+ } else {
+ blink_signals(&mut led_pin, &mut delay, &BLINK_OK_SHORT_LONG);
+ }
+
+ delay.delay_ms(1000);
+ }
+}
+
+// Can be removed once we have https://github.com/rp-rs/rp-hal/pull/614,
+// ie. when we move to rp2040-hal 0.9
+struct SharedDelay {
+ inner: RefCell<cortex_m::delay::Delay>,
+}
+
+impl SharedDelay {
+ fn new(delay: cortex_m::delay::Delay) -> Self {
+ Self {
+ inner: delay.into(),
+ }
+ }
+}
+
+impl DelayMs<u32> for &SharedDelay {
+ fn delay_ms(&mut self, ms: u32) {
+ self.inner.borrow_mut().delay_ms(ms);
+ }
+}
+
+impl DelayUs<u8> for &SharedDelay {
+ fn delay_us(&mut self, us: u8) {
+ self.inner.borrow_mut().delay_us(us as u32);
+ }
+}
+//! # UART IRQ TX Buffer Example
+//!
+//! This application demonstrates how to use the UART Driver to talk to a
+//! serial connection. In this example, the IRQ owns the UART and you cannot
+//! do any UART access from the main thread. You can, however, write to a
+//! static queue, and have the queue contents transferred to the UART under
+//! interrupt.
+//!
+//! The pinouts are:
+//!
+//! * GPIO 0 - UART TX (out of the RP2040)
+//! * GPIO 1 - UART RX (in to the RP2040)
+//! * GPIO 25 - An LED we can blink (active high)
+//!
+//! See the `Cargo.toml` file for Copyright and license details.
+
+#![no_std]
+#![no_main]
+
+// These are the traits we need from Embedded HAL to treat our hardware
+// objects as generic embedded devices.
+use embedded_hal::{digital::v2::OutputPin, serial::Write as UartWrite};
+
+// The writeln! trait.
+use core::fmt::Write;
+
+// We also need this for the 'Delay' object to work.
+use rp2040_hal::Clock;
+
+// The macro for our start-up function
+use rp_pico::entry;
+
+// Time handling traits
+use fugit::RateExtU32;
+
+// Ensure we halt the program on panic (if we don't mention this crate it won't
+// be linked)
+use panic_halt as _;
+
+// Alias for our HAL crate
+use rp2040_hal as hal;
+
+// A shorter alias for the Peripheral Access Crate, which provides low-level
+// register access
+use hal::pac;
+
+// Our interrupt macro
+use pac::interrupt;
+
+// Some short-cuts to useful types
+use core::cell::RefCell;
+use critical_section::Mutex;
+use heapless::spsc::Queue;
+
+/// Import the GPIO pins we use
+use hal::gpio::pin::bank0::{Gpio0, Gpio1};
+
+// UART related types
+use hal::uart::{DataBits, StopBits, UartConfig};
+
+/// Alias the type for our UART pins to make things clearer.
+type UartPins = (
+ hal::gpio::Pin<Gpio0, hal::gpio::Function<hal::gpio::Uart>>,
+ hal::gpio::Pin<Gpio1, hal::gpio::Function<hal::gpio::Uart>>,
+);
+
+/// Alias the type for our UART to make things clearer.
+type Uart = hal::uart::UartPeripheral<hal::uart::Enabled, pac::UART0, UartPins>;
+
+/// This describes the queue we use for outbound UART data
+struct UartQueue {
+ mutex_cell_queue: Mutex<RefCell<Queue<u8, 64>>>,
+ interrupt: pac::Interrupt,
+}
+
+/// This how we transfer the UART into the Interrupt Handler
+static GLOBAL_UART: Mutex<RefCell<Option<Uart>>> = Mutex::new(RefCell::new(None));
+
+/// This is our outbound UART queue. We write to it from the main thread, and
+/// read from it in the UART IRQ.
+static UART_TX_QUEUE: UartQueue = UartQueue {
+ mutex_cell_queue: Mutex::new(RefCell::new(Queue::new())),
+ interrupt: hal::pac::Interrupt::UART0_IRQ,
+};
+
+/// Entry point to our bare-metal application.
+///
+/// The `#[entry]` macro ensures the Cortex-M start-up code calls this function
+/// as soon as all global variables are initialised.
+///
+/// The function configures the RP2040 peripherals, then writes to the UART in
+/// an infinite loop.
+#[entry]
+fn main() -> ! {
+ // Grab our singleton objects
+ let mut pac = pac::Peripherals::take().unwrap();
+ let core = pac::CorePeripherals::take().unwrap();
+
+ // Set up the watchdog driver - needed by the clock setup code
+ let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);
+
+ // Configure the clocks
+ let clocks = hal::clocks::init_clocks_and_plls(
+ rp_pico::XOSC_CRYSTAL_FREQ,
+ pac.XOSC,
+ pac.CLOCKS,
+ pac.PLL_SYS,
+ pac.PLL_USB,
+ &mut pac.RESETS,
+ &mut watchdog,
+ )
+ .ok()
+ .unwrap();
+
+ // Lets us wait for fixed periods of time
+ let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz());
+
+ // The single-cycle I/O block controls our GPIO pins
+ let sio = hal::Sio::new(pac.SIO);
+
+ // Set the pins to their default state
+ let pins = rp_pico::Pins::new(
+ pac.IO_BANK0,
+ pac.PADS_BANK0,
+ sio.gpio_bank0,
+ &mut pac.RESETS,
+ );
+
+ let uart_pins = (
+ // UART TX (characters sent from RP2040) on pin 1 (GPIO0)
+ pins.gpio0.into_mode::<hal::gpio::FunctionUart>(),
+ // UART RX (characters received by RP2040) on pin 2 (GPIO1)
+ pins.gpio1.into_mode::<hal::gpio::FunctionUart>(),
+ );
+
+ // Make a UART on the given pins
+ let mut uart = hal::uart::UartPeripheral::new(pac.UART0, uart_pins, &mut pac.RESETS)
+ .enable(
+ UartConfig::new(9600.Hz(), DataBits::Eight, None, StopBits::One),
+ clocks.peripheral_clock.freq(),
+ )
+ .unwrap();
+
+ // Tell the UART to raise its interrupt line on the NVIC when the TX FIFO
+ // has space in it.
+ uart.enable_tx_interrupt();
+
+ // Now we give away the entire UART peripheral, via the variable
+ // `GLOBAL_UART`. We can no longer access the UART from this main thread.
+ critical_section::with(|cs| {
+ GLOBAL_UART.borrow(cs).replace(Some(uart));
+ });
+
+ // But we can blink an LED.
+ let mut led_pin = pins.led.into_push_pull_output();
+
+ loop {
+ // Light the LED whilst the main thread is in the transmit routine. It
+ // shouldn't be on very long, but it will be on until we get enough
+ // data /out/ of the queue and over the UART for this remainder of
+ // this string to fit.
+ led_pin.set_high().unwrap();
+ // Note we can only write to &UART_TX_QUEUE, because it's not mutable and
+ // `core::fmt::Write` takes mutable references.
+ writeln!(
+ &UART_TX_QUEUE,
+ "Hello, this was sent under interrupt! It's quite a \
+ long message, designed not to fit in either the \
+ hardware FIFO or the software queue."
+ )
+ .unwrap();
+ led_pin.set_low().unwrap();
+ // Wait for a second - the UART TX IRQ will transmit the remainder of
+ // our queue contents in the background.
+ delay.delay_ms(1000);
+ }
+}
+
+impl UartQueue {
+ /// Try and get some data out of the UART Queue. Returns None if queue empty.
+ fn read_byte(&self) -> Option<u8> {
+ critical_section::with(|cs| {
+ let cell_queue = self.mutex_cell_queue.borrow(cs);
+ let mut queue = cell_queue.borrow_mut();
+ queue.dequeue()
+ })
+ }
+
+ /// Peek at the next byte in the queue without removing it.
+ fn peek_byte(&self) -> Option<u8> {
+ critical_section::with(|cs| {
+ let cell_queue = self.mutex_cell_queue.borrow(cs);
+ let queue = cell_queue.borrow_mut();
+ queue.peek().cloned()
+ })
+ }
+
+ /// Write some data to the queue, spinning until it all fits.
+ fn write_bytes_blocking(&self, data: &[u8]) {
+ // Go through all the bytes we need to write.
+ for byte in data.iter() {
+ // Keep trying until there is space in the queue. But release the
+ // mutex between each attempt, otherwise the IRQ will never run
+ // and we will never have space!
+ let mut written = false;
+ while !written {
+ // Grab the mutex, by turning interrupts off. NOTE: This
+ // doesn't work if you are using Core 1 as we only turn
+ // interrupts off on one core.
+ critical_section::with(|cs| {
+ // Grab the mutex contents.
+ let cell_queue = self.mutex_cell_queue.borrow(cs);
+ // Grab mutable access to the queue. This can't fail
+ // because there are no interrupts running.
+ let mut queue = cell_queue.borrow_mut();
+ // Try and put the byte in the queue.
+ if queue.enqueue(*byte).is_ok() {
+ // It worked! We must have had space.
+ if !pac::NVIC::is_enabled(self.interrupt) {
+ unsafe {
+ // Now enable the UART interrupt in the *Nested
+ // Vectored Interrupt Controller*, which is part
+ // of the Cortex-M0+ core. If the FIFO has space,
+ // the interrupt will run as soon as we're out of
+ // the closure.
+ pac::NVIC::unmask(self.interrupt);
+ // We also have to kick the IRQ in case the FIFO
+ // was already below the threshold level.
+ pac::NVIC::pend(self.interrupt);
+ }
+ }
+ written = true;
+ }
+ });
+ }
+ }
+ }
+}
+
+impl core::fmt::Write for &UartQueue {
+ /// This function allows us to `writeln!` on our global static UART queue.
+ /// Note we have an impl for &UartQueue, because our global static queue
+ /// is not mutable and `core::fmt::Write` takes mutable references.
+ fn write_str(&mut self, data: &str) -> core::fmt::Result {
+ self.write_bytes_blocking(data.as_bytes());
+ Ok(())
+ }
+}
+
+#[interrupt]
+fn UART0_IRQ() {
+ // This variable is special. It gets mangled by the `#[interrupt]` macro
+ // into something that we can access without the `unsafe` keyword. It can
+ // do this because this function cannot be called re-entrantly. We know
+ // this because the function's 'real' name is unknown, and hence it cannot
+ // be called from the main thread. We also know that the NVIC will not
+ // re-entrantly call an interrupt.
+ static mut UART: Option<hal::uart::UartPeripheral<hal::uart::Enabled, pac::UART0, UartPins>> =
+ None;
+
+ // This is one-time lazy initialisation. We steal the variable given to us
+ // via `GLOBAL_UART`.
+ if UART.is_none() {
+ critical_section::with(|cs| {
+ *UART = GLOBAL_UART.borrow(cs).take();
+ });
+ }
+
+ // Check if we have a UART to work with
+ if let Some(uart) = UART {
+ // Check if we have data to transmit
+ while let Some(byte) = UART_TX_QUEUE.peek_byte() {
+ if uart.write(byte).is_ok() {
+ // The UART took it, so pop it off the queue.
+ let _ = UART_TX_QUEUE.read_byte();
+ } else {
+ break;
+ }
+ }
+
+ if UART_TX_QUEUE.peek_byte().is_none() {
+ pac::NVIC::mask(hal::pac::Interrupt::UART0_IRQ);
+ }
+ }
+
+ // Set an event to ensure the main thread always wakes up, even if it's in
+ // the process of going to sleep.
+ cortex_m::asm::sev();
+}
+
+// End of file
+//! # UART IRQ Echo Example
+//!
+//! This application demonstrates how to use the UART Driver to talk to a serial
+//! connection. In this example, the IRQ owns the UART and you cannot do any UART
+//! access from the main thread.
+//!
+//! The pinouts are:
+//!
+//! * GPIO 0 - UART TX (out of the RP2040)
+//! * GPIO 1 - UART RX (in to the RP2040)
+//! * GPIO 25 - An LED we can blink (active high)
+//!
+//! See the `Cargo.toml` file for Copyright and license details.
+
+#![no_std]
+#![no_main]
+
+// These are the traits we need from Embedded HAL to treat our hardware
+// objects as generic embedded devices.
+use embedded_hal::{
+ digital::v2::OutputPin,
+ serial::{Read, Write},
+};
+
+// We also need this for the 'Delay' object to work.
+use rp2040_hal::Clock;
+
+// The macro for our start-up function
+use rp_pico::entry;
+
+// Time handling traits
+use fugit::RateExtU32;
+
+// Ensure we halt the program on panic (if we don't mention this crate it won't
+// be linked)
+use panic_halt as _;
+
+// Alias for our HAL crate
+use rp2040_hal as hal;
+
+// A shorter alias for the Peripheral Access Crate, which provides low-level
+// register access
+use hal::pac;
+
+// Our interrupt macro
+use hal::pac::interrupt;
+
+// Some short-cuts to useful types
+use core::cell::RefCell;
+use critical_section::Mutex;
+
+/// Import the GPIO pins we use
+use hal::gpio::pin::bank0::{Gpio0, Gpio1};
+
+// UART related types
+use hal::uart::{DataBits, StopBits, UartConfig};
+
+/// Alias the type for our UART pins to make things clearer.
+type UartPins = (
+ hal::gpio::Pin<Gpio0, hal::gpio::Function<hal::gpio::Uart>>,
+ hal::gpio::Pin<Gpio1, hal::gpio::Function<hal::gpio::Uart>>,
+);
+
+/// Alias the type for our UART to make things clearer.
+type Uart = hal::uart::UartPeripheral<hal::uart::Enabled, pac::UART0, UartPins>;
+
+/// This how we transfer the UART into the Interrupt Handler
+static GLOBAL_UART: Mutex<RefCell<Option<Uart>>> = Mutex::new(RefCell::new(None));
+
+/// Entry point to our bare-metal application.
+///
+/// The `#[entry]` macro ensures the Cortex-M start-up code calls this function
+/// as soon as all global variables are initialised.
+///
+/// The function configures the RP2040 peripherals, then writes to the UART in
+/// an infinite loop.
+#[entry]
+fn main() -> ! {
+ // Grab our singleton objects
+ let mut pac = pac::Peripherals::take().unwrap();
+ let core = pac::CorePeripherals::take().unwrap();
+
+ // Set up the watchdog driver - needed by the clock setup code
+ let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);
+
+ // Configure the clocks
+ let clocks = hal::clocks::init_clocks_and_plls(
+ rp_pico::XOSC_CRYSTAL_FREQ,
+ pac.XOSC,
+ pac.CLOCKS,
+ pac.PLL_SYS,
+ pac.PLL_USB,
+ &mut pac.RESETS,
+ &mut watchdog,
+ )
+ .ok()
+ .unwrap();
+
+ // Lets us wait for fixed periods of time
+ let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz());
+
+ // The single-cycle I/O block controls our GPIO pins
+ let sio = hal::Sio::new(pac.SIO);
+
+ // Set the pins to their default state
+ let pins = rp_pico::Pins::new(
+ pac.IO_BANK0,
+ pac.PADS_BANK0,
+ sio.gpio_bank0,
+ &mut pac.RESETS,
+ );
+
+ let uart_pins = (
+ // UART TX (characters sent from RP2040) on pin 1 (GPIO0)
+ pins.gpio0.into_mode::<hal::gpio::FunctionUart>(),
+ // UART RX (characters received by RP2040) on pin 2 (GPIO1)
+ pins.gpio1.into_mode::<hal::gpio::FunctionUart>(),
+ );
+
+ // Make a UART on the given pins
+ let mut uart = hal::uart::UartPeripheral::new(pac.UART0, uart_pins, &mut pac.RESETS)
+ .enable(
+ UartConfig::new(9600.Hz(), DataBits::Eight, None, StopBits::One),
+ clocks.peripheral_clock.freq(),
+ )
+ .unwrap();
+
+ unsafe {
+ // Enable the UART interrupt in the *Nested Vectored Interrupt
+ // Controller*, which is part of the Cortex-M0+ core.
+ pac::NVIC::unmask(hal::pac::Interrupt::UART0_IRQ);
+ }
+
+ // Tell the UART to raise its interrupt line on the NVIC when the RX FIFO
+ // has data in it.
+ uart.enable_rx_interrupt();
+
+ // Write something to the UART on start-up so we can check the output pin
+ // is wired correctly.
+ uart.write_full_blocking(b"uart_interrupt example started...\n");
+
+ // Now we give away the entire UART peripheral, via the variable
+ // `GLOBAL_UART`. We can no longer access the UART from this main thread.
+ critical_section::with(|cs| {
+ GLOBAL_UART.borrow(cs).replace(Some(uart));
+ });
+
+ // But we can blink an LED.
+ let mut led_pin = pins.led.into_push_pull_output();
+
+ loop {
+ // The normal *Wait For Interrupts* (WFI) has a race-hazard - the
+ // interrupt could occur between the CPU checking for interrupts and
+ // the CPU going to sleep. We wait for events (and interrupts), and
+ // then we set an event in every interrupt handler. This ensures we
+ // always wake up correctly.
+ cortex_m::asm::wfe();
+ // Light the LED to indicate we saw an interrupt.
+ led_pin.set_high().unwrap();
+ delay.delay_ms(100);
+ led_pin.set_low().unwrap();
+ }
+}
+
+#[interrupt]
+fn UART0_IRQ() {
+ // This variable is special. It gets mangled by the `#[interrupt]` macro
+ // into something that we can access without the `unsafe` keyword. It can
+ // do this because this function cannot be called re-entrantly. We know
+ // this because the function's 'real' name is unknown, and hence it cannot
+ // be called from the main thread. We also know that the NVIC will not
+ // re-entrantly call an interrupt.
+ static mut UART: Option<hal::uart::UartPeripheral<hal::uart::Enabled, pac::UART0, UartPins>> =
+ None;
+
+ // This is one-time lazy initialisation. We steal the variable given to us
+ // via `GLOBAL_UART`.
+ if UART.is_none() {
+ critical_section::with(|cs| {
+ *UART = GLOBAL_UART.borrow(cs).take();
+ });
+ }
+
+ // Check if we have a UART to work with
+ if let Some(uart) = UART {
+ // Echo the input back to the output until the FIFO is empty. Reading
+ // from the UART should also clear the UART interrupt flag.
+ while let Ok(byte) = uart.read() {
+ let _ = uart.write(byte);
+ }
+ }
+
+ // Set an event to ensure the main thread always wakes up, even if it's in
+ // the process of going to sleep.
+ cortex_m::asm::sev();
+}
+
+// End of file
+//! # Pico USB Serial Example
+//!
+//! Creates a USB Serial device on a Pico board, with the USB driver running in
+//! the main thread.
+//!
+//! This will create a USB Serial device echoing anything it receives. Incoming
+//! ASCII characters are converted to upercase, so you can tell it is working
+//! and not just local-echo!
+//!
+//! See the `Cargo.toml` file for Copyright and license details.
+
+#![no_std]
+#![no_main]
+
+// The macro for our start-up function
+use rp_pico::entry;
+
+// Ensure we halt the program on panic (if we don't mention this crate it won't
+// be linked)
+use panic_halt as _;
+
+// A shorter alias for the Peripheral Access Crate, which provides low-level
+// register access
+use rp_pico::hal::pac;
+
+// A shorter alias for the Hardware Abstraction Layer, which provides
+// higher-level drivers.
+use rp_pico::hal;
+
+// USB Device support
+use usb_device::{class_prelude::*, prelude::*};
+
+// USB Communications Class Device support
+use usbd_serial::SerialPort;
+
+// Used to demonstrate writing formatted strings
+use core::fmt::Write;
+use heapless::String;
+
+/// Entry point to our bare-metal application.
+///
+/// The `#[entry]` macro ensures the Cortex-M start-up code calls this function
+/// as soon as all global variables are initialised.
+///
+/// The function configures the RP2040 peripherals, then echoes any characters
+/// received over USB Serial.
+#[entry]
+fn main() -> ! {
+ // Grab our singleton objects
+ let mut pac = pac::Peripherals::take().unwrap();
+
+ // Set up the watchdog driver - needed by the clock setup code
+ let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);
+
+ // Configure the clocks
+ //
+ // The default is to generate a 125 MHz system clock
+ let clocks = hal::clocks::init_clocks_and_plls(
+ rp_pico::XOSC_CRYSTAL_FREQ,
+ pac.XOSC,
+ pac.CLOCKS,
+ pac.PLL_SYS,
+ pac.PLL_USB,
+ &mut pac.RESETS,
+ &mut watchdog,
+ )
+ .ok()
+ .unwrap();
+
+ #[cfg(feature = "rp2040-e5")]
+ {
+ let sio = hal::Sio::new(pac.SIO);
+ let _pins = rp_pico::Pins::new(
+ pac.IO_BANK0,
+ pac.PADS_BANK0,
+ sio.gpio_bank0,
+ &mut pac.RESETS,
+ );
+ }
+
+ // Set up the USB driver
+ let usb_bus = UsbBusAllocator::new(hal::usb::UsbBus::new(
+ pac.USBCTRL_REGS,
+ pac.USBCTRL_DPRAM,
+ clocks.usb_clock,
+ true,
+ &mut pac.RESETS,
+ ));
+
+ // Set up the USB Communications Class Device driver
+ let mut serial = SerialPort::new(&usb_bus);
+
+ // Create a USB device with a fake VID and PID
+ let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x16c0, 0x27dd))
+ .manufacturer("Fake company")
+ .product("Serial port")
+ .serial_number("TEST")
+ .device_class(2) // from: https://www.usb.org/defined-class-codes
+ .build();
+
+ let timer = hal::Timer::new(pac.TIMER, &mut pac.RESETS);
+ let mut said_hello = false;
+ loop {
+ // A welcome message at the beginning
+ if !said_hello && timer.get_counter().ticks() >= 2_000_000 {
+ said_hello = true;
+ let _ = serial.write(b"Hello, World!\r\n");
+
+ let time = timer.get_counter().ticks();
+ let mut text: String<64> = String::new();
+ writeln!(&mut text, "Current timer ticks: {}", time).unwrap();
+
+ // This only works reliably because the number of bytes written to
+ // the serial port is smaller than the buffers available to the USB
+ // peripheral. In general, the return value should be handled, so that
+ // bytes not transferred yet don't get lost.
+ let _ = serial.write(text.as_bytes());
+ }
+
+ // Check for new data
+ if usb_dev.poll(&mut [&mut serial]) {
+ let mut buf = [0u8; 64];
+ match serial.read(&mut buf) {
+ Err(_e) => {
+ // Do nothing
+ }
+ Ok(0) => {
+ // Do nothing
+ }
+ Ok(count) => {
+ // Convert to upper case
+ buf.iter_mut().take(count).for_each(|b| {
+ b.make_ascii_uppercase();
+ });
+ // Send back to the host
+ let mut wr_ptr = &buf[..count];
+ while !wr_ptr.is_empty() {
+ match serial.write(wr_ptr) {
+ Ok(len) => wr_ptr = &wr_ptr[len..],
+ // On error, just drop unwritten data.
+ // One possible error is Err(WouldBlock), meaning the USB
+ // write buffer is full.
+ Err(_) => break,
+ };
+ }
+ }
+ }
+ }
+ }
+}
+
+// End of file
+//! # Pico USB Serial (with Interrupts) Example
+//!
+//! Creates a USB Serial device on a Pico board, with the USB driver running in
+//! the USB interrupt.
+//!
+//! This will create a USB Serial device echoing anything it receives. Incoming
+//! ASCII characters are converted to upercase, so you can tell it is working
+//! and not just local-echo!
+//!
+//! See the `Cargo.toml` file for Copyright and license details.
+
+#![no_std]
+#![no_main]
+
+// The macro for our start-up function
+use rp_pico::entry;
+
+// The macro for marking our interrupt functions
+use rp_pico::hal::pac::interrupt;
+
+// GPIO traits
+use embedded_hal::digital::v2::OutputPin;
+
+// Ensure we halt the program on panic (if we don't mention this crate it won't
+// be linked)
+use panic_halt as _;
+
+// Pull in any important traits
+use rp_pico::hal::prelude::*;
+
+// A shorter alias for the Peripheral Access Crate, which provides low-level
+// register access
+use rp_pico::hal::pac;
+
+// A shorter alias for the Hardware Abstraction Layer, which provides
+// higher-level drivers.
+use rp_pico::hal;
+
+// USB Device support
+use usb_device::{class_prelude::*, prelude::*};
+
+// USB Communications Class Device support
+use usbd_serial::SerialPort;
+
+/// The USB Device Driver (shared with the interrupt).
+static mut USB_DEVICE: Option<UsbDevice<hal::usb::UsbBus>> = None;
+
+/// The USB Bus Driver (shared with the interrupt).
+static mut USB_BUS: Option<UsbBusAllocator<hal::usb::UsbBus>> = None;
+
+/// The USB Serial Device Driver (shared with the interrupt).
+static mut USB_SERIAL: Option<SerialPort<hal::usb::UsbBus>> = None;
+
+/// Entry point to our bare-metal application.
+///
+/// The `#[entry]` macro ensures the Cortex-M start-up code calls this function
+/// as soon as all global variables are initialised.
+///
+/// The function configures the RP2040 peripherals, then blinks the LED in an
+/// infinite loop.
+#[entry]
+fn main() -> ! {
+ // Grab our singleton objects
+ let mut pac = pac::Peripherals::take().unwrap();
+ let core = pac::CorePeripherals::take().unwrap();
+
+ // Set up the watchdog driver - needed by the clock setup code
+ let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);
+
+ // Configure the clocks
+ //
+ // The default is to generate a 125 MHz system clock
+ let clocks = hal::clocks::init_clocks_and_plls(
+ rp_pico::XOSC_CRYSTAL_FREQ,
+ pac.XOSC,
+ pac.CLOCKS,
+ pac.PLL_SYS,
+ pac.PLL_USB,
+ &mut pac.RESETS,
+ &mut watchdog,
+ )
+ .ok()
+ .unwrap();
+
+ // Set up the USB driver
+ let usb_bus = UsbBusAllocator::new(hal::usb::UsbBus::new(
+ pac.USBCTRL_REGS,
+ pac.USBCTRL_DPRAM,
+ clocks.usb_clock,
+ true,
+ &mut pac.RESETS,
+ ));
+ unsafe {
+ // Note (safety): This is safe as interrupts haven't been started yet
+ USB_BUS = Some(usb_bus);
+ }
+
+ // Grab a reference to the USB Bus allocator. We are promising to the
+ // compiler not to take mutable access to this global variable whilst this
+ // reference exists!
+ let bus_ref = unsafe { USB_BUS.as_ref().unwrap() };
+
+ // Set up the USB Communications Class Device driver
+ let serial = SerialPort::new(bus_ref);
+ unsafe {
+ USB_SERIAL = Some(serial);
+ }
+
+ // Create a USB device with a fake VID and PID
+ let usb_dev = UsbDeviceBuilder::new(bus_ref, UsbVidPid(0x16c0, 0x27dd))
+ .manufacturer("Fake company")
+ .product("Serial port")
+ .serial_number("TEST")
+ .device_class(2) // from: https://www.usb.org/defined-class-codes
+ .build();
+ unsafe {
+ // Note (safety): This is safe as interrupts haven't been started yet
+ USB_DEVICE = Some(usb_dev);
+ }
+
+ // Enable the USB interrupt
+ unsafe {
+ pac::NVIC::unmask(hal::pac::Interrupt::USBCTRL_IRQ);
+ };
+
+ // No more USB code after this point in main! We can do anything we want in
+ // here since USB is handled in the interrupt - let's blink an LED!
+
+ // The delay object lets us wait for specified amounts of time (in
+ // milliseconds)
+ let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz());
+
+ // The single-cycle I/O block controls our GPIO pins
+ let sio = hal::Sio::new(pac.SIO);
+
+ // Set the pins up according to their function on this particular board
+ let pins = rp_pico::Pins::new(
+ pac.IO_BANK0,
+ pac.PADS_BANK0,
+ sio.gpio_bank0,
+ &mut pac.RESETS,
+ );
+
+ // Set the LED to be an output
+ let mut led_pin = pins.led.into_push_pull_output();
+
+ // Blink the LED at 1 Hz
+ loop {
+ led_pin.set_high().unwrap();
+ delay.delay_ms(500);
+ led_pin.set_low().unwrap();
+ delay.delay_ms(500);
+ }
+}
+
+/// This function is called whenever the USB Hardware generates an Interrupt
+/// Request.
+///
+/// We do all our USB work under interrupt, so the main thread can continue on
+/// knowing nothing about USB.
+#[allow(non_snake_case)]
+#[interrupt]
+unsafe fn USBCTRL_IRQ() {
+ use core::sync::atomic::{AtomicBool, Ordering};
+
+ /// Note whether we've already printed the "hello" message.
+ static SAID_HELLO: AtomicBool = AtomicBool::new(false);
+
+ // Grab the global objects. This is OK as we only access them under interrupt.
+ let usb_dev = USB_DEVICE.as_mut().unwrap();
+ let serial = USB_SERIAL.as_mut().unwrap();
+
+ // Say hello exactly once on start-up
+ if !SAID_HELLO.load(Ordering::Relaxed) {
+ SAID_HELLO.store(true, Ordering::Relaxed);
+ let _ = serial.write(b"Hello, World!\r\n");
+ }
+
+ // Poll the USB driver with all of our supported USB Classes
+ if usb_dev.poll(&mut [serial]) {
+ let mut buf = [0u8; 64];
+ match serial.read(&mut buf) {
+ Err(_e) => {
+ // Do nothing
+ }
+ Ok(0) => {
+ // Do nothing
+ }
+ Ok(count) => {
+ // Convert to upper case
+ buf.iter_mut().take(count).for_each(|b| {
+ b.make_ascii_uppercase();
+ });
+
+ // Send back to the host
+ let mut wr_ptr = &buf[..count];
+ while !wr_ptr.is_empty() {
+ let _ = serial.write(wr_ptr).map(|len| {
+ wr_ptr = &wr_ptr[len..];
+ });
+ }
+ }
+ }
+ }
+}
+
+// End of file
+//! # Pico USB 'Twitchy' Mouse Example
+//!
+//! Creates a USB HID Class Pointing device (i.e. a virtual mouse) on a Pico
+//! board, with the USB driver running in the main thread.
+//!
+//! It generates movement reports which will twitch the cursor up and down by a
+//! few pixels, several times a second.
+//!
+//! See the `Cargo.toml` file for Copyright and license details.
+//!
+//! This is a port of
+//! https://github.com/atsamd-rs/atsamd/blob/master/boards/itsybitsy_m0/examples/twitching_usb_mouse.rs
+
+#![no_std]
+#![no_main]
+
+// The macro for our start-up function
+use rp_pico::entry;
+
+// The macro for marking our interrupt functions
+use rp_pico::hal::pac::interrupt;
+
+// Ensure we halt the program on panic (if we don't mention this crate it won't
+// be linked)
+use panic_halt as _;
+
+// Pull in any important traits
+use rp_pico::hal::prelude::*;
+
+// A shorter alias for the Peripheral Access Crate, which provides low-level
+// register access
+use rp_pico::hal::pac;
+
+// A shorter alias for the Hardware Abstraction Layer, which provides
+// higher-level drivers.
+use rp_pico::hal;
+
+// USB Device support
+use usb_device::{class_prelude::*, prelude::*};
+
+// USB Human Interface Device (HID) Class support
+use usbd_hid::descriptor::generator_prelude::*;
+use usbd_hid::descriptor::MouseReport;
+use usbd_hid::hid_class::HIDClass;
+
+/// The USB Device Driver (shared with the interrupt).
+static mut USB_DEVICE: Option<UsbDevice<hal::usb::UsbBus>> = None;
+
+/// The USB Bus Driver (shared with the interrupt).
+static mut USB_BUS: Option<UsbBusAllocator<hal::usb::UsbBus>> = None;
+
+/// The USB Human Interface Device Driver (shared with the interrupt).
+static mut USB_HID: Option<HIDClass<hal::usb::UsbBus>> = None;
+
+/// Entry point to our bare-metal application.
+///
+/// The `#[entry]` macro ensures the Cortex-M start-up code calls this function
+/// as soon as all global variables are initialised.
+///
+/// The function configures the RP2040 peripherals, then submits cursor movement
+/// updates periodically.
+#[entry]
+fn main() -> ! {
+ // Grab our singleton objects
+ let mut pac = pac::Peripherals::take().unwrap();
+
+ // Set up the watchdog driver - needed by the clock setup code
+ let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);
+
+ // Configure the clocks
+ //
+ // The default is to generate a 125 MHz system clock
+ let clocks = hal::clocks::init_clocks_and_plls(
+ rp_pico::XOSC_CRYSTAL_FREQ,
+ pac.XOSC,
+ pac.CLOCKS,
+ pac.PLL_SYS,
+ pac.PLL_USB,
+ &mut pac.RESETS,
+ &mut watchdog,
+ )
+ .ok()
+ .unwrap();
+
+ #[cfg(feature = "rp2040-e5")]
+ {
+ let sio = hal::Sio::new(pac.SIO);
+ let _pins = rp_pico::Pins::new(
+ pac.IO_BANK0,
+ pac.PADS_BANK0,
+ sio.gpio_bank0,
+ &mut pac.RESETS,
+ );
+ }
+
+ // Set up the USB driver
+ let usb_bus = UsbBusAllocator::new(hal::usb::UsbBus::new(
+ pac.USBCTRL_REGS,
+ pac.USBCTRL_DPRAM,
+ clocks.usb_clock,
+ true,
+ &mut pac.RESETS,
+ ));
+ unsafe {
+ // Note (safety): This is safe as interrupts haven't been started yet
+ USB_BUS = Some(usb_bus);
+ }
+
+ // Grab a reference to the USB Bus allocator. We are promising to the
+ // compiler not to take mutable access to this global variable whilst this
+ // reference exists!
+ let bus_ref = unsafe { USB_BUS.as_ref().unwrap() };
+
+ // Set up the USB HID Class Device driver, providing Mouse Reports
+ let usb_hid = HIDClass::new(bus_ref, MouseReport::desc(), 60);
+ unsafe {
+ // Note (safety): This is safe as interrupts haven't been started yet.
+ USB_HID = Some(usb_hid);
+ }
+
+ // Create a USB device with a fake VID and PID
+ let usb_dev = UsbDeviceBuilder::new(bus_ref, UsbVidPid(0x16c0, 0x27da))
+ .manufacturer("Fake company")
+ .product("Twitchy Mousey")
+ .serial_number("TEST")
+ .device_class(0)
+ .build();
+ unsafe {
+ // Note (safety): This is safe as interrupts haven't been started yet
+ USB_DEVICE = Some(usb_dev);
+ }
+
+ unsafe {
+ // Enable the USB interrupt
+ pac::NVIC::unmask(hal::pac::Interrupt::USBCTRL_IRQ);
+ };
+ let core = pac::CorePeripherals::take().unwrap();
+ let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz());
+
+ // Move the cursor up and down every 200ms
+ loop {
+ delay.delay_ms(100);
+
+ let rep_up = MouseReport {
+ x: 0,
+ y: 4,
+ buttons: 0,
+ wheel: 0,
+ pan: 0,
+ };
+ push_mouse_movement(rep_up).ok().unwrap_or(0);
+
+ delay.delay_ms(100);
+
+ let rep_down = MouseReport {
+ x: 0,
+ y: -4,
+ buttons: 0,
+ wheel: 0,
+ pan: 0,
+ };
+ push_mouse_movement(rep_down).ok().unwrap_or(0);
+ }
+}
+
+/// Submit a new mouse movement report to the USB stack.
+///
+/// We do this with interrupts disabled, to avoid a race hazard with the USB IRQ.
+fn push_mouse_movement(report: MouseReport) -> Result<usize, usb_device::UsbError> {
+ critical_section::with(|_| unsafe {
+ // Now interrupts are disabled, grab the global variable and, if
+ // available, send it a HID report
+ USB_HID.as_mut().map(|hid| hid.push_input(&report))
+ })
+ .unwrap()
+}
+
+/// This function is called whenever the USB Hardware generates an Interrupt
+/// Request.
+#[allow(non_snake_case)]
+#[interrupt]
+unsafe fn USBCTRL_IRQ() {
+ // Handle USB request
+ let usb_dev = USB_DEVICE.as_mut().unwrap();
+ let usb_hid = USB_HID.as_mut().unwrap();
+ usb_dev.poll(&mut [usb_hid]);
+}
+
+// End of file
+//! # Pico WS2812 RGB LED Example
+//!
+//! Drives 3 WS2812 LEDs connected directly to the Raspberry Pi Pico.
+//! This assumes you drive the Raspberry Pi Pico via USB power, so that VBUS
+//! delivers the 5V and at least enough amperes to drive the LEDs.
+//!
+//! For a more large scale and longer strips you should use an extra power
+//! supply for the LED strip (or know what you are doing ;-) ).
+//!
+//! The example also comes with an utility function to calculate the colors
+//! from HSV color space. It also limits the brightness a bit to save a
+//! few milliamperes - be careful if you increase the strip length you will
+//! quickly get into power consumption of multiple amperes.
+//!
+//! The example assumes you connected the data input to pin 6 of the
+//! Raspberry Pi Pico, which is GPIO4 of the rp2040. Here is a circuit
+//! diagram that shows the assumed setup:
+//!
+//! ```text
+//! _______________ /----------------------\
+//! |+5V /---\ +5V|----/ _|USB|_ |
+//! |DO <-|LED|<- DI|-\ |1 R 40|-VBUS-/
+//! |GND \---/ GND|--+---\ |2 P 39|
+//! """"""""""""""" | \-GND-|3 38|
+//! | |4 P 37|
+//! | |5 I 36|
+//! \------GP4-|6 C |
+//! |7 O |
+//! | |
+//! .........
+//! |20 21|
+//! """""""
+//! Symbols:
+//! - (+) crossing lines, not connected
+//! - (o) connected lines
+//! ```
+//!
+//! See the `Cargo.toml` file for Copyright and license details.
+
+#![no_std]
+#![no_main]
+
+// The macro for our start-up function
+use rp_pico::entry;
+
+// Ensure we halt the program on panic (if we don't mention this crate it won't
+// be linked)
+use panic_halt as _;
+
+// Pull in any important traits
+use rp_pico::hal::prelude::*;
+
+// A shorter alias for the Peripheral Access Crate, which provides low-level
+// register access
+use rp_pico::hal::pac;
+
+// Import the Timer for Ws2812:
+use rp_pico::hal::timer::Timer;
+
+// A shorter alias for the Hardware Abstraction Layer, which provides
+// higher-level drivers.
+use rp_pico::hal;
+
+// PIOExt for the split() method that is needed to bring
+// PIO0 into useable form for Ws2812:
+use rp_pico::hal::pio::PIOExt;
+
+// Import useful traits to handle the ws2812 LEDs:
+use smart_leds::{brightness, SmartLedsWrite, RGB8};
+
+// Import the actual crate to handle the Ws2812 protocol:
+use ws2812_pio::Ws2812;
+
+// Currently 3 consecutive LEDs are driven by this example
+// to keep the power draw compatible with USB:
+const STRIP_LEN: usize = 3;
+
+#[entry]
+fn main() -> ! {
+ // Grab our singleton objects
+ let mut pac = pac::Peripherals::take().unwrap();
+ let core = pac::CorePeripherals::take().unwrap();
+
+ // Set up the watchdog driver - needed by the clock setup code
+ let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);
+
+ // Configure the clocks
+ //
+ // The default is to generate a 125 MHz system clock
+ let clocks = hal::clocks::init_clocks_and_plls(
+ rp_pico::XOSC_CRYSTAL_FREQ,
+ pac.XOSC,
+ pac.CLOCKS,
+ pac.PLL_SYS,
+ pac.PLL_USB,
+ &mut pac.RESETS,
+ &mut watchdog,
+ )
+ .ok()
+ .unwrap();
+
+ // The single-cycle I/O block controls our GPIO pins
+ let sio = hal::Sio::new(pac.SIO);
+
+ // Set the pins up according to their function on this particular board
+ let pins = rp_pico::Pins::new(
+ pac.IO_BANK0,
+ pac.PADS_BANK0,
+ sio.gpio_bank0,
+ &mut pac.RESETS,
+ );
+
+ // Setup a delay for the LED blink signals:
+ let mut frame_delay =
+ cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz());
+
+ // Import the `sin` function for a smooth hue animation from the
+ // Pico rp2040 ROM:
+ let sin = hal::rom_data::float_funcs::fsin::ptr();
+
+ // Create a count down timer for the Ws2812 instance:
+ let timer = Timer::new(pac.TIMER, &mut pac.RESETS);
+
+ // Split the PIO state machine 0 into individual objects, so that
+ // Ws2812 can use it:
+ let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS);
+
+ // Instanciate a Ws2812 LED strip:
+ let mut ws = Ws2812::new(
+ // Use pin 6 on the Raspberry Pi Pico (which is GPIO4 of the rp2040 chip)
+ // for the LED data output:
+ pins.gpio4.into_mode(),
+ &mut pio,
+ sm0,
+ clocks.peripheral_clock.freq(),
+ timer.count_down(),
+ );
+
+ let mut leds: [RGB8; STRIP_LEN] = [(0, 0, 0).into(); STRIP_LEN];
+ let mut t = 0.0;
+
+ // Bring down the overall brightness of the strip to not blow
+ // the USB power supply: every LED draws ~60mA, RGB means 3 LEDs per
+ // ws2812 LED, for 3 LEDs that would be: 3 * 3 * 60mA, which is
+ // already 540mA for just 3 white LEDs!
+ let strip_brightness = 64u8; // Limit brightness to 64/256
+
+ // Slow down timer by this factor (0.1 will result in 10 seconds):
+ let animation_speed = 0.1;
+
+ loop {
+ for (i, led) in leds.iter_mut().enumerate() {
+ // An offset to give 3 consecutive LEDs a different color:
+ let hue_offs = match i % 3 {
+ 1 => 0.25,
+ 2 => 0.5,
+ _ => 0.0,
+ };
+
+ let sin_11 = sin((t + hue_offs) * 2.0 * core::f32::consts::PI);
+ // Bring -1..1 sine range to 0..1 range:
+ let sin_01 = (sin_11 + 1.0) * 0.5;
+
+ let hue = 360.0 * sin_01;
+ let sat = 1.0;
+ let val = 1.0;
+
+ let rgb = hsv2rgb_u8(hue, sat, val);
+ *led = rgb.into();
+ }
+
+ // Here the magic happens and the `leds` buffer is written to the
+ // ws2812 LEDs:
+ ws.write(brightness(leds.iter().copied(), strip_brightness))
+ .unwrap();
+
+ // Wait a bit until calculating the next frame:
+ frame_delay.delay_ms(16); // ~60 FPS
+
+ // Increase the time counter variable and make sure it
+ // stays inbetween 0.0 to 1.0 range:
+ t += (16.0 / 1000.0) * animation_speed;
+ while t > 1.0 {
+ t -= 1.0;
+ }
+ }
+}
+
+pub fn hsv2rgb(hue: f32, sat: f32, val: f32) -> (f32, f32, f32) {
+ let c = val * sat;
+ let v = (hue / 60.0) % 2.0 - 1.0;
+ let v = if v < 0.0 { -v } else { v };
+ let x = c * (1.0 - v);
+ let m = val - c;
+ let (r, g, b) = if hue < 60.0 {
+ (c, x, 0.0)
+ } else if hue < 120.0 {
+ (x, c, 0.0)
+ } else if hue < 180.0 {
+ (0.0, c, x)
+ } else if hue < 240.0 {
+ (0.0, x, c)
+ } else if hue < 300.0 {
+ (x, 0.0, c)
+ } else {
+ (c, 0.0, x)
+ };
+ (r + m, g + m, b + m)
+}
+
+pub fn hsv2rgb_u8(h: f32, s: f32, v: f32) -> (u8, u8, u8) {
+ let r = hsv2rgb(h, s, v);
+
+ (
+ (r.0 * 255.0) as u8,
+ (r.1 * 255.0) as u8,
+ (r.2 * 255.0) as u8,
+ )
+}
+;
+; Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+;
+; SPDX-License-Identifier: BSD-3-Clause
+;
+
+; Side-set pin 0 is used for PWM output
+
+.program pwm
+.side_set 1 opt
+
+ pull noblock side 0 ; Pull from FIFO to OSR if available, else copy X to OSR.
+ mov x, osr ; Copy most-recently-pulled value back to scratch X
+ mov y, isr ; ISR contains PWM period. Y used as counter.
+countloop:
+ jmp x!=y noset ; Set pin high if X == Y, keep the two paths length matched
+ jmp skip side 1
+noset:
+ nop ; Single dummy cycle to keep the two paths the same length
+skip:
+ jmp y-- countloop ; Loop until Y hits 0, then pull a fresh PWM value from FIFO
+
+% c-sdk {
+static inline void pwm_program_init(PIO pio, uint sm, uint offset, uint pin) {
+ pio_gpio_init(pio, pin);
+ pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);
+ pio_sm_config c = pwm_program_get_default_config(offset);
+ sm_config_set_sideset_pins(&c, pin);
+ pio_sm_init(pio, sm, offset, &c);
+}
+%}
\ No newline at end of file
+#![no_std]
+
+//! A Hardware Abstraction Layer for the DoA Hallönbrod.
+//!
+//! This crate serves as a HAL (Hardware Abstraction Layer) for the DoA Hallönbrod. Since the DoA Hallönbrod
+//! is based on the RP2040 chip, it re-exports the [rp2040_hal] crate which contains the tooling to work with the
+//! rp2040 chip.
+//!
+//! # Examples:
+//!
+//! The following example turns on the onboard LED. Note that most of the logic works through the [rp2040_hal] crate.
+//! ```ignore
+//! #![no_main]
+//! use rp_pico::entry;
+//! use panic_halt as _;
+//! use embedded_hal::digital::v2::OutputPin;
+//! use rp_pico::hal::pac;
+//! use rp_pico::hal;
+
+//! #[entry]
+//! fn does_not_have_to_be_main() -> ! {
+//! let mut pac = pac::Peripherals::take().unwrap();
+//! let sio = hal::Sio::new(pac.SIO);
+//! let pins = rp_pico::Pins::new(
+//! pac.IO_BANK0,
+//! pac.PADS_BANK0,
+//! sio.gpio_bank0,
+//! &mut pac.RESETS,
+//! );
+//! let mut led_pin = pins.led.into_push_pull_output();
+//! led_pin.set_high().unwrap();
+//! loop {
+//! }
+//! }
+//! ```
+
+pub extern crate rp2040_hal as hal;
+
+#[cfg(feature = "rt")]
+extern crate cortex_m_rt;
+
+/// The `entry` macro declares the starting function to the linker.
+/// This is similar to the `main` function in console applications.
+///
+/// It is based on the [cortex_m_rt](https://docs.rs/cortex-m-rt/latest/cortex_m_rt/attr.entry.html) crate.
+///
+/// # Examples
+/// ```ignore
+/// #![no_std]
+/// #![no_main]
+/// use rp_pico::entry;
+/// #[entry]
+/// fn you_can_use_a_custom_main_name_here() -> ! {
+/// loop {}
+/// }
+/// ```
+
+#[cfg(feature = "rt")]
+pub use hal::entry;
+
+/// The linker will place this boot block at the start of our program image. We
+/// need this to help the ROM bootloader get our code up and running.
+#[cfg(feature = "boot2")]
+#[link_section = ".boot2"]
+#[no_mangle]
+#[used]
+pub static BOOT2_FIRMWARE: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080;
+
+pub use hal::pac;
+
+hal::bsp_pins!(
+ /// GPIO 0 supports following functions:
+ ///
+ /// | Function | Alias with applied function |
+ /// |--------------|-----------------------------|
+ /// | `SPI0 RX` | [crate::Gp0Spi0Rx] |
+ /// | `UART0 TX` | [crate::Gp0Uart0Tx] |
+ /// | `I2C0 SDA` | [crate::Gp0I2C0Sda] |
+ /// | `PWM0 A` | [crate::Gp0Pwm0A] |
+ /// | `PIO0` | [crate::Gp0Pio0] |
+ /// | `PIO1` | [crate::Gp0Pio1] |
+ Gpio0 {
+ name: gpio0,
+ aliases: {
+ /// UART Function alias for pin [crate::Pins::gpio0].
+ FunctionUart: Gp0Uart0Tx,
+ /// SPI Function alias for pin [crate::Pins::gpio0].
+ FunctionSpi: Gp0Spi0Rx,
+ /// I2C Function alias for pin [crate::Pins::gpio0].
+ FunctionI2C: Gp0I2C0Sda,
+ /// PWM Function alias for pin [crate::Pins::gpio0].
+ FunctionPwm: Gp0Pwm0A,
+ /// PIO0 Function alias for pin [crate::Pins::gpio0].
+ FunctionPio0: Gp0Pio0,
+ /// PIO1 Function alias for pin [crate::Pins::gpio0].
+ FunctionPio1: Gp0Pio1
+ }
+ },
+
+ /// GPIO 1 supports following functions:
+ ///
+ /// | Function | Alias with applied function |
+ /// |--------------|-----------------------------|
+ /// | `SPI0 CSn` | [crate::Gp1Spi0Csn] |
+ /// | `UART0 RX` | [crate::Gp1Uart0Rx] |
+ /// | `I2C0 SCL` | [crate::Gp1I2C0Scl] |
+ /// | `PWM0 B` | [crate::Gp1Pwm0B] |
+ /// | `PIO0` | [crate::Gp1Pio0] |
+ /// | `PIO1` | [crate::Gp1Pio1] |
+ Gpio1 {
+ name: gpio1,
+ aliases: {
+ /// UART Function alias for pin [crate::Pins::gpio1].
+ FunctionUart: Gp1Uart0Rx,
+ /// SPI Function alias for pin [crate::Pins::gpio1].
+ FunctionSpi: Gp1Spi0Csn,
+ /// I2C Function alias for pin [crate::Pins::gpio1].
+ FunctionI2C: Gp1I2C0Scl,
+ /// PWM Function alias for pin [crate::Pins::gpio1].
+ FunctionPwm: Gp1Pwm0B,
+ /// PIO0 Function alias for pin [crate::Pins::gpio1].
+ FunctionPio0: Gp1Pio0,
+ /// PIO1 Function alias for pin [crate::Pins::gpio1].
+ FunctionPio1: Gp1Pio1
+ }
+ },
+
+ /// GPIO 2 supports following functions:
+ ///
+ /// | Function | Alias with applied function |
+ /// |--------------|-----------------------------|
+ /// | `SPI0 SCK` | [crate::Gp2Spi0Sck] |
+ /// | `UART0 CTS` | [crate::Gp2Uart0Cts] |
+ /// | `I2C1 SDA` | [crate::Gp2I2C1Sda] |
+ /// | `PWM1 A` | [crate::Gp2Pwm1A] |
+ /// | `PIO0` | [crate::Gp2Pio0] |
+ /// | `PIO1` | [crate::Gp2Pio1] |
+ Gpio2 {
+ name: gpio2,
+ aliases: {
+ /// UART Function alias for pin [crate::Pins::gpio2].
+ FunctionUart: Gp2Uart0Cts,
+ /// SPI Function alias for pin [crate::Pins::gpio2].
+ FunctionSpi: Gp2Spi0Sck,
+ /// I2C Function alias for pin [crate::Pins::gpio2].
+ FunctionI2C: Gp2I2C1Sda,
+ /// PWM Function alias for pin [crate::Pins::gpio2].
+ FunctionPwm: Gp2Pwm1A,
+ /// PIO0 Function alias for pin [crate::Pins::gpio2].
+ FunctionPio0: Gp2Pio0,
+ /// PIO1 Function alias for pin [crate::Pins::gpio2].
+ FunctionPio1: Gp2Pio1
+ }
+ },
+
+ /// GPIO 3 supports following functions:
+ ///
+ /// | Function | Alias with applied function |
+ /// |--------------|-----------------------------|
+ /// | `SPI0 TX` | [crate::Gp3Spi0Tx] |
+ /// | `UART0 RTS` | [crate::Gp3Uart0Rts] |
+ /// | `I2C1 SCL` | [crate::Gp3I2C1Scl] |
+ /// | `PWM1 B` | [crate::Gp3Pwm1B] |
+ /// | `PIO0` | [crate::Gp3Pio0] |
+ /// | `PIO1` | [crate::Gp3Pio1] |
+ Gpio3 {
+ name: gpio3,
+ aliases: {
+ /// UART Function alias for pin [crate::Pins::gpio3].
+ FunctionUart: Gp3Uart0Rts,
+ /// SPI Function alias for pin [crate::Pins::gpio3].
+ FunctionSpi: Gp3Spi0Tx,
+ /// I2C Function alias for pin [crate::Pins::gpio3].
+ FunctionI2C: Gp3I2C1Scl,
+ /// PWM Function alias for pin [crate::Pins::gpio3].
+ FunctionPwm: Gp3Pwm1B,
+ /// PIO0 Function alias for pin [crate::Pins::gpio3].
+ FunctionPio0: Gp3Pio0,
+ /// PIO1 Function alias for pin [crate::Pins::gpio3].
+ FunctionPio1: Gp3Pio1
+ }
+ },
+
+ /// GPIO 4 supports following functions:
+ ///
+ /// | Function | Alias with applied function |
+ /// |--------------|-----------------------------|
+ /// | `SPI0 RX` | [crate::Gp4Spi0Rx] |
+ /// | `UART1 TX` | [crate::Gp4Uart1Tx] |
+ /// | `I2C0 SDA` | [crate::Gp4I2C0Sda] |
+ /// | `PWM2 A` | [crate::Gp4Pwm2A] |
+ /// | `PIO0` | [crate::Gp4Pio0] |
+ /// | `PIO1` | [crate::Gp4Pio1] |
+ Gpio4 {
+ name: gpio4,
+ aliases: {
+ /// UART Function alias for pin [crate::Pins::gpio4].
+ FunctionUart: Gp4Uart1Tx,
+ /// SPI Function alias for pin [crate::Pins::gpio4].
+ FunctionSpi: Gp4Spi0Rx,
+ /// I2C Function alias for pin [crate::Pins::gpio4].
+ FunctionI2C: Gp4I2C0Sda,
+ /// PWM Function alias for pin [crate::Pins::gpio4].
+ FunctionPwm: Gp4Pwm2A,
+ /// PIO0 Function alias for pin [crate::Pins::gpio4].
+ FunctionPio0: Gp4Pio0,
+ /// PIO1 Function alias for pin [crate::Pins::gpio4].
+ FunctionPio1: Gp4Pio1
+ }
+ },
+
+ /// GPIO 5 supports following functions:
+ ///
+ /// | Function | Alias with applied function |
+ /// |--------------|-----------------------------|
+ /// | `SPI0 CSn` | [crate::Gp5Spi0Csn] |
+ /// | `UART1 RX` | [crate::Gp5Uart1Rx] |
+ /// | `I2C0 SCL` | [crate::Gp5I2C0Scl] |
+ /// | `PWM2 B` | [crate::Gp5Pwm2B] |
+ /// | `PIO0` | [crate::Gp5Pio0] |
+ /// | `PIO1` | [crate::Gp5Pio1] |
+ Gpio5 {
+ name: gpio5,
+ aliases: {
+ /// UART Function alias for pin [crate::Pins::gpio5].
+ FunctionUart: Gp5Uart1Rx,
+ /// SPI Function alias for pin [crate::Pins::gpio5].
+ FunctionSpi: Gp5Spi0Csn,
+ /// I2C Function alias for pin [crate::Pins::gpio5].
+ FunctionI2C: Gp5I2C0Scl,
+ /// PWM Function alias for pin [crate::Pins::gpio5].
+ FunctionPwm: Gp5Pwm2B,
+ /// PIO0 Function alias for pin [crate::Pins::gpio5].
+ FunctionPio0: Gp5Pio0,
+ /// PIO1 Function alias for pin [crate::Pins::gpio5].
+ FunctionPio1: Gp5Pio1
+ }
+ },
+
+ /// GPIO 6 supports following functions:
+ ///
+ /// | Function | Alias with applied function |
+ /// |--------------|-----------------------------|
+ /// | `SPI0 SCK` | [crate::Gp6Spi0Sck] |
+ /// | `UART1 CTS` | [crate::Gp6Uart1Cts] |
+ /// | `I2C1 SDA` | [crate::Gp6I2C1Sda] |
+ /// | `PWM3 A` | [crate::Gp6Pwm3A] |
+ /// | `PIO0` | [crate::Gp6Pio0] |
+ /// | `PIO1` | [crate::Gp6Pio1] |
+ Gpio6 {
+ name: gpio6,
+ aliases: {
+ /// UART Function alias for pin [crate::Pins::gpio6].
+ FunctionUart: Gp6Uart1Cts,
+ /// SPI Function alias for pin [crate::Pins::gpio6].
+ FunctionSpi: Gp6Spi0Sck,
+ /// I2C Function alias for pin [crate::Pins::gpio6].
+ FunctionI2C: Gp6I2C1Sda,
+ /// PWM Function alias for pin [crate::Pins::gpio6].
+ FunctionPwm: Gp6Pwm3A,
+ /// PIO0 Function alias for pin [crate::Pins::gpio6].
+ FunctionPio0: Gp6Pio0,
+ /// PIO1 Function alias for pin [crate::Pins::gpio6].
+ FunctionPio1: Gp6Pio1
+ }
+ },
+
+ /// GPIO 7 supports following functions:
+ ///
+ /// | Function | Alias with applied function |
+ /// |--------------|-----------------------------|
+ /// | `SPI0 TX` | [crate::Gp7Spi0Tx] |
+ /// | `UART1 RTS` | [crate::Gp7Uart1Rts] |
+ /// | `I2C1 SCL` | [crate::Gp7I2C1Scl] |
+ /// | `PWM3 B` | [crate::Gp7Pwm3B] |
+ /// | `PIO0` | [crate::Gp7Pio0] |
+ /// | `PIO1` | [crate::Gp7Pio1] |
+ Gpio7 {
+ name: led,
+ aliases: {
+ /// UART Function alias for pin [crate::Pins::led].
+ FunctionUart: Gp7Uart1Rts,
+ /// SPI Function alias for pin [crate::Pins::led].
+ FunctionSpi: Gp7Spi0Tx,
+ /// I2C Function alias for pin [crate::Pins::led].
+ FunctionI2C: Gp7I2C1Scl,
+ /// PWM Function alias for pin [crate::Pins::led].
+ FunctionPwm: Gp7Pwm3B,
+ /// PIO0 Function alias for pin [crate::Pins::led].
+ FunctionPio0: Gp7Pio0,
+ /// PIO1 Function alias for pin [crate::Pins::led].
+ FunctionPio1: Gp7Pio1
+ }
+ },
+
+ /// GPIO 8 is connected to keyboard column 9
+ Gpio8 {
+ name: kb_c9
+ },
+
+ /// GPIO 9 is connected to keyboard column 8
+ Gpio9 {
+ name: kb_c8
+ },
+
+ /// GPIO 10 is connected to keyboard :
+ Gpio10 {
+ name: kb_c7,
+ },
+
+ /// GPIO 11 is connected to keyboard :
+ Gpio11 {
+ name: kb_c6,
+ },
+
+ /// GPIO 12 is connected to keyboard :
+ Gpio12 {
+ name: kb_c5,
+ },
+
+ /// GPIO 13 is connected to keyboard :
+ Gpio13 {
+ name: kb_c4,
+ },
+
+ /// GPIO 14 is connected to keyboard :
+ Gpio14 {
+ name: kb_c3,
+ },
+
+ /// GPIO 15 is connected to keyboard :
+ Gpio15 {
+ name: kb_c2,
+ },
+
+ /// GPIO 16 is connected to keyboard :
+ Gpio16 {
+ name: kb_c1,
+ },
+
+ /// GPIO 17 is connected to keyboard :
+ Gpio17 {
+ name: kb_r9,
+ },
+
+ /// GPIO 18 is connected to keyboard :
+ Gpio18 {
+ name: kb_r8,
+ },
+
+ /// GPIO 19 is connected to keyboard :
+ Gpio19 {
+ name: kb_r7,
+ },
+
+ /// GPIO 20 is connected to keyboard :
+ Gpio20 {
+ name: kb_r6,
+ },
+
+ /// GPIO 21 is connected to keyboard :
+ Gpio21 {
+ name: kb_r5,
+ },
+
+ /// GPIO 22 is connected to keyboard :
+ Gpio22 {
+ name: kb_r4,
+ },
+
+ /// GPIO 23 is connected to keyboard row 3
+ Gpio23 {
+ name: kb_r3,
+ },
+
+ /// GPIO 24 is connected to keyboard row 2
+ Gpio24 {
+ name: kb_r2,
+ },
+
+ /// GPIO 25 is connected to keyboard row 1
+ Gpio25 {
+ name: kb_r1,
+ },
+
+ /// GPIO 26 supports following functions:
+ ///
+ /// | Function | Alias with applied function |
+ /// |--------------|-----------------------------|
+ /// | `SPI1 SCK` | [crate::Gp26Spi1Sck] |
+ /// | `UART1 CTS` | [crate::Gp26Uart1Cts] |
+ /// | `I2C1 SDA` | [crate::Gp26I2C1Sda] |
+ /// | `PWM5 A` | [crate::Gp26Pwm5A] |
+ /// | `PIO0` | [crate::Gp26Pio0] |
+ /// | `PIO1` | [crate::Gp26Pio1] |
+ Gpio26 {
+ name: gpio26,
+ aliases: {
+ /// UART Function alias for pin [crate::Pins::gpio26].
+ FunctionUart: Gp26Uart1Cts,
+ /// SPI Function alias for pin [crate::Pins::gpio26].
+ FunctionSpi: Gp26Spi1Sck,
+ /// I2C Function alias for pin [crate::Pins::gpio26].
+ FunctionI2C: Gp26I2C1Sda,
+ /// PWM Function alias for pin [crate::Pins::gpio26].
+ FunctionPwm: Gp26Pwm5A,
+ /// PIO0 Function alias for pin [crate::Pins::gpio26].
+ FunctionPio0: Gp26Pio0,
+ /// PIO1 Function alias for pin [crate::Pins::gpio26].
+ FunctionPio1: Gp26Pio1
+ }
+ },
+
+ /// GPIO 27 supports following functions:
+ ///
+ /// | Function | Alias with applied function |
+ /// |--------------|-----------------------------|
+ /// | `SPI1 TX` | [crate::Gp27Spi1Tx] |
+ /// | `UART1 RTS` | [crate::Gp27Uart1Rts] |
+ /// | `I2C1 SCL` | [crate::Gp27I2C1Scl] |
+ /// | `PWM5 B` | [crate::Gp27Pwm5B] |
+ /// | `PIO0` | [crate::Gp27Pio0] |
+ /// | `PIO1` | [crate::Gp27Pio1] |
+ Gpio27 {
+ name: gpio27,
+ aliases: {
+ /// UART Function alias for pin [crate::Pins::gpio27].
+ FunctionUart: Gp27Uart1Rts,
+ /// SPI Function alias for pin [crate::Pins::gpio27].
+ FunctionSpi: Gp27Spi1Tx,
+ /// I2C Function alias for pin [crate::Pins::gpio27].
+ FunctionI2C: Gp27I2C1Scl,
+ /// PWM Function alias for pin [crate::Pins::gpio27].
+ FunctionPwm: Gp27Pwm5B,
+ /// PIO0 Function alias for pin [crate::Pins::gpio27].
+ FunctionPio0: Gp27Pio0,
+ /// PIO1 Function alias for pin [crate::Pins::gpio27].
+ FunctionPio1: Gp27Pio1
+ }
+ },
+
+ /// GPIO 28 supports following functions:
+ ///
+ /// | Function | Alias with applied function |
+ /// |--------------|-----------------------------|
+ /// | `SPI1 RX` | [crate::Gp28Spi1Rx] |
+ /// | `UART0 TX` | [crate::Gp28Uart0Tx] |
+ /// | `I2C0 SDA` | [crate::Gp28I2C0Sda] |
+ /// | `PWM6 A` | [crate::Gp28Pwm6A] |
+ /// | `PIO0` | [crate::Gp28Pio0] |
+ /// | `PIO1` | [crate::Gp28Pio1] |
+ Gpio28 {
+ name: gpio28,
+ aliases: {
+ /// UART Function alias for pin [crate::Pins::gpio28].
+ FunctionUart: Gp28Uart0Tx,
+ /// SPI Function alias for pin [crate::Pins::gpio28].
+ FunctionSpi: Gp28Spi1Rx,
+ /// I2C Function alias for pin [crate::Pins::gpio28].
+ FunctionI2C: Gp28I2C0Sda,
+ /// PWM Function alias for pin [crate::Pins::gpio28].
+ FunctionPwm: Gp28Pwm6A,
+ /// PIO0 Function alias for pin [crate::Pins::gpio28].
+ FunctionPio0: Gp28Pio0,
+ /// PIO1 Function alias for pin [crate::Pins::gpio28].
+ FunctionPio1: Gp28Pio1
+ }
+ },
+
+ /// GPIO 29 supports following functions
+ ///
+ /// | Function | Alias with applied function |
+ /// |--------------|-----------------------------|
+ /// | `SPI1 RX` | [crate::Gp29Spi1Rx] |
+ /// | `UART0 TX` | [crate::Gp29Uart0Tx] |
+ /// | `I2C0 SDA` | [crate::Gp29I2C0Sda] |
+ /// | `PWM6 A` | [crate::Gp29Pwm6A] |
+ /// | `PIO0` | [crate::Gp29Pio0] |
+ /// | `PIO1` | [crate::Gp29Pio1] |
+ Gpio29 {
+ name: gpio29,
+ aliases: {
+ /// UART Function alias for pin [crate::Pins::gpio29].
+ FunctionUart: Gp29Uart0Tx,
+ /// SPI Function alias for pin [crate::Pins::gpio29].
+ FunctionSpi: Gp29Spi1Rx,
+ /// I2C Function alias for pin [crate::Pins::gpio29].
+ FunctionI2C: Gp29I2C0Sda,
+ /// PWM Function alias for pin [crate::Pins::gpio29].
+ FunctionPwm: Gp29Pwm6A,
+ /// PIO0 Function alias for pin [crate::Pins::gpio29].
+ FunctionPio0: Gp29Pio0,
+ /// PIO1 Function alias for pin [crate::Pins::gpio29].
+ FunctionPio1: Gp29Pio1
+ }
+ },
+);
+
+pub const XOSC_CRYSTAL_FREQ: u32 = 12_000_000;