diff options
| author | Caleb Jamison <[email protected]> | 2024-10-09 10:04:35 -0400 |
|---|---|---|
| committer | Caleb Jamison <[email protected]> | 2024-10-09 10:18:00 -0400 |
| commit | 57c1fbf3089e2a2dc9fe5b7d1f1e094596566395 (patch) | |
| tree | 833856b7da855b8de56dec1494c2da88ac29e415 /embassy-rp/src/pio_programs/uart.rs | |
| parent | 456c226b29799f7db56ab60b0ae3d95cc7d6a32a (diff) | |
Move pio programs into embassy-rp
Diffstat (limited to 'embassy-rp/src/pio_programs/uart.rs')
| -rw-r--r-- | embassy-rp/src/pio_programs/uart.rs | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/embassy-rp/src/pio_programs/uart.rs b/embassy-rp/src/pio_programs/uart.rs new file mode 100644 index 000000000..f4b3b204e --- /dev/null +++ b/embassy-rp/src/pio_programs/uart.rs | |||
| @@ -0,0 +1,186 @@ | |||
| 1 | //! Pio backed uart drivers | ||
| 2 | |||
| 3 | use crate::{ | ||
| 4 | clocks::clk_sys_freq, | ||
| 5 | gpio::Level, | ||
| 6 | pio::{ | ||
| 7 | Common, Config, Direction as PioDirection, FifoJoin, Instance, LoadedProgram, PioPin, ShiftDirection, | ||
| 8 | StateMachine, | ||
| 9 | }, | ||
| 10 | }; | ||
| 11 | use core::convert::Infallible; | ||
| 12 | use embedded_io_async::{ErrorType, Read, Write}; | ||
| 13 | use fixed::traits::ToFixed; | ||
| 14 | |||
| 15 | /// This struct represents a uart tx program loaded into pio instruction memory. | ||
| 16 | pub struct PioUartTxProgram<'a, PIO: Instance> { | ||
| 17 | prg: LoadedProgram<'a, PIO>, | ||
| 18 | } | ||
| 19 | |||
| 20 | impl<'a, PIO: Instance> PioUartTxProgram<'a, PIO> { | ||
| 21 | /// Load the uart tx program into the given pio | ||
| 22 | pub fn new(common: &mut Common<'a, PIO>) -> Self { | ||
| 23 | let prg = pio_proc::pio_asm!( | ||
| 24 | r#" | ||
| 25 | .side_set 1 opt | ||
| 26 | |||
| 27 | ; An 8n1 UART transmit program. | ||
| 28 | ; OUT pin 0 and side-set pin 0 are both mapped to UART TX pin. | ||
| 29 | |||
| 30 | pull side 1 [7] ; Assert stop bit, or stall with line in idle state | ||
| 31 | set x, 7 side 0 [7] ; Preload bit counter, assert start bit for 8 clocks | ||
| 32 | bitloop: ; This loop will run 8 times (8n1 UART) | ||
| 33 | out pins, 1 ; Shift 1 bit from OSR to the first OUT pin | ||
| 34 | jmp x-- bitloop [6] ; Each loop iteration is 8 cycles. | ||
| 35 | "# | ||
| 36 | ); | ||
| 37 | |||
| 38 | let prg = common.load_program(&prg.program); | ||
| 39 | |||
| 40 | Self { prg } | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | /// PIO backed Uart transmitter | ||
| 45 | pub struct PioUartTx<'a, PIO: Instance, const SM: usize> { | ||
| 46 | sm_tx: StateMachine<'a, PIO, SM>, | ||
| 47 | } | ||
| 48 | |||
| 49 | impl<'a, PIO: Instance, const SM: usize> PioUartTx<'a, PIO, SM> { | ||
| 50 | /// Configure a pio state machine to use the loaded tx program. | ||
| 51 | pub fn new( | ||
| 52 | baud: u32, | ||
| 53 | common: &mut Common<'a, PIO>, | ||
| 54 | mut sm_tx: StateMachine<'a, PIO, SM>, | ||
| 55 | tx_pin: impl PioPin, | ||
| 56 | program: &PioUartTxProgram<'a, PIO>, | ||
| 57 | ) -> Self { | ||
| 58 | let tx_pin = common.make_pio_pin(tx_pin); | ||
| 59 | sm_tx.set_pins(Level::High, &[&tx_pin]); | ||
| 60 | sm_tx.set_pin_dirs(PioDirection::Out, &[&tx_pin]); | ||
| 61 | |||
| 62 | let mut cfg = Config::default(); | ||
| 63 | |||
| 64 | cfg.set_out_pins(&[&tx_pin]); | ||
| 65 | cfg.use_program(&program.prg, &[&tx_pin]); | ||
| 66 | cfg.shift_out.auto_fill = false; | ||
| 67 | cfg.shift_out.direction = ShiftDirection::Right; | ||
| 68 | cfg.fifo_join = FifoJoin::TxOnly; | ||
| 69 | cfg.clock_divider = (clk_sys_freq() / (8 * baud)).to_fixed(); | ||
| 70 | sm_tx.set_config(&cfg); | ||
| 71 | sm_tx.set_enable(true); | ||
| 72 | |||
| 73 | Self { sm_tx } | ||
| 74 | } | ||
| 75 | |||
| 76 | /// Write a single u8 | ||
| 77 | pub async fn write_u8(&mut self, data: u8) { | ||
| 78 | self.sm_tx.tx().wait_push(data as u32).await; | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | impl<PIO: Instance, const SM: usize> ErrorType for PioUartTx<'_, PIO, SM> { | ||
| 83 | type Error = Infallible; | ||
| 84 | } | ||
| 85 | |||
| 86 | impl<PIO: Instance, const SM: usize> Write for PioUartTx<'_, PIO, SM> { | ||
| 87 | async fn write(&mut self, buf: &[u8]) -> Result<usize, Infallible> { | ||
| 88 | for byte in buf { | ||
| 89 | self.write_u8(*byte).await; | ||
| 90 | } | ||
| 91 | Ok(buf.len()) | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | /// This struct represents a Uart Rx program loaded into pio instruction memory. | ||
| 96 | pub struct PioUartRxProgram<'a, PIO: Instance> { | ||
| 97 | prg: LoadedProgram<'a, PIO>, | ||
| 98 | } | ||
| 99 | |||
| 100 | impl<'a, PIO: Instance> PioUartRxProgram<'a, PIO> { | ||
| 101 | /// Load the uart rx program into the given pio | ||
| 102 | pub fn new(common: &mut Common<'a, PIO>) -> Self { | ||
| 103 | let prg = pio_proc::pio_asm!( | ||
| 104 | r#" | ||
| 105 | ; Slightly more fleshed-out 8n1 UART receiver which handles framing errors and | ||
| 106 | ; break conditions more gracefully. | ||
| 107 | ; IN pin 0 and JMP pin are both mapped to the GPIO used as UART RX. | ||
| 108 | |||
| 109 | start: | ||
| 110 | wait 0 pin 0 ; Stall until start bit is asserted | ||
| 111 | set x, 7 [10] ; Preload bit counter, then delay until halfway through | ||
| 112 | rx_bitloop: ; the first data bit (12 cycles incl wait, set). | ||
| 113 | in pins, 1 ; Shift data bit into ISR | ||
| 114 | jmp x-- rx_bitloop [6] ; Loop 8 times, each loop iteration is 8 cycles | ||
| 115 | jmp pin good_rx_stop ; Check stop bit (should be high) | ||
| 116 | |||
| 117 | irq 4 rel ; Either a framing error or a break. Set a sticky flag, | ||
| 118 | wait 1 pin 0 ; and wait for line to return to idle state. | ||
| 119 | jmp start ; Don't push data if we didn't see good framing. | ||
| 120 | |||
| 121 | good_rx_stop: ; No delay before returning to start; a little slack is | ||
| 122 | in null 24 | ||
| 123 | push ; important in case the TX clock is slightly too fast. | ||
| 124 | "# | ||
| 125 | ); | ||
| 126 | |||
| 127 | let prg = common.load_program(&prg.program); | ||
| 128 | |||
| 129 | Self { prg } | ||
| 130 | } | ||
| 131 | } | ||
| 132 | |||
| 133 | /// PIO backed Uart reciever | ||
| 134 | pub struct PioUartRx<'a, PIO: Instance, const SM: usize> { | ||
| 135 | sm_rx: StateMachine<'a, PIO, SM>, | ||
| 136 | } | ||
| 137 | |||
| 138 | impl<'a, PIO: Instance, const SM: usize> PioUartRx<'a, PIO, SM> { | ||
| 139 | /// Configure a pio state machine to use the loaded rx program. | ||
| 140 | pub fn new( | ||
| 141 | baud: u32, | ||
| 142 | common: &mut Common<'a, PIO>, | ||
| 143 | mut sm_rx: StateMachine<'a, PIO, SM>, | ||
| 144 | rx_pin: impl PioPin, | ||
| 145 | program: &PioUartRxProgram<'a, PIO>, | ||
| 146 | ) -> Self { | ||
| 147 | let mut cfg = Config::default(); | ||
| 148 | cfg.use_program(&program.prg, &[]); | ||
| 149 | |||
| 150 | let rx_pin = common.make_pio_pin(rx_pin); | ||
| 151 | sm_rx.set_pins(Level::High, &[&rx_pin]); | ||
| 152 | cfg.set_in_pins(&[&rx_pin]); | ||
| 153 | cfg.set_jmp_pin(&rx_pin); | ||
| 154 | sm_rx.set_pin_dirs(PioDirection::In, &[&rx_pin]); | ||
| 155 | |||
| 156 | cfg.clock_divider = (clk_sys_freq() / (8 * baud)).to_fixed(); | ||
| 157 | cfg.shift_in.auto_fill = false; | ||
| 158 | cfg.shift_in.direction = ShiftDirection::Right; | ||
| 159 | cfg.shift_in.threshold = 32; | ||
| 160 | cfg.fifo_join = FifoJoin::RxOnly; | ||
| 161 | sm_rx.set_config(&cfg); | ||
| 162 | sm_rx.set_enable(true); | ||
| 163 | |||
| 164 | Self { sm_rx } | ||
| 165 | } | ||
| 166 | |||
| 167 | /// Wait for a single u8 | ||
| 168 | pub async fn read_u8(&mut self) -> u8 { | ||
| 169 | self.sm_rx.rx().wait_pull().await as u8 | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 | impl<PIO: Instance, const SM: usize> ErrorType for PioUartRx<'_, PIO, SM> { | ||
| 174 | type Error = Infallible; | ||
| 175 | } | ||
| 176 | |||
| 177 | impl<PIO: Instance, const SM: usize> Read for PioUartRx<'_, PIO, SM> { | ||
| 178 | async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Infallible> { | ||
| 179 | let mut i = 0; | ||
| 180 | while i < buf.len() { | ||
| 181 | buf[i] = self.read_u8().await; | ||
| 182 | i += 1; | ||
| 183 | } | ||
| 184 | Ok(i) | ||
| 185 | } | ||
| 186 | } | ||
