串口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