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
This commit is contained in:
Wilfried Chauveau 2022-08-31 21:44:53 +01:00 committed by GitHub
parent 6d75cd8291
commit 0e2b4cf7be
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 30 additions and 18 deletions

View file

@ -61,10 +61,10 @@ fn main() -> ! {
// Initialize and start PIO // Initialize and start PIO
let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS);
let installed = pio.install(&program).unwrap(); 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) let (sm, _, _) = rp2040_hal::pio::PIOBuilder::from_program(installed)
.set_pins(led_pin_id, 1) .set_pins(led_pin_id, 1)
.clock_divisor(div) .clock_divisor_fixed_point(int, frac)
.build(sm0); .build(sm0);
sm.start(); sm.start();

View file

@ -47,10 +47,10 @@ fn main() -> ! {
// Initialize and start PIO // Initialize and start PIO
let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS);
let installed = pio.install(&program.program).unwrap(); 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) let (mut sm, _, _) = rp2040_hal::pio::PIOBuilder::from_program(installed)
.set_pins(led_pin_id, 1) .set_pins(led_pin_id, 1)
.clock_divisor(div) .clock_divisor_fixed_point(int, frac)
.build(sm0); .build(sm0);
// The GPIO pin needs to be configured as an output. // The GPIO pin needs to be configured as an output.
sm.set_pindirs([(led_pin_id, hal::pio::PinDir::Output)]); sm.set_pindirs([(led_pin_id, hal::pio::PinDir::Output)]);

View file

@ -50,10 +50,10 @@ fn main() -> ! {
// Initialize and start PIO // Initialize and start PIO
let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS);
let installed = pio.install(&program.program).unwrap(); 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) let (mut sm, _, _) = rp2040_hal::pio::PIOBuilder::from_program(installed)
.side_set_pin_base(led_pin_id) .side_set_pin_base(led_pin_id)
.clock_divisor(div) .clock_divisor_fixed_point(int, frac)
.build(sm0); .build(sm0);
// The GPIO pin needs to be configured as an output. // The GPIO pin needs to be configured as an output.
sm.set_pindirs([(led_pin_id, hal::pio::PinDir::Output)]); sm.set_pindirs([(led_pin_id, hal::pio::PinDir::Output)]);

View file

@ -57,12 +57,12 @@ fn main() -> ! {
// then through a LED. If there is a clock offset, there will be a // 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. // 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. // 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 installed = pio.install(&program.program).unwrap();
let (mut sm0, _, _) = rp2040_hal::pio::PIOBuilder::from_program(installed) let (mut sm0, _, _) = rp2040_hal::pio::PIOBuilder::from_program(installed)
.set_pins(pin0, 1) .set_pins(pin0, 1)
.clock_divisor(div) .clock_divisor_fixed_point(int, frac)
.build(sm0); .build(sm0);
// The GPIO pin needs to be configured as an output. // The GPIO pin needs to be configured as an output.
sm0.set_pindirs([(pin0, hal::pio::PinDir::Output)]); sm0.set_pindirs([(pin0, hal::pio::PinDir::Output)]);
@ -72,7 +72,7 @@ fn main() -> ! {
let installed = pio.install(&program.program).unwrap(); let installed = pio.install(&program.program).unwrap();
let (mut sm1, _, _) = rp2040_hal::pio::PIOBuilder::from_program(installed) let (mut sm1, _, _) = rp2040_hal::pio::PIOBuilder::from_program(installed)
.set_pins(pin1, 1) .set_pins(pin1, 1)
.clock_divisor(div) .clock_divisor_fixed_point(int, frac)
.build(sm1); .build(sm1);
// The GPIO pin needs to be configured as an output. // The GPIO pin needs to be configured as an output.
sm1.set_pindirs([(pin1, hal::pio::PinDir::Output)]); sm1.set_pindirs([(pin1, hal::pio::PinDir::Output)]);

View file

@ -471,11 +471,7 @@ impl<SM: ValidStateMachine> UninitStateMachine<SM> {
} }
// Safety: The Send trait assumes this is the only write to sm_clkdiv // Safety: The Send trait assumes this is the only write to sm_clkdiv
fn set_clock_divisor(&self, divisor: f32) { fn set_clock_divisor(&self, int: u16, frac: u8) {
// sm frequency = clock freq / (CLKDIV_INT + CLKDIV_FRAC / 256)
let int = divisor as u16;
let frac = ((divisor - int as f32) * 256.0) as u8;
self.sm().sm_clkdiv.write(|w| { self.sm().sm_clkdiv.write(|w| {
unsafe { unsafe {
w.int().bits(int); w.int().bits(int);
@ -1619,7 +1615,7 @@ impl ShiftDirection {
#[derive(Debug)] #[derive(Debug)]
pub struct PIOBuilder<P> { pub struct PIOBuilder<P> {
/// Clock divisor. /// Clock divisor.
clock_divisor: f32, clock_divisor: (u16, u8),
/// Program location and configuration. /// Program location and configuration.
program: InstalledProgram<P>, program: InstalledProgram<P>,
@ -1688,7 +1684,7 @@ impl<P: PIOExt> PIOBuilder<P> {
/// Additional configuration may be needed in addition to this. /// Additional configuration may be needed in addition to this.
pub fn from_program(p: InstalledProgram<P>) -> Self { pub fn from_program(p: InstalledProgram<P>) -> Self {
PIOBuilder { PIOBuilder {
clock_divisor: 1.0, clock_divisor: (1, 0),
program: p, program: p,
jmp_pin: 0, jmp_pin: 0,
out_sticky: false, out_sticky: false,
@ -1771,8 +1767,24 @@ impl<P: PIOExt> PIOBuilder<P> {
/// ///
/// 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 /// 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. /// 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 { 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 self
} }
@ -1852,7 +1864,7 @@ impl<P: PIOExt> PIOBuilder<P> {
sm.set_enabled(false); sm.set_enabled(false);
// Write all configuration bits // 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| { sm.sm().sm_execctrl.write(|w| {
w.side_en().bit(self.program.side_set.optional()); w.side_en().bit(self.program.side_set.optional());