Skip to content

Commit

Permalink
feat: uart tx software break
Browse files Browse the repository at this point in the history
  • Loading branch information
zpg6 committed Dec 30, 2024
1 parent 36095e4 commit 4698877
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 0 deletions.
53 changes: 53 additions & 0 deletions esp-hal/src/uart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,26 @@ where
}
}

/// Sends a break signal for a specified duration in bit time, i.e. the time
/// it takes to transfer one bit at the current baud rate. The delay during
/// the break is just is busy-waiting.
pub fn send_break(&mut self, bits: u32) {
// Invert the TX line
self.register_block()
.conf0()
.modify(|_, w| w.txd_inv().bit(true));

// 1 bit time in microseconds = 1_000_000 / baudrate
// TODO: Proper baudrate retrieval!
let bit_period_us: u32 = 1_000_000 / 19200;
crate::rom::ets_delay_us(bit_period_us * bits);

// Revert the TX line
self.register_block()
.conf0()
.modify(|_, w| w.txd_inv().bit(false));
}

/// Checks if the TX line is idle for this UART instance.
///
/// Returns `true` if the transmit line is idle, meaning no data is
Expand Down Expand Up @@ -1252,6 +1272,11 @@ where
self.tx.flush()
}

/// Sends a break signal for a specified duration
pub fn send_break(&mut self, bits: u32) {
self.tx.send_break(bits)
}

/// Read a byte from the UART
pub fn read_byte(&mut self) -> nb::Result<u8, Error> {
self.rx.read_byte()
Expand Down Expand Up @@ -1802,6 +1827,11 @@ where
self.tx.write_async(words).await
}

/// Asynchronously sends a break signal.
pub async fn send_break_async(&mut self, bits: u32) {
self.tx.send_break_async(bits).await;
}

/// Asynchronously flushes the UART transmit buffer.
pub async fn flush_async(&mut self) -> Result<(), Error> {
self.tx.flush_async().await
Expand Down Expand Up @@ -1856,6 +1886,29 @@ where

Ok(())
}

/// Asynchronously sends a break signal.
///
/// This function sends a break signal on the UART TX line. The break
/// duration is specified in bit time, i.e. the time it takes to send
/// one bit at the current baudrate.
pub async fn send_break_async(&mut self, bits: u32) {
// Invert the TX line
self.register_block()
.conf0()
.modify(|_, w| w.txd_inv().bit(true));

// 1 bit time in microseconds = 1_000_000 / baudrate
// TODO: Proper baudrate retrieval!
let bit_period_us: u32 = 1_000_000 / 19200;
// TODO: Proper async delay!
crate::rom::ets_delay_us(bit_period_us * bits);

// Revert the TX line
self.register_block()
.conf0()
.modify(|_, w| w.txd_inv().bit(false));
}
}

impl<T> UartRx<'_, Async, T>
Expand Down
50 changes: 50 additions & 0 deletions examples/src/bin/uart_send_break.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//! Example of sending a software break signal from a UART in
//! Blocking mode.
//!
//! The following wiring is assumed:
//! - TEST IO PIN => GPIO2
//! - TX => GPIO17
//! - RX => GPIO16
//% CHIPS: esp32

#![no_std]
#![no_main]

use esp_backtrace as _;
use esp_hal::{
delay::Delay,
entry,
gpio::{Level, Output},
uart::{Config as UartConfig, DataBits, StopBits, Uart},
};

#[entry]
fn main() -> ! {
let peripherals = esp_hal::init(esp_hal::Config::default());
let uart_config = UartConfig::default()
.baudrate(19200)
.data_bits(DataBits::DataBits8)
.parity_none()
.stop_bits(StopBits::Stop1);

let mut uart = Uart::new(
peripherals.UART1,
uart_config,
peripherals.GPIO16, // RX
peripherals.GPIO17, // TX
)
.expect("Failed to initialize UART");

let delay = Delay::new();

// Used to toggle an output pin for comparing its timing with
// the TX line on an oscilloscope. It's also the LED pin.
let mut test_io_pin = Output::new(peripherals.GPIO2, Level::Low);

loop {
test_io_pin.toggle();
uart.send_break(19200); // 19200 bits at 19200bps = 1 second
test_io_pin.toggle();
delay.delay_millis(1000);
}
}
57 changes: 57 additions & 0 deletions examples/src/bin/uart_send_break_async.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//! Example of sending a software break signal from a UART in
//! Async mode.
//!
//! The following wiring is assumed:
//! - TEST IO PIN => GPIO2
//! - TX => GPIO17
//! - RX => GPIO16
//% CHIPS: esp32
//% FEATURES: embassy embassy-generic-timers esp-hal/unstable

#![no_std]
#![no_main]

use embassy_executor::Spawner;
use embassy_time::Timer;
use esp_backtrace as _;
use esp_hal::{
delay::Delay,
gpio::{Level, Output},
timer::timg::TimerGroup,
uart::{Config as UartConfig, DataBits, StopBits, Uart},
};

#[esp_hal_embassy::main]
async fn main(_spawner: Spawner) {
let peripherals = esp_hal::init(esp_hal::Config::default());
let timg0 = TimerGroup::new(peripherals.TIMG0);
esp_hal_embassy::init(timg0.timer0);

let uart_config = UartConfig::default()
.baudrate(19200)
.data_bits(DataBits::DataBits8)
.parity_none()
.stop_bits(StopBits::Stop1);

let mut uart = Uart::new(
peripherals.UART1,
uart_config,
peripherals.GPIO16, // RX
peripherals.GPIO17, // TX
)
.expect("Failed to initialize UART")
.into_async();

let delay = Delay::new();

// Used to toggle an output pin for comparing its timing with
// the TX line on an oscilloscope. It's also the LED pin.
let mut test_io_pin = Output::new(peripherals.GPIO2, Level::Low);

loop {
test_io_pin.toggle();
uart.send_break_async(19200).await; // 19200 bits at 19200bps = 1 second
test_io_pin.toggle();
Timer::after_millis(1000).await;
}
}

0 comments on commit 4698877

Please sign in to comment.