其他分享
首页 > 其他分享> > 串口fifo模式学习笔记

串口fifo模式学习笔记

作者:互联网

本文结合实际工作项目用到的串口外设来总结一下串口fifo模式的使用

背景:博主使用的是一款国产的32位MCU,基于厂商提供的串口demo例程做开发,在此过程中学习demo例程所写的中断收发机制

接下来我们看串口的驱动配置代码

 1 UART_HandleTypeDef UART3_Handle;
 2 
 3 void Uart_Init3(void)
 4 {
 5     UART3_Handle.Instance        = UART3;    
 6     UART3_Handle.Init.BaudRate   = UART_BAUD_RATE;        //9600
 7     UART3_Handle.Init.WordLength = UART_WORDLENGTH_8B;    //8位数据位
 8     UART3_Handle.Init.StopBits   = UART_STOPBITS_1;        //1位停止位
 9     UART3_Handle.Init.Parity     = UART_PARITY_NONE;    //无奇偶校验
10     UART3_Handle.Init.Mode       = UART_MODE_TX_RX;        //正常收发模式
11     UART3_Handle.Init.HwFlowCtl  = UART_HWCONTROL_NONE;    //不使用流控制
12     
13     HAL_UART_Init(&UART3_Handle);
14 }

这部分代码调用HAL的库函数初始化串口的基本工作参数,HAL_UART_Init()函数里面还调用了GPIO初始化的HAL库,这些很好理解,不详细介绍。

 

接下来详细看一下接收处理的HAL库函数

 1 HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *fu8_Data, uint32_t fu32_Size)
 2 {
 3 #if (USE_FULL_ASSERT == 1)
 4     if (!IS_UART_ALL_INSTANCE(huart->Instance))    return HAL_ERROR;
 5 #endif
 6     
 7     if (huart->lu8_RxBusy == true) 
 8     {
 9         return HAL_BUSY;
10     }
11 
12     if (fu32_Size == 0 || fu8_Data == NULL) 
13     {
14         return HAL_ERROR;
15     }
16     
17     huart->lu32_RxSize  = fu32_Size;
18     huart->lu32_RxCount = 0;
19     huart->lu8_RxData   = fu8_Data;
20     huart->lu8_RxBusy   = true;
21 
22     /* Clear RXI Status */
23     huart->Instance->ICR = UART_ICR_RXI;
24     /* FIFO Enable */
25     SET_BIT(huart->Instance->LCRH, UART_LCRH_FEN);
26     /*FIFO Select*/
27     MODIFY_REG(huart->Instance->IFLS, UART_IFLS_RXIFLSEL, UART_RX_FIFO_1_2);  
28     huart->lu32_fifo_level_minus1 = 8-1;      
29     /* Enable the UART Errors interrupt */
30     SET_BIT(huart->Instance->IE,UART_IE_OEI|UART_IE_BEI|UART_IE_PEI|UART_IE_FEI);
31     /* Enable RX and RTI interrupt */
32     SET_BIT(huart->Instance->IE,UART_IE_RXI|UART_IE_RTI); 
33 
34     return HAL_OK;
35 }

函数调用举例:HAL_UART_Receive_IT(&UART3_Handle, SCIA_RX_TMP, sizeof(SCIA_RX_TMP));

作用:将串口DR寄存器的数据存储到SCIA_RX_TMP数组,大小一般定义为255

代码27 28行是关于fifo的配置,可选宏如下

 1 #define UART_TX_FIFO_1_16             (0x00000005)        /*!< Transfer 1 Data  */
 2 #define UART_TX_FIFO_1_8              (0x00000000)        /*!< Transfer 2 Data  */
 3 #define UART_TX_FIFO_1_4              (0x00000001)        /*!< Transfer 4 Data  */
 4 #define UART_TX_FIFO_1_2              (0x00000002)        /*!< Transfer 8 Data  */
 5 #define UART_TX_FIFO_3_4              (0x00000003)        /*!< Transfer 12 Data */
 6 #define UART_TX_FIFO_7_8              (0x00000004)        /*!< Transfer 14 Data */
 7 
 8 #define UART_RX_FIFO_1_16             (0x00000028)        /*!< Receive  1 Data  */
 9 #define UART_RX_FIFO_1_8              (0x00000000)        /*!< Receive  2 Data  */
10 #define UART_RX_FIFO_1_4              (0x00000008)        /*!< Receive  4 Data  */
11 #define UART_RX_FIFO_1_2              (0x00000010)        /*!< Receive  8 Data  */
12 #define UART_RX_FIFO_3_4              (0x00000018)        /*!< Receive  12 Data */
13 #define UART_RX_FIFO_7_8              (0x00000020)        /*!< Receive  14 Data */

 

下面结合串口中断服务函数仿真现象来理解第28行的8-1是什么含义。下图仅截取了接收部分的代码段

 1 /* RXI */
 2     if ((huart->Instance->IE & UART_IE_RXI || huart->Instance->IE& UART_IE_RTI) && errorflags == 0) 
 3     { 
 4         if (huart->Instance->RIS & UART_RIS_RXI) 
 5         {
 6             read_bytes_number = 0;   
 7             /* Clear RXI Status */
 8             SET_BIT(huart->Instance->ICR, UART_ICR_RXI);
 9                                     
10             /* Receive end */
11             while(huart->lu32_RxCount <huart->lu32_RxSize )  
12             {
13                 if(!READ_BIT(huart->Instance->FR, UART_FR_RXFE))
14                 {
15                      /* Store Data in buffer */
16                      huart->lu8_RxData[huart->lu32_RxCount++] = huart->Instance->DR;        
17                      read_bytes_number++; 
18                      SciaRxPC++;
19                     
20                 }  
21                 else
22                 {
23                     break;
24                 }  
25                 if (read_bytes_number == huart->lu32_fifo_level_minus1)   
26                 {
27                     break;   
28                 }
29             }
30             if(huart->lu32_RxCount ==huart->lu32_RxSize )
31             {
32                 huart->lu8_RxBusy = false;
33             
34                 /* Disable RX and RTI interrupt */
35                 CLEAR_BIT(huart->Instance->IE, (UART_IE_RXI|UART_IE_RTI));
36                 
37                 /* clear error interrupt */
38                 CLEAR_BIT(huart->Instance->IE, UART_IE_OEI|UART_IE_BEI|UART_IE_PEI|UART_IE_FEI);
39                 
40                 HAL_UART_RxCpltCallback(huart);
41            }
42         }
43         else if(huart->Instance->RIS & UART_RIS_RTI)
44         {
45             /*clear RTI Status */
46             SET_BIT(huart->Instance->ICR ,UART_ICR_RTI);
47 
48             while(!READ_BIT(huart->Instance->FR, UART_FR_RXFE))
49             {
50                 huart->lu8_RxData[huart->lu32_RxCount++] = huart->Instance->DR;
51                 SciaRxPC++;
52             }
53 
54             huart->lu8_RxBusy = false;
55 
56             /* Disable RX and RTI interrupt */
57             CLEAR_BIT(huart->Instance->IE, (UART_IE_RXI|UART_IE_RTI));
58 
59             /* clear error interrupt */
60             CLEAR_BIT(huart->Instance->IE, UART_IE_OEI|UART_IE_BEI|UART_IE_PEI|UART_IE_FEI);
61             
62             HAL_UART_RxCpltCallback(huart);
63         }        
64     }

接收服务函数通过判断IE寄存器的 UART_IE_RXI  或 UART_IE_RTI 标志进入到内部的 if 或 else if 语句,对DR寄存器的数据进行读取。

产看手册,UART_IE_RXI  是 接收中断标志,UART_IE_RTI  是 超时中断标志

 

 

 此外还有一个很重要的 UART_FR_RXFE 标志 ,表示fifo的状态

 

在fifo模式下的工作机制:

1、发送的数据字节数如果小于等于lu32_fifo_level_minus1 (博主的配置是8-1),那么将不产生UART_IE_RXI  接收中断,只产生UART_IE_RTI  超时中断,也就是只执行上面else if 里面的内容。产生超时中断后,通过判断UART_FR_RXFE 标志得知fifo非空,那么就连续读取DR寄存器的数据。整个过程只产生1次中断就获取了7个字节以内的数据。

仿真现象:

 

 

2、发送的数据如果大于lu32_fifo_level_minus1 且小于2倍的lu32_fifo_level_minus1 ,比如发送8个字节的数据。整个过程会产生2次中断,一次是fifo满了,等于7个的时候产生一次接收中断,搬走7个字节的数据。然后再产生一次超时中断,搬走剩余的1个字节数据。

仿真现象:

第一次进入中断:

 第二次进入中断

 

 

 通过以上仿真试验,可以得出如下结论:

1.使用fifo模式时,当数据量是n倍的lu32_fifo_level_minus1 值时,将产生n次中断;数据量大于n倍且小于n+1倍lu32_fifo_level_minus1 时,将产生n+1次中断

2.相比普通的串口中断,一个数据包就产生一次中断的方式,使用fifo模式可大大降低进入中断的频率,提高CPU的利用率,提高数据收发效率

 

以上就是关于串口fifo模式的使用,谢谢大家,此处应该有掌声!!!

 

 

--------------------------------------------------------------------------------分割线--------------------------------------------------------------------------------------

为了再次验证博主的猜想,修改了两条语句,配置成以下参数:

    /*FIFO Select*/
    MODIFY_REG(huart->Instance->IFLS, UART_IFLS_RXIFLSEL, UART_RX_FIFO_7_8);  
    huart->lu32_fifo_level_minus1 = 14-1;      

 

标签:Instance,UART,笔记,huart,fifo,串口,IE,FIFO
来源: https://www.cnblogs.com/jankeyblog/p/16376325.html