This commit is contained in:
Priec
2025-10-30 12:22:47 +01:00
parent 8072ea15f0
commit e09231635f
5 changed files with 132 additions and 82 deletions

View File

@@ -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<CriticalSectionRawMutex, 64> = 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<CriticalSectionRawMutex, 256> = 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::<TIM6>().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;
}
}