Troubleshooting KEA128 UART2 RDRF Interrupt Timing

Claire Rousseau5 min read
Other ManufacturerSerial CommunicationTroubleshooting
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

The receive callback runs, but UART2_S1[RDRF] reads 0 until UART_GetChar() or a polling loop is used. Do not wait for RDRF inside the interrupt. If UART2_C2[RIE] caused the interrupt, RDRF was already set when the request was generated. A zero reading means the handler serviced a different or stale request, an earlier read consumed the receive condition, or the observation method changed the peripheral state.

Interrupt-entry status capture

  1. Place the first breakpoint at the entry of UART2_IRQHandler(), before any driver helper, callback, logging function, or receive-data access.
  2. Read UART2_S1[RDRF] once through an ordinary volatile CPU access. Do not keep a live peripheral-register window open if it reads the receive data register automatically.
  3. Capture the complete UART status and interrupt-enable state at the same point. Confirm that UART2_C2[RIE] is enabled and identify every other enabled UART interrupt source.
  4. Do not move on until the branch is clear: an entry snapshot with RDRF set points to consumption inside the driver path; a snapshot with it clear points to a stale pending request, another interrupt source, or intrusive debugging.
Entry reading Meaning Next check
RDRF = 1 The receiver completed a character and asserted its data-ready condition. Trace every status and data-register access before UartManager_Interrupt().
RDRF = 0 The current callback cannot be attributed to a still-active receive-data-ready condition. Check pending state, other enabled sources, and debugger register reads.
Changes only while halted The debugger or halt interval is affecting the observation. Repeat with memory logging and no peripheral-register window.

Driver callback access path

UART_SetCallback(TERMINAL_UART_PORT, UartManager_Interrupt) places a driver dispatch layer between the hardware vector and the application callback. The callback is therefore not automatically the first code to inspect the peripheral. Review UART2_IRQHandler() and every function it calls before invoking UartManager_Interrupt().

  1. Locate all calls to UART_IsRxBuffFull(), UART_GetChar(), and UART_ReadDataReg() in the vector and dispatch path.
  2. Confirm that no path reads the receive data before the callback. UART receive flags commonly use an ordered status-read/data-read clearing sequence. A helper that completes that sequence can make a later test report RDRF = 0.
  3. Confirm that UART_IsRxBuffFull() reads the UART instance passed to it. For this installation, that instance must resolve to UART2.
  4. Confirm that the status register is accessed as volatile hardware state. A cached software value is not a valid replacement for the current peripheral status.

The fact that UART_GetChar() returns the character does not prove that the original interrupt arrived early. A blocking receive helper may poll until data becomes ready, masking the actual interrupt source or an access-order defect. That behavior makes it unsuitable as the normal interrupt-service operation.

Pending-request and source checks

A receiver-data interrupt cannot legitimately vector ahead of its own data-ready condition. When the first CPU status snapshot is zero, identify what actually caused entry.

  1. Disable UART receive interrupts while initializing the UART, callback, software FIFO indices, and interrupt controller state.
  2. Clear any pending interrupt-controller request for the UART after configuration and before enabling UART2_C2[RIE].
  3. Read and classify pre-existing UART status. If unread data exists, either transfer it deliberately into the software FIFO or discard it using the documented status/data read order.
  4. Enable the receiver and then UART2_C2[RIE] only after the handler and FIFO are ready.
  5. If the handler still enters with RDRF = 0, temporarily disable every UART interrupt source except the receive-buffer-full source. Re-enable sources one at a time after the receive path passes verification.

Also check whether UART2_IRQHandler() is shared by multiple UART conditions. A correct handler must test each enabled source and service only the active condition. Calling the receive callback unconditionally on every UART interrupt creates exactly the observed symptom.

Receiver timing and baud configuration

The receiver samples a serial frame from the configured clock and baud divisor. It sets UART2_S1[RDRF] only after a complete character has been assembled and transferred to the receive data register. The interrupt controller then recognizes the enabled request and vectors to UART2_IRQHandler(). Interrupt latency occurs after the flag is set; it does not require software to wait for the flag afterward.

The reported configuration uses a 20 MHz bus clock and a numerical baud-rate setting of 115200 bps. The source comment stating “115200kbps” has incorrect units. Verify that BUS_CLK_FREQ evaluates to 20000000 and that UART_BIT_BAUDRATE evaluates to 115200. Then calculate the baud divisor using the MCU reference manual and compare the resulting actual baud rate with the terminal configuration. A baud mismatch normally produces framing or character errors; it does not justify polling for RDRF after an RDRF-generated interrupt.

Nonblocking receive-service procedure

  1. At vector entry, capture the UART status once.
  2. If the captured status shows RDRF, read exactly one character with UART_ReadDataReg(TERMINAL_UART_PORT). This both obtains the byte and completes the receive-condition service sequence.
  3. Write the byte into the software FIFO only if space is available. Advance the producer index after storing the byte so foreground code never observes an index pointing to unwritten data.
  4. If the FIFO is full, record an overflow condition and apply the bootloader's defined discard or flow-control policy. Never spin in the ISR waiting for FIFO space.
  5. Service any other captured UART conditions through their own branches. Do not call the receive-data path when the captured RDRF bit was clear.
  6. Exit immediately. Foreground bootloader code should parse or process queued bytes outside the interrupt context.

Remove while(!UART_IsRxBuffFull(TERMINAL_UART_PORT)); from the final handler. An unbounded polling loop can lock the processor if the entry was caused by another source, a stale pending request, or a condition already cleared by the driver.

Verification sequence

  1. Run without breakpoints or live peripheral-register views and transmit one byte from the terminal at 115200 bps.
  2. Record an entry counter, the captured RDRF state, and the received byte in RAM. Confirm one receive service for the transmitted byte.
  3. Transmit a multi-byte burst and confirm byte order, FIFO producer/consumer index behavior, and absence of FIFO overflow.
  4. Repeat after a reset with the terminal already connected. Confirm that initialization does not generate a callback with RDRF = 0.
  5. Re-enable any additional UART interrupt sources one at a time and repeat the single-byte and burst tests.

FAQ

How do I know whether RDRF caused the KEA128 UART2 interrupt?

Capture UART2_S1[RDRF] as the first CPU operation in UART2_IRQHandler(). If it is clear, inspect pending controller state and every other enabled UART source before entering the receive callback.

How do I clear UART2 RDRF correctly?

Follow the MCU-defined status-read followed by receive-data-read sequence. In this driver path, read the byte once with UART_ReadDataReg(TERMINAL_UART_PORT) after the captured status reports RDRF.

How do I stop UART_GetChar from blocking inside the ISR?

Replace the blocking helper with a conditional data-register read based on the entry status snapshot. If RDRF is clear, classify the actual interrupt source and exit instead of polling.

How do I configure the KEA128 UART2 baud-rate inputs?

Set the UART clock input to the reported 20 MHz bus clock and the baud-rate value to 115200 bps. Verify that BUS_CLK_FREQ is 20000000 and UART_BIT_BAUDRATE is 115200 before checking the calculated divisor.

How do I verify the UART2 software FIFO fix?

Transmit a multi-byte burst at 115200 bps with no breakpoints, then confirm the RAM log contains the same bytes in order, one data-register read occurred per received byte, and the FIFO reports no overflow.

Back to blog