3 Commits

Author SHA1 Message Date
Priec
3a2c65f16b hardfault fixed 2025-11-07 20:04:20 +01:00
Filipriec
dd978ec65c compiled ping pong buffer setup 2025-11-07 19:23:00 +01:00
Filipriec
3930716ac3 clean code 2025-11-07 19:22:46 +01:00
2 changed files with 63 additions and 69 deletions

1
.gitignore vendored
View File

@@ -1 +1,2 @@
*.pdf *.pdf
dma_example/

View File

@@ -1,102 +1,95 @@
// src/bin/main.rs // src/bin/main.rs
#![no_std] #![no_std]
#![no_main] #![no_main]
use defmt::*; use defmt::*;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_futures::yield_now; use embassy_futures::yield_now;
use embassy_stm32::dma::Request;
use embassy_stm32::gpio::{Input, Output, Level, Pull, Speed}; use embassy_stm32::gpio::{Input, Output, Level, Pull, Speed};
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, pipe::Pipe}; use embassy_stm32::dma::{TransferOptions, Transfer, Priority, Request};
use embassy_time::{Duration, Timer};
use embassy_stm32::dma::{TransferOptions, WritableRingBuffer};
use dma_gpio::software_uart::{ use dma_gpio::software_uart::{
dma_timer::init_tim6_for_uart, dma_timer::init_tim6_for_uart,
gpio_dma_uart_tx::encode_uart_frames, gpio_dma_uart_tx::encode_uart_frames,
debug::dump_tim6_regs, debug::dump_tim6_regs,
}; };
use dma_gpio::config::{BAUD, TX_PIN_BIT, RX_OVERSAMPLE, TX_OVERSAMPLE}; use dma_gpio::config::{BAUD, TX_PIN_BIT, TX_OVERSAMPLE};
use dma_gpio::config::{TX_RING_BYTES, RX_RING_BYTES, PIPE_RX_SIZE};
use static_cell::StaticCell; use static_cell::StaticCell;
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
// kapitola 17.4.11 - 2 casovace pre 2 DMA unsafe fn start_dma<'a>(
pub const TIM6_UP_REQ: Request = 4; // Table 137: tim6_upd_dma, strana 687 STM32U5xx datasheet ch: embassy_hal_internal::Peri<'a, impl embassy_stm32::dma::Channel>,
request: Request,
static TX_RING: StaticCell<[u32; TX_RING_BYTES]> = StaticCell::new(); odr_ptr: *mut u32,
buf: &'a [u32],
use core::future::poll_fn; opts: TransferOptions,
use core::task::Poll; ) -> Transfer<'a> {
// new_write itself is unsafe
async fn wait_for_space<'a, W: embassy_stm32::dma::word::Word>( unsafe { Transfer::new_write(ch, request, buf, odr_ptr, opts) }
ring: &mut embassy_stm32::dma::WritableRingBuffer<'a, W>,
min_free: usize,
) {
poll_fn(|cx| {
let used = ring.len().unwrap_or(0);
let cap = ring.capacity();
if cap - used > min_free {
Poll::Ready(())
} else {
ring.set_waker(cx.waker());
Poll::Pending
}
}).await
} }
pub const TIM6_UP_REQ: Request = 4;
const DMA_BUF_WORDS: usize = 256;
static BUF_A: StaticCell<[u32; DMA_BUF_WORDS]> = StaticCell::new();
static BUF_B: StaticCell<[u32; DMA_BUF_WORDS]> = StaticCell::new();
#[embassy_executor::main] #[embassy_executor::main]
async fn main(spawner: Spawner) { async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(Default::default()); let p = embassy_stm32::init(Default::default());
info!("Hehe"); let odr_ptr = embassy_stm32::pac::GPIOA.odr().as_ptr() as *mut u32;
let _rx = Input::new(p.PA3, Pull::Up);
let _tx = Output::new(p.PA2, Level::High, Speed::VeryHigh);
init_tim6_for_uart(p.TIM6, BAUD, TX_OVERSAMPLE); init_tim6_for_uart(p.TIM6, BAUD, TX_OVERSAMPLE);
dump_tim6_regs(); dump_tim6_regs();
// Safe one-time init from StaticCell let buf_a = BUF_A.init([0u32; DMA_BUF_WORDS]);
let tx_ring_mem: &mut [u32; TX_RING_BYTES] = TX_RING.init([0; TX_RING_BYTES]); let buf_b = BUF_B.init([0u32; DMA_BUF_WORDS]);
// Pre-fill with idle high level (stop bit level)
let idle = 1u32 << TX_PIN_BIT;
for w in buf_a.iter_mut() {
*w = idle;
}
for w in buf_b.iter_mut() {
*w = idle;
}
// Create and start the TX DMA ring in main. let mut opts = TransferOptions::default();
// let bsrr_ptr = embassy_stm32::pac::GPIOA.bsrr().as_ptr() as *mut u32; opts.priority = Priority::VeryHigh;
let odr_ptr = embassy_stm32::pac::GPIOA.odr().as_ptr() as *mut u32; opts.complete_transfer_ir = true;
let mut tx_opts = TransferOptions::default();
tx_opts.half_transfer_ir = true;
tx_opts.complete_transfer_ir = true;
// SAFETY: tx_ring_mem is exclusive let mut ch0 = p.GPDMA1_CH0;
let mut tx_ring = unsafe { let mut using_a = true;
WritableRingBuffer::new(
p.GPDMA1_CH0,
TIM6_UP_REQ,
odr_ptr,
tx_ring_mem,
tx_opts,
)
};
// Start DMA
tx_ring.start();
info!("TX DMA ring started");
let mut frame_buf = [0u32; 4096];
loop { loop {
info!("tick start"); let (dma_buf, cpu_buf) = if using_a {
Timer::after(Duration::from_millis(400)).await; (&*buf_a, &mut *buf_b)
info!("tick end");
let used = encode_uart_frames(TX_PIN_BIT, b"Hello marshmallow\r\n", &mut frame_buf).await;
// Wait for DMA to free space, async style
wait_for_space(&mut tx_ring, used / 2).await;
if let Err(e) = tx_ring.write_exact(&frame_buf[..used]).await {
warn!("DMA ring write error: {:?}", e);
} else { } else {
info!("Frame queued to DMA ring"); (&*buf_b, &mut *buf_a)
};
// Start from idle pattern
let idle = 1u32 << TX_PIN_BIT;
for w in cpu_buf.iter_mut() {
*w = idle;
} }
let used = encode_uart_frames(TX_PIN_BIT, b"Hello marshmallow\r\n", cpu_buf).await;
let len = if used == 0 { 1 } else { used };
// At least one word so DMA is always valid.
let transfer = unsafe {
start_dma(
ch0.reborrow(),
TIM6_UP_REQ,
odr_ptr,
&dma_buf[..len],
opts,
)
};
transfer.await;
using_a = !using_a;
yield_now().await; yield_now().await;
} }
} }