本文章主要针对沁恒科技的CH58x芯片,以
BLE_UART
工程为依托,介绍串口数据的接收与处理。
该工程中 串口数据的处理用到了环形FIFO机制,可作为其他开发工具
📋 个人简介
- 💖 作者简介:大家好,我是喜欢记录零碎知识点的小菜鸟。😎
- 📝 个人主页:欢迎访问我的 Ethernet_Comm 博客主页🔥
- 🎉 支持我:点赞👍+收藏⭐️+留言📝
- 📣 系列专栏:沁恒蓝牙mesh二次开发 🍁
- 💬格言:写文档啊不是写文章,重要的还是直白!🔥
【沁恒蓝牙mesh】CH58x串口环形FIFO数据处理
- 1. 串口数据处理的几个问题
- 2. 环形FIFO图示
- 3. 代码思路解析
- 3.1 数据流向过程解析
- 3.2 buffer_size_mask 解析
- 3.3【fifo初始化】
- 3.4【状态判断】
- 3.5【数据写入与读出】
- 4. 代码示例
- 4.1 app_drv_fifo.h
- 4.2 app_drv_fifo.c
1. 串口数据处理的几个问题
考虑几个问题:
- 读取速度大于写入速度时,会读取到空数据
- 当写入速度大于读取速度时,会出现数据覆盖的情况(这是不允许的)
2. 环形FIFO图示
假设定义一个 size 为10 的环形FIFO缓冲区,下图分别表示:
- 初始化
- 写入5个字节
- 读取4个字节
- 写入9个字节
-
fifo缓冲区的长度
fifo->end - fifo->begin
3. 代码思路解析
本文以南京沁恒微电子公司的 CH583 提供的 SDK中的 BLE_UART
工程为例,解析串口数据解析的过程, .c 和 .h 置于文末供参考备份。
3.1 数据流向过程解析
1️⃣ : 定义fifo 缓冲区以及发送接收数组
typedef struct Fifo_s
{uint16_t begin;uint16_t end;uint8_t *data;uint16_t size;uint16_t size_mask;
} app_drv_fifo_t;static uint8_t app_uart_tx_buffer[APP_UART_TX_BUFFER_LENGTH] = {0}; // 512
static uint8_t app_uart_rx_buffer[APP_UART_RX_BUFFER_LENGTH] = {0}; // 2048static app_drv_fifo_t app_uart_tx_fifo;
static app_drv_fifo_t app_uart_rx_fifo;
初始化:
2️⃣ :在串口接收中断中,将接收FIFO寄存器中的数据写入 app_uart_rx_fifo
,并将接收一帧数据完成的标志位置1;
void UART3_IRQHandler(void){switch(UART3_GetITFlag()){case UART_II_RECV_TOUT: /*接收fifo一段时间内没有数据,产生超时中断*//*将R8_UART3_RBR 寄存器中的数据,长度为 R8_UART3_RFC ,写入 rx_fifo */error = app_drv_fifo_write_from_same_addr(&app_uart_rx_fifo, (uint8_t *)&R8_UART3_RBR, R8_UART3_RFC);uart_rx_flag = true; /*表示接口完成一次数据*/break; }
}
app_drv_fifo_write_from_same_addr
: 将硬件 rx fifo 寄存器中的数据读出,存储到 rx_fifo中, push data to fifo
app_drv_fifo_read_to_same_addr
: 将硬件 tx fifo 寄存器中的数据读出,存储到 tx_fifo 中 , pop data from fifo
3.2 buffer_size_mask 解析
3.3【fifo初始化】
typedef struct Fifo_s
{uint16_t begin;uint16_t end;uint8_t *data;uint16_t size;uint16_t size_mask;
} app_drv_fifo_t;// size_mask = size - 1
// 通过判断 size & (size -1 ) == 0 限制,size大小必须为 2 的整数次幂// 比如初始化一个 fifo ,长度为 16 ;
uint8_t uart_buffer[16] = {0}; // 512
static app_drv_fifo_t uart_fifo;uart_fifo.begin = uart_fifo.end = 0;
uart_fifo.size =16;
uart_fifo.size_mask = 16 -1;
uart_fifo.data = &uart_buffer[0];
3.4【状态判断】
// 刷新 fifo
void app_drv_fifo_flush(app_drv_fifo_t *fifo){fifo->begin = 0;fifo->end = 0;
}
// 判断已经占用的长度
uint16_t app_drv_fifo_length(app_drv_fifo_t *fifo){uint16_t tmp = fifo->begin;return fifo->end - tmp;
}// 判断空
bool app_drv_fifo_is_empty(app_drv_fifo_t *fifo){return (fifo->begin == fifo->end);
}// 判断满
bool app_drv_fifo_is_full(app_drv_fifo_t *fifo){ return ((fifo->end - fifo->begin) == fifo->size);
}
3.5【数据写入与读出】
关于唤醒FIFO防止数组索引溢出,有时候还采用 , (begin + size - out ) % size
/*将一组数据 push到fifo中*/
void app_drv_fifo_push(app_drv_fifo_t *fifo, uint8_t data){uint16_t index = fifo->end & fifo->size_mask; /*将数组的index永远限制在 0:size-1 范围内,不会越界*/fifo->data[index] = data; /*为了保证数组不越界 */fifo->end++;
}/*将fifo中的最后一个元素 pop出来*/
uint8_t app_drv_fifo_pop(app_drv_fifo_t *fifo){uint16_t index = fifo->end & fifo->size_mask;fifo->data[index] = data; /*为了保证数组不越界 */return data;
}// 若 a = 2^n - 1 即 a = 3 7 15 这些数字
// 则 n & (a-1) 的结果就是,将n的结果分组:
// 假设 a = 16; 则 n & 15 的结果就是:/*n = 0-15 结果为 0-15n = 16-31 结果为 0-15
*/
4. 代码示例
4.1 app_drv_fifo.h
/********************************** (C) COPYRIGHT ******************************** File Name : app_drv_fifo.h* Author : WCH* Version : V1.1* Date : 2022/01/19* Description :********************************************************************************** Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.* Attention: This software (modified or not) and binary are used for * microcontroller manufactured by Nanjing Qinheng Microelectronics.*******************************************************************************/#ifndef __APP_DRV_FIFO_H__
#define __APP_DRV_FIFO_H__#include <stdbool.h>
#include <stdint.h>#ifndef BV#define BV(n) (1 << (n))
#endif#ifndef BF#define BF(x, b, s) (((x) & (b)) >> (s))
#endif#ifndef MIN#define MIN(n, m) (((n) < (m)) ? (n) : (m))
#endif#ifndef MAX#define MAX(n, m) (((n) < (m)) ? (m) : (n))
#endif#ifndef ABS#define ABS(n) (((n) < 0) ? -(n) : (n))
#endiftypedef enum
{APP_DRV_FIFO_RESULT_SUCCESS = 0,APP_DRV_FIFO_RESULT_LENGTH_ERROR,APP_DRV_FIFO_RESULT_NOT_FOUND,APP_DRV_FIFO_RESULT_NOT_MEM,APP_DRV_FIFO_RESULT_NULL,} app_drv_fifo_result_t;#ifndef NULL#define NULL 0
#endif/*!* FIFO structure*/
typedef struct Fifo_s
{uint16_t begin;uint16_t end;uint8_t *data;uint16_t size;uint16_t size_mask;
} app_drv_fifo_t;//__inline uint16_t app_drv_fifo_length(app_drv_fifo_t *fifo);uint16_t app_drv_fifo_length(app_drv_fifo_t *fifo);/*!* Initializes the FIFO structure** \param [IN] fifo Pointer to the FIFO object* \param [IN] buffer Buffer to be used as FIFO* \param [IN] size size of the buffer*/
app_drv_fifo_result_t
app_drv_fifo_init(app_drv_fifo_t *fifo, uint8_t *buffer, uint16_t buffer_size);/*!* Pushes data to the FIFO** \param [IN] fifo Pointer to the FIFO object* \param [IN] data data to be pushed into the FIFO*/
void app_drv_fifo_push(app_drv_fifo_t *fifo, uint8_t data);/*!* Pops data from the FIFO** \param [IN] fifo Pointer to the FIFO object* \retval data data popped from the FIFO*/
uint8_t app_drv_fifo_pop(app_drv_fifo_t *fifo);/*!* Flushes the FIFO** \param [IN] fifo Pointer to the FIFO object*/
void app_drv_fifo_flush(app_drv_fifo_t *fifo);/*!* Checks if the FIFO is empty** \param [IN] fifo Pointer to the FIFO object* \retval isEmpty true: FIFO is empty, false FIFO is not empty*/
bool app_drv_fifo_is_empty(app_drv_fifo_t *fifo);/*!* Checks if the FIFO is full** \param [IN] fifo Pointer to the FIFO object* \retval isFull true: FIFO is full, false FIFO is not full*/
bool app_drv_fifo_is_full(app_drv_fifo_t *fifo);app_drv_fifo_result_t
app_drv_fifo_write(app_drv_fifo_t *fifo, uint8_t *data,uint16_t *p_write_length);app_drv_fifo_result_t
app_drv_fifo_write_from_same_addr(app_drv_fifo_t *fifo, uint8_t *data,uint16_t write_length);app_drv_fifo_result_t
app_drv_fifo_read(app_drv_fifo_t *fifo, uint8_t *data, uint16_t *p_read_length);app_drv_fifo_result_t
app_drv_fifo_read_to_same_addr(app_drv_fifo_t *fifo, uint8_t *data,uint16_t read_length);#endif // __APP_DRV_FIFO_H__
4.2 app_drv_fifo.c
/********************************** (C) COPYRIGHT ******************************** File Name : app_drv_fifo.c* Author : WCH* Version : V1.1* Date : 2022/01/19* Description :********************************************************************************** Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.* Attention: This software (modified or not) and binary are used for * microcontroller manufactured by Nanjing Qinheng Microelectronics.*******************************************************************************/#include "app_drv_fifo.h"static __inline uint16_t fifo_length(app_drv_fifo_t *fifo)
{uint16_t tmp = fifo->begin;return fifo->end - tmp;
}uint16_t app_drv_fifo_length(app_drv_fifo_t *fifo)
{return fifo_length(fifo);
}app_drv_fifo_result_t
app_drv_fifo_init(app_drv_fifo_t *fifo, uint8_t *buffer, uint16_t buffer_size)
{if(buffer_size == 0){return APP_DRV_FIFO_RESULT_LENGTH_ERROR;}if(0 != ((buffer_size) & (buffer_size - 1))){return APP_DRV_FIFO_RESULT_LENGTH_ERROR;}fifo->begin = 0;fifo->end = 0;fifo->data = buffer;fifo->size = buffer_size;fifo->size_mask = buffer_size - 1;return APP_DRV_FIFO_RESULT_SUCCESS;
}void app_drv_fifo_push(app_drv_fifo_t *fifo, uint8_t data)
{fifo->data[fifo->end & fifo->size_mask] = data;fifo->end++;
}uint8_t app_drv_fifo_pop(app_drv_fifo_t *fifo)
{uint8_t data = fifo->data[fifo->begin & fifo->size_mask];fifo->begin++;return data;
}void app_drv_fifo_flush(app_drv_fifo_t *fifo)
{fifo->begin = 0;fifo->end = 0;
}bool app_drv_fifo_is_empty(app_drv_fifo_t *fifo)
{return (fifo->begin == fifo->end);
}bool app_drv_fifo_is_full(app_drv_fifo_t *fifo)
{return (fifo_length(fifo) == fifo->size);
}app_drv_fifo_result_t
app_drv_fifo_write(app_drv_fifo_t *fifo, uint8_t *data, uint16_t *p_write_length)
{if(fifo == NULL){return APP_DRV_FIFO_RESULT_NULL;}if(p_write_length == NULL){return APP_DRV_FIFO_RESULT_NULL;}//PRINT("fifo_length = %d\r\n",fifo_length(fifo));const uint16_t available_count = fifo->size - fifo_length(fifo);const uint16_t requested_len = (*p_write_length);uint16_t index = 0;uint16_t write_size = MIN(requested_len, available_count);//PRINT("available_count %d\r\n",available_count);// Check if the FIFO is FULL.if(available_count == 0){return APP_DRV_FIFO_RESULT_NOT_MEM;}// Check if application has requested only the size.if(data == NULL){return APP_DRV_FIFO_RESULT_SUCCESS;}for(index = 0; index < write_size; index++){//pushfifo->data[fifo->end & fifo->size_mask] = data[index];fifo->end++;}(*p_write_length) = write_size;return APP_DRV_FIFO_RESULT_SUCCESS;
}app_drv_fifo_result_t
app_drv_fifo_write_from_same_addr(app_drv_fifo_t *fifo, uint8_t *data, uint16_t write_length)
{if(fifo == NULL){return APP_DRV_FIFO_RESULT_NULL;}const uint16_t available_count = fifo->size_mask - fifo_length(fifo) + 1;const uint16_t requested_len = (write_length);uint16_t index = 0;uint16_t write_size = MIN(requested_len, available_count);// Check if the FIFO is FULL.if(available_count == 0){return APP_DRV_FIFO_RESULT_NOT_MEM;}for(index = 0; index < write_size; index++){//pushfifo->data[fifo->end & fifo->size_mask] = data[0];fifo->end++;}return APP_DRV_FIFO_RESULT_SUCCESS;
}app_drv_fifo_result_t
app_drv_fifo_read(app_drv_fifo_t *fifo, uint8_t *data, uint16_t *p_read_length)
{if(fifo == NULL){return APP_DRV_FIFO_RESULT_NULL;}if(p_read_length == NULL){return APP_DRV_FIFO_RESULT_NULL;}const uint16_t byte_count = fifo_length(fifo);const uint16_t requested_len = (*p_read_length);uint32_t index = 0;uint32_t read_size = MIN(requested_len, byte_count);if(byte_count == 0){return APP_DRV_FIFO_RESULT_NOT_FOUND;}//PRINT("read size = %d,byte_count = %d\r\n",read_size,byte_count);for(index = 0; index < read_size; index++){//popdata[index] = fifo->data[fifo->begin & fifo->size_mask];fifo->begin++;}(*p_read_length) = read_size;return APP_DRV_FIFO_RESULT_SUCCESS;
}app_drv_fifo_result_t
app_drv_fifo_read_to_same_addr(app_drv_fifo_t *fifo, uint8_t *data, uint16_t read_length)
{if(fifo == NULL){return APP_DRV_FIFO_RESULT_NULL;}const uint16_t byte_count = fifo_length(fifo);const uint16_t requested_len = (read_length);uint32_t index = 0;uint32_t read_size = MIN(requested_len, byte_count);for(index = 0; index < read_size; index++){//popdata[0] = fifo->data[fifo->begin & fifo->size_mask];fifo->begin++;}return APP_DRV_FIFO_RESULT_SUCCESS;
}