Почему stm32nucleo board uart не может получать сообщения почти три или четыреста раз, используя HAL_UART_Receive_IT - PullRequest
2 голосов
/ 12 февраля 2020

Я занимаюсь разработкой связи Uart на плате STMicroelectronics NUCLEO-G474RE (микроконтроллер stm32G474RETX, 64 контакта) с использованием MDK-v5, но в эти несколько дней я сталкиваюсь с недоумением, не добиваясь прогресса и должен обратиться за помощью. Если бы кто-нибудь мог дать мне правильный путь к go, он был бы очень признателен.

Код не сложен, я использую cubeMX для инициализации базы кода с настроенным usart2 и использую два потока на основе cmsis v2 API для приема иногда и передачи периодически (через 2 секунды).

Сгенерированный автоматически код инициализации usart2

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 */

}

Код обратного вызова прерывания

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

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;
}

Мой вопрос: Он мог принимать и передавать сообщения в самом начале, но после получения три или четыреста раз, он не мог получить сообщение больше, пока передача в порядке, и я также использую таймер api для замены потока передачи, результат тот же, он не мог получить сообщение через сотни раз. результат тестирования пи c

1 Ответ

0 голосов
/ 15 февраля 2020

Вы можете выполнить проверки состояния и ошибок HAL, используя uint32_t HAL_UART_GetError(UART_HandleTypeDef * huart) и 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)

Исходный код для HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size) и HAL_UART_RxCplt_Callback() находится в 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; 
  }
}

Обратите внимание, что HAL взаимно использует механизмы блокировки (__HAL_LOCK, кодовая строка 107 в https://github.com/ARMmbed/mbed-os/blob/master/targets/TARGET_STM/TARGET_STM32L1/device/stm32l1xx_hal_def.h)

Для получения статуса UART используйте, например,

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

Определение HAL_UART_StateTypeDef равно

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 кодовая строка 97)

Определение HAL_StatusTypeDef (общий статус HAL):

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

Вы можете распечатать статус HAL (т. Е. С передачей UART или SWO ITM_SendChar((*ptr++));, см. https://ralimtek.com/stm32_debugging/)

HAL имеет собственное справочное руководство, статус HAL описан в справочном руководстве 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 на странице 54 в главе 2.9 Общие ресурсы HAL .

Методы отладки описаны в 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 , также для вашего адаптер программирования, который вы можете направить y интегрировать в CubeMX (я использую Atolli c со встроенным CubeMX, потому что Atolli c основан на Eclipse IDE и практически идентичен использованию)

Еще одно руководство по отладке: https://ardupilot.org/dev/docs/debugging-with-gdb-on-stm32.html (если вы на linux).

Это также может быть состояние гонки HAL или ОС. У меня проблема в том, что вы не публикуете свой полный код, особенно не касающийся вашей ОС, и это, возможно, очень важно здесь

Так что, возможно, сначала проверьте статус HAL, а затем сосредоточьтесь на части ОС (условия гонки, переполнение буфера, стека или кучи, ... 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 )

Переполнение стека всегда критично для встроенных систем, поэтому здесь есть ссылки 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/

Также см. UART dma получает прерывания приема прекращает прием данных через несколько минут и UART вызывает прерывание приема прерываний после нескольких часов успешного получения

Многие разработчики избегают использования HAL, потому что он немного глючит и не очень прозрачен, я лично также не буду использовать его, когда я хочу полный контроль над поведением системы

...