cancel
Showing results for 
Search instead for 
Did you mean: 

[STM32L031G6Ux] LPUART LL ISR Routine - defense code for prevent unknown error

YS.K
Associate III

As follows, LL UART interrupt code with ring buffer were compose.

0693W00000QMDhzQAH.png0693W00000QMDi4QAH.png0693W00000QMDi9QAH.png

< stm32l0xx_it.c >

uint8_t Uart1_recvData[64];
uint8_t Uart1_sendData[64];
 
volatile uint8_t Uart1_sendDataSize;
volatile uint16_t Uart1_sendPush;
volatile uint16_t Uart1_sendPop;
 
volatile uint8_t Uart1_recvDataSize;
volatile uint16_t Uart1_recvPush;
volatile uint16_t Uart1_recvPop;
 
void LPUART1_IRQHandler(void)
{
 /* USER CODE BEGIN LPUART1_IRQn 0 */
 
 /* USER CODE END LPUART1_IRQn 0 */
 
 /* USER CODE BEGIN LPUART1_IRQn 1 */
  uint32_t isrflags = READ_REG(LPUART1->ISR);
  uint8_t UartRDR = LL_USART_ReceiveData8(LPUART1);
 
  WRITE_REG(LPUART1->ICR, ((uint32_t)isrflags) & (USART_ICR_PECF | USART_ICR_FECF | USART_ICR_ORECF | USART_ICR_NCF | USART_ICR_RTOCF));
 
  if ((isrflags & USART_ISR_RXNE)) {
    if (Uart1_recvDataSize < (COUNTOF(Uart1_recvData)-1)) {
      if (0 == Uart1_recvDataSize) { Uart1_recvPop = Uart1_recvPush = (Uart1_recvPush % COUNTOF(Uart1_recvData)); }//fix error, problem about 1 hour with field work
 
      Uart1_recvData[Uart1_recvPush] = UartRDR;
      Uart1_recvPush = (Uart1_recvPush + 1) % COUNTOF(Uart1_recvData);
      Uart1_recvDataSize++;
    }
  }
 
  if ((isrflags & USART_ISR_TXE)) {
//  if (Uart1_sendDataSize) {
//      Uart1_sendDataSize--;
//      LL_USART_TransmitData8(LPUART1, Uart1_sendData[Uart1_sendPop]);
//      Uart1_sendPop = (Uart1_sendPop + 1) % COUNTOF(Uart1_sendData);
//    }
//    else {
//      ATOMIC_CLEAR_BIT(LPUART1->CR1, (USART_CR1_TXEIE | USART_CR1_TCIE));//Disable TXEIE and TCIE interrupts
//    }
  }
 /* USER CODE END LPUART1_IRQn 1 */
}

< main.c >

uint8_t UART1Send(uint8_t *a_pbuff, uint8_t a_len)
{
  uint32_t count;
  for (count = 0; count < a_len; count++) {
    Uart1_sendData[Uart1_sendPush] = a_pbuff[count];
    Uart1_sendPush = (Uart1_sendPush + 1) % COUNTOF(Uart1_sendData);
    Uart1_sendDataSize += 1;
  }
//  LL_USART_EnableIT_TXE(LPUART1);
  return 1;
}
 
int main(void)
{
 /* USER CODE BEGIN 1 */
...................................
 /* USER CODE BEGIN WHILE */
 while (1)
 {
  /* USER CODE END WHILE */
 
  /* USER CODE BEGIN 3 */
  if (Uart1_sendDataSize) {
    if (LL_USART_IsActiveFlag_TXE(LPUART1)) {//lpuart1 TX Send
      Uart1_sendDataSize--;
      LL_USART_TransmitData8(LPUART1, Uart1_sendData[Uart1_sendPop]);
      Uart1_sendPop = (Uart1_sendPop + 1) % COUNTOF(Uart1_sendData);
    }
  }
...................................
}

I don't know why, but in connection with a particular device, the ring buffer's head & tail index mismatch error was solved by adding the following if statement in the ISR function.

if (0 == Uart1_recvDataSize) { Uart1_recvPop = Uart1_recvPush = (Uart1_recvPush % COUNTOF(Uart1_recvData));

And the reason is unknown, but when the interrupt UART TX function was used using the TX function below, the first & second BYTEs were broken, so the TX function was moved to the main() function and resolved the data was broken.

// LL_USART_EnableIT_TXE(LPUART1);

I don't know if it was caused by another problem with my code,

If there is a user who can experience something similar to me,

I leave the above test results to help you.

4 REPLIES 4
S.Ma
Principal

I would use another sw fifo on the tx side, and capture fifo become empty or full to dynamically interrupt enable/disable the peripheral, the same way rts and cts do flow control outside.

I got no pb at 48 Mhz for 115200 bps using HC05 bluetooth dongle with teraterm and Bluetooth Electronics android app. No HAL as it is like a console type protocol.

YS.K
Associate III

The example I posted above seems to be a little different from your problem.

Using the LL UART interrupt TX with the STM32L031+Example above, the operation works fine about 0.5~1 hour. However, RX ring buffer index mismatch & TX data is broken after some times, so add "safe if" & the TX routine has been moved to the interrupt -> main() function.

Piranha
Chief II

This is not some "unknown error". Your code is just full of race conditions. And no - you cannot "fix" it the way you tried...

You should learn about race conditions and interrupt-safe code. When you've understood that, you can additionally learn about lock-free programming, which is the best solution for this type of tasks.

YS.K
Associate III

I wonder how to program the UART interrupt service routine to prevent race condition.

All variables used by ISR are declared with volatile.

Is there any other better way to do volatile declaration to prevent race conditions ?

For example, would ATOMIC_XX macros help in ISR routine ?

Thank you.​