Clive One

Implementing Interrupt driven Stream UART Rx Handling on L4

Discussion created by Clive One on Jan 13, 2018
Latest reply on Apr 1, 2018 by avi_crak.videocrak

Here processing a continuous GPS stream via interrupt with no callbacks or multiple levels of abstraction. Complete lines are queued to a worker task/thread for parsing.

 

#define USART_GPS LPUART1
#define USART_GPS_IRQn LPUART1_IRQn
#define USART_GPS_IRQHandler LPUART1_IRQHandler


#ifdef USART_CR1_TXEIE_TXFNFIE // FIFO Support (L4R9)
#define USART_CR1_TXEIE   USART_CR1_TXEIE_TXFNFIE
#define USART_ISR_TXE     USART_ISR_TXE_TXFNF
#define USART_CR1_RXNEIE  USART_CR1_RXNEIE_RXFNEIE
#define USART_ISR_RXNE    USART_ISR_RXNE_RXFNE
#endif


#define LINEMAX 200 // Maximal allowed/expected line length

void USART_GPS_IRQHandler(void) // Sync and Queue NMEA Sentences
{
  static char rx_buffer[LINEMAX + 1];   // Local holding buffer to build line, w/NUL
  static int rx_index = 0;

  if (USART_GPS->ISR & USART_ISR_ORE) // Overrun Error
    USART_GPS->ICR = USART_ICR_ORECF;

  if (USART_GPS->ISR & USART_ISR_NE) // Noise Error
    USART_GPS->ICR = USART_ICR_NCF;

  if (USART_GPS->ISR & USART_ISR_FE) // Framing Error
    USART_GPS->ICR = USART_ICR_FECF;

  if (USART_GPS->ISR & USART_ISR_RXNE) // Received character?
  {
    char rx = (char)(USART_GPS->RDR & 0xFF);

    if ((rx == '\r') || (rx == '\n')) // Is this an end-of-line condition, either will suffice?
    {
        if (rx_index != 0) // Line has some content?
        {
            rx_buffer[rx_index++] = 0; // Add NUL if required down stream

            QueueBuffer(rx_buffer, rx_index); // Copy to queue from live dynamic receive buffer

            rx_index = 0; // Reset content pointer
        }
    }
    else
    {
        if ((rx == '$') || (rx_index == LINEMAX)) // If resync or overflows pull back to start
            rx_index = 0;

        rx_buffer[rx_index++] = rx; // Copy to buffer and increment
    }
  }
}

...

  HAL_NVIC_SetPriority(GPS_USART_IRQn, 1, 0);
  HAL_NVIC_EnableIRQ(GPS_USART_IRQn);

  USART_GPS->CR1 |= USART_CR1_RXNEIE; // Enable Interrupt

Outcomes