From e09231635f171b27bab6685581c55d43ba2235a3 Mon Sep 17 00:00:00 2001 From: Priec Date: Thu, 30 Oct 2025 12:22:47 +0100 Subject: [PATCH] working --- dma_gpio/Cargo.lock | 46 +++++++++---------- dma_gpio/Cargo.toml | 2 +- dma_gpio/src/bin/main.rs | 81 ++++++++++------------------------ dma_gpio/src/gpio_dma_uart.rs | 83 +++++++++++++++++++++++++++++++++++ dma_gpio/src/lib.rs | 2 + 5 files changed, 132 insertions(+), 82 deletions(-) create mode 100644 dma_gpio/src/gpio_dma_uart.rs diff --git a/dma_gpio/Cargo.lock b/dma_gpio/Cargo.lock index dfd24ee..452e059 100644 --- a/dma_gpio/Cargo.lock +++ b/dma_gpio/Cargo.lock @@ -229,6 +229,29 @@ dependencies = [ "defmt 1.0.1", ] +[[package]] +name = "dma_gpio" +version = "0.1.0" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "defmt 1.0.1", + "defmt-rtt", + "embassy-executor", + "embassy-futures", + "embassy-stm32", + "embassy-sync", + "embassy-time", + "embassy-usb", + "embedded-graphics", + "embedded-hal 1.0.0", + "heapless 0.9.1", + "micromath", + "panic-halt", + "panic-probe", + "tinybmp", +] + [[package]] name = "document-features" version = "0.2.11" @@ -616,29 +639,6 @@ dependencies = [ "pin-utils", ] -[[package]] -name = "hal_rng" -version = "0.1.0" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "defmt 1.0.1", - "defmt-rtt", - "embassy-executor", - "embassy-futures", - "embassy-stm32", - "embassy-sync", - "embassy-time", - "embassy-usb", - "embedded-graphics", - "embedded-hal 1.0.0", - "heapless 0.9.1", - "micromath", - "panic-halt", - "panic-probe", - "tinybmp", -] - [[package]] name = "hash32" version = "0.3.1" diff --git a/dma_gpio/Cargo.toml b/dma_gpio/Cargo.toml index 7b606c3..89ab975 100644 --- a/dma_gpio/Cargo.toml +++ b/dma_gpio/Cargo.toml @@ -1,6 +1,6 @@ [package] authors = ["Priec "] -name = "hal_rng" +name = "dma_gpio" edition = "2024" version = "0.1.0" diff --git a/dma_gpio/src/bin/main.rs b/dma_gpio/src/bin/main.rs index cf6d0e7..ff06329 100644 --- a/dma_gpio/src/bin/main.rs +++ b/dma_gpio/src/bin/main.rs @@ -10,7 +10,7 @@ use embassy_time::{Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; use embassy_stm32::{ - dma::{Request, Transfer, TransferOptions}, + dma::Request, gpio::{Level, Output, Speed}, peripherals::{GPDMA1_CH0, TIM6}, rcc, @@ -18,26 +18,27 @@ use embassy_stm32::{ }; use embassy_stm32::Peri; -static PIPE: Pipe = Pipe::new(); +use dma_gpio::gpio_dma_uart::{encode_uart_byte, write_uart_frames_to_pipe, GpioDmaBsrrTx, TIM6_UP_REQ}; -// One DMA beat per TIM6 update -const RATE_HZ: u32 = 100; -// GPDMA REQSEL for TIM6 update (RM0456 Table 137 -> 4) -const TIM6_UP_REQ: Request = 4; +static PIPE: Pipe = Pipe::new(); + +// Baud rate: one TIM6 update equals one UART bit-time +const BAUD: u32 = 115_200; +const TX_PIN_BIT: u8 = 2; // PA2 #[embassy_executor::main] async fn main(spawner: Spawner) { let p = embassy_stm32::init(Default::default()); - info!("DMA Pipe -> GPIO (single pin) using GPDMA HAL"); + info!("DMA Pipe -> GPIO UART-like TX (safe wrapper)"); - // Single pin: PA2 as output (DMA will hit PA2->BSRR) - let _pa2 = Output::new(p.PA2, Level::Low, Speed::VeryHigh); + // PA2 is the TX "wire" + let _pa2 = Output::new(p.PA2, Level::High, Speed::VeryHigh); drop(_pa2); - // TIM6: enable Update DMA request at RATE_HZ + // TIM6 generates one DMA request per bit-time let tim6 = LlTimer::new(p.TIM6); let f_tim6 = rcc::frequency::().0; - let arr = (f_tim6 / RATE_HZ).saturating_sub(1) as u16; + let arr = (f_tim6 / BAUD).saturating_sub(1) as u16; tim6.regs_basic().arr().modify(|w| w.set_arr(arr)); tim6.regs_basic().dier().modify(|w| w.set_ude(true)); tim6.regs_basic().cr1().modify(|w| { @@ -45,68 +46,32 @@ async fn main(spawner: Spawner) { w.set_cen(true); }); - // DMA worker: reads u32 words (as 4 bytes) and writes to GPIOA BSRR + // Start DMA consumer task spawner.spawn(dma_tx_task(p.GPDMA1_CH0)).unwrap(); - // Producer: PA2 logic every second - // The pattern repeats every 4 timer ticks: HIGH, HIGH, HIGH, LOW. - let high = (1u32 << 2).to_le_bytes(); // PA2 high - let low = (1u32 << (2 + 16)).to_le_bytes(); // PA2 low - let pattern = [high, high, high, low]; - + // Example: transmit a string as UART frames via the Pipe loop { - for chunk in pattern { - PIPE.write(&chunk).await; - info!("Producer queued pattern word: [{:02X} {:02X} {:02X} {:02X}]", - chunk[0], chunk[1], chunk[2], chunk[3]); - // No long wait — the timer pacing handles timing. - // Small pause just to keep logging readable. - Timer::after_millis(200).await; - } + write_uart_frames_to_pipe(&PIPE, TX_PIN_BIT, b"Hello, DMA UART!\r\n").await; + Timer::after(Duration::from_secs(2)).await; } } -// DMA task: for each 4 bytes from PIPE, submit one 32-bit write to GPIOA->BSRR, -// paced by TIM6 update requests (REQ=4). #[embassy_executor::task] -async fn dma_tx_task(mut ch: Peri<'static, GPDMA1_CH0>) { - // Raw destination address (GPIOA->BSRR register) - let bsrr_ptr = embassy_stm32::pac::GPIOA.bsrr().as_ptr() as *mut u32; - - let opts = TransferOptions::default(); - static mut WORD: [u32; 1] = [0; 1]; - - info!("DMA task started, waiting for data"); +async fn dma_tx_task(ch: Peri<'static, GPDMA1_CH0>) { + let mut tx = GpioDmaBsrrTx::new(ch); + info!("DMA task started, waiting for frames..."); loop { + // Read one 32-bit BSRR word (4 bytes) from the Pipe let mut b = [0u8; 4]; - - // Wait until the producer pushes 4 bytes into the Pipe. let n = PIPE.read(&mut b).await; if n != 4 { - warn!("Received {} bytes (expected 4), skip.", n); continue; } - let w = u32::from_le_bytes(b); - unsafe { WORD[0] = w; } - // Log the value that is about to be written by DMA. - info!("DMA starting transfer 0x{:08X} to GPIOA->BSRR", w); - - // Perform the single-word DMA transfer paced by TIM6 update request. - let transfer = unsafe { - Transfer::new_write( - ch.reborrow(), - TIM6_UP_REQ, // request = 4 (TIM6_UPD_DMA) - core::slice::from_ref(&WORD[0]), - bsrr_ptr, - opts, - ) - }; - - transfer.await; - - info!("DMA transfer complete."); + // Log + send via DMA (timer-paced, 1 beat per bit time) + info!("DMA write 0x{:08X} -> GPIOA.BSRR", w); + tx.write_word(w).await; } } diff --git a/dma_gpio/src/gpio_dma_uart.rs b/dma_gpio/src/gpio_dma_uart.rs new file mode 100644 index 0000000..a0c18c6 --- /dev/null +++ b/dma_gpio/src/gpio_dma_uart.rs @@ -0,0 +1,83 @@ +// src/gpio_dma_uart.rs +use embassy_stm32::{ + dma::{Request, Transfer, TransferOptions}, + peripherals::GPDMA1_CH0, + Peri, +}; +use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, pipe::Pipe}; + +pub const TIM6_UP_REQ: Request = 4; // Table 137: tim6_upd_dma, strana 687 + +pub struct GpioDmaBsrrTx<'d> { + ch: Peri<'d, GPDMA1_CH0>, + bsrr: *mut u32, + opts: TransferOptions, +} + +impl<'d> GpioDmaBsrrTx<'d> { + // Constructor. Hides the raw register pointer internally. + pub fn new(ch: Peri<'d, GPDMA1_CH0>) -> Self { + let bsrr = embassy_stm32::pac::GPIOA.bsrr().as_ptr() as *mut u32; + Self { + ch, + bsrr, + opts: TransferOptions::default(), + } + } + + // Safe API: perform one timer-paced DMA write of a single 32-bit BSRR word. + pub async fn write_word(&mut self, word: u32) { + let buf = [word]; + // Safety: bsrr is a valid 32-bit aligned register, buf lives until DMA completes, + // request selects TIM6_UP, which paces one beat per update. + unsafe { + Transfer::new_write( + self.ch.reborrow(), + TIM6_UP_REQ, + &buf, + self.bsrr, + self.opts, + ) + } + .await; + } +} + +// Build 10 BSRR words for one UART frame (8N1) on a given GPIO bit. +// start bit, 8 data bits LSB-first, stop bit +// BSRR je safe atomic write only shortcut +pub fn encode_uart_byte(pin_bit: u8, data: u8) -> [u32; 10] { + let mut words = [0u32; 10]; + + // Dokumentacia strana 636 13.4.7 + // set bit - HIGH, reset bit - LOW + let set_high = |bit: u8| -> u32 { 1u32 << bit }; + let set_low = |bit: u8| -> u32 { 1u32 << (bit as u32 + 16) }; + + // start bit LOW + words[0] = set_low(pin_bit); + + // data bits, LSB first + for i in 0..8 { + let one = (data >> i) & 1 != 0; + words[1 + i] = if one { set_high(pin_bit) } else { set_low(pin_bit) }; + } + + // stop bit HIGH + words[9] = set_high(pin_bit); + words +} + +// Convenience: push UART frames for a whole byte slice into a Pipe. +pub async fn write_uart_frames_to_pipe( + pipe: &Pipe, + pin_bit: u8, + bytes: &[u8], +) { + for &b in bytes { + let frames = encode_uart_byte(pin_bit, b); + for w in frames { + pipe.write(&w.to_le_bytes()).await; + } + } +} diff --git a/dma_gpio/src/lib.rs b/dma_gpio/src/lib.rs index 0c9ac1a..2533591 100644 --- a/dma_gpio/src/lib.rs +++ b/dma_gpio/src/lib.rs @@ -1 +1,3 @@ #![no_std] +pub mod gpio_dma_uart; +pub use gpio_dma_uart::*;