问题描述:我在串口接收回调函数中使用了任务通知,接收到数据之后存到固定缓冲区后,在任务中阻塞等待任务通知处理。但偶尔会出现接收模块数据打印后出现\0的问题。

问题排查:先更换了不同模块,结果都一致。用模块厂的开发板接TTL转USB和上位机试了试,没有这个问题。用他们模块串口焊到我的mcu,同样出现这类问题。此时已经大致判断出是我mcu串口接收的问题。看了看配置,16位采样,没什么问题。继续排查,用逻辑分析仪抓数据,仔细排查了半天,发现出现这个问题的情况是两条消息间隔太短,大概200us左右。而正常的消息是2ms以上收到,导致收到第一条数据可能没有被处理完成,第二条消息中断接收到消息后,缓冲区被清除,第一条消息就误被清除掉消息头的几个字节。

以下是有问题的接收代码:

  if (huart->Instance == USART1) {
      
    /* We have not woken a task at the start of the ISR. */
      #if 1
        cmd_def_t.rx_lens = Size;
      log_debug("Size:%d\r\n",Size);
    debug_thread_notify_vaule(true, CMD_TASK_NOTIFY_DEBUG);
  }

void debug_thread_notify_vaule(bool irq, uint32_t nofity_bit) {

  BaseType_t xHigherPriorityTaskWoken = pdFALSE;
  if (irq == true) {
    xTaskNotifyFromISR((TaskHandle_t)debugThread_t, nofity_bit, eSetBits,
                       &xHigherPriorityTaskWoken); //
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
  } else {
    xTaskNotify((TaskHandle_t)debugThread_t, nofity_bit, eSetBits);
  }
}

接续排查,将debug_thread_notify_vaule(true, CMD_TASK_NOTIFY_DEBUG);注释,直接在中断内答应,不处理数据。数据打印完整,已经可以锁定是中断内调用任务通知的原因了。

换成rtos自带的流缓冲区接收数据,单开一个最高优先级任务处理数据。

else if (huart->Instance == USART2) {
    HAL_UARTEx_ReceiveToIdle_DMA(&huart2, uart2_def_t.rx_buf, UART_RX_MAX_SZIE);
     BaseType_t xHigherPriorityTaskWoken;
     xStreamBufferSendFromISR(xStreamBuffer,uart2_def_t.rx_buf,Size,xHigherPriorityTaskWoken);
  }

void StartHtdmUsartTask(void *argument) {
for (;;) {
    xReceivedBytes = xStreamBufferReceive(
    xStreamBuffer, ucRxData, sizeof(ucRxData), pdMS_TO_TICKS(100));
      if( xReceivedBytes > 0 )
      {
        htdm_cmd_handle((char *)ucRxData, xReceivedBytes);
      }
  }
}在处理中打印,这回不会出现\0了,应该可以确定xTaskNotifyFromISR占用的时间较长导致的问题。

头疼了一周的问题总算解决。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐