From fd40190823583435ef286992688e8dbeb5ae9e71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Dobrowolski?= Date: Thu, 27 Nov 2025 22:51:53 +0100 Subject: [PATCH 1/3] embassy-rp: Add a simple clk generator using pio --- embassy-rp/src/pio_programs/clk.rs | 66 ++++++++++++++++++++++++++++++ embassy-rp/src/pio_programs/mod.rs | 1 + 2 files changed, 67 insertions(+) create mode 100644 embassy-rp/src/pio_programs/clk.rs diff --git a/embassy-rp/src/pio_programs/clk.rs b/embassy-rp/src/pio_programs/clk.rs new file mode 100644 index 0000000000..69996353df --- /dev/null +++ b/embassy-rp/src/pio_programs/clk.rs @@ -0,0 +1,66 @@ +//! Clock generator using PIO + +use crate::Peri; +use crate::pio::program::pio_asm; +use crate::pio::{Common, Config, Direction, Instance, LoadedProgram, Pin, PioPin, StateMachine}; +use crate::pio_programs::clock_divider::calculate_pio_clock_divider; + +/// Clock PIO program. +pub struct PioClkProgram<'a, PIO: Instance> { + prg: LoadedProgram<'a, PIO>, +} + +impl<'a, PIO: Instance> PioClkProgram<'a, PIO> { + /// Load the program into PIO instruction memory. + pub fn new(common: &mut Common<'a, PIO>) -> Self { + let prg = pio_asm!("set pins 0", "set pins 1"); + let prg = common.load_program(&prg.program); + Self { prg } + } +} + +/// Pio backed PWM output +pub struct PioClk<'d, T: Instance, const SM: usize> { + sm: StateMachine<'d, T, SM>, + pin: Pin<'d, T>, +} + +impl<'d, T: Instance, const SM: usize> PioClk<'d, T, SM> { + /// Configure state mashine for clock generation. + pub fn new( + pio: &mut Common<'d, T>, + mut sm: StateMachine<'d, T, SM>, + pin: Peri<'d, impl PioPin>, + program: &PioClkProgram<'d, T>, + frequency: u32, + ) -> Self { + let pin = pio.make_pio_pin(pin); + sm.set_pin_dirs(Direction::Out, &[&pin]); + + let mut cfg = Config::default(); + let program_critical_loop_len = 2; + let sm_frequency = frequency * program_critical_loop_len; + cfg.clock_divider = calculate_pio_clock_divider(sm_frequency); + cfg.set_set_pins(&[&pin]); + cfg.use_program(&program.prg, &[]); + + sm.set_config(&cfg); + + Self { sm, pin } + } + + /// Start emmiting clock. + pub fn start(&mut self) { + self.sm.set_enable(true); + } + + /// Stop emmiting clock. + pub fn stop(&mut self) { + self.sm.set_enable(false); + } + + /// Return the state machine and pin. + pub fn release(self) -> (StateMachine<'d, T, SM>, Pin<'d, T>) { + (self.sm, self.pin) + } +} diff --git a/embassy-rp/src/pio_programs/mod.rs b/embassy-rp/src/pio_programs/mod.rs index d05ba38841..74a3714c77 100644 --- a/embassy-rp/src/pio_programs/mod.rs +++ b/embassy-rp/src/pio_programs/mod.rs @@ -1,5 +1,6 @@ //! Pre-built pio programs for common interfaces +pub mod clk; pub mod clock_divider; pub mod hd44780; pub mod i2s; From 312ca919357e7b6d87d3e8278ee5d062cf6bad0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Dobrowolski?= Date: Thu, 27 Nov 2025 22:52:38 +0100 Subject: [PATCH 2/3] examples/rp: Add pio_clk example --- examples/rp/src/bin/pio_clk.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 examples/rp/src/bin/pio_clk.rs diff --git a/examples/rp/src/bin/pio_clk.rs b/examples/rp/src/bin/pio_clk.rs new file mode 100644 index 0000000000..56ab6ceb3d --- /dev/null +++ b/examples/rp/src/bin/pio_clk.rs @@ -0,0 +1,32 @@ +//! This example shows how to create a clock using the PIO module in the RP2040 chip. + +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; +use embassy_rp::peripherals::PIO0; +use embassy_rp::pio::{InterruptHandler, Pio}; +use embassy_rp::pio_programs::clk::{PioClk, PioClkProgram}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + PIO0_IRQ_0 => InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); + + let prg = PioClkProgram::new(&mut common); + let mut clk = PioClk::new(&mut common, sm0, p.PIN_0, &prg, 10_000); + + loop { + clk.start(); + Timer::after_millis(500).await; + clk.stop(); + Timer::after_millis(500).await; + } +} From 198c5337bc31915046434a1ba4445d0cfc6802df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Dobrowolski?= Date: Thu, 27 Nov 2025 22:59:24 +0100 Subject: [PATCH 3/3] Update CHANGELOG --- embassy-rp/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-rp/CHANGELOG.md b/embassy-rp/CHANGELOG.md index 773301b0fb..5e45c2af19 100644 --- a/embassy-rp/CHANGELOG.md +++ b/embassy-rp/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add PIO SPI - Add PIO I2S input - Add PIO onewire parasite power strong pullup +- Add PIO clock generator - add `wait_for_alarm` and `alarm_scheduled` methods to rtc module ([#4216](https://github.com/embassy-rs/embassy/pull/4216)) - rp235x: use msplim for stack guard instead of MPU - Add reset_to_usb_boot for rp235x ([#4705](https://github.com/embassy-rs/embassy/pull/4705))