cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L0xx UART can't wakeup MCU after RX line was in low level during stop mode

YohannDrc
Associate III

Hi,

I am using a custom board integrating a STM32L071kzt6 MCU and have an issue to wakeup the MCU with uart start bit detection if the MCU uart rx line was no more pullup by the device with which the MCU communicates (A FT230XS USB to RX bridge).

It is the case when the USB which powered the FT230XS chip is disconnected.
When the USB is then reconnected, the FT230XS chip re pull-up the MCU uart rx line as expected, but communication is no more possible.
If the UART RX pin is internally pulled up, the problem disappear as the RX line does't get low when USB is disconnected, but I don't know if it is a relevant solution

In fact the MCU wakeup with UART start bit detection when USB is disconnected the first time, then a frame error appears, and then the MCU re-enter stop mode.
But it is not possible to wakeup again the MCU with UART start bit detection.
(It is still possible with other way as EXTI, or I2C on match address detection for exemple)
There is no problem if the MCU is in RUN mode, so it is really a problem with how I handle STOP mode

Here are the main code :

 

 

/* USER CODE BEGIN WHILE */

  printf("Enter main  SandboxMockupStopMode\n\r");

  // LED (Green for mockup V1, RED for mockup V2
  HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_SET);

  // ##### UART #####

  HAL_UARTEx_ReceiveToIdle_IT(_huartUsb, rxBuffer, RX_BUFFER_SIZE);

  // Enable the UART peripheral to wakeup the MCU
  configureUartStopMode();

  printf("Enter Stop mode in 1 second\n\r");
  HAL_Delay(1000);

  enableStopMode = 1;

  while (1)
  {
      if (uartMessageCompleted == 1)
      {
          // Reset indication
          uartMessageCompleted = 0;

          printf("UART buffer : ");
          printf((char*)rxBuffer);
          printf("\r\n");

          printf("uartWakeupCount : %lu\r\n", uartWakeupCount);
          printf("uartRxEventCount : %lu\r\n", uartRxEventCount);
          printf("uartErrorCount : %lu\r\n", uartErrorCount);
          printf("uartErrorCode : %lu\r\n", uartErrorCode);
          printf("uartAbortCount : %lu\r\n", uartAbortCount);
          printf("uartAbortTransmitCallbackCount : %lu\r\n", uartAbortTransmitCallbackCount);
          printf("uartAbortReceiveCount : %lu\r\n", uartAbortReceiveCount);
          printf("statusAbortReceive : %d\r\n", statusAbortReceive);
          printf("statusActivateReceive : %d\r\n", statusActivateReceive);
      }

      if (enableStopMode == 1 && usbUartReceiving == 0 && uartMessageCompleted == 0)
      {
          enterStopMode();

          leaveStopMode();
      }

    /* USER CODE END WHILE */
void configureUartStopMode()
{
    // Set the wake-up event: specify wake-up on start-bit detection
    UART_WakeUpTypeDef wakeUpSelection;
    wakeUpSelection.WakeUpEvent = UART_WAKEUP_ON_STARTBIT;
    HAL_UARTEx_StopModeWakeUpSourceConfig(_huartUsb, wakeUpSelection);

    // Enable the UART2 Wake UP from stop mode Interrupt
    __HAL_UART_ENABLE_IT(_huartUsb, UART_IT_WUF);

    // Enable MCU wake-up by UART2
    HAL_UARTEx_EnableStopMode(_huartUsb);
}

void enterStopMode()
{
    HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_RESET); // LED (Green for mockup V1, RED for mockup V2)
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET); // For debug only

    /* Clear Wakeup interrupt flag if needed */
    if (__HAL_UART_GET_FLAG(_huartUsb, USART_ISR_WUF) != RESET)
    {
        __HAL_UART_CLEAR_FLAG(_huartUsb, USART_ISR_WUF);
    }

    __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);

    // Suspend Tick increment to prevent wakeup by Systick interrupt.
    // Otherwise the Systick interrupt will wake up the device within 1ms (HAL time base)
    HAL_SuspendTick();

    // Enter Stop Mode
    HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
}

void leaveStopMode()
{
    HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_SET); // LED (Green for mockup V1, RED for mockup V2)
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET); // For debug only

    // Set system clock back to ... oscillator because when exiting Stop mode by using an interrupt or a wake up event,
    // ... oscillator is selected as system clock
    SystemClock_Config ();
    //Resume Tick interrupt if disabled prior to Stop mode entry
    HAL_ResumeTick();
}

 

 

And here how callbacks are handled:

 

 

void HAL_UARTEx_WakeupCallback(UART_HandleTypeDef *huart)
{
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET); // For debug only

    uartWakeupCount++;

    usbUartReceiving = 1; // To prevent the mcu to enter stop mode

    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET); // For debug only
}

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET); // For debug only

    uartRxEventCount++;

    if(huart->Instance == _instanceUsartUsb)
    {
        //printf((char*)rxBuffer);

        uartMessageCompleted = 1;   // Indicate uart message can be treated
        usbUartReceiving = 0;       // Accept the mcu to enter stop mode

        HAL_UARTEx_ReceiveToIdle_IT(_huartUsb, rxBuffer, RX_BUFFER_SIZE);
    }

    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET); // For debug only
}

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_SET); // For debug only

    uartErrorCount++;

    uartErrorCode = huart->ErrorCode;

    // Noise error
    if (uartErrorCode & HAL_UART_ERROR_NE)
    {
        // Clear noise error flag
        __HAL_UART_CLEAR_FLAG(huart, UART_FLAG_NE);
    }

    // Parity error
    if (uartErrorCode & HAL_UART_ERROR_PE)
    {
        // Clear frame error flag
        __HAL_UART_CLEAR_FLAG(huart, UART_FLAG_PE);
    }

    // Frame error
    if (uartErrorCode & HAL_UART_ERROR_FE)
    {
        // Clear frame error flag
        __HAL_UART_CLEAR_FLAG(huart, UART_FLAG_FE);
    }

    // Overrun error
    if (uartErrorCode & HAL_UART_ERROR_ORE)
    {
        // Clear overrun flag
        __HAL_UART_CLEAR_FLAG(huart, UART_FLAG_ORE);
        __HAL_UART_FLUSH_DRREGISTER(huart); //flush data
    }

    usbUartReceiving = 0;       // Accept the mcu to enter stop mode

    // Restart Uart RX
    statusAbortReceive = HAL_UART_AbortReceive_IT(_huartUsb);
    statusActivateReceive = HAL_UARTEx_ReceiveToIdle_IT(_huartUsb, rxBuffer, RX_BUFFER_SIZE);

    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET); // For debug only
}

void HAL_UART_AbortCpltCallback(UART_HandleTypeDef *huart)
{
    uartAbortCount++;
}

void HAL_UART_AbortTransmitCpltCallback(UART_HandleTypeDef *huart)
{
    uartAbortTransmitCallbackCount++;
}

void HAL_UART_AbortReceiveCpltCallback(UART_HandleTypeDef *huart)
{
    uartAbortReceiveCount++;
}

 

 

 

And below captures show when callback functions are called and MCU UART RX and TX line state:

Disconnect and reconnect USB.png

 

 

 

Disconnect USB.png

  

 

 

 

5 REPLIES 5
PGump.1
Senior III

I'm not 100% sure, but I think I remember something about that in the Errata docs on that device. Have a look there.

Kind regards
Pedro

AI = Artificial Intelligence, NI = No Intelligence, RI = Real Intelligence.

Hi Pedro,

Thanks for the advice, I will look at it and return to you when done.

Kind regards,
Yohann

I read the STM32L07xxx/L08xxx device errata documentation.
There was indeed issues with wakeup from stop mode with UART on MCU revision A and B.
However the issue disappeared on current revision (1, P, Q, Z) of the MCU. The MCU I used is rev Z, so there is normally no problem with that.

Only 2 things I can think of are:

1) The UART status is not being cleared correctly when an error (PE, FE...).

2) The UART does not start correctly with a break character...

Kind regards
Pedro

AI = Artificial Intelligence, NI = No Intelligence, RI = Real Intelligence.

Thank you Pedro for your suggestions.

For now I will just pullup the MCU uart RX pin to avoid this behaviour.

I will later go deeper in your ideas.