From 0e2b4cf7be66c7dec04ca9113f9f633c9ed3f36a Mon Sep 17 00:00:00 2001 From: Wilfried Chauveau Date: Wed, 31 Aug 2022 21:44:53 +0100 Subject: [PATCH] Add a method to allow setting the PIO's clock divisor without floats (#440) * pio: Changes `PIOBuilder::clock_divisor` from f32 to fixed point) * pio: mark clock_divisor as deprecated --- rp2040-hal/examples/pio_blink.rs | 4 ++-- rp2040-hal/examples/pio_proc_blink.rs | 4 ++-- rp2040-hal/examples/pio_side_set.rs | 4 ++-- rp2040-hal/examples/pio_synchronized.rs | 6 ++--- rp2040-hal/src/pio.rs | 30 +++++++++++++++++-------- 5 files changed, 30 insertions(+), 18 deletions(-) diff --git a/rp2040-hal/examples/pio_blink.rs b/rp2040-hal/examples/pio_blink.rs index aa762d1..fc3b4b7 100644 --- a/rp2040-hal/examples/pio_blink.rs +++ b/rp2040-hal/examples/pio_blink.rs @@ -61,10 +61,10 @@ fn main() -> ! { // Initialize and start PIO let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); let installed = pio.install(&program).unwrap(); - let div = 0f32; // as slow as possible (0 is interpreted as 65536) + let (int, frac) = (0, 0); // as slow as possible (0 is interpreted as 65536) let (sm, _, _) = rp2040_hal::pio::PIOBuilder::from_program(installed) .set_pins(led_pin_id, 1) - .clock_divisor(div) + .clock_divisor_fixed_point(int, frac) .build(sm0); sm.start(); diff --git a/rp2040-hal/examples/pio_proc_blink.rs b/rp2040-hal/examples/pio_proc_blink.rs index 0868b05..35c689e 100644 --- a/rp2040-hal/examples/pio_proc_blink.rs +++ b/rp2040-hal/examples/pio_proc_blink.rs @@ -47,10 +47,10 @@ fn main() -> ! { // Initialize and start PIO let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); let installed = pio.install(&program.program).unwrap(); - let div = 0f32; // as slow as possible (0 is interpreted as 65536) + let (int, frac) = (0, 0); // as slow as possible (0 is interpreted as 65536) let (mut sm, _, _) = rp2040_hal::pio::PIOBuilder::from_program(installed) .set_pins(led_pin_id, 1) - .clock_divisor(div) + .clock_divisor_fixed_point(int, frac) .build(sm0); // The GPIO pin needs to be configured as an output. sm.set_pindirs([(led_pin_id, hal::pio::PinDir::Output)]); diff --git a/rp2040-hal/examples/pio_side_set.rs b/rp2040-hal/examples/pio_side_set.rs index f66e65d..7f32ea9 100644 --- a/rp2040-hal/examples/pio_side_set.rs +++ b/rp2040-hal/examples/pio_side_set.rs @@ -50,10 +50,10 @@ fn main() -> ! { // Initialize and start PIO let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); let installed = pio.install(&program.program).unwrap(); - let div = 0f32; // as slow as possible (0 is interpreted as 65536) + let (int, frac) = (0, 0); // as slow as possible (0 is interpreted as 65536) let (mut sm, _, _) = rp2040_hal::pio::PIOBuilder::from_program(installed) .side_set_pin_base(led_pin_id) - .clock_divisor(div) + .clock_divisor_fixed_point(int, frac) .build(sm0); // The GPIO pin needs to be configured as an output. sm.set_pindirs([(led_pin_id, hal::pio::PinDir::Output)]); diff --git a/rp2040-hal/examples/pio_synchronized.rs b/rp2040-hal/examples/pio_synchronized.rs index e161aa2..1c608c5 100644 --- a/rp2040-hal/examples/pio_synchronized.rs +++ b/rp2040-hal/examples/pio_synchronized.rs @@ -57,12 +57,12 @@ fn main() -> ! { // then through a LED. If there is a clock offset, there will be a // short time with a voltage between the pins, so the LED will flash up. // With a slow clock this is not visible, so use a reasonably fast clock. - let div = 256f32; + let (int, frac) = (256, 0); let installed = pio.install(&program.program).unwrap(); let (mut sm0, _, _) = rp2040_hal::pio::PIOBuilder::from_program(installed) .set_pins(pin0, 1) - .clock_divisor(div) + .clock_divisor_fixed_point(int, frac) .build(sm0); // The GPIO pin needs to be configured as an output. sm0.set_pindirs([(pin0, hal::pio::PinDir::Output)]); @@ -72,7 +72,7 @@ fn main() -> ! { let installed = pio.install(&program.program).unwrap(); let (mut sm1, _, _) = rp2040_hal::pio::PIOBuilder::from_program(installed) .set_pins(pin1, 1) - .clock_divisor(div) + .clock_divisor_fixed_point(int, frac) .build(sm1); // The GPIO pin needs to be configured as an output. sm1.set_pindirs([(pin1, hal::pio::PinDir::Output)]); diff --git a/rp2040-hal/src/pio.rs b/rp2040-hal/src/pio.rs index a8f04f4..ed58d2f 100644 --- a/rp2040-hal/src/pio.rs +++ b/rp2040-hal/src/pio.rs @@ -471,11 +471,7 @@ impl UninitStateMachine { } // Safety: The Send trait assumes this is the only write to sm_clkdiv - fn set_clock_divisor(&self, divisor: f32) { - // sm frequency = clock freq / (CLKDIV_INT + CLKDIV_FRAC / 256) - let int = divisor as u16; - let frac = ((divisor - int as f32) * 256.0) as u8; - + fn set_clock_divisor(&self, int: u16, frac: u8) { self.sm().sm_clkdiv.write(|w| { unsafe { w.int().bits(int); @@ -1619,7 +1615,7 @@ impl ShiftDirection { #[derive(Debug)] pub struct PIOBuilder

{ /// Clock divisor. - clock_divisor: f32, + clock_divisor: (u16, u8), /// Program location and configuration. program: InstalledProgram

, @@ -1688,7 +1684,7 @@ impl PIOBuilder

{ /// Additional configuration may be needed in addition to this. pub fn from_program(p: InstalledProgram

) -> Self { PIOBuilder { - clock_divisor: 1.0, + clock_divisor: (1, 0), program: p, jmp_pin: 0, out_sticky: false, @@ -1771,8 +1767,24 @@ impl PIOBuilder

{ /// /// The is based on the sys_clk. Set 1 for full speed. A clock divisor of `n` will cause the state machine to run 1 /// cycle every `n` clock cycles. For small values of `n`, a fractional divisor may introduce unacceptable jitter. + #[deprecated( + since = "0.7.0", + note = "Pulls in floating points. Use the fixed point alternative: clock_divisor_fixed_point" + )] pub fn clock_divisor(mut self, divisor: f32) -> Self { - self.clock_divisor = divisor; + self.clock_divisor = (divisor as u16, (divisor * 256.0) as u8); + self + } + + /// The clock is based on the `sys_clk` and will execute an intruction every `int + (frac/256)` ticks. + /// + /// A clock divisor of `n` will cause the state machine to run 1 cycle every `n` clock cycles. If the integer part + /// is 0 then the fractional part must be 0. This is interpreted by the device as the integer 65536. + /// + /// For small values of `int`, a fractional divisor may introduce unacceptable jitter. + pub fn clock_divisor_fixed_point(mut self, int: u16, frac: u8) -> Self { + assert!(int != 0 || frac == 0); + self.clock_divisor = (int, frac); self } @@ -1852,7 +1864,7 @@ impl PIOBuilder

{ sm.set_enabled(false); // Write all configuration bits - sm.set_clock_divisor(self.clock_divisor); + sm.set_clock_divisor(self.clock_divisor.0, self.clock_divisor.1); sm.sm().sm_execctrl.write(|w| { w.side_en().bit(self.program.side_set.optional());