Files
stm32_rust/semestralka_1d_rx_bez_dma/src/bin/main.rs
2025-11-19 17:50:33 +01:00

226 lines
7.1 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// src/bin/main.rs
#![no_std]
#![no_main]
use defmt::*;
use embassy_executor::Spawner;
use embassy_time::Instant;
use embassy_stm32::dma::Request;
use embassy_stm32::gpio::{Input, Output, Level, Pull, Speed};
use dma_gpio::software_uart::{
dma_timer::{init_tim6_for_uart, init_tim7_for_uart},
gpio_dma_uart_rx::rx_dma_task,
debug::dump_tim6_regs,
};
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 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 cortex_m::interrupt::Mutex;
use core::cell::RefCell;
use embassy_sync::channel::Channel;
static PD6_BITS: Channel<CriticalSectionRawMutex, u8, 16384> = Channel::new();
bind_interrupts!(struct Irqs {
USART1 => BufferedInterruptHandler<peripherals::USART1>;
});
bind_interrupts!(struct Irqs2 {
USART2 => BufferedInterruptHandler<peripherals::USART2>;
});
// Software uart
pub const TIM6_UP_REQ: Request = 4;
static SW_TX_RING: StaticCell<[u32; TX_RING_BYTES]> = StaticCell::new();
static SW_RX_RING: StaticCell<[u8; RX_RING_BYTES]> = StaticCell::new();
static mut RX_PIN: Option<Input<'static>> = None;
#[embassy_executor::main]
async fn main(spawner: Spawner) {
info!("boot");
let p = embassy_stm32::init(Default::default());
info!("init m8");
// HARDWARE UART to the PC
let mut cfg = Config::default();
cfg.baudrate = BAUD;
static TX_BUF: StaticCell<[u8; 256]> = StaticCell::new();
static RX_BUF: StaticCell<[u8; 256]> = StaticCell::new();
let uart = BufferedUart::new(
p.USART1,
p.PA10, // RX pin
p.PA9, // TX pin
TX_BUF.init([0; 256]),
RX_BUF.init([0; 256]),
Irqs,
cfg,
).unwrap();
let yield_period = usart1::setup_and_spawn(BAUD);
spawner.spawn(uart_task(uart, &PIPE_HW_TX, &PIPE_HW_RX).unwrap());
// END OF HARDWARE UART to the PC
// INTERNAL HARDWARE UART (USART2)
let mut cfg2 = Config::default();
cfg2.baudrate = BAUD;
static TX_BUF2: StaticCell<[u8; 256]> = StaticCell::new();
static RX_BUF2: StaticCell<[u8; 256]> = StaticCell::new();
let uart2 = BufferedUart::new(
p.USART2,
p.PA3, // RX
p.PA2, // TX
TX_BUF2.init([0; 256]),
RX_BUF2.init([0; 256]),
Irqs2,
cfg2,
).unwrap();
let _ = 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)
// USART1 <-> USART2 bridge
spawner.spawn(bridge_usart1_rx_to_usart2_tx(&PIPE_HW_RX, &PIPE_INT_TX).unwrap());
spawner.spawn(bridge_usart2_rx_to_usart1_tx(&PIPE_INT_RX, &PIPE_HW_TX).unwrap());
info!("USART1 <-> USART2 bridge active");
// 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) };
// Configure TX as output (PB0)
let mut tx_pin = Output::new(p.PB0, Level::High, Speed::VeryHigh);
init_tim6_for_uart(p.TIM6, BAUD, TX_OVERSAMPLE);
init_tim7_for_uart(p.TIM7, BAUD, RX_OVERSAMPLE);
dump_tim6_regs();
// EDN OF SOFTWARE UART
unsafe { cortex_m::peripheral::NVIC::unmask(pac::Interrupt::TIM7); }
let frame_samples = (10 * RX_OVERSAMPLE as usize); // 1 start + 8 data + 1 stop
let mut rx_samples = [0u8; 4096]; // plenty of space
let mut rx_count = 0usize;
loop {
// === 1. Drain channel into local buffer in bursts ===
let mut drained = 0;
while let Ok(bit) = PD6_BITS.try_receive() {
if rx_count < rx_samples.len() {
rx_samples[rx_count] = bit;
rx_count += 1;
} else {
warn!("RX Buffer overflow, resetting");
rx_count = 0;
}
drained += 1;
// Periodically yield while draining to avoid hogging CPU
if drained >= 512 {
yield_now().await;
drained = 0;
}
}
// === 2. Process only when we have enough samples for a frame ===
if rx_count >= frame_samples {
let (decoded, consumed) = decode_uart_samples(
&rx_samples[..rx_count],
RX_OVERSAMPLE,
&UART_CFG,
);
// Print decoded chars
if !decoded.is_empty() {
// For debugging: only print when you actually have data
for &b in &decoded {
info!("{}", b as char);
}
}
// === 3. Remove processed samples ===
if consumed > 0 {
// Slide unprocessed samples to the start
rx_samples.copy_within(consumed..rx_count, 0);
rx_count -= consumed;
}
// Yield briefly so other embassy tasks run
yield_now().await;
} else {
// === 4. Buffer not yet full enough, short sleep ===
yield_now().await;
}
}
}
#[interrupt]
fn TIM7() {
let tim = unsafe { pac::TIM7 };
if tim.sr().read().uif() {
tim.sr().modify(|w| w.set_uif(false));
unsafe {
if let Some(ref pin) = RX_PIN {
// one instruction read no locking needed
let bit = pin.is_high() as u8;
let _ = PD6_BITS.try_send(bit);
}
}
}
}
#[embassy_executor::task]
pub async fn bridge_usart1_rx_to_usart2_tx(
usart1_rx: &'static Pipe<CriticalSectionRawMutex, 1024>,
usart2_tx: &'static Pipe<CriticalSectionRawMutex, 1024>,
) {
let mut buf = [0u8; 64];
loop {
let n = usart1_rx.read(&mut buf).await;
if n > 0 {
let _ = usart2_tx.write(&buf[..n]).await;
// info!("bridge: USART1 -> USART2 sent {} bytes", n);
}
yield_now().await;
}
}
#[embassy_executor::task]
pub async fn bridge_usart2_rx_to_usart1_tx(
usart2_rx: &'static Pipe<CriticalSectionRawMutex, 1024>,
usart1_tx: &'static Pipe<CriticalSectionRawMutex, 1024>,
) {
let mut buf = [0u8; 64];
loop {
let n = usart2_rx.read(&mut buf).await;
if n > 0 {
let _ = usart1_tx.write(&buf[..n]).await;
// info!("bridge: USART2 -> USART1 sent {} bytes", n);
}
yield_now().await;
}
}