From db8641e429833f4367ee5c3f2cab81de911b50ff Mon Sep 17 00:00:00 2001 From: Jan Niehusmann Date: Tue, 19 Dec 2023 23:05:41 +0000 Subject: [PATCH] Implement embedded_hal::pwm::SetDutyCycle of embedded-hal 1.0 Also add a new example pwm_blink_embedded_hal_1 which uses this trait, to have a minimal test case. --- rp2040-hal/Cargo.toml | 4 + .../examples/pwm_blink_embedded_hal_1.rs | 122 ++++++++++++++++++ rp2040-hal/src/pwm/mod.rs | 21 ++- 3 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 rp2040-hal/examples/pwm_blink_embedded_hal_1.rs diff --git a/rp2040-hal/Cargo.toml b/rp2040-hal/Cargo.toml index 0a8b2fc38..3c06c6eb2 100644 --- a/rp2040-hal/Cargo.toml +++ b/rp2040-hal/Cargo.toml @@ -180,6 +180,10 @@ required-features = ["critical-section-impl"] name = "pwm_blink" required-features = ["critical-section-impl"] +[[example]] +name = "pwm_blink_embedded_hal_1" +required-features = ["critical-section-impl", "eh1_0_alpha"] + [[example]] name = "rom_funcs" required-features = ["critical-section-impl"] diff --git a/rp2040-hal/examples/pwm_blink_embedded_hal_1.rs b/rp2040-hal/examples/pwm_blink_embedded_hal_1.rs new file mode 100644 index 000000000..02e2e240b --- /dev/null +++ b/rp2040-hal/examples/pwm_blink_embedded_hal_1.rs @@ -0,0 +1,122 @@ +//! # 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 license details. + +#![no_std] +#![no_main] + +// Ensure we halt the program on panic (if we don't mention this crate it won't +// be linked) +use panic_halt as _; + +// Alias for our HAL crate +use rp2040_hal as hal; + +// Some traits we need +use eh1_0_alpha::pwm::SetDutyCycle; +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. +/// Note: This boot block is not necessary when using a rp-hal based BSP +/// as the BSPs already perform this step. +#[link_section = ".boot2"] +#[used] +pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_GENERIC_03H; + +/// 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 `#[rp2040_hal::entry]` macro ensures the Cortex-M start-up code calls this function +/// as soon as all global variables and the spinlock are initialised. +/// +/// The function configures the RP2040 peripherals, then fades the LED in an +/// infinite loop. +#[rp2040_hal::entry] +fn main() -> ! { + // Grab our singleton objects + let mut pac = pac::Peripherals::take().unwrap(); + let core = pac::CorePeripherals::take().unwrap(); + + // Set up the watchdog driver - needed by the clock setup code + let mut watchdog = hal::Watchdog::new(pac.WATCHDOG); + + // Configure the clocks + // + // The default is to generate a 125 MHz system clock + let clocks = hal::clocks::init_clocks_and_plls( + 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::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().to_Hz()); + + // Init PWMs + let mut pwm_slices = hal::pwm::Slices::new(pac.PWM, &mut pac.RESETS); + + // Configure PWM4 + let pwm = &mut pwm_slices.pwm4; + pwm.set_ph_correct(); + pwm.enable(); + + // Output channel B on PWM4 to GPIO 25 + let channel = &mut pwm.channel_b; + channel.output_to(pins.gpio25); + + // 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_cycle(i).unwrap(); + } + + // Ramp brightness down + for i in (LOW..=HIGH).rev().skip(100) { + delay.delay_us(8); + channel.set_duty_cycle(i).unwrap(); + } + + delay.delay_ms(500); + } +} + +// End of file diff --git a/rp2040-hal/src/pwm/mod.rs b/rp2040-hal/src/pwm/mod.rs index b06e1b8c6..acabc915a 100644 --- a/rp2040-hal/src/pwm/mod.rs +++ b/rp2040-hal/src/pwm/mod.rs @@ -76,8 +76,10 @@ //! min_config() leaves those registers in the state they were before it was called (Careful, this can lead to unexpected behavior) //! It's recommended to only call min_config() after calling default_config() on a pin that shares a PWM block. -use core::marker::PhantomData; +use core::{convert::Infallible, marker::PhantomData}; +#[cfg(feature = "eh1_0_alpha")] +use eh1_0_alpha::pwm::{ErrorType, SetDutyCycle}; use embedded_dma::Word; use embedded_hal::PwmPin; @@ -652,6 +654,23 @@ impl PwmPin for Channel { } } +#[cfg(feature = "eh1_0_alpha")] +impl ErrorType for Channel { + type Error = Infallible; +} + +#[cfg(feature = "eh1_0_alpha")] +impl SetDutyCycle for Channel { + fn max_duty_cycle(&self) -> u16 { + self.get_max_duty() + } + + fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> { + self.set_duty(duty); + Ok(()) + } +} + impl PwmPin for Channel { type Duty = u16;