xiaoqilo 发表于 2025-4-24 09:54

APM32F107串口中断接收丢包

APM32F107在串口同时发送和接收的情况下串口接收丢字节,具体表现为偶发进入串口接收中断了,但是USART_FLAG_RXBNE标志位没有触发,导致读不到这个字节进而丢字节,通过计数发现进入中断的次数与实际应该收到的字节数一致。1、发送是阻塞式发送的,没有用发送中断,排除进入的是发送中断的可能。
2、出现这种情况时打断点看了,其他的溢出及错误标志位并没有置位,也打印检查了,没有置位。
3、排查代码了没有在其他地方主动调用USART_RxDatad读取。
4、串口中断优先级已调至最高。
5、只接收不发送不会丢字节,挂一晚上都不丢,只要一发送接收就会丢。

发送代码:
void Uart1_Send(char buf)
{
    uint16_t data_9th = buf;
    dog_feed_count_clean(); // 循环清除喂狗变量,超过DOG_PROTECT_TIME_100MS不清除则认为主循环异常,并停止喂狗。
    if (g_rParameters.sPort[0].ucParity == UART_CHK_MARK)
    {
      data_9th |= (1 << (uart1_data_bit - 1));
    }
    else if (g_rParameters.sPort[0].ucParity == UART_CHK_SPACE)
    {
      data_9th &= ~(1 << (uart1_data_bit - 1));
    }

    WAIT_TX_EMPTY; // wait data register empty//等待发送完
    USART_TxData(USART1, data_9th);
}


接收中断:
void USART1_IRQHandler(void)
{
    uint8_t data;
    uint8_t longth = g_sParameters.sPort[0].ucDataSize;
    if (USART_ReadStatusFlag(USART1, USART_FLAG_OVRE) == SET)
    {
      // 由软件清0,先读取USART_STS寄存器,再读USART_DATA寄存器完成清0。
      USART_RxData(USART1);
    }
    if (USART_ReadStatusFlag(USART1, USART_FLAG_RXBNE) == SET)
    {
      data = (uint8_t)USART_RxData(USART1); // fetch recv data from buffer
      if (g_sParameters.sPort[0].ucParity != UART_CHK_NONE)
      {
            data = data & (~(1 << longth)); // 去掉校验位
      }
      if (AtCmd_enter_mode(0, data) == 1)
      {
            packet_count = 0;
      }
      else
      {
            packet_count = 0;
            uart1_rx_ringbuf_push(&uart1_rx_ringbuf, data);
            // uart_rec_len ++;
      }
      usart_recv_total_len++;
    }
    timer_pack_reset_func();
}


风暴之眸 发表于 2025-4-24 11:29

感觉应该不会呀!
F107的主频近百兆呢!处理一个kbps级别的通讯。
即使错误进入了串口接收中断了,只要没有读出 ,下次仍然会进入串口中断

xiaoqilo 发表于 2025-4-24 11:44

风暴之眸 发表于 2025-4-24 11:29
感觉应该不会呀!
F107的主频近百兆呢!处理一个kbps级别的通讯。
即使错误进入了串口接收中断了,只要没有 ...

你是极海的技术支持么?

伏尔加的鱼 发表于 2025-4-24 12:44

检查你其它地方程序吧不知道你波特率用的多少我115200的很多都是中断收发也没出现大概率的丢包,不行你就上DMA

风暴之眸 发表于 2025-4-24 14:41

我不是技术支持。版主们应该是!

Gfan 发表于 2025-4-24 18:00

这部分代码看不出问题噢,需要更多的代码内容才能分析

建议先排查两个方面:

[*]中断处理函数中清除过载标志在判断接收buff非空之前,是否已经发生过载,但被清除。
[*]检查发送速度和接收速度是否一致,如果发送和接收时的速度不一致,可能导致数据丢失。

jobszheng 发表于 2025-4-25 19:03

这个真心没有遇到过。
我们使用的是应答方式来通讯。直接全双工的方式,还真没有实践过

xiaoqilo 发表于 2025-4-26 11:28

更神奇的是我用STM32F107的例程代码就没问题,APM的例程和STM的例程都已经删除的只剩串口部分了,没有其他代码,HCLK、PCLK时钟也检查了完全一致,串口寄存器值也完全一致

xiaoqilo 发表于 2025-4-26 11:33

Gfan 发表于 2025-4-24 18:00
这部分代码看不出问题噢,需要更多的代码内容才能分析

建议先排查两个方面:


1、没有,后面我代码修改了,没发现过载
2、波特率是一致的,而且只发送或者只接受都不会有问题

另外我用STM32F107的例程代码就没问题,APM的例程和STM的例程都已经删除的只剩串口部分了,没有其他代码,HCLK、PCLK时钟也检查了完全一致,串口寄存器值也完全一致。

cooldog123pp 发表于 2025-4-26 14:30


这个真心没有遇到过。不过丢包影响很大么。大数据量丢一两个也是很正常啊,或者你开开奇偶校验事实。

lemonboard 发表于 2025-4-26 20:02

感觉这个bug还有点严重,不过倒是可以通过对数据帧添加校验来workaround掉。

xiaoqilo 发表于 2025-4-26 20:24

解决了,库函数有问题:
void USART_TxData(USART_T* usart, uint16_t data)
{
    usart->DATA_B.DATA = data;
}
这个DATA_B.DATA只使用了DATA寄存器的9位没使用保留的部分,换为以下方式就没问题
void USART_TxData(USART_T* usart, uint16_t data)
{
    usart->DATA = data;
}
猜测,DATA寄存器会有两个,一个是TX的一个是RX的,但为了兼容性在逻辑地址上是一个,当执行写寄存器操作时会映射到TX的DATA寄存器,执行读操作时映射到RX的DATA寄存器,而官方库这种只操作DATA寄存器一部分bit的写法可能会导致逻辑地址与物理地址的映射错乱,也就造成了只有在发送时才会导致接收丢包这种现象,这只是我的猜测,还得官方解释一下。

不过,这么容易复现的严重问题竟然在官方库出现了,确实不应该啊,而且竟然用ST的库没问题,难道用这个片子的都在用ST的库?

Gfan 发表于 2025-4-29 10:05

本帖最后由 Gfan 于 2025-4-29 10:35 编辑

xiaoqilo 发表于 2025-4-26 20:24
解决了,库函数有问题:
void USART_TxData(USART_T* usart, uint16_t data)
{

你好呀,我们尝试复现问题,但使用我们的SDK,并未出现丢包情况,是否方便提供更多信息,以便定位问题呢?



[*]您是怎么判断数据丢失的呢?是少了数据个数,还是数据内容有错误?
[*]出错的概率大概是多少?比如是偶尔出现还是比较频繁?
[*]方便的话,能简单说下您的测试方案吗?

1988020566 发表于 2025-5-6 09:25

串口通信线路可能受到周围环境中的电磁干扰

mnynt121 发表于 2025-5-6 10:24

确认发送端和接收端的波特率设置一致,并且是双方都支持的标准值。

saservice 发表于 2025-5-6 11:38

中断服务函数执行时间过长            

nomomy 发表于 2025-5-6 12:57

优化中断服务函数的代码,尽量减少不必要的操作。

ulystronglll 发表于 2025-5-6 14:43

使用环形缓冲区            

ingramward 发表于 2025-5-6 16:57

检查地线是否完整,避免共模干扰。

jobszheng 发表于 2025-5-6 17:46

都是32位的地址寻址,读9位和读32位应该是一样的呀!
页: [1] 2
查看完整版本: APM32F107串口中断接收丢包