ChenXC1121 发表于 2022-8-21 15:48:15

STM32的串口是否具有硬件缓存的功能?

本帖最后由 ChenXC1121 于 2022-8-21 16:03 编辑

程序如下,STM32跑UCOS II系统,在串口中断中收取数据(串口数据来的时间不定的,有时间隔很短)并缓存到全局数组usart_rxbuf中,另外在主程序中判断到rec_flag标志被置2了,就关闭串口中断,之后把全局数组usart_rxbuf中的数据拷贝到主程序中定义的一个局部数组中,拷贝时间应该很快,之后又马上开启串口中断,如果刚刚好在主程序关闭串口中断拷贝数据的时候串口数据来了,请问STM32内部有硬件缓存功能来缓存这段时间来的数据吗?还是这时候的数据一定会丢,请大神帮忙分析下,谢谢!


/********************串口中断处理函数*******************************/
volatile u8 usart_rxbuf;
volatile u8 rec_flag=0;
volatile u8 USART2_RX_BUF;                                 //接收缓冲

void USART2_IRQHandler(void)
{
      u8 res;
      u8 i=0,j=0;
      u8 temp=0;
      u16 crc_check=0;      
      OSIntEnter();   
      if(USART2->SR&(1<<5))//接收到数据
      {         
                res=USART2->DR;         
                if((res==0xAA)&&(start_rev==0))
                {
                        rev_num=0;
                        start_rev=1;
                }
                if(start_rev==1)
                {
                        USART2_RX_BUF=res;
                        rev_num++;
                        if(rev_num>63)
                        {
                              if(USART2_RX_BUF==0x55)
                              {
                                        if(USART2_RX_BUF==0x5C)      //采集模块数据上报
                                        {
                                                crc_check=cal_crc(&USART2_RX_BUF,63);
                                                temp=crc_check&0x00ff;
                                                if(temp==USART2_RX_BUF)      //必须校验和正确才会执行写入动作
                                                {               
                                                      rec_flag=2;                                 
                                                      for(j=0;j<4;j++)
                                                      {
                                                                temp=j*50;
                                                                if(usart_rxbuf==0xff)      //0xff代表本段没数据可以存入
                                                                {
                                                                        for(i=5;i<45;i++)
                                                                              usart_rxbuf=USART2_RX_BUF;                  
                                                                        break;
                                                                }
                                                      }
                                                }
                                        }                                       
                                        start_rev=0;
                                        rev_num=0;                                       
                              }                              
                              else
                              {
                                        start_rev=0;
                                        rev_num=0;
                              }
                        }
                }
      }                                 
      OSIntExit();
}



/************主任务程序*****************/
while(1)
{
      if(rec_flag==2)
      {
                rec_flag=0;
               
                for(i=0;i<4;i++)
                {
                        temp=i*50;
                        USART_INT_DISABLE();                                //关闭串口中断
                        if(usart_rxbuf!=0xff)              //代表该位置存在数据
                        {
                              for(j=0;j<50;j++)      
                              {
                                        //usart_rxbuffer数组是while循环内部定义的局部数组变量
                                        usart_rxbuffer=usart_rxbuf;                                       
                              }
                              usart_rxbuf=0xff;              //该条数据处理完成后第一个BYTE置FF代表数据已处理过了
                              USART_INT_ENABLE();                        //开启串口中断

                               //后面是对usart_rxbuffer数组进行分析处理

                        }
                }
      }
}


zchong 发表于 2022-8-21 16:13:46

stm32的串口没有缓存或者某种意义上是1Byte的缓存,简单讲就是在关闭串口中断时间这段时间内串口若发生“接收中断”则数据就会丢失,也就是说你最大只有1一个字节的传输时间去拷贝数据,和你关闭中断的时刻有关。这样的设计是很容丢数据的。比较好的实现方式:开辟环形缓冲区,中断只负责将接收的串口数据塞入环形缓冲区中,数据处理在其它地方进行。

akey3000 发表于 2022-8-21 16:14:15

本帖最后由 akey3000 于 2022-8-21 16:16 编辑

网上转的:

众所周知,STM32串口通讯,接收及发送都没有设计硬件FIFO,这对大部分程序员来说,算是一个硬伤。但实际上,由于STM32串口可以利用DMA收发,这样比固定16字节的FIFO更灵活。


在编写串口接收的bsp层代码时,同时启动DMA接收和空闲中断,就可以实现一个硬件接收缓冲,在空闲中断中,
实现数据从硬件接收缓冲的读取。

串口接收bsp层接收缓冲两层结构
--第一层FIFO硬件接收缓冲 (第一层硬件FIFO接收缓冲,利用DMA自动传输,不占用CPU时间,一般大小可设置为16-1024字节)
--第二层FIFO软件接收缓冲 (第二层软件FIFO接收缓冲,在DMA传输完毕中断中处理,缓冲可设置的比较大,一般是1024~8192字节)

但实际上,由于STM32串口可以利用DMA收发,这样比固定16字节的FIFO更灵活。

同时启动DMA接收和空闲中断,就可以实现一个硬件接收缓冲,空闲中断中,实现数据从硬件接收缓冲的读取。

在3至10Mbps串口通讯的情况下,只有这一个办法。逐个字符中断式接收来不及。

发送一般没有问题,这里主要说接收。波特率低的话,中断可以。波特率高的话,如果是5Mbps,2.2微秒需要接收一个11位串口字符,中断方式显然不现实。

HAL库的串口中断函数,并没有认真考虑DMA和空闲中断,非常不专业。

中断函数应该展开(高速收发仅打开发送完成中断和空闲中断),DMA中断应该跟根据用户定义存在别名。

没有空闲中断,应该算是HAL库不完善。
另外,接收完数据,不应该自以为是的关闭串口,应该由用户决定是否关闭。

HAL库串口空闲中断处理代码:

/* UART in mode Transmitter end --------------------------------------------*/
if(((isrflag & USART_SR_TC) != RESET) && ((crlits & USART_CR1_TCIE) != RESET))
{
    UART_EndTransmit_IT(huart);
    return;
}
/* UART in mode Receiver end -----------------------------------------------*/
if(((isrflags & USART_SR_IDLE) != RESET) && ((crlits & USART_CR1_IDLEIE) != RESET))
{
    /* Clear the UART IDLE pending flag */
    __HAL_UART_CLEAR_IDLEFLAG(huart);
    return;
}
}

ChenXC1121 发表于 2022-8-21 16:16:27

akey3000 发表于 2022-8-21 16:14
fifo,是硬件缓存
(引用自3楼)


请问STM32能通过代码设置开启这个功能吗?

akey3000 发表于 2022-8-21 16:17:36

ChenXC1121 发表于 2022-8-21 16:16
请问STM32能通过代码设置开启这个功能吗?
(引用自4楼)

stm32串口接收硬件FIFO的实现

ChenXC1121 发表于 2022-8-21 16:24:02

akey3000 发表于 2022-8-21 16:17
stm32串口接收硬件FIFO的实现
(引用自5楼)


这个FIFO是不是就相当于环形缓冲区啦?

akey3000 发表于 2022-8-21 16:34:45

ChenXC1121 发表于 2022-8-21 16:24
这个FIFO是不是就相当于环形缓冲区啦?
(引用自6楼)

串口通信速率不高,就在中断中把数据放到软件fifo,速率高,可以参考楼上文章

my_avr 发表于 2022-8-21 16:38:06

每隔一段时间就有人问类似的问题,这个问题的根源是在串口中断里有做数据处理,耗费太多时间。

正常的处理流程是串口中断程序只负责把数据从RX寄存器中读出(没用DMA的情况),然后压入环形缓冲。

主程序中不断判断缓冲里是否有数据,有则取出、判断、处理。

lb0857 发表于 2022-8-21 17:21:55

全双工的吗增加fifo就有啦

cnxh 发表于 2022-8-21 18:25:45

好像有2个,调试时接收一个进中断,发送方已发送完,出中断,还会进入一次,avr好像有3个,进入后中断,还会进入2次

skype 发表于 2022-8-22 08:57:31

dma怎么不利用起来?

2nd 发表于 2022-8-22 23:08:57

有的,一般8或16字节缓冲。

qwe2231695 发表于 2022-8-22 23:38:59

stm32H7 有16字节缓冲,开了以后,可以减少16倍中断的频率。但是16字节才能处理一次数据。正确的方案是DMA加串口空闲中断。

AUDIO_TANXIAOLI 发表于 2023-6-29 12:09:16

DMA加持下不需要经常进入中断的

jssd 发表于 2023-6-29 12:32:50

这样处理数据明摆着增加硬件成本!中断里只负责读数据,然后放进环形缓冲就出来了,不会丢数据。
页: [1]
查看完整版本: STM32的串口是否具有硬件缓存的功能?