From 28b468902ad17856897c7dd96d74c6dcd3587b8b Mon Sep 17 00:00:00 2001 From: Priec Date: Fri, 31 Oct 2025 14:31:25 +0100 Subject: [PATCH] Rx is not using dma now --- dma_gpio/src/bin/main.rs | 19 +++++++++++--- dma_gpio/src/gpio_uart_rx.rs | 48 ++++++++++++++++++++++++++++++++++++ dma_gpio/src/lib.rs | 1 + 3 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 dma_gpio/src/gpio_uart_rx.rs diff --git a/dma_gpio/src/bin/main.rs b/dma_gpio/src/bin/main.rs index 575ad42..6ef40d3 100644 --- a/dma_gpio/src/bin/main.rs +++ b/dma_gpio/src/bin/main.rs @@ -8,6 +8,9 @@ use embassy_executor::Spawner; use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, pipe::Pipe}; use embassy_time::{Duration, Timer}; use dma_gpio::dma_timer::init_tim6_for_uart; +use embassy_stm32::gpio::Input; +use embassy_stm32::gpio::Pull; +use dma_gpio::gpio_uart_rx::GpioUartRx; use {defmt_rtt as _, panic_probe as _}; use embassy_stm32::{ @@ -20,7 +23,8 @@ use dma_gpio::gpio_dma_uart::{ write_uart_frames_to_pipe, GpioDmaBsrrTx, Parity, StopBits, UartConfig, }; -static PIPE: Pipe = Pipe::new(); +static PIPE_TX: Pipe = Pipe::new(); +static PIPE_RX: Pipe = Pipe::new(); // Baud rate: one TIM6 update equals one UART bit-time const BAUD: u32 = 115_200; @@ -76,11 +80,20 @@ fn dump_dma_ch0_regs() { ); } +#[embassy_executor::task] +async fn rx_task(pin: Input<'static>) { + let mut rx = GpioUartRx::new(pin, BAUD, UART_CFG, &PIPE_RX); + rx.run().await; +} + #[embassy_executor::main] async fn main(spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("DMA Pipe -> GPIO UART-like TX"); + let pa3_rx = Input::new(p.PA3, Pull::Up); + spawner.spawn(rx_task(pa3_rx)).unwrap(); + // PA2 is the TX "wire" let _pa2 = Output::new(p.PA2, Level::High, Speed::VeryHigh); // drop(_pa2); @@ -93,7 +106,7 @@ async fn main(spawner: Spawner) { // Example: transmit a string as UART frames via the Pipe loop { write_uart_frames_to_pipe( - &PIPE, + &PIPE_TX, TX_PIN_BIT, b"Hello, DMA UART (configurable)!\r\n", &UART_CFG, @@ -110,7 +123,7 @@ async fn dma_tx_task(ch: Peri<'static, GPDMA1_CH0>) { loop { // Read one 32-bit BSRR word (4 bytes) from the Pipe let mut b = [0u8; 4]; - let n = PIPE.read(&mut b).await; + let n = PIPE_TX.read(&mut b).await; if n != 4 { continue; } diff --git a/dma_gpio/src/gpio_uart_rx.rs b/dma_gpio/src/gpio_uart_rx.rs new file mode 100644 index 0000000..a72da8e --- /dev/null +++ b/dma_gpio/src/gpio_uart_rx.rs @@ -0,0 +1,48 @@ +// src/gpio_uart_rx.rs + +use embassy_stm32::gpio::{Input, Level, Pull}; +use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, pipe::Pipe}; +use embassy_time::{Timer, Duration}; +use crate::gpio_dma_uart::UartConfig; + +/// Simplified bit-banged UART RX using a timer for sampling. +/// Sample pin every bit-time once start bit is detected. +pub struct GpioUartRx<'d, const N: usize> { + pin: Input<'d>, + baud: u32, + cfg: UartConfig, + pipe: &'d Pipe, +} + +impl<'d, const N: usize> GpioUartRx<'d, N> { + pub fn new(pin: Input<'d>, baud: u32, cfg: UartConfig, pipe: &'d Pipe) -> Self { + Self { pin, baud, cfg, pipe } + } + + /// Async read loop: waits for start bit, samples bits, pushes received byte into pipe. + pub async fn run(&mut self) -> ! { + let bit_time = Duration::from_hz(self.baud.into()); + + loop { + // Wait for start bit edge + while self.pin.get_level() == Level::High { + Timer::after_micros(1).await; + } + + // Skip only 1 bit-time since you *don’t* want 1.5 bit delay + Timer::after(bit_time).await; + + let nbits = self.cfg.data_bits.clamp(5, 8); + let mut data = 0u8; + for i in 0..nbits { + if self.pin.get_level() == Level::High { + data |= 1 << i; + } + Timer::after(bit_time).await; + } + + // push into Pipe as soon as byte is complete + self.pipe.write(&[data]).await; + } + } +} diff --git a/dma_gpio/src/lib.rs b/dma_gpio/src/lib.rs index 26fe4b2..92f6125 100644 --- a/dma_gpio/src/lib.rs +++ b/dma_gpio/src/lib.rs @@ -5,3 +5,4 @@ pub use gpio_dma_uart::*; pub mod dma_timer; pub use dma_timer::*; +pub mod gpio_uart_rx;