Compare commits
1 Commits
v1.9.0
...
685067a75f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
685067a75f |
@@ -68,11 +68,11 @@ async fn main(spawner: Spawner) {
|
|||||||
config.rcc.pll1 = Some(Pll {
|
config.rcc.pll1 = Some(Pll {
|
||||||
source: PllSource::HSI,
|
source: PllSource::HSI,
|
||||||
// 16 MHz / 1 × 20 / 2 = 160 MHz
|
// 16 MHz / 1 × 20 / 2 = 160 MHz
|
||||||
prediv: PllPreDiv::DIV1, // or 1.into()
|
prediv: PllPreDiv::DIV1,
|
||||||
mul: PllMul::MUL20, // or 20.into()
|
mul: PllMul::MUL20,
|
||||||
divp: None,
|
divp: None,
|
||||||
divq: None,
|
divq: None,
|
||||||
divr: Some(PllDiv::DIV2), // or Some(2.into())
|
divr: Some(PllDiv::DIV2),
|
||||||
});
|
});
|
||||||
config.enable_independent_io_supply = true;
|
config.enable_independent_io_supply = true;
|
||||||
config.enable_independent_analog_supply = true;
|
config.enable_independent_analog_supply = true;
|
||||||
@@ -131,14 +131,12 @@ async fn main(spawner: Spawner) {
|
|||||||
let rx_pin = Input::new(p.PD6, Pull::Up);
|
let rx_pin = Input::new(p.PD6, Pull::Up);
|
||||||
unsafe { RX_PIN = Some(rx_pin) };
|
unsafe { RX_PIN = Some(rx_pin) };
|
||||||
|
|
||||||
// Configure TX as output (PB0)
|
|
||||||
let mut tx_pin = Output::new(p.PB0, Level::High, Speed::VeryHigh);
|
let mut tx_pin = Output::new(p.PB0, Level::High, Speed::VeryHigh);
|
||||||
init_tim6_for_uart(p.TIM6, BAUD, TX_OVERSAMPLE);
|
init_tim6_for_uart(p.TIM6, BAUD, TX_OVERSAMPLE);
|
||||||
init_tim7_for_uart(p.TIM7, BAUD, RX_OVERSAMPLE);
|
init_tim7_for_uart(p.TIM7, BAUD, RX_OVERSAMPLE);
|
||||||
|
|
||||||
dump_tim6_regs();
|
dump_tim6_regs();
|
||||||
let bsrr_ptr = embassy_stm32::pac::GPIOB.bsrr().as_ptr() as *mut u32; // POZOR B REGISTER
|
|
||||||
|
|
||||||
|
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());
|
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
|
// EDN OF SOFTWARE UART
|
||||||
|
|
||||||
@@ -148,7 +146,6 @@ async fn main(spawner: Spawner) {
|
|||||||
spawner.spawn(rx_dma_task(p.GPDMA1_CH1, gpio_idr, rx_ring, &PIPE_SW_RX).unwrap());
|
spawner.spawn(rx_dma_task(p.GPDMA1_CH1, gpio_idr, rx_ring, &PIPE_SW_RX).unwrap());
|
||||||
info!("SW UART RX DMA started");
|
info!("SW UART RX DMA started");
|
||||||
|
|
||||||
// Process decoded bytes coming from PIPE_SW_RX
|
|
||||||
let mut buf = [0u8; 64];
|
let mut buf = [0u8; 64];
|
||||||
loop {
|
loop {
|
||||||
let n = PIPE_SW_RX.read(&mut buf).await;
|
let n = PIPE_SW_RX.read(&mut buf).await;
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ fn configure_basic_timer<T: BasicInstance>(ll: &Timer<'_, T>, baud: u32, oversam
|
|||||||
let target = baud.saturating_mul(oversample.max(1) as u32).max(1);
|
let target = baud.saturating_mul(oversample.max(1) as u32).max(1);
|
||||||
|
|
||||||
// Compute ARR (prescaler = 0)
|
// Compute ARR (prescaler = 0)
|
||||||
let mut arr = (f_timer / target).saturating_sub(1) as u16;
|
// let mut arr = (f_timer / target).saturating_sub(1) as u16;
|
||||||
|
let mut arr = ((f_timer + target / 2) / target).saturating_sub(1) as u16;
|
||||||
if arr == 0 { arr = 1; }
|
if arr == 0 { arr = 1; }
|
||||||
|
|
||||||
ll.regs_basic().cr1().write(|w| {
|
ll.regs_basic().cr1().write(|w| {
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ pub async fn rx_dma_task(
|
|||||||
|
|
||||||
// We read into the second half of a buffer, keeping "leftovers" in the first half.
|
// We read into the second half of a buffer, keeping "leftovers" in the first half.
|
||||||
const CHUNK_SIZE: usize = 4096;
|
const CHUNK_SIZE: usize = 4096;
|
||||||
const HISTORY_SIZE: usize = 512; // Enough to hold a potential split frame
|
const HISTORY_SIZE: usize = 512;
|
||||||
const TOTAL_BUF_SIZE: usize = HISTORY_SIZE + CHUNK_SIZE;
|
const TOTAL_BUF_SIZE: usize = HISTORY_SIZE + CHUNK_SIZE;
|
||||||
|
|
||||||
// Logic level buffer
|
// Logic level buffer
|
||||||
@@ -54,7 +54,6 @@ pub async fn rx_dma_task(
|
|||||||
}
|
}
|
||||||
let current_end = valid_len + CHUNK_SIZE;
|
let current_end = valid_len + CHUNK_SIZE;
|
||||||
|
|
||||||
// 3. Decode everything we have
|
|
||||||
let (decoded, consumed) = decode_uart_samples(
|
let (decoded, consumed) = decode_uart_samples(
|
||||||
&level_buf[..current_end],
|
&level_buf[..current_end],
|
||||||
RX_OVERSAMPLE,
|
RX_OVERSAMPLE,
|
||||||
@@ -69,13 +68,12 @@ pub async fn rx_dma_task(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Shift remaining data to front
|
// Shift remaining data to front
|
||||||
// We processed 'consumed' samples.
|
// We processed 'consumed' samples.
|
||||||
// We keep everything from 'consumed' up to 'current_end'.
|
// We keep everything from 'consumed' up to 'current_end'.
|
||||||
let remaining = current_end - consumed;
|
let remaining = current_end - consumed;
|
||||||
|
|
||||||
// Safety check: if remaining > HISTORY_SIZE, we are in trouble (buffer too small / decoder stuck).
|
// SAFETY if remaining > HISTORY_SIZE, we are in trouble (buffer too small / decoder stuck).
|
||||||
// But for now, just shift.
|
|
||||||
if remaining > 0 {
|
if remaining > 0 {
|
||||||
level_buf.copy_within(consumed..current_end, 0);
|
level_buf.copy_within(consumed..current_end, 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,14 +59,13 @@ pub async fn tx_dma_task(
|
|||||||
|
|
||||||
let used = encode_uart_frames(TX_PIN_BIT, &rx_buf[..n], &mut frame_buf).await;
|
let used = encode_uart_frames(TX_PIN_BIT, &rx_buf[..n], &mut frame_buf).await;
|
||||||
if used > 0 {
|
if used > 0 {
|
||||||
// Align arming to a clean TIM6 update boundary:
|
// Clear pending UIF
|
||||||
// 1) clear any pending UIF
|
|
||||||
tim6.sr().write(|w| w.set_uif(false));
|
tim6.sr().write(|w| w.set_uif(false));
|
||||||
// 2) wait for the next UIF (next bit tick)
|
// Wait for the next UIF (next bit tick)
|
||||||
while !tim6.sr().read().uif() {
|
while !tim6.sr().read().uif() {
|
||||||
yield_now().await;
|
yield_now().await;
|
||||||
}
|
}
|
||||||
// 3) clear UIF so first DMA beat happens on the FOLLOWING tick
|
// Clear UIF so first DMA beat happens on the FOLLOWING tick
|
||||||
tim6.sr().write(|w| w.set_uif(false));
|
tim6.sr().write(|w| w.set_uif(false));
|
||||||
|
|
||||||
let mut tx_opts = TransferOptions::default();
|
let mut tx_opts = TransferOptions::default();
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ pub fn decode_uart_samples(
|
|||||||
let frame_bits = 1 + nbits + parity_bits + stop_bits_count;
|
let frame_bits = 1 + nbits + parity_bits + stop_bits_count;
|
||||||
let frame_len = frame_bits * ovs;
|
let frame_len = frame_bits * ovs;
|
||||||
|
|
||||||
// Helper: Majority vote over 3 samples centered at `i`
|
// Majority vote over 3 samples centered at `i`
|
||||||
let get_bit = |i: usize| -> u8 {
|
let get_bit = |i: usize| -> u8 {
|
||||||
let mut votes = 0;
|
let mut votes = 0;
|
||||||
// Check i-1, i, i+1. Saturating sub/add handles boundaries roughly.
|
// Check i-1, i, i+1. Saturating sub/add handles boundaries roughly.
|
||||||
@@ -136,7 +136,7 @@ pub fn decode_uart_samples(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// We loop while we have enough remaining samples for a full frame
|
// Loop while we have enough remaining samples for a full frame
|
||||||
while idx + frame_len <= samples.len() {
|
while idx + frame_len <= samples.len() {
|
||||||
// Wait for falling edge (High -> Low)
|
// Wait for falling edge (High -> Low)
|
||||||
// samples[idx] == 1 (Idle/Stop) && samples[idx+1] == 0 (Start)
|
// samples[idx] == 1 (Idle/Stop) && samples[idx+1] == 0 (Start)
|
||||||
@@ -146,7 +146,7 @@ pub fn decode_uart_samples(
|
|||||||
let center_offset = 1 + (ovs / 2);
|
let center_offset = 1 + (ovs / 2);
|
||||||
let mut scan_idx = idx + center_offset;
|
let mut scan_idx = idx + center_offset;
|
||||||
|
|
||||||
// 1. Validate Start Bit (Must be 0)
|
// Validate Start Bit
|
||||||
if get_bit(scan_idx) != 0 {
|
if get_bit(scan_idx) != 0 {
|
||||||
idx += 1; // False start (noise), move on
|
idx += 1; // False start (noise), move on
|
||||||
continue;
|
continue;
|
||||||
@@ -155,7 +155,7 @@ pub fn decode_uart_samples(
|
|||||||
// Move to center of first data bit
|
// Move to center of first data bit
|
||||||
scan_idx += ovs;
|
scan_idx += ovs;
|
||||||
|
|
||||||
// 2. Read Data Bits
|
// Read Data Bits
|
||||||
let mut data: u8 = 0;
|
let mut data: u8 = 0;
|
||||||
for bit in 0..nbits {
|
for bit in 0..nbits {
|
||||||
if get_bit(scan_idx) == 1 {
|
if get_bit(scan_idx) == 1 {
|
||||||
@@ -164,22 +164,22 @@ pub fn decode_uart_samples(
|
|||||||
scan_idx += ovs;
|
scan_idx += ovs;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Skip Parity (if any)
|
// Skip Parity
|
||||||
if cfg.parity != Parity::None {
|
if cfg.parity != Parity::None {
|
||||||
scan_idx += ovs;
|
scan_idx += ovs;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Validate Stop Bit (Must be 1)
|
// Validate Stop Bit (Must be 1)
|
||||||
// If stop bit is 0, it's a framing error. We reject the whole byte.
|
// If stop bit is 0, it's a framing error. We reject the whole byte.
|
||||||
if get_bit(scan_idx) == 0 {
|
if get_bit(scan_idx) == 0 {
|
||||||
idx += 1; // Try to find a real start bit on the next sample
|
idx += 1; // Next sample
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Byte is valid
|
// Byte is valid
|
||||||
let _ = out.push(data);
|
let _ = out.push(data);
|
||||||
|
|
||||||
// 6. Active Resync: Fast-forward through the stop bit(s) and idle time
|
// Active Resync: Fast-forward through the stop bit(s) and idle time
|
||||||
// scan_idx is currently at the center of the Stop bit.
|
// scan_idx is currently at the center of the Stop bit.
|
||||||
idx = scan_idx;
|
idx = scan_idx;
|
||||||
// Advance while we are reading High (1).
|
// Advance while we are reading High (1).
|
||||||
|
|||||||
Reference in New Issue
Block a user