diff --git a/dma_gpio/src/bin/main.rs b/dma_gpio/src/bin/main.rs index 8e76301..cf6d0e7 100644 --- a/dma_gpio/src/bin/main.rs +++ b/dma_gpio/src/bin/main.rs @@ -5,49 +5,108 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_sync::{ - blocking_mutex::raw::CriticalSectionRawMutex, - pipe::Pipe, -}; +use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, pipe::Pipe}; use embassy_time::{Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; use embassy_stm32::{ + dma::{Request, Transfer, TransferOptions}, gpio::{Level, Output, Speed}, - pac::{self, GPDMA1, GPIOB, dmamux}, - peripherals::TIM6, + peripherals::{GPDMA1_CH0, TIM6}, rcc, timer::low_level::Timer as LlTimer, }; +use embassy_stm32::Peri; static PIPE: Pipe = Pipe::new(); +// 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; + #[embassy_executor::main] async fn main(spawner: Spawner) { let p = embassy_stm32::init(Default::default()); - info!("Hello World!"); + info!("DMA Pipe -> GPIO (single pin) using GPDMA HAL"); - spawner.spawn(pipe_consumer_task()).unwrap(); + // Single pin: PA2 as output (DMA will hit PA2->BSRR) + let _pa2 = Output::new(p.PA2, Level::Low, Speed::VeryHigh); + drop(_pa2); + + // TIM6: enable Update DMA request at RATE_HZ + let tim6 = LlTimer::new(p.TIM6); + let f_tim6 = rcc::frequency::().0; + let arr = (f_tim6 / RATE_HZ).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| { + w.set_opm(false); + w.set_cen(true); + }); + + // DMA worker: reads u32 words (as 4 bytes) and writes to GPIOA BSRR + 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]; - let mut counter: u32 = 0; loop { - let bytes = counter.to_le_bytes(); // convert 4 bytes - PIPE.write(&bytes).await; - info!("Producer pushed value {}", counter); - - counter = counter.wrapping_add(1); - Timer::after(Duration::from_secs(2)).await; - } -} - -#[embassy_executor::task] -async fn pipe_consumer_task() { - let mut buf = [0u8; 4]; - loop { - let n = PIPE.read(&mut buf).await; - if n == 4 { - let val = u32::from_le_bytes(buf); - info!("Consumer read {}", val); + 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; } } } + +// 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"); + + loop { + 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."); + } +} diff --git a/pinout1.png b/pinout1.png new file mode 100644 index 0000000..d5a9981 Binary files /dev/null and b/pinout1.png differ diff --git a/pinout2.png b/pinout2.png new file mode 100644 index 0000000..39de56d Binary files /dev/null and b/pinout2.png differ