-
Notifications
You must be signed in to change notification settings - Fork 227
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: uart break detection interrupt #2858
base: main
Are you sure you want to change the base?
Conversation
Opened discussion on interrupt handlers in general to better inform the design of this feature: |
Usage with UART Interrupt HandlerAdded an example to test my implementation, it works well and handles some consistent load. static SERIAL: Mutex<RefCell<Option<Uart<Blocking>>>> = Mutex::new(RefCell::new(None));
#[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)
.rx_fifo_full_threshold(1); // interrupt every time a byte is received
let mut uart = Uart::new(
peripherals.UART1,
uart_config,
peripherals.GPIO16, // RX
peripherals.GPIO17, // TX
)
.expect("Failed to initialize UART");
uart.set_interrupt_handler(handler);
critical_section::with(|cs| {
uart.clear_interrupts(UartInterrupt::RxBreakDetected | UartInterrupt::RxFifoFull);
uart.listen(UartInterrupt::RxBreakDetected | UartInterrupt::RxFifoFull);
SERIAL.borrow_ref_mut(cs).replace(uart);
});
loop {}
}
#[handler]
#[ram]
fn handler() {
critical_section::with(|cs| {
let mut serial = SERIAL.borrow_ref_mut(cs);
let serial = serial.as_mut().unwrap();
if serial.interrupts().contains(UartInterrupt::RxBreakDetected) {
esp_println::print!("\nBREAK");
}
if serial.interrupts().contains(UartInterrupt::RxFifoFull) {
esp_println::print!(" {:02X}", serial.read_byte().expect("Read byte failed"));
}
serial.clear_interrupts(UartInterrupt::RxBreakDetected | UartInterrupt::RxFifoFull);
});
} |
Usage without HandlerAlso added some simple examples for using break detection without handlers: Blocking#[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)
.rx_fifo_full_threshold(1); // interrupt every time a byte is received
let mut uart = Uart::new(
peripherals.UART1,
uart_config,
peripherals.GPIO16, // RX
peripherals.GPIO17, // TX
)
.expect("Failed to initialize UART");
loop {
uart.wait_for_break();
esp_println::print!("\nBREAK");
while let Ok(byte) = uart.read_byte() {
esp_println::print!(" {:02X}", byte);
}
}
} Async#[esp_hal_embassy::main]
async fn main(_spawner: Spawner) {
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)
.rx_fifo_full_threshold(1); // interrupt every time a byte is received
let mut uart = Uart::new(
peripherals.UART1,
uart_config,
peripherals.GPIO16, // RX
peripherals.GPIO17, // TX
)
.expect("Failed to initialize UART")
.into_async();
loop {
uart.wait_for_break_async().await;
esp_println::print!("\nBREAK");
let mut buf = [0u8; 11];
let len = uart.read_async(&mut buf).await.unwrap();
for byte in buf.iter().take(len) {
esp_println::print!(" {:02X}", byte);
}
}
} ... these both work for me. |
My output for all three examples looks like:
Works like a charm - for a test case that's not repeatable (you need to send yourself data and breaks with another tool or device). Maybe we can add the |
Added a HIL test for (They will fail on the 3sec test timeout until we add a break or simulated break) |
I suppose we should get the send break PR merged before this one, so that the HIL tests succeed. |
IMHO |
I suspect most will use the interrupt handler anyways, not the wait functions |
I think that for the context of this PR it doesn't really matter what most users will use. I'm just saying this shouldn't be part of the initially stable API. Other than that, I don't have objections to include this unstably until we either accept that this is the best solution, or we find something better. An unstable solution is better than no solution after all :) |
Thank you for your contribution!
We appreciate the time and effort you've put into this pull request.
To help us review it efficiently, please ensure you've gone through the following checklist:
Submission Checklist 📝
cargo xtask fmt-packages
command to ensure that all changed code is formatted correctly.CHANGELOG.md
in the proper section.Extra:
Pull Request Details 📖
Description
Adding interrupt-based detection of UART break (closes #2753). Break condition is met when the receiver detects a NULL character (i.e. logic 0 for one NULL character transmission) after stop bits (register:
UART_BRK_DET_INT
).Testing
Ongoing