diff --git a/semestralka_1_connected/src/bin/main.rs b/semestralka_1_connected/src/bin/main.rs index 1b5a1a6..c520cb8 100644 --- a/semestralka_1_connected/src/bin/main.rs +++ b/semestralka_1_connected/src/bin/main.rs @@ -3,47 +3,46 @@ #![no_main] use defmt::*; +use core::cell::RefCell; +use cortex_m::interrupt::Mutex; use embassy_executor::Spawner; -use embassy_time::Instant; -use embassy_stm32::dma::Request; -use embassy_stm32::gpio::{Input, Output, Level, Pull, Speed}; +use embassy_futures::yield_now; +use embassy_sync::{ + blocking_mutex::raw::CriticalSectionRawMutex, + channel::Channel, + pipe::Pipe, +}; +use embassy_time::{Duration, Instant, Timer}; +use embassy_stm32::{ + bind_interrupts, + dma::Request, + gpio::{Input, Level, Output, Pull, Speed}, + interrupt, + pac, + peripherals, + rcc::{self, Pll, PllDiv, PllMul, PllPreDiv, PllSource, Sysclk}, + usart::{BufferedInterruptHandler, BufferedUart, Config}, + Config as CPUConfig, +}; +use static_cell::StaticCell; +use dma_gpio::config::{ + BAUD, PIPE_HW_RX, PIPE_HW_TX, PIPE_INT_RX, PIPE_INT_TX, PIPE_SW_RX, + PIPE_SW_TX, RX_OVERSAMPLE, RX_RING_BYTES, TX_OVERSAMPLE, TX_RING_BYTES, + UART_CFG, +}; +use dma_gpio::hw_uart_pc::{driver::uart_task, usart1}; +use dma_gpio::hw_uart_internal::{ + driver::uart_task as uart_task_internal, + usart2, +}; use dma_gpio::software_uart::{ + debug::dump_tim6_regs, + decode_uart_samples, dma_timer::{init_tim6_for_uart, init_tim7_for_uart}, gpio_dma_uart_rx::rx_dma_task, - debug::dump_tim6_regs, + gpio_dma_uart_tx::tx_dma_task, }; -use dma_gpio::config::{BAUD, RX_OVERSAMPLE, TX_OVERSAMPLE}; -use dma_gpio::config::{TX_RING_BYTES, RX_RING_BYTES}; -use dma_gpio::software_uart::gpio_dma_uart_tx::tx_dma_task; -use static_cell::StaticCell; -use embassy_futures::yield_now; -use dma_gpio::hw_uart_pc::usart1; -use dma_gpio::hw_uart_pc::driver::uart_task; -use embassy_stm32::usart::{BufferedUart, Config, BufferedInterruptHandler}; -use embassy_stm32::peripherals; -use embassy_stm32::bind_interrupts; -use embassy_stm32::Config as CPUConfig; -use dma_gpio::config::{PIPE_HW_TX, PIPE_HW_RX, PIPE_SW_TX, PIPE_SW_RX}; -use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, pipe::Pipe}; -use dma_gpio::hw_uart_internal::usart2; -use dma_gpio::hw_uart_internal::driver::uart_task as uart_task_internal; -use dma_gpio::software_uart::decode_uart_samples; -use dma_gpio::config::UART_CFG; -use dma_gpio::config::{PIPE_INT_TX, PIPE_INT_RX}; -use embassy_time::{Duration, Timer}; -use embassy_stm32::pac; -use embassy_stm32::interrupt; use {defmt_rtt as _, panic_probe as _}; -use embassy_stm32::{ - rcc::{self, Pll, PllSource}, -}; -use embassy_stm32::rcc::PllMul; -use embassy_stm32::rcc::PllDiv; -use embassy_stm32::rcc::PllPreDiv; -use embassy_stm32::rcc::Sysclk; -use cortex_m::interrupt::Mutex; -use core::cell::RefCell; -use embassy_sync::channel::Channel; static PD6_BITS: Channel = Channel::new(); @@ -81,6 +80,8 @@ async fn main(spawner: Spawner) { let p = embassy_stm32::init(config); let f_tim7 = rcc::frequency::().0; info!("TIM7 clock after PLL config = {} Hz", f_tim7); + let f_tim6 = rcc::frequency::().0; + info!("TIM6 clock after PLL config = {} Hz", f_tim6); // HARDWARE UART to the PC let mut cfg = Config::default(); @@ -115,7 +116,7 @@ async fn main(spawner: Spawner) { Irqs2, cfg2, ).unwrap(); - let _ = usart2::setup_and_spawn(BAUD); + let yield_period2 = usart2::setup_and_spawn(BAUD); spawner.spawn(uart_task_internal(uart2, &PIPE_INT_TX, &PIPE_INT_RX).unwrap()); info!("USART2 ready"); // END OF INTERNAL HARDWARE UART (USART2) @@ -127,7 +128,6 @@ async fn main(spawner: Spawner) { // END OF USART1 <-> USART2 bridge // SOFTWARE UART - // let _rx = Input::new(p.PD6, Pull::Up); let rx_pin = Input::new(p.PD6, Pull::Up); unsafe { RX_PIN = Some(rx_pin) }; @@ -137,18 +137,15 @@ async fn main(spawner: Spawner) { init_tim7_for_uart(p.TIM7, BAUD, RX_OVERSAMPLE); dump_tim6_regs(); + let bsrr_ptr = embassy_stm32::pac::GPIOB.bsrr().as_ptr() as *mut u32; // POZOR B REGISTER + + spawner.spawn(tx_dma_task(p.GPDMA1_CH0, bsrr_ptr, SW_TX_RING.init([0; TX_RING_BYTES]), &PIPE_SW_TX).unwrap()); // EDN OF SOFTWARE UART - // Allocate DMA RX ring buffer let rx_ring = SW_RX_RING.init([0u8; RX_RING_BYTES]); - - // Pointer to GPIOD Input Data Register (IDR) let gpio_idr = embassy_stm32::pac::GPIOD.idr().as_ptr() as *mut u8; - - // Spawn software UART RX DMA task spawner.spawn(rx_dma_task(p.GPDMA1_CH1, gpio_idr, rx_ring, &PIPE_SW_RX).unwrap()); - info!("SW UART RX DMA started"); // Process decoded bytes coming from PIPE_SW_RX @@ -156,7 +153,8 @@ async fn main(spawner: Spawner) { loop { let n = PIPE_SW_RX.read(&mut buf).await; if n > 0 { - info!("SW UART decoded: {:a}", &buf[..n]); + let _ = PIPE_SW_TX.write(&buf[..n]).await; + // info!("SW UART decoded: {:a}", &buf[..n]); } yield_now().await; } diff --git a/semestralka_1_connected/src/software_uart/gpio_dma_uart_tx.rs b/semestralka_1_connected/src/software_uart/gpio_dma_uart_tx.rs index d995156..c98dbbe 100644 --- a/semestralka_1_connected/src/software_uart/gpio_dma_uart_tx.rs +++ b/semestralka_1_connected/src/software_uart/gpio_dma_uart_tx.rs @@ -1,7 +1,7 @@ // src/software_uart/gpio_dma_uart_tx.rs use embassy_executor::task; use embassy_stm32::{ - dma::{Request, TransferOptions, WritableRingBuffer}, + dma::{Request, Transfer, TransferOptions}, peripherals::GPDMA1_CH0, Peri, }; @@ -32,40 +32,23 @@ pub async fn encode_uart_frames<'a>( break; } - // cooperative async yield yield_now().await; } offset } -/// TX DMA task: encodes UART frames and sends them via DMA at TIM6 rate #[task] pub async fn tx_dma_task( - ch: Peri<'static, GPDMA1_CH0>, - register: *mut u32, // Either odr or bsrr - tx_ring_mem: &'static mut [u32], + mut ch: Peri<'static, GPDMA1_CH0>, + register: *mut u32, // GPIOx_BSRR + _tx_ring_mem: &'static mut [u32], pipe_rx: &'static Pipe, ) { - let mut tx_opts = TransferOptions::default(); - tx_opts.half_transfer_ir = true; - tx_opts.complete_transfer_ir = true; - - // SAFETY: tx_ring is exclusive to this task - let mut tx_ring = unsafe { - WritableRingBuffer::new( - ch, - TIM6_UP_REQ, - register, - tx_ring_mem, - tx_opts, - ) - }; - - tx_ring.start(); - info!("TX DMA ring started"); + info!("TX DMA task ready (One‑shot)"); let mut frame_buf = [0u32; 4096]; let mut rx_buf = [0u8; 256]; + let tim6 = embassy_stm32::pac::TIM6; loop { let n = pipe_rx.read(&mut rx_buf).await; @@ -76,9 +59,33 @@ pub async fn tx_dma_task( let used = encode_uart_frames(TX_PIN_BIT, &rx_buf[..n], &mut frame_buf).await; if used > 0 { - let _ = tx_ring.write_exact(&frame_buf[..used]).await; + // Align arming to a clean TIM6 update boundary: + // 1) clear any pending UIF + tim6.sr().write(|w| w.set_uif(false)); + // 2) wait for the next UIF (next bit tick) + while !tim6.sr().read().uif() { + yield_now().await; + } + // 3) clear UIF so first DMA beat happens on the FOLLOWING tick + tim6.sr().write(|w| w.set_uif(false)); + + let mut tx_opts = TransferOptions::default(); + tx_opts.half_transfer_ir = false; + tx_opts.complete_transfer_ir = true; + + unsafe { + let transfer = Transfer::new_write( + ch.reborrow(), + TIM6_UP_REQ, + &frame_buf[..used], + register, + tx_opts, + ); + transfer.await; + } } - info!("tx_dma_task wrote {} words", used); + + // info!("tx_dma_task sent {} words", used); yield_now().await; } } diff --git a/semestralka_1j_tx_dma/src/bin/main.rs b/semestralka_1j_tx_dma/src/bin/main.rs index 201d643..c36b416 100644 --- a/semestralka_1j_tx_dma/src/bin/main.rs +++ b/semestralka_1j_tx_dma/src/bin/main.rs @@ -104,7 +104,7 @@ async fn main(spawner: Spawner) { ).unwrap()); // END OF SOFTWARE UART - let mut buf = [0u8; 32]; + // let mut buf = [0u8; 32]; let mut counter: u32 = 0; loop {