diff options
| -rw-r--r-- | embassy-rp/src/pio_programs/clock_divider.rs | 25 | ||||
| -rw-r--r-- | embassy-rp/src/pio_programs/hd44780.rs | 14 | ||||
| -rw-r--r-- | embassy-rp/src/pio_programs/mod.rs | 1 | ||||
| -rw-r--r-- | embassy-rp/src/pio_programs/rotary_encoder.rs | 10 | ||||
| -rw-r--r-- | embassy-rp/src/pio_programs/stepper.rs | 18 |
5 files changed, 43 insertions, 25 deletions
diff --git a/embassy-rp/src/pio_programs/clock_divider.rs b/embassy-rp/src/pio_programs/clock_divider.rs new file mode 100644 index 000000000..02e353f53 --- /dev/null +++ b/embassy-rp/src/pio_programs/clock_divider.rs | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | //! Helper functions for calculating PIO clock dividers | ||
| 2 | |||
| 3 | use fixed::traits::ToFixed; | ||
| 4 | use fixed::types::extra::U8; | ||
| 5 | |||
| 6 | use crate::clocks::clk_sys_freq; | ||
| 7 | |||
| 8 | /// Calculate a PIO clock divider value based on the desired target frequency. | ||
| 9 | /// | ||
| 10 | /// # Arguments | ||
| 11 | /// | ||
| 12 | /// * `target_hz` - The desired PIO clock frequency in Hz | ||
| 13 | /// | ||
| 14 | /// # Returns | ||
| 15 | /// | ||
| 16 | /// A fixed-point divider value suitable for use in a PIO state machine configuration | ||
| 17 | #[inline] | ||
| 18 | pub fn calculate_pio_clock_divider(target_hz: u32) -> fixed::FixedU32<U8> { | ||
| 19 | // Requires a non-zero frequency | ||
| 20 | assert!(target_hz > 0, "PIO clock frequency cannot be zero"); | ||
| 21 | |||
| 22 | // Calculate the divider | ||
| 23 | let divider = (clk_sys_freq() + target_hz / 2) / target_hz; | ||
| 24 | divider.to_fixed() | ||
| 25 | } | ||
diff --git a/embassy-rp/src/pio_programs/hd44780.rs b/embassy-rp/src/pio_programs/hd44780.rs index 3aa54495f..546c85a89 100644 --- a/embassy-rp/src/pio_programs/hd44780.rs +++ b/embassy-rp/src/pio_programs/hd44780.rs | |||
| @@ -1,11 +1,11 @@ | |||
| 1 | //! [HD44780 display driver](https://www.sparkfun.com/datasheets/LCD/HD44780.pdf) | 1 | //! [HD44780 display driver](https://www.sparkfun.com/datasheets/LCD/HD44780.pdf) |
| 2 | 2 | ||
| 3 | use crate::clocks::clk_sys_freq; | ||
| 4 | use crate::dma::{AnyChannel, Channel}; | 3 | use crate::dma::{AnyChannel, Channel}; |
| 5 | use crate::pio::{ | 4 | use crate::pio::{ |
| 6 | Common, Config, Direction, FifoJoin, Instance, Irq, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, | 5 | Common, Config, Direction, FifoJoin, Instance, Irq, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, |
| 7 | StateMachine, | 6 | StateMachine, |
| 8 | }; | 7 | }; |
| 8 | use crate::pio_programs::clock_divider::calculate_pio_clock_divider; | ||
| 9 | use crate::Peri; | 9 | use crate::Peri; |
| 10 | 10 | ||
| 11 | /// This struct represents a HD44780 program that takes command words (<wait:24> <command:4> <0:4>) | 11 | /// 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> { | |||
| 136 | let mut cfg = Config::default(); | 136 | let mut cfg = Config::default(); |
| 137 | cfg.use_program(&word_prg.prg, &[&e]); | 137 | cfg.use_program(&word_prg.prg, &[&e]); |
| 138 | 138 | ||
| 139 | // Scale the divider based on system clock frequency | 139 | // Target 1 MHz PIO clock (each cycle is 1µs) |
| 140 | // Original: 125 at 125 MHz (1 MHz PIO clock) | 140 | cfg.clock_divider = calculate_pio_clock_divider(1_000_000); |
| 141 | let word_divider = (clk_sys_freq() / 1_000_000) as u8; // Target 1 MHz PIO clock | ||
| 142 | cfg.clock_divider = word_divider.into(); | ||
| 143 | 141 | ||
| 144 | cfg.set_out_pins(&[&db4, &db5, &db6, &db7]); | 142 | cfg.set_out_pins(&[&db4, &db5, &db6, &db7]); |
| 145 | cfg.shift_out = ShiftConfig { | 143 | cfg.shift_out = ShiftConfig { |
| @@ -167,10 +165,8 @@ impl<'l, P: Instance, const S: usize> PioHD44780<'l, P, S> { | |||
| 167 | let mut cfg = Config::default(); | 165 | let mut cfg = Config::default(); |
| 168 | cfg.use_program(&seq_prg.prg, &[&e]); | 166 | cfg.use_program(&seq_prg.prg, &[&e]); |
| 169 | 167 | ||
| 170 | // Original: 8 at 125 MHz (~15.6 MHz PIO clock) | 168 | // Target ~15.6 MHz PIO clock (~64ns/insn) |
| 171 | // Comment says ~64ns/insn which is 1/(15.6 MHz) = ~64ns | 169 | cfg.clock_divider = calculate_pio_clock_divider(15_600_000); |
| 172 | let seq_divider = (clk_sys_freq() / 15_600_000) as u8; // Target ~15.6 MHz PIO clock (~64ns/insn) | ||
| 173 | cfg.clock_divider = seq_divider.into(); | ||
| 174 | 170 | ||
| 175 | cfg.set_jmp_pin(&db7); | 171 | cfg.set_jmp_pin(&db7); |
| 176 | cfg.set_set_pins(&[&rs, &rw]); | 172 | cfg.set_set_pins(&[&rs, &rw]); |
diff --git a/embassy-rp/src/pio_programs/mod.rs b/embassy-rp/src/pio_programs/mod.rs index 74537825b..8eac328b3 100644 --- a/embassy-rp/src/pio_programs/mod.rs +++ b/embassy-rp/src/pio_programs/mod.rs | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | //! Pre-built pio programs for common interfaces | 1 | //! Pre-built pio programs for common interfaces |
| 2 | 2 | ||
| 3 | pub mod clock_divider; | ||
| 3 | pub mod hd44780; | 4 | pub mod hd44780; |
| 4 | pub mod i2s; | 5 | pub mod i2s; |
| 5 | pub mod onewire; | 6 | pub mod onewire; |
diff --git a/embassy-rp/src/pio_programs/rotary_encoder.rs b/embassy-rp/src/pio_programs/rotary_encoder.rs index 71567a602..70b3795e9 100644 --- a/embassy-rp/src/pio_programs/rotary_encoder.rs +++ b/embassy-rp/src/pio_programs/rotary_encoder.rs | |||
| @@ -1,12 +1,10 @@ | |||
| 1 | //! PIO backed quadrature encoder | 1 | //! PIO backed quadrature encoder |
| 2 | 2 | ||
| 3 | use fixed::traits::ToFixed; | ||
| 4 | |||
| 5 | use crate::clocks::clk_sys_freq; | ||
| 6 | use crate::gpio::Pull; | 3 | use crate::gpio::Pull; |
| 7 | use crate::pio::{ | 4 | use crate::pio::{ |
| 8 | Common, Config, Direction as PioDirection, FifoJoin, Instance, LoadedProgram, PioPin, ShiftDirection, StateMachine, | 5 | Common, Config, Direction as PioDirection, FifoJoin, Instance, LoadedProgram, PioPin, ShiftDirection, StateMachine, |
| 9 | }; | 6 | }; |
| 7 | use crate::pio_programs::clock_divider::calculate_pio_clock_divider; | ||
| 10 | use crate::Peri; | 8 | use crate::Peri; |
| 11 | 9 | ||
| 12 | /// This struct represents an Encoder program loaded into pio instruction memory. | 10 | /// 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> { | |||
| 50 | cfg.fifo_join = FifoJoin::RxOnly; | 48 | cfg.fifo_join = FifoJoin::RxOnly; |
| 51 | cfg.shift_in.direction = ShiftDirection::Left; | 49 | cfg.shift_in.direction = ShiftDirection::Left; |
| 52 | 50 | ||
| 53 | // Original: 10_000 at 125 MHz (12.5 KHz PIO clock) | 51 | // Target 12.5 KHz PIO clock |
| 54 | // Scale divider to maintain same PIO clock frequency at different system clocks | 52 | cfg.clock_divider = calculate_pio_clock_divider(12_500); |
| 55 | let divider = (clk_sys_freq() as f32 / 12_500.0).to_fixed(); | ||
| 56 | cfg.clock_divider = divider; | ||
| 57 | 53 | ||
| 58 | cfg.use_program(&program.prg, &[]); | 54 | cfg.use_program(&program.prg, &[]); |
| 59 | sm.set_config(&cfg); | 55 | sm.set_config(&cfg); |
diff --git a/embassy-rp/src/pio_programs/stepper.rs b/embassy-rp/src/pio_programs/stepper.rs index 6878c32f5..0e9a8daf9 100644 --- a/embassy-rp/src/pio_programs/stepper.rs +++ b/embassy-rp/src/pio_programs/stepper.rs | |||
| @@ -2,12 +2,8 @@ | |||
| 2 | 2 | ||
| 3 | use core::mem::{self, MaybeUninit}; | 3 | use core::mem::{self, MaybeUninit}; |
| 4 | 4 | ||
| 5 | use fixed::traits::ToFixed; | ||
| 6 | use fixed::types::extra::U8; | ||
| 7 | use fixed::FixedU32; | ||
| 8 | |||
| 9 | use crate::clocks::clk_sys_freq; | ||
| 10 | use crate::pio::{Common, Config, Direction, Instance, Irq, LoadedProgram, PioPin, StateMachine}; | 5 | use crate::pio::{Common, Config, Direction, Instance, Irq, LoadedProgram, PioPin, StateMachine}; |
| 6 | use crate::pio_programs::clock_divider::calculate_pio_clock_divider; | ||
| 11 | use crate::Peri; | 7 | use crate::Peri; |
| 12 | 8 | ||
| 13 | /// This struct represents a Stepper driver program loaded into pio instruction memory. | 9 | /// 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> { | |||
| 65 | sm.set_pin_dirs(Direction::Out, &[&pin0, &pin1, &pin2, &pin3]); | 61 | sm.set_pin_dirs(Direction::Out, &[&pin0, &pin1, &pin2, &pin3]); |
| 66 | let mut cfg = Config::default(); | 62 | let mut cfg = Config::default(); |
| 67 | cfg.set_out_pins(&[&pin0, &pin1, &pin2, &pin3]); | 63 | cfg.set_out_pins(&[&pin0, &pin1, &pin2, &pin3]); |
| 68 | cfg.clock_divider = (clk_sys_freq() / (100 * 136)).to_fixed(); | 64 | |
| 65 | cfg.clock_divider = calculate_pio_clock_divider(100 * 136); | ||
| 66 | |||
| 69 | cfg.use_program(&program.prg, &[]); | 67 | cfg.use_program(&program.prg, &[]); |
| 70 | sm.set_config(&cfg); | 68 | sm.set_config(&cfg); |
| 71 | sm.set_enable(true); | 69 | sm.set_enable(true); |
| @@ -74,9 +72,11 @@ impl<'d, T: Instance, const SM: usize> PioStepper<'d, T, SM> { | |||
| 74 | 72 | ||
| 75 | /// Set pulse frequency | 73 | /// Set pulse frequency |
| 76 | pub fn set_frequency(&mut self, freq: u32) { | 74 | pub fn set_frequency(&mut self, freq: u32) { |
| 77 | let clock_divider: FixedU32<U8> = (clk_sys_freq() / (freq * 136)).to_fixed(); | 75 | let clock_divider = calculate_pio_clock_divider(freq * 136); |
| 78 | assert!(clock_divider <= 65536, "clkdiv must be <= 65536"); | 76 | let divider_f32 = clock_divider.to_num::<f32>(); |
| 79 | assert!(clock_divider >= 1, "clkdiv must be >= 1"); | 77 | assert!(divider_f32 <= 65536.0, "clkdiv must be <= 65536"); |
| 78 | assert!(divider_f32 >= 1.0, "clkdiv must be >= 1"); | ||
| 79 | |||
| 80 | self.sm.set_clock_divider(clock_divider); | 80 | self.sm.set_clock_divider(clock_divider); |
| 81 | self.sm.clkdiv_restart(); | 81 | self.sm.clkdiv_restart(); |
| 82 | } | 82 | } |
