From 3e036cf9b0174379fabd2b42bfb89d9e60b1aa6b Mon Sep 17 00:00:00 2001 From: "Jonathan Pallant (42 Technology)" Date: Tue, 21 Sep 2021 10:03:47 +0100 Subject: [PATCH 01/12] Polishing the blinky examples. --- boards/pico/examples/pico_blinky.rs | 73 +++++++++++++++---- boards/pico/examples/pico_countdown_blinky.rs | 61 ++++++++++++---- rp2040-hal/src/prelude.rs | 1 + 3 files changed, 104 insertions(+), 31 deletions(-) diff --git a/boards/pico/examples/pico_blinky.rs b/boards/pico/examples/pico_blinky.rs index a75d3bb..56aa957 100644 --- a/boards/pico/examples/pico_blinky.rs +++ b/boards/pico/examples/pico_blinky.rs @@ -1,35 +1,66 @@ -//! Blinks the LED on a Pico board +//! # Pico Blinky //! -//! This will blink an LED attached to GP25, which is the pin the Pico uses for the on-board LED. +//! 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 licence details. + #![no_std] #![no_main] +// The macro for our start-up function use cortex_m_rt::entry; + +// GPIO traits use embedded_hal::digital::v2::OutputPin; + +// Time handling traits use embedded_time::rate::*; + +// Ensure we halt the program on panic (if we don't mention this crate it won't +// be linked) use panic_halt as _; -use pico::{ - hal::{ - clocks::{init_clocks_and_plls, Clock}, - pac, - sio::Sio, - watchdog::Watchdog, - }, - Pins, XOSC_CRYSTAL_FREQ, -}; + +// Pull in any important traits +use pico::hal::prelude::*; + +// A shorter alias for the Peripheral Access Crate, which provides low-level +// register access +use pico::hal::pac; + +// A shorter alias for the Hardware Abstraction Layer, which provides +// 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. #[link_section = ".boot2"] #[used] pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; +/// 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(); - let mut watchdog = Watchdog::new(pac.WATCHDOG); + // 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( - XOSC_CRYSTAL_FREQ, + // Configure the clocks + // + // Our default is 12 MHz crystal input, 125 MHz system clock + let clocks = hal::clocks::init_clocks_and_plls( + pico::XOSC_CRYSTAL_FREQ, pac.XOSC, pac.CLOCKS, pac.PLL_SYS, @@ -40,17 +71,25 @@ fn main() -> ! { .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()); - let sio = Sio::new(pac.SIO); - 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 up according to their function on this particular board + let pins = 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); @@ -58,3 +97,5 @@ fn main() -> ! { delay.delay_ms(500); } } + +// End of file diff --git a/boards/pico/examples/pico_countdown_blinky.rs b/boards/pico/examples/pico_countdown_blinky.rs index 5957a1c..b377a04 100644 --- a/boards/pico/examples/pico_countdown_blinky.rs +++ b/boards/pico/examples/pico_countdown_blinky.rs @@ -1,18 +1,37 @@ -//! Blinks the LED on a Pico board +//! # Pico Countdown Blinky //! -//! This will blink an LED attached to GP25, which is the pin the Pico uses for the on-board LED. +//! 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 licence details. + #![no_std] #![no_main] -use cortex_m::prelude::_embedded_hal_timer_CountDown; +// The macro for our start-up function use cortex_m_rt::entry; + +use cortex_m::prelude::*; + +// GPIO traits use embedded_hal::digital::v2::OutputPin; + +// Traits for converting integers to amounts of time use embedded_time::duration::Extensions; + +// Ensure we halt the program on panic (if we don't mention this crate it won't +// be linked) use panic_halt as _; -use pico::{ - hal::{self as hal, clocks::init_clocks_and_plls, pac, sio::Sio, watchdog::Watchdog}, - XOSC_CRYSTAL_FREQ, -}; + +// A shorter alias for the Peripheral Access Crate, which provides low-level +// register access +use pico::hal::pac; + +// A shorter alias for the Hardware Abstraction Layer, which provides +// higher-level drivers. +use pico::hal; #[link_section = ".boot2"] #[used] @@ -20,11 +39,17 @@ pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; #[entry] fn main() -> ! { + // Grab our singleton objects let mut pac = pac::Peripherals::take().unwrap(); - let mut watchdog = Watchdog::new(pac.WATCHDOG); - let _clocks = init_clocks_and_plls( - XOSC_CRYSTAL_FREQ, + // Set up the watchdog driver - needed by the clock setup code + let mut watchdog = hal::watchdog::Watchdog::new(pac.WATCHDOG); + + // Configure the clocks + // + // Our default is 12 MHz crystal input, 125 MHz system clock + let _clocks = hal::clocks::init_clocks_and_plls( + pico::XOSC_CRYSTAL_FREQ, pac.XOSC, pac.CLOCKS, pac.PLL_SYS, @@ -35,26 +60,32 @@ fn main() -> ! { .ok() .unwrap(); + // Configure the Timer peripheral in count-down mode let timer = hal::timer::Timer::new(pac.TIMER); let mut count_down = timer.count_down(); - let sio = Sio::new(pac.SIO); - let pins = hal::gpio::Pins::new( + // 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 = pico::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 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(); - // wait for 500ms count_down.start(500.milliseconds()); let _ = nb::block!(count_down.wait()); + // LED off, and wait for 500ms led_pin.set_low().unwrap(); - // wait for 500ms count_down.start(500.milliseconds()); let _ = nb::block!(count_down.wait()); } diff --git a/rp2040-hal/src/prelude.rs b/rp2040-hal/src/prelude.rs index 8e3e645..49bdc3c 100644 --- a/rp2040-hal/src/prelude.rs +++ b/rp2040-hal/src/prelude.rs @@ -1 +1,2 @@ //! Prelude +pub use crate::clocks::Clock as _rphal_clocks_Clock; From 35f001f61decd6ecfa560f83dd2d1fdf18f1bfbf Mon Sep 17 00:00:00 2001 From: "Jonathan Pallant (42 Technology)" Date: Tue, 21 Sep 2021 10:47:43 +0100 Subject: [PATCH 02/12] Polishing the PWM and USB examples. --- boards/pico/examples/pico_blinky.rs | 2 +- boards/pico/examples/pico_countdown_blinky.rs | 2 +- boards/pico/examples/pico_gpio_in_out.rs | 62 +++++-- boards/pico/examples/pico_pwm_blink.rs | 86 ++++++--- .../examples/pico_usb_serial_interrupt.rs | 174 ++++++++++++------ 5 files changed, 237 insertions(+), 89 deletions(-) diff --git a/boards/pico/examples/pico_blinky.rs b/boards/pico/examples/pico_blinky.rs index 56aa957..7bb82ee 100644 --- a/boards/pico/examples/pico_blinky.rs +++ b/boards/pico/examples/pico_blinky.rs @@ -1,4 +1,4 @@ -//! # Pico Blinky +//! # Pico Blinky Example //! //! Blinks the LED on a Pico board. //! diff --git a/boards/pico/examples/pico_countdown_blinky.rs b/boards/pico/examples/pico_countdown_blinky.rs index b377a04..cb4a13d 100644 --- a/boards/pico/examples/pico_countdown_blinky.rs +++ b/boards/pico/examples/pico_countdown_blinky.rs @@ -1,4 +1,4 @@ -//! # Pico Countdown Blinky +//! # Pico Countdown Blinky Example //! //! Blinks the LED on a Pico board, using an RP2040 Timer in Count-down mode. //! diff --git a/boards/pico/examples/pico_gpio_in_out.rs b/boards/pico/examples/pico_gpio_in_out.rs index 65ca94d..d2c446e 100644 --- a/boards/pico/examples/pico_gpio_in_out.rs +++ b/boards/pico/examples/pico_gpio_in_out.rs @@ -1,36 +1,74 @@ -//! Toggle LED based on GPIO input +//! # Pico GPIO In/Out 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. +//! 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 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; -use panic_halt as _; -use pico::{hal, Pins}; +// 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 pico::hal::pac; + +// A shorter alias for the Hardware Abstraction Layer, which provides +// 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. #[link_section = ".boot2"] #[used] pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; +/// 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 sio = Sio::new(pac.SIO); - let pins = Pins::new( + // 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::Sio::new(pac.SIO); + + // Set the pins up according to their function on this particular board + let pins = 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.bootsel.into_pull_down_input(); + // Run forever, setting the LED according to the button loop { if button_pin.is_low().unwrap() { led_pin.set_high().unwrap(); @@ -39,3 +77,5 @@ fn main() -> ! { } } } + +// End of file diff --git a/boards/pico/examples/pico_pwm_blink.rs b/boards/pico/examples/pico_pwm_blink.rs index 1a2c655..9bd1eb5 100644 --- a/boards/pico/examples/pico_pwm_blink.rs +++ b/boards/pico/examples/pico_pwm_blink.rs @@ -1,40 +1,72 @@ -//! Blinks the LED on a Pico board +//! # Pico PWM Blink Example //! -//! This will fade in/out the LED attached to GP25, which is the pin the Pico uses for the on-board LED. +//! 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 licence details. + #![no_std] #![no_main] +// The macro for our start-up function use cortex_m_rt::entry; -use embedded_hal::PwmPin; -use embedded_time::fixed_point::FixedPoint; -use panic_halt as _; -use pico::{ - hal::{ - clocks::{init_clocks_and_plls, Clock}, - pac, - pwm::*, - watchdog::Watchdog, - }, - Pins, XOSC_CRYSTAL_FREQ, -}; -use rp2040_hal::sio::Sio; +// GPIO traits +use embedded_hal::PwmPin; + +// Time handling traits +use embedded_time::rate::*; + +// 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 pico::hal::prelude::*; + +// A shorter alias for the Peripheral Access Crate, which provides low-level +// register access +use pico::hal::pac; + +// A shorter alias for the Hardware Abstraction Layer, which provides +// 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. #[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; +/// 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(); - let mut watchdog = Watchdog::new(pac.WATCHDOG); + // 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( - XOSC_CRYSTAL_FREQ, + // Configure the clocks + // + // Our default is 12 MHz crystal input, 125 MHz system clock + let clocks = hal::clocks::init_clocks_and_plls( + pico::XOSC_CRYSTAL_FREQ, pac.XOSC, pac.CLOCKS, pac.PLL_SYS, @@ -45,34 +77,42 @@ fn main() -> ! { .ok() .unwrap(); - let sio = Sio::new(pac.SIO); - 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 up according to their function on this particular board + let pins = 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().integer()); // Init PWMs - let mut 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 pwm = &mut pwm_slices.pwm4; pwm.set_ph_correct(); pwm.enable(); - // Use B channel (which outputs to GPIO 25) + // 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); @@ -81,3 +121,5 @@ fn main() -> ! { delay.delay_ms(500); } } + +// End of file diff --git a/boards/pico/examples/pico_usb_serial_interrupt.rs b/boards/pico/examples/pico_usb_serial_interrupt.rs index a1a715e..5801e25 100644 --- a/boards/pico/examples/pico_usb_serial_interrupt.rs +++ b/boards/pico/examples/pico_usb_serial_interrupt.rs @@ -1,49 +1,86 @@ -//! Creates a USB Serial device on a Pico board, with the USB driver running in the USB interrupt +//! # Pico USB Serial (with Interrupts) Example //! -//! This will create a USB Serial device echoing anything it receives converting to caps the ASCII -//! alphabetical caracters. +//! 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 licence details. + #![no_std] #![no_main] -use crate::pac::interrupt; +// The macro for our start-up function use cortex_m_rt::entry; + +// The macro for marking our interrupt functions +use pico::hal::pac::interrupt; + +// GPIO traits +use embedded_hal::digital::v2::OutputPin; + +// Time handling traits +use embedded_time::rate::*; + +// Ensure we halt the program on panic (if we don't mention this crate it won't +// be linked) use panic_halt as _; -use pico::{ - hal::{ - self, - clocks::{init_clocks_and_plls, Clock}, - pac, - sio::Sio, - usb::UsbBus, - watchdog::Watchdog, - }, - XOSC_CRYSTAL_FREQ, -}; + +// Pull in any important traits +use pico::hal::prelude::*; + +// A shorter alias for the Peripheral Access Crate, which provides low-level +// register access +use pico::hal::pac; + +// A shorter alias for the Hardware Abstraction Layer, which provides +// higher-level drivers. +use pico::hal; + +// USB Device support 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. #[link_section = ".boot2"] #[used] pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; -// Static data so that it can be accessed in both main and interrupt context -static mut USB_DEVICE: Option> = None; -static mut USB_BUS: Option> = None; -static mut USB_SERIAL: Option> = None; -static mut SAID_HELLO: bool = false; +/// The USB Device Driver (shared with the interrupt). +static mut USB_DEVICE: Option> = None; -// Blinky-related imports, not needed for USB -use embedded_hal::digital::v2::OutputPin; -use embedded_time::rate::*; -use pico::Pins; +/// The USB Bus Driver (shared with the interrupt). +static mut USB_BUS: Option> = None; +/// The USB Serial Device Driver (shared with the interrupt). +static mut USB_SERIAL: Option> = 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 mut watchdog = Watchdog::new(pac.WATCHDOG); + let core = pac::CorePeripherals::take().unwrap(); - let clocks = init_clocks_and_plls( - XOSC_CRYSTAL_FREQ, + // Set up the watchdog driver - needed by the clock setup code + let mut watchdog = hal::watchdog::Watchdog::new(pac.WATCHDOG); + + // Configure the clocks + // + // Our default is 12 MHz crystal input, 125 MHz system clock + let clocks = hal::clocks::init_clocks_and_plls( + pico::XOSC_CRYSTAL_FREQ, pac.XOSC, pac.CLOCKS, pac.PLL_SYS, @@ -54,7 +91,7 @@ fn main() -> ! { .ok() .unwrap(); - let usb_bus = UsbBusAllocator::new(UsbBus::new( + let usb_bus = UsbBusAllocator::new(hal::usb::UsbBus::new( pac.USBCTRL_REGS, pac.USBCTRL_DPRAM, clocks.usb_clock, @@ -62,6 +99,7 @@ fn main() -> ! { &mut pac.RESETS, )); unsafe { + // Note (safety): This is safe as interrupts haven't been started yet USB_BUS = Some(usb_bus); } @@ -71,6 +109,7 @@ fn main() -> ! { } let usb_dev = UsbDeviceBuilder::new( + // Note (safety): This is safe as interrupts haven't been started yet unsafe { USB_BUS.as_ref().unwrap() }, UsbVidPid(0x16c0, 0x27dd), ) @@ -80,6 +119,7 @@ fn main() -> ! { .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); } @@ -88,20 +128,28 @@ fn main() -> ! { 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. - let core = pac::CorePeripherals::take().unwrap(); + // 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().integer()); - let sio = Sio::new(pac.SIO); - 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 up according to their function on this particular board + let pins = 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); @@ -110,37 +158,55 @@ fn main() -> ! { } } +/// 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() { - let mut buf = [0u8; 64]; + 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(); - if !SAID_HELLO { - SAID_HELLO = true; - let _ = serial.write(b"HelloWorld!\r\n"); + // Say hello exactly once on start-up + if SAID_HELLO.load(Ordering::Relaxed) == false { + 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 _ = serial.read(&mut buf).map(|count| { - if count == 0 { - return; + let mut buf = [0u8; 64]; + match serial.read(&mut buf) { + Err(_e) => { + // Do nothing } - - // Echo back in upper case - buf.iter_mut().take(count).for_each(|c| { - if let 0x61..=0x7a = *c { - *c &= !0x20; - } - }); - - let mut wr_ptr = &buf[..count]; - while !wr_ptr.is_empty() { - let _ = serial.write(wr_ptr).map(|len| { - wr_ptr = &wr_ptr[len..]; + 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 From ba6c409f21b862b8163471caaf060552df9c2a6e Mon Sep 17 00:00:00 2001 From: "Jonathan Pallant (42 Technology)" Date: Tue, 21 Sep 2021 10:54:13 +0100 Subject: [PATCH 03/12] Update non-IRQ USB example. --- boards/pico/examples/pico_usb_serial.rs | 113 ++++++++++++------ .../examples/pico_usb_serial_interrupt.rs | 3 + 2 files changed, 81 insertions(+), 35 deletions(-) diff --git a/boards/pico/examples/pico_usb_serial.rs b/boards/pico/examples/pico_usb_serial.rs index a6c2b1f..8a69aed 100644 --- a/boards/pico/examples/pico_usb_serial.rs +++ b/boards/pico/examples/pico_usb_serial.rs @@ -1,30 +1,64 @@ -//! Creates a USB Serial device on a Pico board. +//! # Pico USB Serial Example //! -//! This will create a USB Serial device echoing anything it receives converting to caps the ASCII -//! alphabetical caracters. +//! 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 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 _; -use pico::{ - hal::{clocks::init_clocks_and_plls, pac, timer::Timer, usb::UsbBus, watchdog::Watchdog}, - XOSC_CRYSTAL_FREQ, -}; + +// A shorter alias for the Peripheral Access Crate, which provides low-level +// register access +use pico::hal::pac; + +// A shorter alias for the Hardware Abstraction Layer, which provides +// higher-level drivers. +use pico::hal; + +// USB Device support 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. #[link_section = ".boot2"] #[used] pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; +/// 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(); - let mut watchdog = Watchdog::new(pac.WATCHDOG); - let clocks = init_clocks_and_plls( - XOSC_CRYSTAL_FREQ, + // Set up the watchdog driver - needed by the clock setup code + let mut watchdog = hal::watchdog::Watchdog::new(pac.WATCHDOG); + + // Configure the clocks + // + // Our default is 12 MHz crystal input, 125 MHz system clock + let clocks = hal::clocks::init_clocks_and_plls( + pico::XOSC_CRYSTAL_FREQ, pac.XOSC, pac.CLOCKS, pac.PLL_SYS, @@ -35,15 +69,19 @@ fn main() -> ! { .ok() .unwrap(); - let timer = Timer::new(pac.TIMER); - let usb_bus = UsbBusAllocator::new(UsbBus::new( + // 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") @@ -51,36 +89,41 @@ fn main() -> ! { .device_class(2) // from: https://www.usb.org/defined-class-codes .build(); + let timer = hal::timer::Timer::new(pac.TIMER); let mut said_hello = false; loop { + // A welcome message at the beginning if !said_hello && timer.get_counter() >= 2_000_000 { said_hello = true; - let _ = serial.write(b"HelloWorld!\r\n"); + let _ = serial.write(b"Hello, World!\r\n"); } - if !usb_dev.poll(&mut [&mut serial]) { - continue; - } - - let mut buf = [0u8; 64]; - let _ = serial.read(&mut buf).map(|count| { - if count == 0 { - return; - } - - // Echo back in upper case - buf.iter_mut().take(count).for_each(|c| { - if let 0x61..=0x7a = *c { - *c &= !0x20; + // 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() { + let _ = serial.write(wr_ptr).map(|len| { + wr_ptr = &wr_ptr[len..]; + }); + } } - }); - - 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 diff --git a/boards/pico/examples/pico_usb_serial_interrupt.rs b/boards/pico/examples/pico_usb_serial_interrupt.rs index 5801e25..cc67de8 100644 --- a/boards/pico/examples/pico_usb_serial_interrupt.rs +++ b/boards/pico/examples/pico_usb_serial_interrupt.rs @@ -91,6 +91,7 @@ fn main() -> ! { .ok() .unwrap(); + // Set up the USB driver let usb_bus = UsbBusAllocator::new(hal::usb::UsbBus::new( pac.USBCTRL_REGS, pac.USBCTRL_DPRAM, @@ -103,11 +104,13 @@ fn main() -> ! { USB_BUS = Some(usb_bus); } + // Set up the USB Communications Class Device driver let serial = SerialPort::new(unsafe { USB_BUS.as_ref().unwrap() }); unsafe { USB_SERIAL = Some(serial); } + // Create a USB device with a fake VID and PID let usb_dev = UsbDeviceBuilder::new( // Note (safety): This is safe as interrupts haven't been started yet unsafe { USB_BUS.as_ref().unwrap() }, From b89e728e9c5268aedd5e16f52617bfff85e0b3ce Mon Sep 17 00:00:00 2001 From: "Jonathan Pallant (42 Technology)" Date: Tue, 21 Sep 2021 12:37:44 +0100 Subject: [PATCH 04/12] Polishing the USB interrupt examples. Answers on a postcard please on how to avoid `static mut` when you have lazy initialization, and static objects holding references to other static objects. --- .../examples/pico_usb_serial_interrupt.rs | 22 +-- .../pico/examples/pico_usb_twitchy_mouse.rs | 150 ++++++++++++------ 2 files changed, 116 insertions(+), 56 deletions(-) diff --git a/boards/pico/examples/pico_usb_serial_interrupt.rs b/boards/pico/examples/pico_usb_serial_interrupt.rs index cc67de8..559d8a9 100644 --- a/boards/pico/examples/pico_usb_serial_interrupt.rs +++ b/boards/pico/examples/pico_usb_serial_interrupt.rs @@ -104,23 +104,23 @@ fn main() -> ! { USB_BUS = Some(usb_bus); } + // Grab a reference to the USB Bus allocator. We must promise not to take + // mutable access to this global variable whilst the reference exists! + let bus_ref = unsafe { USB_BUS.as_ref().unwrap() }; + // Set up the USB Communications Class Device driver - let serial = SerialPort::new(unsafe { USB_BUS.as_ref().unwrap() }); + 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( - // Note (safety): This is safe as interrupts haven't been started yet - unsafe { USB_BUS.as_ref().unwrap() }, - 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 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); diff --git a/boards/pico/examples/pico_usb_twitchy_mouse.rs b/boards/pico/examples/pico_usb_twitchy_mouse.rs index 25a0782..4871c86 100644 --- a/boards/pico/examples/pico_usb_twitchy_mouse.rs +++ b/boards/pico/examples/pico_usb_twitchy_mouse.rs @@ -1,39 +1,84 @@ +//! # Pico USB 'Twitchy' Mouse Example +//! +//! Creates a USB HID Class Poiting 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 licence 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] -use cortex_m::interrupt::free as disable_interrupts; +// The macro for our start-up function use cortex_m_rt::entry; -use embedded_time::fixed_point::FixedPoint; + +// The macro for marking our interrupt functions +use 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 _; -use pico::{ - hal::{ - self, - clocks::{init_clocks_and_plls, Clock}, - pac::{self, interrupt}, - usb::UsbBus, - watchdog::Watchdog, - }, - XOSC_CRYSTAL_FREQ, -}; -use usb_device::bus::UsbBusAllocator; -use usb_device::prelude::*; + +// Pull in any important traits +use embedded_time::fixed_point::FixedPoint; +use pico::hal::prelude::*; + +// A shorter alias for the Peripheral Access Crate, which provides low-level +// register access +use pico::hal::pac; + +// A shorter alias for the Hardware Abstraction Layer, which provides +// higher-level drivers. +use 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 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 USB Device Driver (shared with the interrupt). +static mut USB_DEVICE: Option> = None; + +/// The USB Bus Driver (shared with the interrupt). +static mut USB_BUS: Option> = None; + +/// The USB Human Interface Device Driver (shared with the interrupt). +static mut USB_HID: Option> = 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(); - let mut watchdog = Watchdog::new(pac.WATCHDOG); - let clocks = init_clocks_and_plls( - XOSC_CRYSTAL_FREQ, + // Set up the watchdog driver - needed by the clock setup code + let mut watchdog = hal::watchdog::Watchdog::new(pac.WATCHDOG); + + // Configure the clocks + // + // Our default is 12 MHz crystal input, 125 MHz system clock + let clocks = hal::clocks::init_clocks_and_plls( + pico::XOSC_CRYSTAL_FREQ, pac.XOSC, pac.CLOCKS, pac.PLL_SYS, @@ -44,7 +89,8 @@ fn main() -> ! { .ok() .unwrap(); - let usb_bus = UsbBusAllocator::new(UsbBus::new( + // Set up the USB driver + let usb_bus = UsbBusAllocator::new(hal::usb::UsbBus::new( pac.USBCTRL_REGS, pac.USBCTRL_DPRAM, clocks.usb_clock, @@ -52,67 +98,79 @@ fn main() -> ! { &mut pac.RESETS, )); unsafe { + // Note (safety): This is safe as interrupts haven't been started yet USB_BUS = Some(usb_bus); } - let usb_hid = HIDClass::new( - unsafe { USB_BUS.as_ref().unwrap() }, - MouseReport::desc(), - 60, - ); + // Grab a reference to the USB Bus allocator. We 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); } - let usb_dev = UsbDeviceBuilder::new( - unsafe { USB_BUS.as_ref().unwrap() }, - UsbVidPid(0x16c0, 0x27dd), - ) - .manufacturer("Fake company") - .product("Twitchy Mousey") - .serial_number("TEST") - .device_class(0xEF) // misc - .build(); + // 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(0xEF) // misc + .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().integer()); + // Move the cursor up and down every 200ms loop { delay.delay_ms(100); - push_mouse_movement(MouseReport { + + let rep_up = MouseReport { x: 0, y: 4, buttons: 0, wheel: 0, - }) - .ok() - .unwrap_or(0); + }; + push_mouse_movement(rep_up).ok().unwrap_or(0); + delay.delay_ms(100); - push_mouse_movement(MouseReport { + + let rep_down = MouseReport { x: 0, y: -4, buttons: 0, wheel: 0, - }) - .ok() - .unwrap_or(0); + }; + push_mouse_movement(rep_down).ok().unwrap_or(0); } } -static mut USB_DEVICE: Option> = None; -static mut USB_BUS: Option> = None; -static mut USB_HID: Option> = None; - +/// 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 { - disable_interrupts(|_| unsafe { USB_HID.as_mut().map(|hid| hid.push_input(&report)) }).unwrap() + cortex_m::interrupt::free(|_| 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() { @@ -121,3 +179,5 @@ unsafe fn USBCTRL_IRQ() { let usb_hid = USB_HID.as_mut().unwrap(); usb_dev.poll(&mut [usb_hid]); } + +// End of file From 25d87b838b9a78875467ce9f250cc341b7c8bec3 Mon Sep 17 00:00:00 2001 From: "Jonathan Pallant (42 Technology)" Date: Tue, 21 Sep 2021 12:42:34 +0100 Subject: [PATCH 05/12] Good ol' clippy. --- boards/pico/examples/pico_usb_serial_interrupt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/pico/examples/pico_usb_serial_interrupt.rs b/boards/pico/examples/pico_usb_serial_interrupt.rs index 559d8a9..bc9747f 100644 --- a/boards/pico/examples/pico_usb_serial_interrupt.rs +++ b/boards/pico/examples/pico_usb_serial_interrupt.rs @@ -179,7 +179,7 @@ unsafe fn USBCTRL_IRQ() { let serial = USB_SERIAL.as_mut().unwrap(); // Say hello exactly once on start-up - if SAID_HELLO.load(Ordering::Relaxed) == false { + if !SAID_HELLO.load(Ordering::Relaxed) { SAID_HELLO.store(true, Ordering::Relaxed); let _ = serial.write(b"Hello, World!\r\n"); } From f0fc4ed3ad9bb53e1f354d435cda305f4c247d3b Mon Sep 17 00:00:00 2001 From: "Jonathan Pallant (42 Technology)" Date: Tue, 21 Sep 2021 12:43:16 +0100 Subject: [PATCH 06/12] Typo in comments. --- boards/pico/examples/pico_usb_serial_interrupt.rs | 5 +++-- boards/pico/examples/pico_usb_twitchy_mouse.rs | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/boards/pico/examples/pico_usb_serial_interrupt.rs b/boards/pico/examples/pico_usb_serial_interrupt.rs index bc9747f..6d9fd5c 100644 --- a/boards/pico/examples/pico_usb_serial_interrupt.rs +++ b/boards/pico/examples/pico_usb_serial_interrupt.rs @@ -104,8 +104,9 @@ fn main() -> ! { USB_BUS = Some(usb_bus); } - // Grab a reference to the USB Bus allocator. We must promise not to take - // mutable access to this global variable whilst the reference exists! + // 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 diff --git a/boards/pico/examples/pico_usb_twitchy_mouse.rs b/boards/pico/examples/pico_usb_twitchy_mouse.rs index 4871c86..e1643ff 100644 --- a/boards/pico/examples/pico_usb_twitchy_mouse.rs +++ b/boards/pico/examples/pico_usb_twitchy_mouse.rs @@ -102,9 +102,9 @@ fn main() -> ! { USB_BUS = Some(usb_bus); } - // Grab a reference to the USB Bus allocator. We promising to the compiler - // not to take mutable access to this global variable whilst this reference - // exists! + // 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 From bc68ee32fb8be4fa6f703f529ccf4c08e3bcb7ed Mon Sep 17 00:00:00 2001 From: "Jonathan Pallant (42 Technology)" Date: Tue, 21 Sep 2021 16:17:14 +0100 Subject: [PATCH 07/12] Add Pimoroni Pico Lipo README and example. --- boards/pico_lipo_16mb/README.md | 97 ++++++++++++++++- .../examples/pico_lipo_16mb_blinky.rs | 101 ++++++++++++++++++ 2 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 boards/pico_lipo_16mb/examples/pico_lipo_16mb_blinky.rs diff --git a/boards/pico_lipo_16mb/README.md b/boards/pico_lipo_16mb/README.md index d7dacd1..c1a3317 100644 --- a/boards/pico_lipo_16mb/README.md +++ b/boards/pico_lipo_16mb/README.md @@ -1 +1,96 @@ -Pimoroni Pico Lipo 16mb Board Support Crate \ No newline at end of file +# [pico_lipo_16mb] - Board Support for the [Pimoroni Pico Lipo 16MB] + +You should include this crate if you are writing code that you want to run on +a [Pimoroni Pico Lipo 16MB] - a board with USB-C, STEMMA QT/Qwiic connectors, +plus a Li-Po battery charging circuit. + +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 Lipo. + +Note that if you use this crate the compiler will expect the full 16MB flash +space, and so it may not work if you only have the 4MB variant. + +[Pimoroni Pico Lipo 16MB]: https://shop.pimoroni.com/products/pimoroni-pico-lipo?variant=39335427080275 +[pico_lipo_16mb]: https://github.com/rp-rs/rp-hal/tree/main/boards/pico_lipo_16mb + +## Using + +To use this crate, your `Cargo.toml` file should contain: + +```toml +pico_lipo_16mb = { git = "https://github.com/rp-rs/rp-hal.git" } +``` + +In your program, you will need to call `pico_lipo_16mb::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_ repository and run: + +```console +rp-hal/boards/pico_lipo_16mb $ cargo build --release --example +``` + +You will get an ELF file called +`./target/thumbv6m-none-eabi/release/examples/`, where the `target` +folder is located at the top of the _rp-hal_ 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/pico_lipo_16mb $ cargo run --release --example +``` + +If you get an error about not being able to find `elf2uf2-rs`, try: + +```console +$ cargo install elf2uf2-rs, then repeating the `cargo run` command above. +``` + +### [pico_lipo_16mb_blinky](./examples/pico_lipo_16mb_blinky.rs) + +Flashes the Pico Lipo's on-board LED on and off. + +## 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/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 chose either the MIT licence or the +Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more +information on each specific licence. + +Any submissions to this project (e.g. as Pull Requests) must be made available +under these terms. diff --git a/boards/pico_lipo_16mb/examples/pico_lipo_16mb_blinky.rs b/boards/pico_lipo_16mb/examples/pico_lipo_16mb_blinky.rs new file mode 100644 index 0000000..7a1a89e --- /dev/null +++ b/boards/pico_lipo_16mb/examples/pico_lipo_16mb_blinky.rs @@ -0,0 +1,101 @@ +//! # Pimoroni Pico Lipo Blinky Example +//! +//! Blinks the LED on a Pimoroni Pico Lipo 16MB board. +//! +//! This will blink an LED attached to GPIO25, which is the pin the Pico Lipo uses +//! for the on-board LED. +//! +//! 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; + +// GPIO traits +use embedded_hal::digital::v2::OutputPin; + +// Time handling traits +use embedded_time::rate::*; + +// 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 pico::hal::prelude::*; + +// A shorter alias for the Peripheral Access Crate, which provides low-level +// register access +use pico::hal::pac; + +// A shorter alias for the Hardware Abstraction Layer, which provides +// 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. +#[link_section = ".boot2"] +#[used] +pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; + +/// 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::Watchdog::new(pac.WATCHDOG); + + // Configure the clocks + // + // Our default is 12 MHz crystal input, 125 MHz system clock + let clocks = hal::clocks::init_clocks_and_plls( + 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().integer()); + + // 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 = 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); + } +} + +// End of file From efe32e627f03488c5b2eb5c34ca4b7b2edff5933 Mon Sep 17 00:00:00 2001 From: "Jonathan Pallant (42 Technology)" Date: Tue, 21 Sep 2021 16:17:24 +0100 Subject: [PATCH 08/12] Add Pico Explorer README --- boards/pico_explorer/README.md | 96 +++++++++++++++++++++++++++++++++- 1 file changed, 95 insertions(+), 1 deletion(-) diff --git a/boards/pico_explorer/README.md b/boards/pico_explorer/README.md index 381b021..c9167d2 100644 --- a/boards/pico_explorer/README.md +++ b/boards/pico_explorer/README.md @@ -1 +1,95 @@ -Pimoroni Pico Explorer Board Support Crate +# [pico_explorer] - Board Support for the [Pimoroni Pico Explorer] + +You should include this crate if you are writing code that you want to run on +a [Pimoroni Pico Explorer] - a board featuring a small LCD screen, a +breadboard and some breakout headers. + +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 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/ + +## Using + +To use this crate, your `Cargo.toml` file should contain: + +```toml +pico_explorer = { git = "https://github.com/rp-rs/rp-hal.git" } +``` + +In your program, you will need to call `pico_explorer::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_ repository and run: + +```console +rp-hal/boards/pico_explorer $ cargo build --release --example +``` + +You will get an ELF file called +`./target/thumbv6m-none-eabi/release/examples/`, where the `target` +folder is located at the top of the _rp-hal_ 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/pico_explorer $ cargo run --release --example +``` + +If you get an error about not being able to find `elf2uf2-rs`, try: + +```console +$ cargo install elf2uf2-rs, then repeating the `cargo run` command above. +``` + +### [pico_explorer_showcase](./examples/pico_explorer_showcase.rs) + +Displays the current temperature on the Pico Explorer's on-board LCD screen. + +## 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/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 chose either the MIT licence or the +Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more +information on each specific licence. + +Any submissions to this project (e.g. as Pull Requests) must be made available +under these terms. From 34687a2ebe9aba39092ed59a60b3739ddeb19a93 Mon Sep 17 00:00:00 2001 From: "Jonathan Pallant (42 Technology)" Date: Tue, 21 Sep 2021 16:17:35 +0100 Subject: [PATCH 09/12] Add Adafruit Macropad README --- boards/adafruit_macropad/README.md | 95 +++++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 1 deletion(-) diff --git a/boards/adafruit_macropad/README.md b/boards/adafruit_macropad/README.md index 3da558f..dc2bdd9 100644 --- a/boards/adafruit_macropad/README.md +++ b/boards/adafruit_macropad/README.md @@ -1 +1,94 @@ -Adafruit Macropad Board Support Crate +# [adafruit_macropad] - Board Support for the [Adafruit Macropad] + +You should include this crate if you are writing code that you want to run on +an [Adafruit Macropad] - a 3x4 keyboard and OLED combo board from Adafruit. + +This crate includes the [rp2040-hal], but also configures each pin of the +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/ + +## Using + +To use this crate, your `Cargo.toml` file should contain: + +```toml +adafruit_macropad = { git = "https://github.com/rp-rs/rp-hal.git" } +``` + +In your program, you will need to call `adafruit_macropad::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_ repository and run: + +```console +rp-hal/boards/adafruit_macropad $ cargo build --release --example +``` + +You will get an ELF file called +`./target/thumbv6m-none-eabi/release/examples/`, where the `target` +folder is located at the top of the _rp-hal_ 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/adafruit_macropad $ cargo run --release --example +``` + +If you get an error about not being able to find `elf2uf2-rs`, try: + +```console +$ cargo install elf2uf2-rs, then repeating the `cargo run` command above. +``` + +### [feather_blinky](./examples/feather_blinky.rs) + +Flashes the Feather's on-board LED on and off. + +## 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/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 chose either the MIT licence or the +Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more +information on each specific licence. + +Any submissions to this project (e.g. as Pull Requests) must be made available +under these terms. From 43a22e6e427a8803be0a83ff389e4c7cf27376da Mon Sep 17 00:00:00 2001 From: "Jonathan Pallant (42 Technology)" Date: Tue, 21 Sep 2021 16:17:51 +0100 Subject: [PATCH 10/12] Add Feather RP2040 README --- boards/feather_rp2040/README.md | 95 ++++++++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 1 deletion(-) diff --git a/boards/feather_rp2040/README.md b/boards/feather_rp2040/README.md index 320fbe4..42833e1 100644 --- a/boards/feather_rp2040/README.md +++ b/boards/feather_rp2040/README.md @@ -1 +1,94 @@ -Adafruit Feather RP2040 Board Support Crate +# [feather_rp2040] - Board Support for the [Adafruit Feather RP2040] + +You should include this crate if you are writing code that you want to run on +an [Adafruit Feather RP2040] - a Feather form-factor RP2040 board from Adafruit. + +This crate includes the [rp2040-hal], but also configures each pin of the +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/ + +## Using + +To use this crate, your `Cargo.toml` file should contain: + +```toml +feather_rp2040 = { git = "https://github.com/rp-rs/rp-hal.git" } +``` + +In your program, you will need to call `feather_rp2040::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_ repository and run: + +```console +rp-hal/boards/feather_rp2040 $ cargo build --release --example +``` + +You will get an ELF file called +`./target/thumbv6m-none-eabi/release/examples/`, where the `target` +folder is located at the top of the _rp-hal_ 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/feather_rp2040 $ cargo run --release --example +``` + +If you get an error about not being able to find `elf2uf2-rs`, try: + +```console +$ cargo install elf2uf2-rs, then repeating the `cargo run` command above. +``` + +### [feather_blinky](./examples/feather_blinky.rs) + +Flashes the Feather's on-board LED on and off. + +## 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/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 chose either the MIT licence or the +Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more +information on each specific licence. + +Any submissions to this project (e.g. as Pull Requests) must be made available +under these terms. From 1e6d14abb03ca27b45bc9916badcea60822363c4 Mon Sep 17 00:00:00 2001 From: "Jonathan Pallant (42 Technology)" Date: Tue, 21 Sep 2021 16:18:19 +0100 Subject: [PATCH 11/12] Correct typo. --- README.md | 2 +- boards/pico/README.md | 4 ++-- boards/pro_micro_rp2040/README.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 645671a..808656a 100644 --- a/README.md +++ b/README.md @@ -186,7 +186,7 @@ to intervene to uphold that code of conduct. The contents of this repository are dual-licensed under the _MIT OR Apache 2.0_ License. That means you can chose either the MIT licence or the -Apache-2.0 when you re-use this code. See `MIT` or `APACHE2.0` for more +Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more information on each specific licence. Any submissions to this project (e.g. as Pull Requests) must be made available diff --git a/boards/pico/README.md b/boards/pico/README.md index 21df1ec..08330db 100644 --- a/boards/pico/README.md +++ b/boards/pico/README.md @@ -4,7 +4,7 @@ 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 Pro Micro RP2040. +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 @@ -123,7 +123,7 @@ to intervene to uphold that code of conduct. The contents of this repository are dual-licensed under the _MIT OR Apache 2.0_ License. That means you can chose either the MIT licence or the -Apache-2.0 when you re-use this code. See `MIT` or `APACHE2.0` for more +Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more information on each specific licence. Any submissions to this project (e.g. as Pull Requests) must be made available diff --git a/boards/pro_micro_rp2040/README.md b/boards/pro_micro_rp2040/README.md index a9809ef..40ad916 100644 --- a/boards/pro_micro_rp2040/README.md +++ b/boards/pro_micro_rp2040/README.md @@ -87,7 +87,7 @@ to intervene to uphold that code of conduct. The contents of this repository are dual-licensed under the _MIT OR Apache 2.0_ License. That means you can chose either the MIT licence or the -Apache-2.0 when you re-use this code. See `MIT` or `APACHE2.0` for more +Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more information on each specific licence. Any submissions to this project (e.g. as Pull Requests) must be made available From cbff22b911b7401dc66436d677abaa7e9f6dc140 Mon Sep 17 00:00:00 2001 From: "Jonathan Pallant (42 Technology)" Date: Tue, 21 Sep 2021 16:38:03 +0100 Subject: [PATCH 12/12] Fix the pico lipo example. --- boards/pico_lipo_16mb/Cargo.toml | 9 +++++++++ .../pico_lipo_16mb/examples/pico_lipo_16mb_blinky.rs | 10 +++++----- boards/pico_lipo_16mb/src/lib.rs | 2 +- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/boards/pico_lipo_16mb/Cargo.toml b/boards/pico_lipo_16mb/Cargo.toml index 2842cf7..8790b46 100644 --- a/boards/pico_lipo_16mb/Cargo.toml +++ b/boards/pico_lipo_16mb/Cargo.toml @@ -14,6 +14,15 @@ cortex-m = "0.7.2" rp2040-hal = { path = "../../rp2040-hal", version = "0.2.0"} cortex-m-rt = { version = "0.7", optional = true } +[dev-dependencies] +embedded-time = "0.12.0" +panic-halt= "0.2.0" +embedded-hal ="0.2.5" +cortex-m-rtic = "0.6.0-alpha.5" +rp2040-boot2 = "0.1.2" +nb = "1.0" + + [features] default = ["rt"] rt = ["cortex-m-rt","rp2040-hal/rt"] \ No newline at end of file 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 7a1a89e..0fc65f5 100644 --- a/boards/pico_lipo_16mb/examples/pico_lipo_16mb_blinky.rs +++ b/boards/pico_lipo_16mb/examples/pico_lipo_16mb_blinky.rs @@ -24,15 +24,15 @@ use embedded_time::rate::*; use panic_halt as _; // Pull in any important traits -use pico::hal::prelude::*; +use pico_lipo_16_mb::hal::prelude::*; // A shorter alias for the Peripheral Access Crate, which provides low-level // register access -use pico::hal::pac; +use pico_lipo_16_mb::hal::pac; // A shorter alias for the Hardware Abstraction Layer, which provides // higher-level drivers. -use pico::hal; +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. @@ -60,7 +60,7 @@ fn main() -> ! { // // Our default is 12 MHz crystal input, 125 MHz system clock let clocks = hal::clocks::init_clocks_and_plls( - pico::XOSC_CRYSTAL_FREQ, + pico_lipo_16_mb::XOSC_CRYSTAL_FREQ, pac.XOSC, pac.CLOCKS, pac.PLL_SYS, @@ -79,7 +79,7 @@ fn main() -> ! { let sio = hal::sio::Sio::new(pac.SIO); // Set the pins up according to their function on this particular board - let pins = pico::Pins::new( + let pins = pico_lipo_16_mb::Pins::new( pac.IO_BANK0, pac.PADS_BANK0, sio.gpio_bank0, diff --git a/boards/pico_lipo_16mb/src/lib.rs b/boards/pico_lipo_16mb/src/lib.rs index dc5a760..b9c65ad 100644 --- a/boards/pico_lipo_16mb/src/lib.rs +++ b/boards/pico_lipo_16mb/src/lib.rs @@ -1,6 +1,6 @@ #![no_std] -extern crate rp2040_hal as hal; +pub use rp2040_hal as hal; #[cfg(feature = "rt")] extern crate cortex_m_rt;