diff --git a/.cargo/config b/.cargo/config index 55974e3..6486a00 100644 --- a/.cargo/config +++ b/.cargo/config @@ -10,3 +10,4 @@ rustflags = [ "-C", "no-vectorize-loops", ] runner = "elf2uf2-rs -d" +# runner = "probe-run-rp --chip RP2040" diff --git a/README.md b/README.md index 808656a..5c30850 100644 --- a/README.md +++ b/README.md @@ -8,26 +8,26 @@

rp-hal

- A Rust HAL and board support packages for the RP family of microcontrollers from the Raspberry Pi Foundation + Rust support for the "Raspberry Silicon" family of microcontrollers
- Explore the docs » + Explore the API docs »

- View Demo + View Demos · - Report Bug + Report a Bug · - Request Feature + Chat on Matrix

-

Table of Contents

    -
  1. Packages
  2. +
  3. Getting Started
  4. +
  5. Programming
  6. Roadmap
  7. Contributing
  8. License
  9. @@ -37,6 +37,45 @@
+ +## Getting Started + +So, you want to program your new Raspberry Silicon microcontroller, using the +Rust programming language. You've come to the right place! + +This repository is `rp-hal` - a collection of high-level drivers for the +Raspberry Silicon RP2040 microcontroller and various associated boards, like +the Raspberry Pi Pico and the Adafruit Feather RP2040. + +If you want to write an application for Raspberry Silicon, check out our +[RP2040 Project Template](https://github.com/rp-rs/rp2040-project-template). + +If you want to write code that uses the Raspberry Silicon PIO State Machines, +check out [pio-rs](https://github.com/rp-rs/pio-rs). You can even compile PIO +programs at run-time, on the RP2040 itself! + +If you want to try out some examples on one of our supported boards, check out +the list of *Board Support Packages* below, and click through to see the various +examples for each board. + +Before trying any of the examples, please ensure you have the latest stable +version of Rust installed, along with the right target support: + +```sh +rustup self update +rustup update stable +rustup target add thumbv6m-none-eabi +``` + +You may also want to install these helpful tools: + +```sh +# Useful to creating UF2 images for the RP2040 USB Bootloader +cargo install elf2uf2-rs +# Useful for flashing over the SWD pins using a supported JTAG probe +cargo install --git https://github.com/rp-rs/probe-run.git --branch rp2040-support +``` + ## Packages This git repository is organised as a [Cargo Workspace]. @@ -52,16 +91,16 @@ crate (which will include the _HAL_ crate for you). Please note, you cannot depend on multiple _BSP_ crates; you have to pick one, or use [Cargo Features] to select one at build time. -Each BSP will include some examples to show off the features of that particular board. +Each BSP includes some examples to show off the features of that particular board. [Cargo Workspace]: https://doc.rust-lang.org/cargo/reference/workspaces.html] [Embedded HAL]: https://github.com/rust-embedded/embedded-hal [Cargo Features]: https://doc.rust-lang.org/cargo/reference/features.html -### [rp2040-hal] - The HAL for the [Raspberry Pi Silicon RP2040] +### [rp2040-hal] - The HAL for the [Raspberry Silicon RP2040] You should include this crate in your project if you want to write a driver or -library that runs on the [Raspberry Pi Silicon RP2040], or if you are writing a Board +library that runs on the [Raspberry Silicon RP2040], or if you are writing a Board Support Package (see later on). The crate provides high-level drivers for the RP2040's internal peripherals, @@ -74,7 +113,7 @@ There are examples in this crate to show how to use various peripherals particular board. [rp2040-hal]: https://github.com/rp-rs/rp-hal/tree/main/rp2040-hal -[Raspberry Pi Silicon RP2040]: https://www.raspberrypi.org/products/rp2040/ +[Raspberry Silicon RP2040]: https://www.raspberrypi.org/products/rp2040/ ### [pico] - Board Support for the [Raspberry Pi Pico] @@ -147,12 +186,130 @@ RP2040 chip according to how it is connected up on the Pro Micro RP2040. [Sparkfun Pro Micro RP2040]: https://www.sparkfun.com/products/18288 [pro_micro_rp2040]: https://github.com/rp-rs/rp-hal/tree/main/boards/pro_micro_rp2040 + +## Programming + +Rust generates standard Arm ELF files, which you can load onto your Raspberry Pi +Silicon device with your favourite Arm flashing/debugging tool. In addition, the +RP2040 contains a ROM bootloader which appears as a Mass Storage Device over USB +that accepts UF2 format images. You can use the `elf2uf2-rs` package to convert +the Arm ELF file to a UF2 format image. + +For boards with USB Device support like the Raspberry Pi Pico, we recommend you +use the UF2 process. + +The RP2040 contains two Cortex-M0+ processors, which execute Thumb-2 encoded +ARMv6-M instructions. There are no operating-specific features in the binaries +produced - they are for 'bare-metal' systems. For compatibilty with other Arm +code (e.g. as produced by GCC), Rust uses the *Arm Embedded-Application Binary +Interface* standard or EABI. Therefore, any Rust code for the RP2040 should be +compiled with the target *`thumbv6m-none-eabi`*. + +More details can be found in the [Project Template](https://github.com/rp-rs/rp2040-project-template). + +### Loading a UF2 over USB + +*Step 1* - Install [`elf2uf2-rs`](https://github.com/JoNil/elf2uf2-rs): + +```console +$ cargo install elf2uf2-rs +``` + +*Step 2* - Make sure your .cargo/config contains the following (it should by +default if you are working in this repository): + +```toml +[target.thumbv6m-none-eabi] +runner = "elf2uf2-rs -d" +``` + +The `thumbv6m-none-eabi` target may be replaced by the all-Arm wildcard +`'cfg(all(target_arch = "arm", target_os = "none"))'`. + +*Step 3* - Boot your RP2040 into "USB Bootloader mode", typically by rebooting +whilst holding some kind of "Boot Select" button. On Linux, you will also need +to 'mount' the device, like you would a USB Thumb Drive. + +*Step 4* - Use `cargo run`, which will compile the code and started the +specified 'runner'. As the 'runner' is the elf2uf2-rs tool, it will build a UF2 +file and copy it to your RP2040. + +```console +$ cargo run --release --example pico_pwm_blink +``` + +### Loading with probe-run + +The Knurling project has a tool called +[probe-run](https://github.com/knurling-rs/probe-run). This is a command-line +tool which can flash a wide variety of microcontrollers using a wide variety of +debug/JTAG probes. It is based on a library called +[probe-rs](https://github.com/probe-rs/probe-rs). Unlike using, say, OpenOCD, +probe-rs can autodetect your debug probe, which can make it easier to use. + +Currently, probe-rs supports the slightly unusual debug hardware in the RP2040, +but the last released probe-run tool (v0.2.6, as of September 2021), does not. +However, there is a special version of probe-run for the RP2040 called +[probe-run-rp](https://github.com/rp-rs/probe-run/tree/rp2040-support). + +*Step 1* - Install `probe-run-rp`: + +```console +$ cargo install --git https://github.com/rp-rs/probe-run.git --branch rp2040-support +``` + +*Step 2* - Make sure your .cargo/config contains the following: + +```toml +[target.thumbv6m-none-eabi] +runner = "probe-run-rp --chip RP2040" +``` + +*Step 3* - Connect your USB JTAG/debug probe (such as a Raspberry Pi Pico +running [this firmware](https://github.com/majbthrd/DapperMime)) to the SWD +programming pins on your RP2040 board. Check the probe has been found by +running: + +```console +$ probe-run-rp --chip RP2040 --list-probes +The following devices were found: +[0]: J-Link (J-Link) (VID: 1366, PID: 0101, Serial: 000099999999, JLink) +``` + +There is a SEGGER J-Link connected in the example above - the mesage you see +will reflect the probe you have connected. + +*Step 4* - Use `cargo run`, which will compile the code and start the specified +'runner'. As the 'runner' is the `probe-run-rp` tool, it will connect to the +RP2040 via the first probe it finds, and install your firmware into the Flash +connected to the RP2040. + +```console +$ cargo run --release --example pico_pwm_blink +``` + +### Loading with picotool + +As ELF files produced by compiling Rust code are completely compatible with ELF +files produced by compiling C or C++ code, you can also use the Raspberry Pi +tool [picoprobe](https://github.com/raspberrypi/picotool). The only thing to be +aware of is that picotool expects your ELF files to have a `.elf` extension, and +by default Rust does not give the ELF files any extension. You can fix this by +simply renaming the file. + +Also of note is that the special +[pico-sdk](https://github.com/raspberrypi/pico-sdk) macros which hide +information in the ELF file in a way that `picotool info` can read it out, are +not supported in Rust. An alternative is TBC. + ## Roadmap -NOTE These packages are under active development. As such, it is likely to remain volatile until a 1.0.0 release. +NOTE These packages are under active development. As such, it is likely to +remain volatile until a 1.0.0 release. -See the [open issues](https://github.com/rp-rs/rp-hal/issues) for a list of proposed features (and known issues). +See the [open issues](https://github.com/rp-rs/rp-hal/issues) for a list of +proposed features (and known issues). @@ -195,9 +352,8 @@ under these terms. ## Contact -Project Link: [https://github.com/rp-rs/rp-hal/issues](https://github.com/rp-rs/rp-hal/issues) -Matrix: [#rp-rs:matrix.org](https://matrix.to/#/#rp-rs:matrix.org) - +Raise an issue: [https://github.com/rp-rs/rp-hal/issues](https://github.com/rp-rs/rp-hal/issues) +Chat to us on Matrix: [#rp-rs:matrix.org](https://matrix.to/#/#rp-rs:matrix.org) ## Acknowledgements diff --git a/boards/adafruit_macropad/README.md b/boards/adafruit_macropad/README.md index dc2bdd9..b5875dd 100644 --- a/boards/adafruit_macropad/README.md +++ b/boards/adafruit_macropad/README.md @@ -9,7 +9,7 @@ RP2040 chip according to how it is connected up on the Feather. [adafruit_macropad]: https://github.com/rp-rs/rp-hal/tree/main/boards/adafruit_macropad [Adafruit Macropad]: https://www.adafruit.com/product/5128 [rp2040-hal]: https://github.com/rp-rs/rp-hal/tree/main/rp2040-hal -[Raspberry Pi Silicon RP2040]: https://www.raspberrypi.org/products/rp2040/ +[Raspberry Silicon RP2040]: https://www.raspberrypi.org/products/rp2040/ ## Using diff --git a/boards/feather_rp2040/README.md b/boards/feather_rp2040/README.md index 42833e1..76f9173 100644 --- a/boards/feather_rp2040/README.md +++ b/boards/feather_rp2040/README.md @@ -9,7 +9,7 @@ RP2040 chip according to how it is connected up on the Feather. [Adafruit Feather RP2040]: https://www.adafruit.com/product/4884 [feather_rp2040]: https://github.com/rp-rs/rp-hal/tree/main/boards/feather_rp2040 [rp2040-hal]: https://github.com/rp-rs/rp-hal/tree/main/rp2040-hal -[Raspberry Pi Silicon RP2040]: https://www.raspberrypi.org/products/rp2040/ +[Raspberry Silicon RP2040]: https://www.raspberrypi.org/products/rp2040/ ## Using diff --git a/boards/pico/README.md b/boards/pico/README.md index 2ab637d..5470fb4 100644 --- a/boards/pico/README.md +++ b/boards/pico/README.md @@ -9,7 +9,7 @@ RP2040 chip according to how it is connected up on the Pico. [Raspberry Pi Pico]: https://www.raspberrypi.org/products/raspberry-pi-pico/ [pico]: https://github.com/rp-rs/rp-hal/tree/main/boards/pico [rp2040-hal]: https://github.com/rp-rs/rp-hal/tree/main/rp2040-hal -[Raspberry Pi Silicon RP2040]: https://www.raspberrypi.org/products/rp2040/ +[Raspberry Silicon RP2040]: https://www.raspberrypi.org/products/rp2040/ ## Using diff --git a/boards/pico/examples/pico_blinky.rs b/boards/pico/examples/pico_blinky.rs index 7bb82ee..2970ee5 100644 --- a/boards/pico/examples/pico_blinky.rs +++ b/boards/pico/examples/pico_blinky.rs @@ -34,8 +34,8 @@ use pico::hal::pac; // higher-level drivers. use pico::hal; -/// 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. +//// 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. #[link_section = ".boot2"] #[used] pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; @@ -58,7 +58,7 @@ fn main() -> ! { // Configure the clocks // - // Our default is 12 MHz crystal input, 125 MHz system clock + // The default is to generate a 125 MHz system clock let clocks = hal::clocks::init_clocks_and_plls( pico::XOSC_CRYSTAL_FREQ, pac.XOSC, diff --git a/boards/pico/examples/pico_countdown_blinky.rs b/boards/pico/examples/pico_countdown_blinky.rs index cb4a13d..f6a3ea7 100644 --- a/boards/pico/examples/pico_countdown_blinky.rs +++ b/boards/pico/examples/pico_countdown_blinky.rs @@ -47,7 +47,7 @@ fn main() -> ! { // Configure the clocks // - // Our default is 12 MHz crystal input, 125 MHz system clock + // The default is to generate a 125 MHz system clock let _clocks = hal::clocks::init_clocks_and_plls( pico::XOSC_CRYSTAL_FREQ, pac.XOSC, diff --git a/boards/pico/examples/pico_gpio_in_out.rs b/boards/pico/examples/pico_gpio_in_out.rs index d2c446e..81d1c9b 100644 --- a/boards/pico/examples/pico_gpio_in_out.rs +++ b/boards/pico/examples/pico_gpio_in_out.rs @@ -30,8 +30,8 @@ use pico::hal::pac; // higher-level drivers. use pico::hal; -/// 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. +//// 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. #[link_section = ".boot2"] #[used] pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; diff --git a/boards/pico/examples/pico_pwm_blink.rs b/boards/pico/examples/pico_pwm_blink.rs index 9bd1eb5..16b48f8 100644 --- a/boards/pico/examples/pico_pwm_blink.rs +++ b/boards/pico/examples/pico_pwm_blink.rs @@ -34,8 +34,8 @@ use pico::hal::pac; // higher-level drivers. use pico::hal; -/// 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. +//// 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. #[link_section = ".boot2"] #[used] pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; @@ -64,7 +64,7 @@ fn main() -> ! { // Configure the clocks // - // Our default is 12 MHz crystal input, 125 MHz system clock + // The default is to generate a 125 MHz system clock let clocks = hal::clocks::init_clocks_and_plls( pico::XOSC_CRYSTAL_FREQ, pac.XOSC, diff --git a/boards/pico/examples/pico_usb_serial.rs b/boards/pico/examples/pico_usb_serial.rs index 8a69aed..2732da2 100644 --- a/boards/pico/examples/pico_usb_serial.rs +++ b/boards/pico/examples/pico_usb_serial.rs @@ -33,8 +33,8 @@ use usb_device::{class_prelude::*, prelude::*}; // USB Communications Class Device support use usbd_serial::SerialPort; -/// 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. +//// 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. #[link_section = ".boot2"] #[used] pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; @@ -56,7 +56,7 @@ fn main() -> ! { // Configure the clocks // - // Our default is 12 MHz crystal input, 125 MHz system clock + // The default is to generate a 125 MHz system clock let clocks = hal::clocks::init_clocks_and_plls( pico::XOSC_CRYSTAL_FREQ, pac.XOSC, diff --git a/boards/pico/examples/pico_usb_serial_interrupt.rs b/boards/pico/examples/pico_usb_serial_interrupt.rs index 6d9fd5c..e5b8fe6 100644 --- a/boards/pico/examples/pico_usb_serial_interrupt.rs +++ b/boards/pico/examples/pico_usb_serial_interrupt.rs @@ -45,8 +45,8 @@ use usb_device::{class_prelude::*, prelude::*}; // USB Communications Class Device support use usbd_serial::SerialPort; -/// 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. +//// 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. #[link_section = ".boot2"] #[used] pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; @@ -78,7 +78,7 @@ fn main() -> ! { // Configure the clocks // - // Our default is 12 MHz crystal input, 125 MHz system clock + // The default is to generate a 125 MHz system clock let clocks = hal::clocks::init_clocks_and_plls( pico::XOSC_CRYSTAL_FREQ, pac.XOSC, diff --git a/boards/pico/examples/pico_usb_twitchy_mouse.rs b/boards/pico/examples/pico_usb_twitchy_mouse.rs index 0215bf3..76fff72 100644 --- a/boards/pico/examples/pico_usb_twitchy_mouse.rs +++ b/boards/pico/examples/pico_usb_twitchy_mouse.rs @@ -44,8 +44,8 @@ use usbd_hid::descriptor::generator_prelude::*; use usbd_hid::descriptor::MouseReport; use usbd_hid::hid_class::HIDClass; -/// 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. +//// 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. #[link_section = ".boot2"] #[used] pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; @@ -76,7 +76,7 @@ fn main() -> ! { // Configure the clocks // - // Our default is 12 MHz crystal input, 125 MHz system clock + // The default is to generate a 125 MHz system clock let clocks = hal::clocks::init_clocks_and_plls( pico::XOSC_CRYSTAL_FREQ, pac.XOSC, diff --git a/boards/pico_explorer/README.md b/boards/pico_explorer/README.md index c9167d2..25e99e1 100644 --- a/boards/pico_explorer/README.md +++ b/boards/pico_explorer/README.md @@ -10,7 +10,7 @@ RP2040 chip according to how it is connected up on the Pico Explorer. [Pimoroni Pico Explorer]: https://shop.pimoroni.com/products/pico-explorer-base [pico_explorer]: https://github.com/rp-rs/rp-hal/tree/main/boards/pico_explorer [rp2040-hal]: https://github.com/rp-rs/rp-hal/tree/main/rp2040-hal -[Raspberry Pi Silicon RP2040]: https://www.raspberrypi.org/products/rp2040/ +[Raspberry Silicon RP2040]: https://www.raspberrypi.org/products/rp2040/ ## Using diff --git a/boards/pico_lipo_16mb/examples/pico_lipo_16mb_blinky.rs b/boards/pico_lipo_16mb/examples/pico_lipo_16mb_blinky.rs index 0fc65f5..b5e4318 100644 --- a/boards/pico_lipo_16mb/examples/pico_lipo_16mb_blinky.rs +++ b/boards/pico_lipo_16mb/examples/pico_lipo_16mb_blinky.rs @@ -34,8 +34,8 @@ use pico_lipo_16_mb::hal::pac; // higher-level drivers. use pico_lipo_16_mb::hal; -/// 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. +//// 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. #[link_section = ".boot2"] #[used] pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; @@ -58,7 +58,7 @@ fn main() -> ! { // Configure the clocks // - // Our default is 12 MHz crystal input, 125 MHz system clock + // The default is to generate a 125 MHz system clock let clocks = hal::clocks::init_clocks_and_plls( pico_lipo_16_mb::XOSC_CRYSTAL_FREQ, pac.XOSC, diff --git a/boards/pro_micro_rp2040/README.md b/boards/pro_micro_rp2040/README.md index 40ad916..60abd8c 100644 --- a/boards/pro_micro_rp2040/README.md +++ b/boards/pro_micro_rp2040/README.md @@ -1,7 +1,7 @@ # [pro_micro_rp2040] - Board Support for the [Sparkfun Pro Micro RP2040] You should include this crate if you are writing code that you want to run on -a [Sparkfun Pro Micro RP2040] - a smaller [RP2040][Raspberry Pi Silicon RP2040] board with USB-C and a WS2812B addressable LED. +a [Sparkfun Pro Micro RP2040] - a smaller [RP2040][Raspberry Silicon RP2040] board with USB-C and a WS2812B addressable LED. This crate includes the [rp2040-hal], but also configures each pin of the RP2040 chip according to how it is connected up on the Pro Micro RP2040. @@ -9,7 +9,7 @@ RP2040 chip according to how it is connected up on the Pro Micro RP2040. [Sparkfun Pro Micro RP2040]: https://www.sparkfun.com/products/18288 [pro_micro_rp2040]: https://github.com/rp-rs/rp-hal/tree/main/boards/pro_micro_rp2040 [rp2040-hal]: https://github.com/rp-rs/rp-hal/tree/main/rp2040-hal -[Raspberry Pi Silicon RP2040]: https://www.raspberrypi.org/products/rp2040/ +[Raspberry Silicon RP2040]: https://www.raspberrypi.org/products/rp2040/ ## Using diff --git a/boards/pro_micro_rp2040/examples/pro_micro_rainbow.rs b/boards/pro_micro_rp2040/examples/pro_micro_rainbow.rs index f84a296..dd9a094 100644 --- a/boards/pro_micro_rp2040/examples/pro_micro_rainbow.rs +++ b/boards/pro_micro_rp2040/examples/pro_micro_rainbow.rs @@ -28,7 +28,7 @@ use pro_micro_rp2040::{ use smart_leds::{brightness, SmartLedsWrite, RGB8}; use ws2812_pio::Ws2812; -/// The linker will place this boot block at the start of our program image. +//// 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. #[link_section = ".boot2"] #[used] @@ -80,7 +80,7 @@ fn main() -> ! { 25, pac.PIO0, &mut pac.RESETS, - clocks.system_clock.freq(), + clocks.peripheral_clock.freq(), timer.count_down(), ); diff --git a/rp2040-hal/README.md b/rp2040-hal/README.md index b5d1a0b..bdc4e66 100644 --- a/rp2040-hal/README.md +++ b/rp2040-hal/README.md @@ -8,16 +8,16 @@

rp-hal

- A Rust HAL impl for the RP family of microcontrollers from the Raspberry Pi Foundation + High-level Rust drivers for the Raspberry Silicon RP2040 Microcontroller
- Explore the docs » + Explore the API docs »

- View Demo + View Demos · - Report Bug + Report a Bug · - Request Feature + Chat on Matrix

@@ -27,6 +27,7 @@

Table of Contents

    +
  1. Introduction
  2. Getting Started
  3. -
  4. Usage
  5. Roadmap
  6. Contributing
  7. License
  8. @@ -43,70 +43,60 @@
+ +## Introduction + +This is the `rp2040-hal` package - a library crate of high-level Rust drivers +for the Raspberry Silicon RP2040 microcontroller, along with a collection of +non-board specific example programs for you to study. You should use this crate +in your application if you want to write code for the RP2040 microcontroller. +The *HAL* in the name standards for *Hardware Abstraction Layer*, and comes from +the fact that many of the drivers included implement the generic +hardware-abstraction interfaces defined in the Rust Embedded Working Group's +[embedded-hal](https://github.com/rust-embedded/embedded-hal) crate. + +We also provide a series of *Board Support Package* (BSP) crates, which take +this HAL crate and pre-configure the pins according to a specific PCB design. If +you are using on of the supported boards, you should use one of those crates in +preference, and return here to see documentation about specific peripherals on +the RP2040 and how to use them. See the `boards` folder in +https://github.com/rp-rs/rp-hal/ for more details. + ## Getting Started -To get a local copy up and running follow these simple steps. - -### Prerequisites - -* A [Rust](https://www.rust-lang.org/tools/install) toolchain - -### Installation - -1. Clone the repo or use the crate - - ```sh - git clone https://github.com/rp-rs/rp-hal - ``` - - or - - ```sh - cargo install rp2040-hal - ``` - - -## Usage - -Use this space to show useful examples of how a project can be used. Additional screenshots, code examples and demos work well in this space. You may also link to more resources. - -For more examples, please refer to the [Documentation](https://github.com/rp-rs/rp-hal) - -### Run examples - -#### UF2 - -For boards with uf2 flashloaders like the raspberry pi pico. Install [`elf2uf2-rs`](https://github.com/JoNil/elf2uf2-rs): - -```sh -cargo install elf2uf2-rs -``` - -Make sure .cargo/config contains the following (it should by default): +To include this crate in your project, amend your `Cargo.toml` file to include ```toml -runner = "elf2uf2-rs -d" +rp2040-hal = "0.3" ``` -**IMPORTANT: Make sure you've put your device into bootloader mode and the drive is showing as mounted before executing the next command.** +To obtain a copy of the source code (e.g. if you want to propose a bug-fix or +new feature, or simply to study the code), run: -```sh -cargo run --example pico_pwm_blink # Run `cargo run --example` for more examples +```console +$ git clone https://github.com/rp-rs/rp-hal.git ``` +For details on how to program an RP2040 microcontroller, see the [top-level +rp-hal README](https://github.com/rp-rs/rp-hal/). + ## Roadmap -NOTE This HAL is under active development. As such, it is likely to remain volatile until a 1.0.0 release. +NOTE This HAL is under active development. As such, it is likely to remain +volatile until a 1.0.0 release. -See the [open issues](https://github.com/rp-rs/rp-hal/issues) for a list of proposed features (and known issues). +See the [open issues](https://github.com/rp-rs/rp-hal/issues) for a list of +proposed features (and known issues). ## 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**. +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**. 1. Fork the Project 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`) diff --git a/rp2040-hal/examples/adc.rs b/rp2040-hal/examples/adc.rs index 7fb720a..88809d1 100644 --- a/rp2040-hal/examples/adc.rs +++ b/rp2040-hal/examples/adc.rs @@ -1,40 +1,63 @@ -//! Read ADC samples from the temperature sensor and pin and -//! output them to the UART on pins 1 and 2 at 9600 baud +//! # ADC Example +//! +//! This application demonstrates how to read ADC samples from the temperature +//! sensor and pin and output them to the UART on pins 1 and 2 at 9600 baud. +//! +//! It may need to be adapted to your particular board layout and/or pin assignment. +//! +//! See the `Cargo.toml` file for Copyright and licence details. + #![no_std] #![no_main] -use core::fmt::Write; -use cortex_m::prelude::_embedded_hal_adc_OneShot; +// The macro for our start-up function use cortex_m_rt::entry; -use hal::adc::Adc; -use hal::clocks::init_clocks_and_plls; -use hal::gpio::{self, Pins}; -use hal::pac; -use hal::sio::Sio; -use hal::uart::UartPeripheral; -use hal::watchdog::Watchdog; + +// 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; +// Some traits we need +use core::fmt::Write; +use embedded_hal::adc::OneShot; +use embedded_time::fixed_point::FixedPoint; +use rp2040_hal::clocks::Clock; + +// A shorter alias for the Peripheral Access Crate, which provides low-level +// register access +use hal::pac; + +/// 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. #[link_section = ".boot2"] #[used] pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; -// External high-speed crystal on the pico board is 12Mhz -// Adjust if your board has a different frequency +/// External high-speed crystal on the Raspberry Pi Pico board is 12 MHz. Adjust +/// if your board has a different frequency const XTAL_FREQ_HZ: u32 = 12_000_000u32; -const SYS_FREQ_HZ: u32 = hal::pll::common_configs::PLL_SYS_125MHZ.vco_freq.0; +/// 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 prints the temperature +/// in an infinite loop. #[entry] fn main() -> ! { + // Grab our singleton objects let mut pac = pac::Peripherals::take().unwrap(); let core = pac::CorePeripherals::take().unwrap(); - let mut watchdog = Watchdog::new(pac.WATCHDOG); - let sio = Sio::new(pac.SIO); - // External high-speed crystal on the pico board is 12Mhz + // Set up the watchdog driver - needed by the clock setup code + let mut watchdog = hal::watchdog::Watchdog::new(pac.WATCHDOG); - let clocks = init_clocks_and_plls( + // Configure the clocks + let clocks = hal::clocks::init_clocks_and_plls( XTAL_FREQ_HZ, pac.XOSC, pac.CLOCKS, @@ -46,16 +69,23 @@ fn main() -> ! { .ok() .unwrap(); - let mut delay = cortex_m::delay::Delay::new(core.SYST, SYS_FREQ_HZ); + // 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().integer()); - let pins = Pins::new( + // The single-cycle I/O block controls our GPIO pins + let sio = hal::sio::Sio::new(pac.SIO); + + // Set the pins to their default state + let pins = hal::gpio::Pins::new( pac.IO_BANK0, pac.PADS_BANK0, sio.gpio_bank0, &mut pac.RESETS, ); - let mut uart = UartPeripheral::<_, _>::enable( + // Create a UART driver + let mut uart = hal::uart::UartPeripheral::<_, _>::enable( pac.UART0, &mut pac.RESETS, hal::uart::common_configs::_9600_8_N_1, @@ -64,14 +94,19 @@ fn main() -> ! { .unwrap(); // UART TX (characters sent from pico) on pin 1 (GPIO0) and RX (on pin 2 (GPIO1) - let _tx_pin = pins.gpio0.into_mode::(); - let _rx_pin = pins.gpio1.into_mode::(); + let _tx_pin = pins.gpio0.into_mode::(); + let _rx_pin = pins.gpio1.into_mode::(); + + // Write to the UART uart.write_full_blocking(b"ADC example\r\n"); - // Enable adc - let mut adc = Adc::new(pac.ADC, &mut pac.RESETS); + + // Enable ADC + let mut adc = hal::adc::Adc::new(pac.ADC, &mut pac.RESETS); + // Enable the temperature sense channel let mut temperature_sensor = adc.enable_temp_sensor(); - // Configure one of the pins as an ADC input as well. + + // Configure GPIO26 as an ADC input let mut adc_pin_0 = pins.gpio26.into_floating_input(); loop { // Read the raw ADC counts from the temperature sensor channel. @@ -86,3 +121,5 @@ fn main() -> ! { delay.delay_ms(1000); } } + +// End of file diff --git a/rp2040-hal/examples/blinky.rs b/rp2040-hal/examples/blinky.rs index c7a3806..6cf2f43 100644 --- a/rp2040-hal/examples/blinky.rs +++ b/rp2040-hal/examples/blinky.rs @@ -1,38 +1,94 @@ -//! Blinks the LED on a Pico board +//! # GPIO 'Blinky' Example //! -//! This will blink an LED attached to GP25, which is the pin the Pico uses for the on-board LED. +//! This application demonstrates how to control a GPIO pin on the RP2040. +//! +//! It may need to be adapted to your particular board layout and/or pin assignment. +//! +//! See the `Cargo.toml` file for Copyright and licence details. + #![no_std] #![no_main] +// The macro for our start-up function use cortex_m_rt::entry; -use embedded_hal::digital::v2::OutputPin; -use hal::pac; -use hal::sio::Sio; + +// 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; + +// Some traits we need +use embedded_hal::digital::v2::OutputPin; +use embedded_time::fixed_point::FixedPoint; +use rp2040_hal::clocks::Clock; + +/// 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. #[link_section = ".boot2"] #[used] pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; +/// External high-speed crystal on the Raspberry Pi Pico board is 12 MHz. Adjust +/// if your board has a different frequency +const XTAL_FREQ_HZ: u32 = 12_000_000u32; + +/// 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 toggles a GPIO pin in +/// an infinite loop. If there is an LED connected to that pin, it will blink. #[entry] fn main() -> ! { + // Grab our singleton objects let mut pac = pac::Peripherals::take().unwrap(); + let core = pac::CorePeripherals::take().unwrap(); - let sio = Sio::new(pac.SIO); + // Set up the watchdog driver - needed by the clock setup code + let mut watchdog = hal::watchdog::Watchdog::new(pac.WATCHDOG); + + // Configure the clocks + let clocks = hal::clocks::init_clocks_and_plls( + XTAL_FREQ_HZ, + pac.XOSC, + pac.CLOCKS, + pac.PLL_SYS, + pac.PLL_USB, + &mut pac.RESETS, + &mut watchdog, + ) + .ok() + .unwrap(); + + let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().integer()); + + // The single-cycle I/O block controls our GPIO pins + let sio = hal::sio::Sio::new(pac.SIO); + + // Set the pins to their default state let pins = hal::gpio::Pins::new( pac.IO_BANK0, pac.PADS_BANK0, sio.gpio_bank0, &mut pac.RESETS, ); - let mut led_pin = pins.gpio25.into_push_pull_output(); + // Configure GPIO25 as an output + let mut led_pin = pins.gpio25.into_push_pull_output(); loop { led_pin.set_high().unwrap(); // TODO: Replace with proper 1s delays once we have clocks working - cortex_m::asm::delay(500_000); + delay.delay_ms(500); led_pin.set_low().unwrap(); - cortex_m::asm::delay(500_000); + delay.delay_ms(500); } } + +// End of file diff --git a/rp2040-hal/examples/gpio_in_out.rs b/rp2040-hal/examples/gpio_in_out.rs index b25e9cb..f2aa738 100644 --- a/rp2040-hal/examples/gpio_in_out.rs +++ b/rp2040-hal/examples/gpio_in_out.rs @@ -1,41 +1,95 @@ -//! Toggle LED based on GPIO input +//! # GPIO 'Blinky' Example //! -//! This will control an LED on GP25 based on a button hooked up to GP15. The button should be tied -//! to ground, as the input pin is pulled high internally by this example. When the button is -//! pressed, the LED will turn off. +//! This application demonstrates how to control a GPIO pin on the RP2040. +//! +//! It may need to be adapted to your particular board layout and/or pin assignment. +//! +//! See the `Cargo.toml` file for Copyright and licence details. + #![no_std] #![no_main] +// The macro for our start-up function use cortex_m_rt::entry; -use embedded_hal::digital::v2::{InputPin, OutputPin}; -use hal::pac; -use hal::sio::Sio; + +// 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; + +// Some traits we need +use embedded_hal::digital::v2::InputPin; +use embedded_hal::digital::v2::OutputPin; + +/// 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. #[link_section = ".boot2"] #[used] pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; +/// External high-speed crystal on the Raspberry Pi Pico board is 12 MHz. Adjust +/// if your board has a different frequency +const XTAL_FREQ_HZ: u32 = 12_000_000u32; + +/// 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 toggles a GPIO pin in +/// an infinite loop. If there is an LED connected to that pin, it will blink. #[entry] fn main() -> ! { + // Grab our singleton objects let mut pac = pac::Peripherals::take().unwrap(); - let sio = Sio::new(pac.SIO); + // Set up the watchdog driver - needed by the clock setup code + let mut watchdog = hal::watchdog::Watchdog::new(pac.WATCHDOG); + + // Configure the clocks + let _clocks = hal::clocks::init_clocks_and_plls( + XTAL_FREQ_HZ, + 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::Sio::new(pac.SIO); + + // Set the pins to their default state let pins = hal::gpio::Pins::new( pac.IO_BANK0, pac.PADS_BANK0, sio.gpio_bank0, &mut pac.RESETS, ); - let mut led_pin = pins.gpio25.into_push_pull_output(); - let button_pin = pins.gpio23.into_pull_down_input(); + // Configure GPIO 25 as an output + let mut out_pin = pins.gpio25.into_push_pull_output(); + + // Configure GPIO 23 as an input + let in_pin = pins.gpio23.into_pull_down_input(); + + // Output is the opposite of the input loop { - if button_pin.is_low().unwrap() { - led_pin.set_high().unwrap(); + if in_pin.is_low().unwrap() { + out_pin.set_high().unwrap(); } else { - led_pin.set_low().unwrap(); + out_pin.set_low().unwrap(); } } } + +// End of file diff --git a/rp2040-hal/examples/i2c.rs b/rp2040-hal/examples/i2c.rs index 18c9f91..8d401fd 100644 --- a/rp2040-hal/examples/i2c.rs +++ b/rp2040-hal/examples/i2c.rs @@ -1,49 +1,106 @@ -//! Sends a message using i2c -#![no_std] -#![no_main] - -use cortex_m_rt::entry; -use embedded_hal::blocking::i2c::Write; -use embedded_time::rate::Extensions; -use hal::gpio::FunctionI2C; -use hal::i2c::I2C; -use hal::pac; -use hal::sio::Sio; -use panic_halt as _; -use rp2040_hal as hal; - -#[link_section = ".boot2"] -#[used] -pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; - -const SYS_HZ: u32 = 125_000_000_u32; - -#[entry] -fn main() -> ! { - let mut pac = pac::Peripherals::take().unwrap(); - - let sio = Sio::new(pac.SIO); - let pins = hal::gpio::Pins::new( - pac.IO_BANK0, - pac.PADS_BANK0, - sio.gpio_bank0, - &mut pac.RESETS, - ); - - let sda_pin = pins.gpio18.into_mode::(); - let scl_pin = pins.gpio19.into_mode::(); - - let mut i2c = I2C::i2c1( - pac.I2C1, - sda_pin, - scl_pin, - 400.kHz(), - &mut pac.RESETS, - SYS_HZ.Hz(), - ); - - i2c.write(0x2c, &[1, 2, 3]).unwrap(); - - #[allow(clippy::empty_loop)] - loop {} -} +//! # I²C Example +//! +//! This application demonstrates how to talk to I²C devices with an RP2040. +//! +//! It may need to be adapted to your particular board layout and/or pin assignment. +//! +//! See the `Cargo.toml` file for Copyright and licence details. + +#![no_std] +#![no_main] + +// The macro for our start-up function +use cortex_m_rt::entry; + +// Ensure we halt the program on panic (if we don't mention this crate it won't +// be linked) +use panic_halt as _; + +// Some traits we need +use embedded_hal::blocking::i2c::Write; +use embedded_time::rate::Extensions; + +// 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; + +/// 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. +#[link_section = ".boot2"] +#[used] +pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; + +/// External high-speed crystal on the Raspberry Pi Pico board is 12 MHz. Adjust +/// if your board has a different frequency +const XTAL_FREQ_HZ: u32 = 12_000_000u32; + +/// 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 performs a single I²C +/// write to a fixed address. +#[entry] +fn main() -> ! { + let mut pac = pac::Peripherals::take().unwrap(); + + // Set up the watchdog driver - needed by the clock setup code + let mut watchdog = hal::watchdog::Watchdog::new(pac.WATCHDOG); + + // Configure the clocks + let clocks = hal::clocks::init_clocks_and_plls( + XTAL_FREQ_HZ, + 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::Sio::new(pac.SIO); + + // Set the pins to their default state + let pins = hal::gpio::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.gpio18.into_mode::(); + let scl_pin = pins.gpio19.into_mode::(); + // let not_an_scl_pin = pins.gpio20.into_mode::(); + + // Create the I²C drive, 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 mut i2c = hal::i2c::I2C::i2c1( + pac.I2C1, + sda_pin, + scl_pin, // Try `not_an_scl_pin` here + 400.kHz(), + &mut pac.RESETS, + clocks.peripheral_clock, + ); + + // Write three bytes to the I²C device with 7-bit address 0x2C + i2c.write(0x2c, &[1, 2, 3]).unwrap(); + + // Demo finish - just loop until reset + + #[allow(clippy::empty_loop)] + loop { + // Empty loop + } +} + +// End of file diff --git a/rp2040-hal/examples/lcd_display.rs b/rp2040-hal/examples/lcd_display.rs index f508c55..bb9fe9c 100644 --- a/rp2040-hal/examples/lcd_display.rs +++ b/rp2040-hal/examples/lcd_display.rs @@ -1,26 +1,85 @@ +//! # 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. +//! +//! It drives the LCD by pushing data out of six GPIO pins. It may need to be +//! adapted to your particular board layout and/or pin assignment. +//! +//! See the `Cargo.toml` file for Copyright and licence details. + #![no_std] #![no_main] +// The macro for our start-up function use cortex_m_rt::entry; -use hal::pac; -use hal::sio::Sio; -use hd44780_driver as hd44780; + +// 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; +// Our LCD driver +use hd44780_driver as hd44780; + +// Some traits we need +use embedded_time::fixed_point::FixedPoint; +use rp2040_hal::clocks::Clock; + +// A shorter alias for the Peripheral Access Crate, which provides low-level +// register access +use hal::pac; + +/// 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. #[link_section = ".boot2"] #[used] pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; +/// External high-speed crystal on the Raspberry Pi Pico board is 12 MHz. Adjust +/// if your board has a different frequency +const XTAL_FREQ_HZ: u32 = 12_000_000u32; + +/// 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, writes to the LCD, then goes +/// to sleep. #[entry] fn main() -> ! { + // Grab our singleton objects let mut pac = pac::Peripherals::take().unwrap(); let core = pac::CorePeripherals::take().unwrap(); - // AHL bus speed default - let mut delay_provider = cortex_m::delay::Delay::new(core.SYST, 12_000_000); + // Set up the watchdog driver - needed by the clock setup code + let mut watchdog = hal::watchdog::Watchdog::new(pac.WATCHDOG); - let sio = Sio::new(pac.SIO); + // Configure the clocks + let clocks = hal::clocks::init_clocks_and_plls( + XTAL_FREQ_HZ, + 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().integer()); + + // The single-cycle I/O block controls our GPIO pins + let sio = hal::sio::Sio::new(pac.SIO); + + // Set the pins to their default state let pins = hal::gpio::Pins::new( pac.IO_BANK0, pac.PADS_BANK0, @@ -28,26 +87,36 @@ fn main() -> ! { &mut pac.RESETS, ); - let lcd = hd44780::HD44780::new_4bit( + // Create the LCD driver from some GPIO pins + let mut lcd = hd44780::HD44780::new_4bit( pins.gpio16.into_push_pull_output(), // Register Select pins.gpio17.into_push_pull_output(), // Enable pins.gpio18.into_push_pull_output(), // d4 pins.gpio19.into_push_pull_output(), // d5 pins.gpio20.into_push_pull_output(), // d6 pins.gpio21.into_push_pull_output(), // d7 - &mut delay_provider, - ); + &mut delay, + ) + .unwrap(); - let mut lcd = lcd.unwrap(); + // Clear the screen + lcd.reset(&mut delay).unwrap(); + lcd.clear(&mut delay).unwrap(); - lcd.reset(&mut delay_provider).unwrap(); - lcd.clear(&mut delay_provider).unwrap(); - lcd.write_str("rp-hal on", &mut delay_provider).unwrap(); - lcd.set_cursor_pos(40, &mut delay_provider).unwrap(); - lcd.set_cursor_visibility(hd44780::Cursor::Visible, &mut delay_provider) - .unwrap(); - lcd.write_str("HD44780!", &mut delay_provider).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(); + + // Do nothing - we're finished #[allow(clippy::empty_loop)] - loop {} + loop { + // Empty loop + } } + +// End of file diff --git a/rp2040-hal/examples/pwm_blink.rs b/rp2040-hal/examples/pwm_blink.rs index afd194a..ec81a68 100644 --- a/rp2040-hal/examples/pwm_blink.rs +++ b/rp2040-hal/examples/pwm_blink.rs @@ -1,43 +1,124 @@ +//! # PWM Blink Example +//! +//! If you have an LED connected to pin 25, it will fade the LED using the PWM +//! peripheral. +//! +//! It may need to be adapted to your particular board layout and/or pin assignment. +//! +//! See the `Cargo.toml` file for Copyright and licence details. + #![no_std] #![no_main] +// The macro for our start-up function use cortex_m_rt::entry; -use embedded_hal::PwmPin; -use panic_halt as _; -use rp2040_hal::{gpio::Pins, pwm::*, sio::Sio}; +// 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; + +// Some traits we need +use embedded_hal::PwmPin; +use embedded_time::rate::*; +use rp2040_hal::clocks::Clock; + +// A shorter alias for the Peripheral Access Crate, which provides low-level +// register access +use hal::pac; + +//// 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. #[link_section = ".boot2"] #[used] pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; +/// 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; + +/// External high-speed crystal on the Raspberry Pi Pico board is 12 MHz. Adjust +/// if your board has a different frequency +const XTAL_FREQ_HZ: u32 = 12_000_000u32; + +/// 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() -> ! { - let mut pac = rp2040_pac::Peripherals::take().unwrap(); + // Grab our singleton objects + let mut pac = pac::Peripherals::take().unwrap(); + let core = pac::CorePeripherals::take().unwrap(); - let sio = Sio::new(pac.SIO); - let pins = Pins::new( + // Set up the watchdog driver - needed by the clock setup code + let mut watchdog = hal::watchdog::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( + XTAL_FREQ_HZ, + 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::Sio::new(pac.SIO); + + // Set the pins up according to their function on this particular board + let pins = hal::gpio::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().integer()); + // Init PWMs - let pwm_slices = Slices::new(pac.PWM, &mut pac.RESETS); + let mut pwm_slices = hal::pwm::Slices::new(pac.PWM, &mut pac.RESETS); // Configure PWM4 - let mut pwm = pwm_slices.pwm4; + let pwm = &mut pwm_slices.pwm4; pwm.set_ph_correct(); pwm.enable(); - // Use B channel (which outputs to GPIO 25) - let mut channel = pwm.channel_b; + // Output channel B on PWM4 to GPIO 25 + let channel = &mut pwm.channel_b; channel.output_to(pins.gpio25); + + // Infinite loop, fading LED up and down loop { - channel.set_duty(15000); - // TODO: Replace with proper delays once we have clocks working - cortex_m::asm::delay(5_000_000); - channel.set_duty(30000); - cortex_m::asm::delay(5_000_000); + // 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 diff --git a/rp2040-hal/examples/spi.rs b/rp2040-hal/examples/spi.rs index e6d0f4f..c363aee 100644 --- a/rp2040-hal/examples/spi.rs +++ b/rp2040-hal/examples/spi.rs @@ -1,29 +1,78 @@ -//! Perform ] +//! # SPI Example +//! +//! This application demonstrates how to use the SPI Driver to talk to a remote +//! SPI device. +//! +//! +//! It may need to be adapted to your particular board layout and/or pin +//! assignment. +//! +//! See the `Cargo.toml` file for Copyright and licence details. + #![no_std] #![no_main] -use cortex_m::prelude::{ - _embedded_hal_blocking_spi_Transfer, _embedded_hal_blocking_spi_Write, - _embedded_hal_spi_FullDuplex, -}; +// The macro for our start-up function use cortex_m_rt::entry; -use embedded_hal::spi::MODE_0; -use embedded_time::rate::Extensions; -use hal::{gpio::FunctionSpi, pac, sio::Sio, spi::Spi}; + +// 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; +// Some traits we need +use cortex_m::prelude::*; +use embedded_time::rate::Extensions; +use rp2040_hal::clocks::Clock; + +// A shorter alias for the Peripheral Access Crate, which provides low-level +// register access +use hal::pac; + +/// 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. #[link_section = ".boot2"] #[used] pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; -const SYS_HZ: u32 = 125_000_000_u32; +/// External high-speed crystal on the Raspberry Pi Pico board is 12 MHz. Adjust +/// if your board has a different frequency +const XTAL_FREQ_HZ: u32 = 12_000_000u32; +/// 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 performs some example +/// SPI transactions, then goes to sleep. #[entry] fn main() -> ! { + // Grab our singleton objects let mut pac = pac::Peripherals::take().unwrap(); - let sio = Sio::new(pac.SIO); + // Set up the watchdog driver - needed by the clock setup code + let mut watchdog = hal::watchdog::Watchdog::new(pac.WATCHDOG); + + // Configure the clocks + let clocks = hal::clocks::init_clocks_and_plls( + XTAL_FREQ_HZ, + 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::Sio::new(pac.SIO); + + // Set the pins to their default state let pins = hal::gpio::Pins::new( pac.IO_BANK0, pac.PADS_BANK0, @@ -32,19 +81,22 @@ fn main() -> ! { ); // These are implicitly used by the spi driver if they are in the correct mode - let _spi_sclk = pins.gpio6.into_mode::(); - let _spi_mosi = pins.gpio7.into_mode::(); - let _spi_miso = pins.gpio4.into_mode::(); - let mut spi = Spi::<_, _, 8>::new(pac.SPI0).init( + let _spi_sclk = pins.gpio6.into_mode::(); + let _spi_mosi = pins.gpio7.into_mode::(); + let _spi_miso = pins.gpio4.into_mode::(); + let spi = hal::spi::Spi::<_, _, 8>::new(pac.SPI0); + + // Exchange the uninitialised SPI driver for an initialised one + let mut spi = spi.init( &mut pac.RESETS, - SYS_HZ.Hz(), + clocks.peripheral_clock.freq(), 16_000_000u32.Hz(), - &MODE_0, + &embedded_hal::spi::MODE_0, ); // Write out 0, ignore return value - if let Ok(..) = spi.write(&[0]) { - // Handle success + if spi.write(&[0]).is_ok() { + // SPI write was succesful }; // write 50, then check the return @@ -52,17 +104,17 @@ fn main() -> ! { match send_success { Ok(_) => { // We succeeded, check the read value - if spi.read().is_ok() { - // Output our read value + if let Ok(_x) = spi.read() { + // We got back `x` in exchange for the 0x50 we sent. }; } Err(_) => todo!(), } - // Do a read+write at the same time. - // Data in read_write_cache will be replaced with the read data - let mut read_write_cache: [u8; 4] = [1, 2, 3, 4]; - let transfer_success = spi.transfer(&mut read_write_cache); + // Do a read+write at the same time. Data in `buffer` will be replaced with + // the data read from the SPI device. + let mut buffer: [u8; 4] = [1, 2, 3, 4]; + let transfer_success = spi.transfer(&mut buffer); #[allow(clippy::single_match)] match transfer_success { Ok(_) => {} // Handle success @@ -70,5 +122,9 @@ fn main() -> ! { }; #[allow(clippy::empty_loop)] - loop {} + loop { + // Empty loop + } } + +// End of file diff --git a/rp2040-hal/examples/uart.rs b/rp2040-hal/examples/uart.rs index 27a4710..e20443e 100644 --- a/rp2040-hal/examples/uart.rs +++ b/rp2040-hal/examples/uart.rs @@ -1,32 +1,64 @@ -//! Print an incrementing number to UART0 in a loop +//! # UART Example +//! +//! This application demonstrates how to use the UART Driver to talk to a serial +//! connection. +//! +//! It may need to be adapted to your particular board layout and/or pin +//! assignment. +//! +//! See the `Cargo.toml` file for Copyright and licence details. + #![no_std] #![no_main] -use core::fmt::Write; +// The macro for our start-up function use cortex_m_rt::entry; -use hal::clocks::init_clocks_and_plls; -use hal::gpio::{self, Pins}; -use hal::pac; -use hal::sio::Sio; -use hal::uart::UartPeripheral; -use hal::watchdog::Watchdog; + +// 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; + +// Some traits we need +use core::fmt::Write; +use embedded_time::fixed_point::FixedPoint; +use rp2040_hal::clocks::Clock; + +/// 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. #[link_section = ".boot2"] #[used] pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; +/// External high-speed crystal on the Raspberry Pi Pico board is 12 MHz. Adjust +/// if your board has a different frequency +const XTAL_FREQ_HZ: u32 = 12_000_000u32; + +/// 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 inifinite loop. #[entry] fn main() -> ! { + // Grab our singleton objects let mut pac = pac::Peripherals::take().unwrap(); - let mut watchdog = Watchdog::new(pac.WATCHDOG); - let sio = Sio::new(pac.SIO); + let core = pac::CorePeripherals::take().unwrap(); - // External high-speed crystal on the pico board is 12Mhz - let external_xtal_freq_hz = 12_000_000u32; - let clocks = init_clocks_and_plls( - external_xtal_freq_hz, + // Set up the watchdog driver - needed by the clock setup code + let mut watchdog = hal::watchdog::Watchdog::new(pac.WATCHDOG); + + // Configure the clocks + let clocks = hal::clocks::init_clocks_and_plls( + XTAL_FREQ_HZ, pac.XOSC, pac.CLOCKS, pac.PLL_SYS, @@ -37,14 +69,20 @@ fn main() -> ! { .ok() .unwrap(); - let pins = Pins::new( + let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().integer()); + + // The single-cycle I/O block controls our GPIO pins + let sio = hal::sio::Sio::new(pac.SIO); + + // Set the pins to their default state + let pins = hal::gpio::Pins::new( pac.IO_BANK0, pac.PADS_BANK0, sio.gpio_bank0, &mut pac.RESETS, ); - let mut uart = UartPeripheral::<_, _>::enable( + let mut uart = hal::uart::UartPeripheral::<_, _>::enable( pac.UART0, &mut pac.RESETS, hal::uart::common_configs::_9600_8_N_1, @@ -52,16 +90,19 @@ fn main() -> ! { ) .unwrap(); - // UART TX (characters sent from pico) on pin 1 (GPIO0) and RX (on pin 2 (GPIO1) - let _tx_pin = pins.gpio0.into_mode::(); - let _rx_pin = pins.gpio1.into_mode::(); + // UART TX (characters sent from RP2040) on pin 1 (GPIO0) + let _tx_pin = pins.gpio0.into_mode::(); + // UART RX (characters reveived by RP2040) on pin 2 (GPIO1) + let _rx_pin = pins.gpio1.into_mode::(); uart.write_full_blocking(b"UART example\r\n"); let mut value = 0u32; loop { writeln!(uart, "value: {:02}\r", value).unwrap(); - cortex_m::asm::delay(10_000_000); + delay.delay_ms(1000); value += 1 } } + +// End of file diff --git a/rp2040-hal/examples/watchdog.rs b/rp2040-hal/examples/watchdog.rs index f230f8b..41aae21 100644 --- a/rp2040-hal/examples/watchdog.rs +++ b/rp2040-hal/examples/watchdog.rs @@ -1,37 +1,65 @@ -//! How to use the watchdog peripheral to reset the system in case something takes too long +//! # Watchdog Example +//! +//! This application demonstrates how to use the RP2040 Watchdog. +//! +//! It may need to be adapted to your particular board layout and/or pin assignment. +//! +//! See the `Cargo.toml` file for Copyright and licence details. + #![no_std] #![no_main] -use cortex_m::prelude::{_embedded_hal_watchdog_Watchdog, _embedded_hal_watchdog_WatchdogEnable}; +// The macro for our start-up function use cortex_m_rt::entry; -use embedded_hal::digital::v2::OutputPin; -use embedded_time::duration::units::*; -use embedded_time::fixed_point::FixedPoint; -use hal::clocks::{init_clocks_and_plls, Clock}; -use hal::gpio::Pins; -use hal::pac; -use hal::sio::Sio; -use hal::watchdog::Watchdog; + +// 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; + +// Some traits we need +use embedded_hal::digital::v2::OutputPin; +use embedded_hal::watchdog::{Watchdog, WatchdogEnable}; +use embedded_time::duration::Extensions; +use embedded_time::fixed_point::FixedPoint; +use rp2040_hal::clocks::Clock; + +/// 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. #[link_section = ".boot2"] #[used] pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; -// External high-speed crystal on the pico board is 12Mhz -// Adjust for your board if this isn't the same -const EXTERNAL_XTAL_FREQ_HZ: u32 = 12_000_000; +/// External high-speed crystal on the Raspberry Pi Pico board is 12 MHz. Adjust +/// if your board has a different frequency +const XTAL_FREQ_HZ: u32 = 12_000_000u32; +/// 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 toggles a GPIO pin in +/// an infinite loop. After a period of time, the watchdog will kick in to reset +/// the CPU. #[entry] fn main() -> ! { + // Grab our singleton objects let mut pac = pac::Peripherals::take().unwrap(); - let cp = pac::CorePeripherals::take().unwrap(); - let mut watchdog = Watchdog::new(pac.WATCHDOG); - let sio = Sio::new(pac.SIO); + let core = pac::CorePeripherals::take().unwrap(); - let clocks = init_clocks_and_plls( - EXTERNAL_XTAL_FREQ_HZ, + // Set up the watchdog driver - needed by the clock setup code + let mut watchdog = hal::watchdog::Watchdog::new(pac.WATCHDOG); + + // Configure the clocks + let clocks = hal::clocks::init_clocks_and_plls( + XTAL_FREQ_HZ, pac.XOSC, pac.CLOCKS, pac.PLL_SYS, @@ -42,16 +70,19 @@ fn main() -> ! { .ok() .unwrap(); - let pins = Pins::new( + let mut delay = cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().integer()); + + // The single-cycle I/O block controls our GPIO pins + let sio = hal::sio::Sio::new(pac.SIO); + + // Set the pins to their default state + let pins = hal::gpio::Pins::new( pac.IO_BANK0, pac.PADS_BANK0, sio.gpio_bank0, &mut pac.RESETS, ); - // We need to accurately delay to give feedback that the watchdog is working correctly - let mut delay = cortex_m::delay::Delay::new(cp.SYST, clocks.system_clock.freq().integer()); - // Configure an LED so we can show the current state of the watchdog let mut led_pin = pins.gpio25.into_push_pull_output(); @@ -60,7 +91,7 @@ fn main() -> ! { delay.delay_ms(2000); // Set to watchdog to reset if it's not reloaded within 1.05 seconds, and start it - watchdog.start(1_050_000.microseconds()); + watchdog.start(1_050_000u32.microseconds()); // Blink once a second for 5 seconds, refreshing the watchdog timer once a second to avoid a reset for _ in 1..=5 { @@ -80,3 +111,5 @@ fn main() -> ! { delay.delay_ms(100); } } + +// End of file