the Tx is finished
This commit is contained in:
@@ -10,7 +10,6 @@ use embassy_time::{Duration, Timer};
|
|||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
use embassy_stm32::{
|
use embassy_stm32::{
|
||||||
dma::Request,
|
|
||||||
gpio::{Level, Output, Speed},
|
gpio::{Level, Output, Speed},
|
||||||
peripherals::{GPDMA1_CH0, TIM6},
|
peripherals::{GPDMA1_CH0, TIM6},
|
||||||
rcc,
|
rcc,
|
||||||
@@ -18,7 +17,9 @@ use embassy_stm32::{
|
|||||||
};
|
};
|
||||||
use embassy_stm32::Peri;
|
use embassy_stm32::Peri;
|
||||||
|
|
||||||
use dma_gpio::gpio_dma_uart::{encode_uart_byte, write_uart_frames_to_pipe, GpioDmaBsrrTx, TIM6_UP_REQ};
|
use dma_gpio::gpio_dma_uart::{
|
||||||
|
write_uart_frames_to_pipe, GpioDmaBsrrTx, Parity, StopBits, UartConfig, TIM6_UP_REQ,
|
||||||
|
};
|
||||||
|
|
||||||
static PIPE: Pipe<CriticalSectionRawMutex, 256> = Pipe::new();
|
static PIPE: Pipe<CriticalSectionRawMutex, 256> = Pipe::new();
|
||||||
|
|
||||||
@@ -26,10 +27,16 @@ static PIPE: Pipe<CriticalSectionRawMutex, 256> = Pipe::new();
|
|||||||
const BAUD: u32 = 115_200;
|
const BAUD: u32 = 115_200;
|
||||||
const TX_PIN_BIT: u8 = 2; // PA2
|
const TX_PIN_BIT: u8 = 2; // PA2
|
||||||
|
|
||||||
|
const UART_CFG: UartConfig = UartConfig {
|
||||||
|
data_bits: 8,
|
||||||
|
parity: Parity::None,
|
||||||
|
stop_bits: StopBits::One,
|
||||||
|
};
|
||||||
|
|
||||||
#[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!("DMA Pipe -> GPIO UART-like TX (safe wrapper)");
|
info!("DMA Pipe -> GPIO UART-like TX");
|
||||||
|
|
||||||
// PA2 is the TX "wire"
|
// PA2 is the TX "wire"
|
||||||
let _pa2 = Output::new(p.PA2, Level::High, Speed::VeryHigh);
|
let _pa2 = Output::new(p.PA2, Level::High, Speed::VeryHigh);
|
||||||
@@ -51,7 +58,12 @@ async fn main(spawner: Spawner) {
|
|||||||
|
|
||||||
// Example: transmit a string as UART frames via the Pipe
|
// Example: transmit a string as UART frames via the Pipe
|
||||||
loop {
|
loop {
|
||||||
write_uart_frames_to_pipe(&PIPE, TX_PIN_BIT, b"Hello, DMA UART!\r\n").await;
|
write_uart_frames_to_pipe(
|
||||||
|
&PIPE,
|
||||||
|
TX_PIN_BIT,
|
||||||
|
b"Hello, DMA UART (configurable)!\r\n",
|
||||||
|
&UART_CFG,
|
||||||
|
).await;
|
||||||
Timer::after(Duration::from_secs(2)).await;
|
Timer::after(Duration::from_secs(2)).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -70,7 +82,6 @@ async fn dma_tx_task(ch: Peri<'static, GPDMA1_CH0>) {
|
|||||||
}
|
}
|
||||||
let w = u32::from_le_bytes(b);
|
let w = u32::from_le_bytes(b);
|
||||||
|
|
||||||
// Log + send via DMA (timer-paced, 1 beat per bit time)
|
|
||||||
info!("DMA write 0x{:08X} -> GPIOA.BSRR", w);
|
info!("DMA write 0x{:08X} -> GPIOA.BSRR", w);
|
||||||
tx.write_word(w).await;
|
tx.write_word(w).await;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,37 @@ use embassy_stm32::{
|
|||||||
};
|
};
|
||||||
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, pipe::Pipe};
|
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, pipe::Pipe};
|
||||||
|
|
||||||
pub const TIM6_UP_REQ: Request = 4; // Table 137: tim6_upd_dma, strana 687
|
pub const TIM6_UP_REQ: Request = 4; // Table 137: tim6_upd_dma, strana 687 STM32U5xx datasheet
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum Parity {
|
||||||
|
None,
|
||||||
|
Even,
|
||||||
|
Odd,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum StopBits {
|
||||||
|
One,
|
||||||
|
Two,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct UartConfig {
|
||||||
|
pub data_bits: u8, // 5..=8 bitov strana 16 TI_uart
|
||||||
|
pub parity: Parity,
|
||||||
|
pub stop_bits: StopBits,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for UartConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
data_bits: 8,
|
||||||
|
parity: Parity::None,
|
||||||
|
stop_bits: StopBits::One,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct GpioDmaBsrrTx<'d> {
|
pub struct GpioDmaBsrrTx<'d> {
|
||||||
ch: Peri<'d, GPDMA1_CH0>,
|
ch: Peri<'d, GPDMA1_CH0>,
|
||||||
@@ -43,41 +73,95 @@ impl<'d> GpioDmaBsrrTx<'d> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build 10 BSRR words for one UART frame (8N1) on a given GPIO bit.
|
// Build up to 12 BSRR words for one UART frame on a given GPIO bit.
|
||||||
// start bit, 8 data bits LSB-first, stop bit
|
// Format: 1 START (low), N data (LSB first), optional PARITY, STOP(1/2 -> here 1 or 2 ticks).
|
||||||
// BSRR je safe atomic write only shortcut
|
// BSRR je safe atomic write only shortcut
|
||||||
pub fn encode_uart_byte(pin_bit: u8, data: u8) -> [u32; 10] {
|
pub fn encode_uart_byte_cfg(
|
||||||
let mut words = [0u32; 10];
|
pin_bit: u8,
|
||||||
|
data: u8,
|
||||||
|
cfg: &UartConfig,
|
||||||
|
out: &mut [u32; 12],
|
||||||
|
) -> usize {
|
||||||
// Dokumentacia strana 636 13.4.7
|
// Dokumentacia strana 636 13.4.7
|
||||||
// set bit - HIGH, reset bit - LOW
|
// set bit - HIGH, reset bit - LOW (BSRR)
|
||||||
let set_high = |bit: u8| -> u32 { 1u32 << bit };
|
let set_high = |bit: u8| -> u32 { 1u32 << bit };
|
||||||
let set_low = |bit: u8| -> u32 { 1u32 << (bit as u32 + 16) };
|
let set_low = |bit: u8| -> u32 { 1u32 << (bit as u32 + 16) };
|
||||||
|
|
||||||
// start bit LOW
|
let mut idx = 0usize;
|
||||||
words[0] = set_low(pin_bit);
|
|
||||||
|
|
||||||
// data bits, LSB first
|
// START bit (LOW)
|
||||||
for i in 0..8 {
|
out[idx] = set_low(pin_bit);
|
||||||
let one = (data >> i) & 1 != 0;
|
idx += 1;
|
||||||
words[1 + i] = if one { set_high(pin_bit) } else { set_low(pin_bit) };
|
|
||||||
|
// Data bits, LSB first (5..=8)
|
||||||
|
let nbits = cfg.data_bits.clamp(5, 8);
|
||||||
|
for i in 0..nbits {
|
||||||
|
let one = ((data >> i) & 1) != 0;
|
||||||
|
out[idx] = if one { set_high(pin_bit) } else { set_low(pin_bit) };
|
||||||
|
idx += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop bit HIGH
|
// Optional parity
|
||||||
words[9] = set_high(pin_bit);
|
match cfg.parity {
|
||||||
words
|
Parity::None => {}
|
||||||
|
Parity::Even | Parity::Odd => {
|
||||||
|
// Count ones
|
||||||
|
let mask: u8 = if nbits == 8 { 0xFF } else { (1u16 << nbits) as u8 - 1 };
|
||||||
|
let ones = (data & mask).count_ones() & 1; // 0=even, 1=odd
|
||||||
|
let par_bit_is_one = match cfg.parity {
|
||||||
|
Parity::Even => ones == 1, // make total ones even
|
||||||
|
Parity::Odd => ones == 0, // make total ones odd
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
out[idx] = if par_bit_is_one {
|
||||||
|
set_high(pin_bit)
|
||||||
|
} else {
|
||||||
|
set_low(pin_bit)
|
||||||
|
};
|
||||||
|
idx += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// STOP bits (HIGH)
|
||||||
|
// - STB=0 => 1 stop bit
|
||||||
|
// - STB=1 => 2 stop bits
|
||||||
|
let stop_ticks = match cfg.stop_bits {
|
||||||
|
StopBits::One => 1usize,
|
||||||
|
StopBits::Two => 2usize,
|
||||||
|
};
|
||||||
|
for _ in 0..stop_ticks {
|
||||||
|
out[idx] = set_high(pin_bit);
|
||||||
|
idx += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
idx
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convenience: push UART frames for a whole byte slice into a Pipe.
|
// Push UART frames for a whole byte slice into a Pipe.
|
||||||
pub async fn write_uart_frames_to_pipe<const N: usize>(
|
pub async fn write_uart_frames_to_pipe<const N: usize>(
|
||||||
pipe: &Pipe<CriticalSectionRawMutex, N>,
|
pipe: &Pipe<CriticalSectionRawMutex, N>,
|
||||||
pin_bit: u8,
|
pin_bit: u8,
|
||||||
bytes: &[u8],
|
bytes: &[u8],
|
||||||
|
cfg: &UartConfig,
|
||||||
) {
|
) {
|
||||||
for &b in bytes {
|
for &b in bytes {
|
||||||
let frames = encode_uart_byte(pin_bit, b);
|
let mut frame = [0u32; 12];
|
||||||
for w in frames {
|
let used = encode_uart_byte_cfg(pin_bit, b, cfg, &mut frame);
|
||||||
|
for w in &frame[..used] {
|
||||||
pipe.write(&w.to_le_bytes()).await;
|
pipe.write(&w.to_le_bytes()).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Optional: emit a BREAK (line LOW for 'bits' bit-times).
|
||||||
|
pub async fn write_break_to_pipe<const N: usize>(
|
||||||
|
pipe: &Pipe<CriticalSectionRawMutex, N>,
|
||||||
|
pin_bit: u8,
|
||||||
|
bits: usize,
|
||||||
|
) {
|
||||||
|
let set_low = |bit: u8| -> u32 { 1u32 << (bit as u32 + 16) };
|
||||||
|
let word = set_low(pin_bit);
|
||||||
|
for _ in 0..bits {
|
||||||
|
pipe.write(&word.to_le_bytes()).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user