cancel
Showing results for 
Search instead for 
Did you mean: 

LPUART interrupt occur not immediately cause overrun with FreeRTOS tickless.

kein
Associate II

Hello everyone,

I'm using Board NUCLEO-U031R8 for testing now, and I started with cubeMX and initial component below:

  • System Clock configure to HSI (16MHz)
  • FreeRTOS with USE_TICKLESS_IDLE as 1 (built in functionality enabled), and auto generated two function PreSleepProcessing() / PostSleepProcessing().
  • LPTIM1 with 32kHz LSI and clock presclaer set to Div32, every timer count alomost 1ms, using for replace the sysTick while tickless idle.
  • LPUART1 with 16MHz HSI1, interrupt RXNE/WKUP/ERROR always enabled after system initial done.

The task is startup and print information and delay 1 second, then entering an endless loop that includes a 1-second running delay and a 4-second sleep delay, and everything works fine in 1 second running delay.

But when sending bytes in sleep, it would occur overrun error when received length > 2, so i toggle an output while interrupt occur. and i saw an weird interrupt while receiving bytes, the record here.

kein_0-1727778016161.png

To I modify tickless idle part, I disable sysTick and start LPTIM then go stop1 mode in PreSleepProcessing(), and  restore everything and call vTaskStepTick() in the end of PostSleepProcessing(), and commit out the vTaskStepTick() in vPortSuppressTicksAndSleep() of port.c

 

Task function:

void StartDefaultTask(void *argument) {
  // initial GPIO
  LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA);
  LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOB);
  LL_GPIO_SetPinMode(LED4_GPIO, LED4_PIN, LL_GPIO_MODE_OUTPUT);     // LED4 = PA5 = D13
  LL_GPIO_SetPinMode(OUT1_GPIO, OUT1_PIN, LL_GPIO_MODE_OUTPUT);     // OUT1 = PA8 = D7
  LL_GPIO_SetPinMode(OUT2_GPIO, OUT2_PIN, LL_GPIO_MODE_OUTPUT);     // OUT2 = PB5 = D4
  LL_GPIO_SetPinOutputType(LED4_GPIO, LED4_PIN, LL_GPIO_OUTPUT_PUSHPULL);
  LL_GPIO_SetPinOutputType(OUT1_GPIO, OUT1_PIN, LL_GPIO_OUTPUT_PUSHPULL);
  LL_GPIO_SetPinOutputType(OUT2_GPIO, OUT2_PIN, LL_GPIO_OUTPUT_PUSHPULL);

  LPUART_SendStr("BOOT\n");
  LL_mDelay(1000);
  LPUART_SendStr("Start!\n");
  /* Infinite loop */
  for(;;)
  {
    LL_GPIO_SetOutputPin(LED4_GPIO, LED4_PIN);
    LL_mDelay(1000);    // delay with no sleep

    LPUART_SendStr("SLEEP\n");
    LL_GPIO_ResetOutputPin(LED4_GPIO, LED4_PIN);
    osDelay(pdMS_TO_TICKS(4000));    // delay to entry sleep (tickless idle)
    LPUART_SendStr("WAKE\n");

    // print out if any UART error.
    if (_ParErrCnt > 0)      { LPUART_SendStr(",ParityErr");  LPUART_SendNum(_ParErrCnt, 10);      _ParErrCnt = 0; }
    if (_FrameErrCnt > 0)    { LPUART_SendStr(",FrameErr");   LPUART_SendNum(_FrameErrCnt, 10);    _FrameErrCnt = 0; }
    if (_NoiseErrCnt > 0)    { LPUART_SendStr(",NoiseErr");   LPUART_SendNum(_NoiseErrCnt, 10);    _NoiseErrCnt = 0; }
    if (_OverRunErrCnt > 0)  { LPUART_SendStr(",OverRunErr"); LPUART_SendNum(_OverRunErrCnt, 10);  _OverRunErrCnt = 0; }
  }

Tickless functions:

void PreSleepProcessing(uint32_t ulExpectedIdleTime) {
  LL_SYSTICK_DisableIT();
  LPTIM_Start(ulExpectedIdleTime);
  timeBeforeSleep = 0;

  LL_LPUART_EnableInStopMode(LPUART1);                      // Set   LPUART1->CR1.UESM
  
  // ----------------------------- Sleep ------------------------------
  LL_PWR_SetPowerMode(LL_PWR_MODE_STOP1);                   // Set   PWR->CR1.LPMS
  LL_LPM_EnableDeepSleep();                                 // Set   SCB->SCR
  __WFI();
  LL_LPM_EnableSleep();                                     // Clear SCB->SCR
  LL_LPUART_DisableInStopMode(LPUART1);                     // Clear LPUART1->CR1.UESM
  // ------------------------------------------------------------------
  // Wake-up 
}

void PostSleepProcessing(uint32_t ulExpectedIdleTime) {
  sleepTime = LL_LPTIM_GetCounter(LPTIM1) - timeBeforeSleep;

  LPTIM_Stop();
  LL_SYSTICK_EnableIT();                                    // HAL_ResumeTick();

  // NOTE: call vTaskStepTick() here, commit out the vTaskStepTick() in function vPortSetupTimerInterrupt() which in file port.c
  vTaskStepTick( sleepTime );
}

LPUART IRQHandler:

void USART3_LPUART1_IRQHandler(void)
{
  LL_GPIO_TogglePin(OUT1_GPIO, OUT1_PIN);

  if (LL_LPUART_IsActiveFlag_WKUP(LPUART1) && LL_LPUART_IsEnabledIT_WKUP(LPUART1)) {
    LL_LPUART_ClearFlag_WKUP(LPUART1);
  }

  // Check UART error and clear
  uint32_t uart_isr = LPUART1->ISR;
  if (uart_isr & 0x0F) {
    if(uart_isr & LL_LPUART_ISR_PE) {
      LPUART1->ICR = LL_LPUART_ICR_PECF;
      _ParErrCnt++;
    }
    if(uart_isr & LL_LPUART_ISR_FE) {
      LL_LPUART_RequestRxDataFlush(LPUART1);
      LPUART1->ICR = LL_LPUART_ICR_FECF;
      _FrameErrCnt++;
    }
    if(uart_isr & LL_LPUART_ISR_NE) {
      LL_LPUART_RequestRxDataFlush(LPUART1);
      LPUART1->ICR = LL_LPUART_ICR_NCF;
      _NoiseErrCnt++;
    }
    if(uart_isr & LL_LPUART_ISR_ORE) {
      LPUART1->ICR = LL_LPUART_ICR_ORECF;
      _OverRunErrCnt++;
    }
  }

  if (LL_LPUART_IsActiveFlag_RXNE_RXFNE(LPUART1)) {
    uint8_t ch = LL_LPUART_ReceiveData8(LPUART1);
    rxBuf[rxIdx++] = ch;
    if (ch == '\n') rxFlag = rxIdx;
  }

  LL_GPIO_TogglePin(OUT1_GPIO, OUT1_PIN);
}

 

The test project is upload if anyone needed.

If there are any mistakes or oversights, please correct me.

Regards

Kein.

0 REPLIES 0