Hello Nordic team,
Environment:
- SDK 3.1.0
- nRF54L15
- UART / RS-232
I am seeing different UART TX timing depending on whether I transmit from inside the UART RX callback vs using a k_work handler.
On our nRF‑based device at 9600 baud, each byte correctly takes ~1.04 ms.
However, the gap between bytes (idle time between stop bit of one byte and start bit of the next) changes drastically depending on context:
1. UART RX callback → UART TX
If we call our transmit function directly inside the UART RX callback (or a parser function invoked from it), the inter‑byte gap is only ~53 µs.
2. k_work_delayable handler → UART TX
If we schedule the exact same transmit function using k_work_schedule(), the inter‑byte gap increases to ~313 µs, and the target device (RS‑232 peer) accepts the frame reliably.
Nothing else changes; same bytes, same baud rate, same framing.
This difference in inter‑byte spacing is causing a downstream RS‑232 device (non‑Nordic) to fail to parse frames correctly unless TX happens from a workqueue instead of inside the RX callback.
I will attach logic analyzer screenshots showing both cases.
Questions:
- Is it expected that UART TX behaves differently when called inside the RX callback vs from a workqueue?
- Is there a known restriction that UART TX should not be triggered directly inside the RX callback?
Any guidance or clarification would be appreciated. I will provide LA captures and source snippets in the attachments. Thank you.// This psuedo code is placed in the same location within an UART RX callback.
// My device recieves a UART message then transmits a UART acknoweldgement.
// Non-working code
void ProcessUartRx()
{
SendAck(message->header.message_id);
}
// Working code
void delayed_ack_handler(struct k_work *work);
static uint8_t g_pending_ack_msg_id;
K_WORK_DELAYABLE_DEFINE(g_delayed_ack_work, delayed_ack_handler);
void delayed_ack_handler(struct k_work *work)
{
SendAck(g_pending_ack_msg_id);
}
void ProcessUartRx()
{
_pending_ack_msg_id = message->header.message_id;
k_work_schedule(&g_delayed_ack_work, K_MSEC(0));
}
Saleae Logic Analyzer captures
failed-uart.salworking-uart.sal
Screenshots

