From e9f367f26cc25b62bf228f9fb0c7eb63db2bc776 Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Wed, 1 Jun 2022 06:13:33 +1000 Subject: [PATCH] Restrict PIO FIFO writes to unsigned integers (#318) * Change pio::Tx::write to write u32 instead of * * Add replicated u8/u16 writes to pio::Tx::write * Switching back to generic version of pio::fifo.write() * Fix links to make cargo doc happy Co-authored-by: Jan Niehusmann Co-authored-by: Jan Niehusmann --- rp2040-hal/src/pio.rs | 68 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/rp2040-hal/src/pio.rs b/rp2040-hal/src/pio.rs index 41a8fcc..da16e4d 100644 --- a/rp2040-hal/src/pio.rs +++ b/rp2040-hal/src/pio.rs @@ -1187,6 +1187,74 @@ impl Tx { true } + /// Write a replicated u8 value to TX FIFO. + /// + /// Memory mapped register writes that are smaller than 32bits will trigger + /// "Narrow IO Register Write" behaviour in RP2040 - the value written will + /// be replicated to the rest of the register as described in + /// [RP2040 Datasheet: 2.1.4. - Narrow IO Register Writes][section_2_1_4] + /// + /// + /// This 8bit write will set all 4 bytes of the FIFO to `value` + /// Eg: if you write `0xBA` the value written to the the FIFO will be + /// `0xBABABABA` + /// + /// If you wish to write an 8bit number without replication, + /// use `write(my_u8 as u32)` instead. + /// + /// Returns `true` if the value was written to FIFO, `false` otherwise. + /// + /// [section_2_1_4]: + pub fn write_u8_replicated(&mut self, value: u8) -> bool { + // Safety: The register is never written by software. + let is_full = self.is_full(); + + if is_full { + return false; + } + + unsafe { + let reg_ptr = self.register_block().txf[SM::id()].as_ptr() as *mut u8; + reg_ptr.write_volatile(value); + } + + true + } + + /// Write a replicated 16bit value to TX FIFO. + /// + /// Memory mapped register writes that are smaller than 32bits will trigger + /// "Narrow IO Register Write" behaviour in RP2040 - the value written will + /// be replicated to the rest of the register as described in + /// [RP2040 Datasheet: 2.1.4. - Narrow IO Register Writes][section_2_1_4] + /// + /// This 16bit write will set both the upper and lower half of the FIFO entry to `value`. + /// + /// For example, if you write `0xC0DA` the value written to the FIFO will be + /// `0xC0DAC0DA` + /// + /// If you wish to write a 16bit number without replication, + /// use `write(my_u16 as u32)` instead. + /// + /// Returns `true` if the value was written to FIFO, `false` otherwise. + /// + /// [section_2_1_4]: + pub fn write_u16_replicated(&mut self, value: u16) -> bool { + // Safety: The register is never written by software. + let is_full = self.is_full(); + + if is_full { + return false; + } + + unsafe { + let reg_ptr = self.register_block().txf[SM::id()].as_ptr() as *mut u16; + reg_ptr.write_volatile(value); + } + + true + } + /// Checks if the state machine has stalled on empty TX FIFO during a blocking PULL, or an OUT /// with autopull enabled. ///