mirror of
https://github.com/embassy-rs/embassy.git
synced 2025-10-02 06:40:32 +00:00
Add PIO clock divider utility and refactor related modules
This commit is contained in:
parent
3441e80507
commit
3d9cac361e
25
embassy-rp/src/pio_programs/clock_divider.rs
Normal file
25
embassy-rp/src/pio_programs/clock_divider.rs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
//! Helper functions for calculating PIO clock dividers
|
||||||
|
|
||||||
|
use fixed::traits::ToFixed;
|
||||||
|
use fixed::types::extra::U8;
|
||||||
|
|
||||||
|
use crate::clocks::clk_sys_freq;
|
||||||
|
|
||||||
|
/// Calculate a PIO clock divider value based on the desired target frequency.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `target_hz` - The desired PIO clock frequency in Hz
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// A fixed-point divider value suitable for use in a PIO state machine configuration
|
||||||
|
#[inline]
|
||||||
|
pub fn calculate_pio_clock_divider(target_hz: u32) -> fixed::FixedU32<U8> {
|
||||||
|
// Requires a non-zero frequency
|
||||||
|
assert!(target_hz > 0, "PIO clock frequency cannot be zero");
|
||||||
|
|
||||||
|
// Calculate the divider
|
||||||
|
let divider = (clk_sys_freq() + target_hz / 2) / target_hz;
|
||||||
|
divider.to_fixed()
|
||||||
|
}
|
@ -1,11 +1,11 @@
|
|||||||
//! [HD44780 display driver](https://www.sparkfun.com/datasheets/LCD/HD44780.pdf)
|
//! [HD44780 display driver](https://www.sparkfun.com/datasheets/LCD/HD44780.pdf)
|
||||||
|
|
||||||
use crate::clocks::clk_sys_freq;
|
|
||||||
use crate::dma::{AnyChannel, Channel};
|
use crate::dma::{AnyChannel, Channel};
|
||||||
use crate::pio::{
|
use crate::pio::{
|
||||||
Common, Config, Direction, FifoJoin, Instance, Irq, LoadedProgram, PioPin, ShiftConfig, ShiftDirection,
|
Common, Config, Direction, FifoJoin, Instance, Irq, LoadedProgram, PioPin, ShiftConfig, ShiftDirection,
|
||||||
StateMachine,
|
StateMachine,
|
||||||
};
|
};
|
||||||
|
use crate::pio_programs::clock_divider::calculate_pio_clock_divider;
|
||||||
use crate::Peri;
|
use crate::Peri;
|
||||||
|
|
||||||
/// This struct represents a HD44780 program that takes command words (<wait:24> <command:4> <0:4>)
|
/// This struct represents a HD44780 program that takes command words (<wait:24> <command:4> <0:4>)
|
||||||
@ -136,10 +136,8 @@ impl<'l, P: Instance, const S: usize> PioHD44780<'l, P, S> {
|
|||||||
let mut cfg = Config::default();
|
let mut cfg = Config::default();
|
||||||
cfg.use_program(&word_prg.prg, &[&e]);
|
cfg.use_program(&word_prg.prg, &[&e]);
|
||||||
|
|
||||||
// Scale the divider based on system clock frequency
|
// Target 1 MHz PIO clock (each cycle is 1µs)
|
||||||
// Original: 125 at 125 MHz (1 MHz PIO clock)
|
cfg.clock_divider = calculate_pio_clock_divider(1_000_000);
|
||||||
let word_divider = (clk_sys_freq() / 1_000_000) as u8; // Target 1 MHz PIO clock
|
|
||||||
cfg.clock_divider = word_divider.into();
|
|
||||||
|
|
||||||
cfg.set_out_pins(&[&db4, &db5, &db6, &db7]);
|
cfg.set_out_pins(&[&db4, &db5, &db6, &db7]);
|
||||||
cfg.shift_out = ShiftConfig {
|
cfg.shift_out = ShiftConfig {
|
||||||
@ -167,10 +165,8 @@ impl<'l, P: Instance, const S: usize> PioHD44780<'l, P, S> {
|
|||||||
let mut cfg = Config::default();
|
let mut cfg = Config::default();
|
||||||
cfg.use_program(&seq_prg.prg, &[&e]);
|
cfg.use_program(&seq_prg.prg, &[&e]);
|
||||||
|
|
||||||
// Original: 8 at 125 MHz (~15.6 MHz PIO clock)
|
// Target ~15.6 MHz PIO clock (~64ns/insn)
|
||||||
// Comment says ~64ns/insn which is 1/(15.6 MHz) = ~64ns
|
cfg.clock_divider = calculate_pio_clock_divider(15_600_000);
|
||||||
let seq_divider = (clk_sys_freq() / 15_600_000) as u8; // Target ~15.6 MHz PIO clock (~64ns/insn)
|
|
||||||
cfg.clock_divider = seq_divider.into();
|
|
||||||
|
|
||||||
cfg.set_jmp_pin(&db7);
|
cfg.set_jmp_pin(&db7);
|
||||||
cfg.set_set_pins(&[&rs, &rw]);
|
cfg.set_set_pins(&[&rs, &rw]);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
//! Pre-built pio programs for common interfaces
|
//! Pre-built pio programs for common interfaces
|
||||||
|
|
||||||
|
pub mod clock_divider;
|
||||||
pub mod hd44780;
|
pub mod hd44780;
|
||||||
pub mod i2s;
|
pub mod i2s;
|
||||||
pub mod onewire;
|
pub mod onewire;
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
//! PIO backed quadrature encoder
|
//! PIO backed quadrature encoder
|
||||||
|
|
||||||
use fixed::traits::ToFixed;
|
|
||||||
|
|
||||||
use crate::clocks::clk_sys_freq;
|
|
||||||
use crate::gpio::Pull;
|
use crate::gpio::Pull;
|
||||||
use crate::pio::{
|
use crate::pio::{
|
||||||
Common, Config, Direction as PioDirection, FifoJoin, Instance, LoadedProgram, PioPin, ShiftDirection, StateMachine,
|
Common, Config, Direction as PioDirection, FifoJoin, Instance, LoadedProgram, PioPin, ShiftDirection, StateMachine,
|
||||||
};
|
};
|
||||||
|
use crate::pio_programs::clock_divider::calculate_pio_clock_divider;
|
||||||
use crate::Peri;
|
use crate::Peri;
|
||||||
|
|
||||||
/// This struct represents an Encoder program loaded into pio instruction memory.
|
/// This struct represents an Encoder program loaded into pio instruction memory.
|
||||||
@ -50,10 +48,8 @@ impl<'d, T: Instance, const SM: usize> PioEncoder<'d, T, SM> {
|
|||||||
cfg.fifo_join = FifoJoin::RxOnly;
|
cfg.fifo_join = FifoJoin::RxOnly;
|
||||||
cfg.shift_in.direction = ShiftDirection::Left;
|
cfg.shift_in.direction = ShiftDirection::Left;
|
||||||
|
|
||||||
// Original: 10_000 at 125 MHz (12.5 KHz PIO clock)
|
// Target 12.5 KHz PIO clock
|
||||||
// Scale divider to maintain same PIO clock frequency at different system clocks
|
cfg.clock_divider = calculate_pio_clock_divider(12_500);
|
||||||
let divider = (clk_sys_freq() as f32 / 12_500.0).to_fixed();
|
|
||||||
cfg.clock_divider = divider;
|
|
||||||
|
|
||||||
cfg.use_program(&program.prg, &[]);
|
cfg.use_program(&program.prg, &[]);
|
||||||
sm.set_config(&cfg);
|
sm.set_config(&cfg);
|
||||||
|
@ -2,12 +2,8 @@
|
|||||||
|
|
||||||
use core::mem::{self, MaybeUninit};
|
use core::mem::{self, MaybeUninit};
|
||||||
|
|
||||||
use fixed::traits::ToFixed;
|
|
||||||
use fixed::types::extra::U8;
|
|
||||||
use fixed::FixedU32;
|
|
||||||
|
|
||||||
use crate::clocks::clk_sys_freq;
|
|
||||||
use crate::pio::{Common, Config, Direction, Instance, Irq, LoadedProgram, PioPin, StateMachine};
|
use crate::pio::{Common, Config, Direction, Instance, Irq, LoadedProgram, PioPin, StateMachine};
|
||||||
|
use crate::pio_programs::clock_divider::calculate_pio_clock_divider;
|
||||||
use crate::Peri;
|
use crate::Peri;
|
||||||
|
|
||||||
/// This struct represents a Stepper driver program loaded into pio instruction memory.
|
/// This struct represents a Stepper driver program loaded into pio instruction memory.
|
||||||
@ -65,7 +61,9 @@ impl<'d, T: Instance, const SM: usize> PioStepper<'d, T, SM> {
|
|||||||
sm.set_pin_dirs(Direction::Out, &[&pin0, &pin1, &pin2, &pin3]);
|
sm.set_pin_dirs(Direction::Out, &[&pin0, &pin1, &pin2, &pin3]);
|
||||||
let mut cfg = Config::default();
|
let mut cfg = Config::default();
|
||||||
cfg.set_out_pins(&[&pin0, &pin1, &pin2, &pin3]);
|
cfg.set_out_pins(&[&pin0, &pin1, &pin2, &pin3]);
|
||||||
cfg.clock_divider = (clk_sys_freq() / (100 * 136)).to_fixed();
|
|
||||||
|
cfg.clock_divider = calculate_pio_clock_divider(100 * 136);
|
||||||
|
|
||||||
cfg.use_program(&program.prg, &[]);
|
cfg.use_program(&program.prg, &[]);
|
||||||
sm.set_config(&cfg);
|
sm.set_config(&cfg);
|
||||||
sm.set_enable(true);
|
sm.set_enable(true);
|
||||||
@ -74,9 +72,11 @@ impl<'d, T: Instance, const SM: usize> PioStepper<'d, T, SM> {
|
|||||||
|
|
||||||
/// Set pulse frequency
|
/// Set pulse frequency
|
||||||
pub fn set_frequency(&mut self, freq: u32) {
|
pub fn set_frequency(&mut self, freq: u32) {
|
||||||
let clock_divider: FixedU32<U8> = (clk_sys_freq() / (freq * 136)).to_fixed();
|
let clock_divider = calculate_pio_clock_divider(freq * 136);
|
||||||
assert!(clock_divider <= 65536, "clkdiv must be <= 65536");
|
let divider_f32 = clock_divider.to_num::<f32>();
|
||||||
assert!(clock_divider >= 1, "clkdiv must be >= 1");
|
assert!(divider_f32 <= 65536.0, "clkdiv must be <= 65536");
|
||||||
|
assert!(divider_f32 >= 1.0, "clkdiv must be >= 1");
|
||||||
|
|
||||||
self.sm.set_clock_divider(clock_divider);
|
self.sm.set_clock_divider(clock_divider);
|
||||||
self.sm.clkdiv_restart();
|
self.sm.clkdiv_restart();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user