嵌入式开发中FIFO buffer的使用

FIFO buffer在嵌入式开发中使用是比较频繁的,常用用于数据收发处理,本文用串口数据接收与处理举例

先定义结构体,定义串口数据的buffer与长度

typedef struct USART_Buffer

{

/* @brief Receive buffer. */

volatile uint8_t RX[UART_BUFSIZE];

/* @brief Transmit buffer. */

volatile uint8_t TX[2];

/* @brief Receive buffer head. */

volatile uint16_t RX_Head;

/* @brief Receive buffer tail. */

volatile uint16_t RX_Tail;

/* @brief Transmit buffer head. */

volatile uint16_t TX_Head;

/* @brief Transmit buffer tail. */

volatile uint16_t TX_Tail;

/* @brief Receive buffer full flag */

volatile uint8_t RX_Full;

/* @brief Receive complete flag (new) */

volatile uint8_t RX_Complete;

/* @brief Last received time stamp (new) */

volatile uint32_t LastRxTime;

/* @brief received data len (new) */

volatile uint16_t RX_len;

} USART_Buffer_t;

//每次串口接收数据内存大小

#define GM_UART_RCV_BUFF_LEN 1024

//串口缓冲区内存大小

#define GM_UART_RCV_FIFO_LEN 2048

定义FIFO操作相关函数

GM_ERRCODE fifo_init(FifoType *fifo, u32 size)

{

if (fifo == NULL || size == 0)

{

return GM_PARAM_ERROR;

}

/* allocate fifo space. */

fifo->base_addr = (u8 *)malloc(size * sizeof(u8));

if (fifo->base_addr == NULL)

{

return GM_MEM_NOT_ENOUGH;

}

memset((u8 *)fifo->base_addr, 0x00, sizeof(u8) * size);

fifo->read_idx = 0;

fifo->write_idx = 0;

fifo->size = size;

return GM_SUCCESS;

}

/************************************************************************

Function :

Description : Reset the fifo structure.

fifo : reference to fifo struct.

Change history:

Note:

Author:

Date:

************************************************************************/

GM_ERRCODE fifo_reset(FifoType *fifo)

{

if (fifo == NULL || fifo->base_addr == NULL)

{

return GM_PARAM_ERROR;

}

/* optional (clear memory region) */

memset((u8 *)fifo->base_addr, 0x00, fifo->size);

fifo->read_idx = 0;

fifo->write_idx = 0;

return GM_SUCCESS;

}

/************************************************************************

Function :

Description : delete the fifo structure.

fifo : reference to fifo struct.

Change history:

Note:

Author:

Date:

************************************************************************/

GM_ERRCODE fifo_delete(FifoType *fifo)

{

if (fifo == NULL)

{

return GM_PARAM_ERROR;

}

/* delete fifo space. */

if (fifo->base_addr == NULL)

{

return GM_SUCCESS;

}

free(fifo->base_addr);

fifo->base_addr = 0;

fifo->read_idx = 0;

fifo->write_idx = 0;

fifo->size = 0;

return GM_SUCCESS;

}

/************************************************************************

Function :

Description : returns msg count in the fifo

fifo : reference to fifo struct.

Change history:

Note:

Author:

Date:

************************************************************************/

u32 fifo_get_msg_length(FifoType *fifo)

{

int read_point = 0;

int write_point = 0;

int left_data_size = 0;

if (fifo == NULL)

{

return 0;

}

read_point = fifo->read_idx;

write_point = fifo->write_idx;

left_data_size = write_point - read_point;

if (left_data_size < 0)

{

left_data_size += fifo->size;

}

return left_data_size;

}

/************************************************************************

Function :

Description : returns left space of the fifo

fifo : reference to fifo struct.

Change history:

Note:

Author:

Date:

************************************************************************/

u32 fifo_get_left_space(FifoType *fifo)

{

int read_point = 0;

int write_point = 0;

int left_data_size = 0;

if (fifo == NULL)

{

return 0;

}

read_point = fifo->read_idx;

write_point = fifo->write_idx;

left_data_size = write_point - read_point;

if (left_data_size < 0)

{

left_data_size += fifo->size;

}

return (fifo->size - left_data_size - 1);

}

/************************************************************************

Function :

Description : Insert msg to the fifo.

fifo : reference to fifo struct.

data : reference to msg buffer.

len : msg length.

Change history:

Note:

Author:

Date:

************************************************************************/

GM_ERRCODE fifo_insert(FifoType *fifo, u8 *data, u32 len)

{

int read_point;

int write_point;

int left_size;

int to_end;

if (len > MAX_FIFO_MSG_LEN)

{

return GM_PARAM_ERROR;

}

read_point = fifo->read_idx;

write_point = fifo->write_idx;

left_size = read_point - write_point;

if (left_size <= 0)

{

left_size += fifo->size;

}

if ((u32)left_size <= (len))

{

return GM_MEM_NOT_ENOUGH;

}

to_end = fifo->size - write_point;

if ((u32)to_end >= len)

{

memcpy(fifo->base_addr + write_point, data, len);

write_point += len;

write_point %= fifo->size;

}

else

{

memcpy(fifo->base_addr + write_point, data, to_end);

memcpy(fifo->base_addr, data + to_end, len - to_end);

write_point = len - to_end;

}

fifo->write_idx = write_point;

return GM_SUCCESS;

}

/************************************************************************

Function :

Description : Retrieve one msg from the fifo.

fifo : reference to fifo struct.

data : reference to msg data buffer.

len : data buffer length.

Change history:

Note:

Author:

************************************************************************/

GM_ERRCODE fifo_peek(FifoType *fifo, u8 *data, u32 len)

{

int read_point = 0;

int write_point = 0;

int left_data_size = 0;

int to_end = 0;

read_point = fifo->read_idx;

write_point = fifo->write_idx;

left_data_size = write_point - read_point;

if (left_data_size < 0)

{

left_data_size += fifo->size;

}

if ((u32)left_data_size < len)

{

return GM_EMPTY_BUF;

}

to_end = fifo->size - read_point;

if ((u32)to_end >= len)

{

memcpy(data, fifo->base_addr + read_point, len);

read_point += len;

if (read_point >= fifo->size)

{

read_point = 0;

}

}

else

{

memcpy(data, fifo->base_addr + read_point, to_end);

memcpy(data + to_end, fifo->base_addr, len - to_end);

read_point = len - to_end;

}

return GM_SUCCESS;

}

/************************************************************************

Function :

Description : Retrieve one msg from the fifo.

fifo : reference to fifo struct.

data : reference to msg data buffer.

len : data buffer length. it is input and output varible

Change history:

Note:

Author:

************************************************************************/

GM_ERRCODE fifo_peek_and_get_len(FifoType *fifo, u8 *data, u32 *len_p)

{

int read_point = 0;

int write_point = 0;

int left_data_size = 0;

int to_end = 0;

read_point = fifo->read_idx;

write_point = fifo->write_idx;

left_data_size = write_point - read_point;

if (left_data_size < 0)

{

left_data_size += fifo->size;

}

if ((u32)left_data_size < (*len_p))

{

(*len_p) = (u32)left_data_size;

}

to_end = fifo->size - read_point;

if ((u32)to_end >= (*len_p))

{

memcpy(data, fifo->base_addr + read_point, (*len_p));

read_point += (*len_p);

if (read_point >= fifo->size)

{

read_point = 0;

}

}

else

{

memcpy(data, fifo->base_addr + read_point, to_end);

memcpy(data + to_end, fifo->base_addr, (*len_p) - to_end);

read_point = (*len_p) - to_end;

}

return GM_SUCCESS;

}

GM_ERRCODE fifo_pop_len(FifoType *fifo, u32 len)

{

int read_point = 0;

int write_point = 0;

int left_data_size = 0;

read_point = fifo->read_idx;

write_point = fifo->write_idx;

left_data_size = write_point - read_point;

if (left_data_size < 0)

{

left_data_size += fifo->size;

}

if ((u32)left_data_size < len)

{

return GM_PARAM_ERROR;

}

read_point += len;

if (read_point >= fifo->size)

{

read_point -= fifo->size;

}

fifo->read_idx = read_point;

return GM_SUCCESS;

}

GM_ERRCODE fifo_peek_until(FifoType *fifo, u8 *data, u16 *len_p, const u8 until_char)

{

U32 read_point = fifo->read_idx;

U32 write_point = fifo->write_idx;

S32 data_size = write_point - read_point;

U32 index = 0;

bool has_until_char = false;

if (NULL == fifo || NULL == data || NULL == len_p)

{

return GM_PARAM_ERROR;

}

if (data_size < 0)

{

data_size += fifo->size;

}

// 取分隔符前面的所有字符

for (index = 0; index < data_size && (fifo->base_addr[read_point] != until_char) && index < *len_p - 1; index++)

{

data[index] = fifo->base_addr[read_point];

read_point++;

read_point %= fifo->size;

}

// 取分隔符后面的所有分隔符,包括'\r'

for (; index < data_size && index < *len_p - 1 && ((fifo->base_addr[read_point] == until_char) || (fifo->base_addr[read_point] == '\r')); index++)

{

data[index] = fifo->base_addr[read_point];

read_point++;

read_point %= fifo->size;

has_until_char = true;

}

*len_p = index;

data[index] = '\0';

if (has_until_char)

{

return GM_SUCCESS;

}

else

{

return GM_EMPTY_BUF;

}

}

bool fifo_empty(FifoType *fifo)

{

return (fifo->read_idx == fifo->write_idx);

// return (fifo_get_left_space(fifo) == fifo->size - 1);

}

bool fifo_full(FifoType *fifo)

{

return (fifo_get_msg_length(fifo) == fifo->size - 1);

}

下面简单举例下实际使用

1 初始化对应的串口与buffer,初始化FIFO buffer调用fifo_init

void uart_init(uint8_t port)

{

GM_ERRCODE ret = 0;

/* Turn on USART*/

switch (port)

{

case DEBUG_UART_PORT:

break;

case COMM_UART_PORT:

/* Init fifo Buffer */

g_uart.UARTParas[GM_UART_COMM].is_Idle = true;

ret = fifo_init(&g_uart.UARTParas[GM_UART_COMM].rcv_fifo, GM_UART_RCV_FIFO_LEN);

printf("GM_UART_COMM fifo_init:%d\n",ret);

/* Init Ring Buffer */

comm_Uart_Buf.RX_Tail = 0;

comm_Uart_Buf.RX_Head = 0;

comm_Uart_Buf.TX_Tail = 0;

comm_Uart_Buf.RX_Full = 0;

comm_Uart_Buf.LastRxTime = 0;

memset(&comm_Uart_Buf, 0, sizeof(USART_Buffer_t));

/* Enable RXNE interrupt */

__HAL_UART_ENABLE_IT(&UartHandle_Module, UART_IT_RXNE);

__HAL_UART_ENABLE_IT(&UartHandle_Module, UART_IT_IDLE);

break;

default:

break;

}

}

2 串口有数据产生中断,往FIFO buffer丢数据,判断数据是否接收完毕,是否接收超时。

/*!

@brief is_comm_uart_frame_complete.

*/

bool is_comm_uart_frame_complete(uint32_t inter_byte_timeout) {

USART_Buffer_t *pUSART_Buf = &comm_Uart_Buf;

/* buffer has data and timeout regard as tranfer completed*/

if (pUSART_Buf->RX_len> 0 &&

(HAL_GetTick() - pUSART_Buf->LastRxTime > inter_byte_timeout)) {

return true;

}

return false;

}

/*!

@briefOne frame receive completed or timeout ,add data to fifo

*/

void comm_add_data_to_fifo(void)

{

GM_ERRCODE ret = 0;

USART_Buffer_t *pUSART_Buf = &comm_Uart_Buf;

/* caculate availabe data from ring buffer */

if (pUSART_Buf->RX_len > 0) {

__HAL_UART_DISABLE_IT(&UartHandle_Module, UART_IT_RXNE);

g_uart.UARTParas[GM_UART_COMM].is_Idle = false;

/* read ring buffer data to FIFO */

ret = fifo_insert(&g_uart.UARTParas[GM_UART_COMM].rcv_fifo, &pUSART_Buf->RX[0],pUSART_Buf->RX_len);

//printf("module_add_data_to_fifo ret:%d,data:%s,len:%d,fifolen:%d\r\n",ret,pUSART_Buf->RX,pUSART_Buf->RX_len,fifo_get_msg_length(&g_uart.UARTParas[GM_UART_COMM].rcv_fifo));

pUSART_Buf->RX_len = 0;

/* update Tail */

g_uart.UARTParas[GM_UART_COMM].is_Idle = true;

__HAL_UART_ENABLE_IT(&UartHandle_Module, UART_IT_RXNE);

}

}

/*!

@briefOne module data recieve IRQ

*/

void Comm_IRQHandler(void) {

USART_Buffer_t *pUSART_Buf = &comm_Uart_Buf;

/* receieve data*/

if ((__HAL_UART_GET_FLAG(&UartHandle_Module, UART_FLAG_RXNE) != RESET) && \

(__HAL_UART_GET_IT_SOURCE(&UartHandle_Module, UART_IT_RXNE) != RESET))

{

pUSART_Buf->RX[pUSART_Buf->RX_len] = (uint8_t)(UartHandle_Module.Instance->DR & (uint8_t)0x00FF);

pUSART_Buf->RX_len++;

if(pUSART_Buf->RX_len > (RX_MAX_LEN - 1))

{

pUSART_Buf->RX_len = 0;

}

pUSART_Buf->LastRxTime = HAL_GetTick();

__HAL_UART_CLEAR_FLAG(&UartHandle_Module, UART_FLAG_RXNE);

/* Clear ORE flag if set */

if (__HAL_UART_GET_FLAG(&UartHandle_Module, UART_FLAG_ORE)) {

__HAL_UART_CLEAR_FLAG(&UartHandle_Module, UART_FLAG_ORE);

}

}

/* Check for idle line detection (optional, if your protocol supports it) */

if (__HAL_UART_GET_FLAG(&UartHandle_Module, UART_FLAG_IDLE)) {

__HAL_UART_CLEAR_FLAG(&UartHandle_Module, UART_FLAG_IDLE);

__HAL_UART_CLEAR_IDLEFLAG(&UartHandle_Module);

//printf("Module pUSART_Buf->RX:%s,%d\r\n",pUSART_Buf->RX,pUSART_Buf->RX_len);

comm_add_data_to_fifo();

}

}

2 另外一任务或循环中取FIFO buffer的数据并做相应处理,取出fifo buffer数据调用fifo_peek。

void process_module_Rxfifo_buffer(void) {

GM_ERRCODE ret = GM_SUCCESS;

u16 contentLen, actualLen;

if (g_uart.UARTParas[GM_UART_COMM].is_Idle == false) return;

if(is_comm_uart_frame_complete(COMM_UART_TIMEOUT))

{

comm_add_data_to_fifo();

}

contentLen = fifo_get_msg_length(&g_uart.UARTParas[GM_UART_COMM].rcv_fifo);

if (contentLen > 2) { 根据实际情况修改或添加判断条件

u8 tempBuf[GM_UART_RCV_BUFF_LEN] = {0};

ret = fifo_peek(&g_uart.UARTParas[GM_UART_COMM].rcv_fifo, tempBuf, contentLen);

if (GM_SUCCESS != ret {

fifo_reset(&g_uart.UARTParas[GM_UART_COMM].rcv_fifo);

printf("Receive invalid module data,reset fifo!,ret=%d\n", ret);

return;

}

(数据处理)

......

}

fifo_pop_len(&g_uart.UARTParas[GM_UART_COMM].rcv_fifo, contentLen);

}

}

相关推荐
广药门徒2 小时前
PADS同网络相邻引脚怎么走出粗线 FPC 电源布线如何布出粗线
嵌入式硬件
A星空1234 小时前
二、交叉编译工具链(arm-linux-gnueabihf-gcc)安装与验证,搭建 TFTP+NFS 服务,调试开发板网络连通性;
linux·c++·驱动开发·单片机·嵌入式硬件
z20348315204 小时前
Keil界面优化配置,快捷键格式化配置,警告屏蔽
单片机
搁浅小泽4 小时前
空调风机、四通阀、电辅热的电源如何取电?
单片机·嵌入式硬件·可靠性工程师
恶魔泡泡糖5 小时前
51单片机DS1302时钟
单片机·嵌入式硬件·51单片机
2501_918126915 小时前
野火stm32怎么玩
stm32·单片机·生活·个人开发
czhaii5 小时前
AiCube-ISP功能最全面,界面最友好,操作最方便的取模工具
单片机
2501_918126915 小时前
stm32能做次声波检测器吗?
c语言·stm32·单片机·嵌入式硬件·学习
隔壁大炮6 小时前
【中断】中断的概念
单片机·嵌入式·硬件