Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions embassy-rp/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
66 changes: 66 additions & 0 deletions embassy-rp/src/pio_programs/clk.rs
Original file line number Diff line number Diff line change
@@ -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)
}
}
1 change: 1 addition & 0 deletions embassy-rp/src/pio_programs/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Pre-built pio programs for common interfaces
pub mod clk;
pub mod clock_divider;
pub mod hd44780;
pub mod i2s;
Expand Down
32 changes: 32 additions & 0 deletions examples/rp/src/bin/pio_clk.rs
Original file line number Diff line number Diff line change
@@ -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<PIO0>;
});

#[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;
}
}