// src/bin/main.rs #![no_std] #![no_main] use defmt::*; use embassy_executor::Spawner; use embassy_futures::yield_now; use embassy_stm32::dma::Request; use embassy_stm32::gpio::{Input, Output, Level, Pull, Speed}; use embassy_time::{Duration, Timer}; use embassy_stm32::dma::{TransferOptions, WritableRingBuffer}; use dma_gpio::software_uart::{ dma_timer::init_tim6_for_uart, gpio_dma_uart_tx::encode_uart_frames, debug::dump_tim6_regs, }; use dma_gpio::config::{BAUD, TX_PIN_BIT, TX_OVERSAMPLE, TX_RING_BYTES}; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; pub const TIM6_UP_REQ: Request = 4; static TX_RING: StaticCell<[u32; TX_RING_BYTES]> = StaticCell::new(); #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hehe"); let _rx = Input::new(p.PA3, embassy_stm32::gpio::Pull::Up); let _tx = Output::new(p.PA2, Level::High, Speed::VeryHigh); init_tim6_for_uart(p.TIM6, BAUD, TX_OVERSAMPLE); dump_tim6_regs(); let idle: u32 = 1u32 << TX_PIN_BIT; // Ring initialized to idle (line high). let tx_ring_mem: &mut [u32; TX_RING_BYTES] = TX_RING.init([0; TX_RING_BYTES]); let odr_ptr = embassy_stm32::pac::GPIOA.odr().as_ptr() as *mut u32; let mut tx_opts = TransferOptions::default(); tx_opts.half_transfer_ir = true; tx_opts.complete_transfer_ir = true; let mut tx_ring = unsafe { WritableRingBuffer::new( p.GPDMA1_CH0, TIM6_UP_REQ, odr_ptr, tx_ring_mem, tx_opts, ) }; { // Full idle buffer matching ring capacity. let idle_buf = [idle; TX_RING_BYTES]; let written = tx_ring .write_exact(&idle_buf) .await .expect("Failed to prefill TX ring with idle"); info!( "TX ring prefilled with idle via write_exact: written={} cap={}", written, tx_ring.capacity() ); } tx_ring.start(); info!( "TX DMA ring started: cap_words={}", tx_ring.capacity() ); unsafe { use embassy_stm32::pac::gpdma::Gpdma; let dma = Gpdma::from_ptr(0x4002_0000 as _); // GPDMA1 base for STM32U5 let ch = dma.ch(0); // Channel 0 let cr = ch.cr().read(); let tr1 = ch.tr1().read(); let tr2 = ch.tr2().read(); let br1 = ch.br1().read(); let sar = ch.sar().read(); let dar = ch.dar().read(); let llr = ch.llr().read(); let lbar = ch.lbar().read(); info!( "GPDMA1_CH0: EN={} HTIE={} TCIE={} SDW={:?} DDW={:?} SINC={} DINC={} BNDT={} SAR=0x{:08x} DAR=0x{:08x}", cr.en(), cr.htie(), cr.tcie(), tr1.sdw(), tr1.ddw(), tr1.sinc(), tr1.dinc(), br1.bndt(), sar, // already u32 dar, // already u32 ); info!( "GPDMA1_CH0: LBAR=0x{:08x} LLR=0x{:08x}", lbar.lba(), llr.0 ); } let mut frame_buf = [0u32; 4096]; loop { info!("tick start"); Timer::after(Duration::from_millis(1021)).await; //info!("tick end"); let used = encode_uart_frames( TX_PIN_BIT, b"H\r\n", &mut frame_buf, ) .await; if used == 0 { info!("encode_uart_frames() produced 0 words, skipping write"); yield_now().await; continue; } // Debug: confirm encoded content. let preview = core::cmp::min(used, 32); info!( "TX frame used={} words, head={=[?]}", used, &frame_buf[..preview] ); // Now it is safe to call write_exact. match tx_ring.write_exact(&frame_buf[..used]).await { Ok(written) => { let len = tx_ring.len().unwrap_or(0); info!( "write_exact ok: written={} ring_used={} ring_cap={}", written, len, tx_ring.capacity() ); } Err(e) => { let len = tx_ring.len().unwrap_or(0); warn!( "write_exact error: {:?}, ring_used={} ring_cap={}", e, len, tx_ring.capacity() ); } } info!("tick end"); yield_now().await; } }