2
votes

I am developing uart communication on STMicroelectronics NUCLEO-G474RE Board(stm32G474RETX MCU, 64pins) using MDK-v5, but run into a perplexing problem these several days, make no progress on it and have to reach out to seek some help. If anyone could give me a right way to go, it would be appreciated greatly.

Code is not complicated, I use cubeMX to initialize the code base with usart2 configured, and use two threads based on cmsis v2 api for receiving occassinally and transmiting periodically(in 2 seconds).

The auto-generated usart2 init code

static void MX_USART2_UART_Init(void)
{

  /* USER CODE BEGIN USART2_Init 0 */

  /* USER CODE END USART2_Init 0 */

  /* USER CODE BEGIN USART2_Init 1 */

  /* USER CODE END USART2_Init 1 */
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_RTS;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  huart2.Init.ClockPrescaler = UART_PRESCALER_DIV1;
  huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_SetTxFifoThreshold(&huart2, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_SetRxFifoThreshold(&huart2, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_DisableFifoMode(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART2_Init 2 */

  /* USER CODE END USART2_Init 2 */

}

Interrupt call back code

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
    printf("Interrupt error occured(0x%x)!!!\r\n", huart->ErrorCode);
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef* huart)
{
    UNUSED(huart);
    if(huart == &huart2 || huart == &huart3){
        uint8_t aEnterLine[] = "\r\n";
        //HAL_UART_Transmit(huart, aEnterLine, sizeof(aEnterLine), 0xFFFF);
        //HAL_UART_Transmit(huart, gRxBuffer, 11, 0xFFFF);
        //HAL_UART_Transmit(huart, aEnterLine, sizeof(aEnterLine), 0xFFFF);
        //printf("%s\r\n", gRxBuffer);
        if(g_cmdExecuting == 0)
            osEventFlagsSet(evt_id, 0x00000001U);
    }else if(huart == &huart1){

    }else{

    }

    HAL_UART_Receive_IT(huart, (unsigned char*)gRxBuffer, 11);
}

int8_t app_usart_transmit(uint8_t* buf, uint8_t len)
{

    return 0;
}

int8_t app_usart_init(UART_HandleTypeDef* huart)
{
    if(huart == NULL)
        return -1;

    if(huart == &huart2 || huart == &huart3){
        uint8_t aTxStartMessage[] = "\r\n****UART-Hyperterminal commmunication based on IT****"
                                    "\r\nEnter 10 characters using keyboard: \r\n";

        HAL_UART_Transmit(huart, aTxStartMessage, sizeof(aTxStartMessage), 0xFFFF);                         
    }

    clear_rx_buffer();
    HAL_UART_Receive_IT(huart, (uint8_t*)gRxBuffer, 11);
    return 0;
}

rx & tx worker code

extern osMutexId_t myMutex01Handle;
extern osEventFlagsId_t evt_id;
extern osEventFlagsId_t evt_id1;
osTimerId_t timer_id;

static osThreadId gTask1Handle;
static const osThreadAttr_t gTask1Attrbutes = {
    .name = "Task1",
    .priority = (osPriority_t) osPriorityAboveNormal,
    .stack_size = 512
};

static osThreadId gTask2Handle;
static const osThreadAttr_t gTask2Attrbutes = {
    .name = "Task2",
    .priority = (osPriority_t) osPriorityNormal,
    .stack_size = 512
};

uint8_t g_cmdExecuting = 0;
uint8_t g_SemExec = 0;
uint32_t timer_cnt;

void update_stat_timer(void* argument)
{
    timer_cnt++;
    //osMutexAcquire(myMutex01Handle, osWaitForever);
    printf("update_stat_timer executes %u times, ====++++====++++\r\n", timer_cnt);
    //osMutexRelease(myMutex01Handle);
}


void update_stat_task_run(void* argument)
{
    uint32_t count;
    for(;;){
        osDelay(2000);
        count++;
        osMutexAcquire(myMutex01Handle, osWaitForever);
        printf("update_stat_task_run executes %d times, ====++++====++++\r\n", count);
        osMutexRelease(myMutex01Handle);
    }
}

void exec_cmd_task_run(void* argument)
{
    uint32_t flags;

    for(;;){
        flags = osEventFlagsWait(evt_id, 0x00000001U, osFlagsWaitAny, osWaitForever);
        g_cmdExecuting = 1;
        osMutexAcquire(myMutex01Handle, osWaitForever);
        osDelay(1000);
        printf("exec_cmd_task Print\r\n");
        osMutexRelease(myMutex01Handle);
        g_cmdExecuting = 0;
    }
}

int8_t app_task_init()
{
    osStatus_t status;

    gTask1Handle = osThreadNew(exec_cmd_task_run, NULL, &gTask1Attrbutes);
    gTask2Handle = osThreadNew(update_stat_task_run, NULL, &gTask2Attrbutes);

    //uint32_t exec = 1;
    //timer_id = osTimerNew(update_stat_timer, osTimerPeriodic, &exec, NULL);
    //if(status != osOK){
        //;
    //}
    //osTimerStart(timer_id, 2000U);
    return 0;
}

My Question: It could receive and transmit msg at very begining, but after receiving three or four hundred times, it couldn't receive the msg anymore while the transmitting is ok, and I also use the timer api to replace the transmitting thread, the result is the same, it couldn't receive any msg after hundreds times. the testing result pic

1
There are bugs related this :community.st.com/s/question/0D50X00009XkX6m/…? Beside this the behavior indicates some kind of memory overflow . Do you have the possibility to debug the chip via programmer (JTAG/SWD) ?ralf htp
Thank you very much @ralfhtp, really appreciate your answer. For memory overflow, I don't have much experience on it, I have the programmer JTAG/SWD and could use that to debug my code, could you give me some suggestions on how to find it out? Thanks in advance.LeoYan

1 Answers

0
votes

You can perform the HAL status and error checks using uint32_t HAL_UART_GetError(UART_HandleTypeDef * huart) and HAL_UART_StateTypeDef HAL_UART_GetState(UART_HandleTypeDef *huart) (http://www.disca.upv.es/aperles/arm_cortex_m3/llibre/st/STM32F439xx_User_Manual/group__uart__exported__functions__group4.html)

The source code for HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size) and HAL_UART_RxCplt_Callback() is in https://github.com/ARMmbed/mbed-hal-st-stm32cubef4/blob/master/source/stm32f4xx_hal_uart.c

HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
  uint32_t tmp = 0;

  tmp = huart->State;  
  if((tmp == HAL_UART_STATE_READY) || (tmp == HAL_UART_STATE_BUSY_TX))
  {
    if((pData == HAL_NULL ) || (Size == 0)) 
    {
      return HAL_ERROR;
    }

    /* Process Locked */
    __HAL_LOCK(huart);

    huart->pRxBuffPtr = pData;
    huart->RxXferSize = Size;
    huart->RxXferCount = Size;

    huart->ErrorCode = HAL_UART_ERROR_NONE;
    /* Check if a transmit process is ongoing or not */
    if(huart->State == HAL_UART_STATE_BUSY_TX) 
    {
      huart->State = HAL_UART_STATE_BUSY_TX_RX;
    }
    else
    {
      huart->State = HAL_UART_STATE_BUSY_RX;
    }

    /* Enable the UART Parity Error Interrupt */
    __HAL_UART_ENABLE_IT(huart, UART_IT_PE);

    /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
    __HAL_UART_ENABLE_IT(huart, UART_IT_ERR);

    /* Process Unlocked */
    __HAL_UNLOCK(huart);

    /* Enable the UART Data Register not empty Interrupt */
    __HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);

    return HAL_OK;
  }
  else
  {
    return HAL_BUSY; 
  }
}

Note that the HAL mutually uses locking mechanisms (__HAL_LOCK, code line 107 in https://github.com/ARMmbed/mbed-os/blob/master/targets/TARGET_STM/TARGET_STM32L1/device/stm32l1xx_hal_def.h)

To get the UART status use i.e.

HAL_UART_StateTypeDef UARTStatus;
UARTStatus = HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

The definition of HAL_UART_StateTypeDef is

typedef enum
{
  HAL_UART_STATE_RESET             = 0x00,    /*!< Peripheral is not yet Initialized                  */
  HAL_UART_STATE_READY             = 0x01,    /*!< Peripheral Initialized and ready for use           */
  HAL_UART_STATE_BUSY              = 0x02,    /*!< an internal process is ongoing                     */   
  HAL_UART_STATE_BUSY_TX           = 0x12,    /*!< Data Transmission process is ongoing               */ 
  HAL_UART_STATE_BUSY_RX           = 0x22,    /*!< Data Reception process is ongoing                  */
  HAL_UART_STATE_BUSY_TX_RX        = 0x32,    /*!< Data Transmission and Reception process is ongoing */  
  HAL_UART_STATE_TIMEOUT           = 0x03,    /*!< Timeout state                                      */
  HAL_UART_STATE_ERROR             = 0x04     /*!< Error                                              */      
}HAL_UART_StateTypeDef;

(https://github.com/synthetos/Motate/blob/master/MotateProject/motate/cmsis/TARGET_STM/TARGET_DISCO_F407VG/stm32f4xx_hal_uart.h code line 97)

The definition of HAL_StatusTypeDef (general HAL status) is

typedef enum 
{
  HAL_OK       = 0x00,
  HAL_ERROR    = 0x01,
  HAL_BUSY     = 0x02,
  HAL_TIMEOUT  = 0x03
} HAL_StatusTypeDef;

You can print the HAL status (i.e. with UART transmit or SWO ITM_SendChar((*ptr++));, see https://ralimtek.com/stm32_debugging/ )

The HAL has its own reference manual, the HAL status is described in the reference manual https://www.st.com/content/ccc/resource/technical/document/user_manual/2f/71/ba/b8/75/54/47/cf/DM00105879.pdf/files/DM00105879.pdf/jcr:content/translations/en.DM00105879.pdf on page 54 in chapter 2.9 HAL common resources.

Debugging techniques are described in https://www.st.com/content/ccc/resource/technical/document/application_note/group0/3d/a5/0e/30/76/51/45/58/DM00354244/files/DM00354244.pdf/jcr:content/translations/en.DM00354244.pdf, also for your programming adapter, that you can directly integrate in CubeMX (i use Atollic with integrated CubeMX because Atollic is based on Eclipse IDE and is almost identical to use)

Another debugging tutorial is https://ardupilot.org/dev/docs/debugging-with-gdb-on-stm32.html (if you are on linux).

This could also be a race condition either of the HAL or the OS. The problem that i have is that you do not post your full code, especially not concerning your OS and this is possibly critical here

So maybe first check the HAL status and then focus on the OS part (race conditions, buffer, stack or heap overflow, ... https://www.st.com/content/ccc/resource/technical/document/user_manual/2d/60/ff/15/8c/c9/43/77/DM00105262.pdf/files/DM00105262.pdf/jcr:content/translations/en.DM00105262.pdf)

Stack overflows are always critical on embedded systems so here is links https://barrgroup.com/embedded-systems/how-to/prevent-detect-stack-overflow , https://www.iar.com/support/resources/articles/detecting-and-avoiding-stack-overflow-in-embedded-systems/

Also see Uart dma receive interrupt stops receiving data after several minutes and UART receive interrupt stops triggering after several hours of successful receive

Many developers avoid using the HAL because it is a bit buggy and not very transparent, i personally would also not use it when i want full control over the system behavior