Error in ASF Uart Interrupt Handler?

Go To Last Post
3 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am tracking down an issue where I lose occasional bytes received through the UART (SAMV70).  I am running at 115Kb. I am using RX interrupts and setting the UART to interrupt on each character since I have variable size packets.

 

I have registered a UART error callback, but the code is never hitting the UART Error callback, even though I am getting occasional framing errors.  (I have trapped them in the debugger)  I looked at the ASF _uart_interrupt_handler and it does not seem correct.

 

It appears that it will only call the error callback if the interrupts are disabled.  If they are enabled, it clears the error, reads the holding register but does not call the error callback or the done callback. Is this correct? I would think it should call the error callback without clearing the  errors, so the user can handle the error or at least know they occurred.

 

I added some comments to the ASF handler below:

static void _uart_interrupt_handler(struct _usart_async_device *device)
{
    ASSERT(device);
    void *hw = device->hw;
    // UART TX
    if (hri_uart_get_SR_TXRDY_bit(hw) && hri_uart_get_IMR_TXRDY_bit(hw)) {
        hri_uart_clear_IMR_TXRDY_bit(hw);
        device->usart_cb.tx_byte_sent(device);
    } else if (hri_uart_get_SR_TXEMPTY_bit(hw) && hri_uart_get_IMR_TXEMPTY_bit(hw)) {
        hri_uart_clear_IMR_TXEMPTY_bit(hw);
        device->usart_cb.tx_done_cb(device);
    } else if (hri_uart_get_SR_RXRDY_bit(hw) && hri_uart_get_IMR_RXRDY_bit(hw)) {                // If Rx Ready and RX RDY Interrupt enabled
        if (hri_uart_read_SR_reg(hw) & (UART_SR_OVRE | UART_SR_FRAME | UART_SR_PARE)) {   // If we have an RX error
            hri_uart_read_RHR_reg(hw);                                                                                      // Read the Rx Holding register
            hri_uart_write_CR_reg(hw, UART_CR_RSTSTA);                                                          // Reset error bits
            return;                                                                                                                     // Return with no callbacks
        }
        device->usart_cb.rx_done_cb(device, (uint8_t)hri_uart_read_RHR_RXCHR_bf(hw));         // If no error, call done callback
    } else if (hri_uart_read_SR_reg(hw) & (UART_SR_OVRE | UART_SR_FRAME | UART_SR_PARE)) {  // else if Rx Rda and Rx Int no enabled & Rx errors
        hri_uart_write_CR_reg(hw, UART_CR_RSTSTA);                                                              // Reset error bits
        device->usart_cb.error_cb(device);                                                                            // Call uart error callback
    }
}

 

Last Edited: Sat. Nov 21, 2020 - 10:11 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There are a couple of things wrong with that code.

 

  1. It really ought to handle Rx interrupts before Tx. The latter are usually not time critical.
  2. The hardware will always set RXRDY even in the case of an error, so assuming RXRDY is unmasked then that final error handling statement will never execute.

 

For what it's worth, I have a project which is capable of servicing USART Rx interrupts in software (no DMA) at rates approaching 1M baud with no errors or overruns, all while running a whole bunch of other stuff under FreeRTOS. This is on a SAMD5x, so 120 MHz Cortex-M4F. If that can do it, then the SAMV70's M7 at 300 MHz should be more than able to keep up at 115K baud. Either ASF is even more inefficient than I thought, or your application is spending a lot of time with interrupts masked.

 

Steve

Maverick Embedded Technologies Ltd. Home of Maven and wAVR.

Maven: WiFi ARM Cortex-M Debugger/Programmer

wAVR: WiFi AVR ISP/PDI/uPDI Programmer

https://www.maverick-embedded.co...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Scdoubleu,

 

Thanks for your reply. I agree that the V70  should easily handle 115 Kb communications.  USART Interrupts are only masked for a short time to copy buffers from the interrupt routine to the foreground routine, so I don’t think this is the problem.  ASF does seem to have some calls using the global __disable_irq() call.  I have not examined when and why it does this.

 

It is always possible for external noise to cause an occasional character drop.  And code should be written to handle these situations gracefully. However, I do not think that the ASF4 code interrupt handler handles UART errors well.