【沁恒蓝牙mesh】CH58x串口环形FIFO数据处理

本文章主要针对沁恒科技的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个字节

image-20230810170844358

  • 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;

初始化:

image-20230811085912949

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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/49407.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++信息学奥赛1130:找第一个只出现一次的字符

这段代码的功能是找出输入字符串中第一个重复出现的字符&#xff0c;并输出该字符。 解析注释后的代码如下&#xff1a; #include<bits/stdc.h> using namespace std; int main() {string arr;getline(cin, arr); int a0;for(int i0;i<arr.length();i){for(int j0;j…

OpenEuler 卸载mysql

查询系统是否安装了MySQL rpm -qa | grep -i mysql 关闭mysql 查看MySQL服务运行状态 ps -ef | grep mysql 或者 service mysql status 没有启动 查看rpm包安装的mysql rpm -qa | grep -i mysql 将这些都卸载了 rpm -e mysql5-server rpm -e mysql5-errmsg rpm -e my…

PAT 1114 Family Property

个人学习记录&#xff0c;代码难免不尽人意 Sample Input: 10 6666 5551 5552 1 7777 1 100 1234 5678 9012 1 0002 2 300 8888 -1 -1 0 1 1000 2468 0001 0004 1 2222 1 500 7777 6666 -1 0 2 300 3721 -1 -1 1 2333 2 150 9012 -1 -1 3 1236 1235 1234 1 100 1235 5678 9012 …

【consul】

consul 一、什么是服务注册与发现1.11.2 二、 什么是consul2.1定义2.2特性2.2.1服务注册与发现&#xff1a;2.2.2健康检查&#xff1a;2.2.3Key/Value存储&#xff1a; 三、consul部署-datacenter &#xff1a;指定数据中心名称&#xff0c;默认是dc1。consul &#xff1a;指定…

leetcode做题笔记86分隔链表

给你一个链表的头节点 head 和一个特定值 x &#xff0c;请你对链表进行分隔&#xff0c;使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。 你应当 保留 两个分区中每个节点的初始相对位置。 示例 1&#xff1a; 输入&#xff1a;head [1,4,3,2,5,2], x 3 输出&am…

关于灾备系统中的完全备份,增量备份,差异备份是什么?

完全备份&#xff1a; 完全备份就是用存储介质对整个系统进行备份&#xff0c;包括系统和数据。这种备份方式的好处就是很直观&#xff0c;容易被人理解。而且当发生数据丢失时&#xff0c;只要用备份数据&#xff0c;就可以恢复丢失的数据。 然而它也有不足之处&#xff1a;…

Vue全局组件与局部组件(详解)

当使用 Vue.js 构建应用时&#xff0c;组件是其核心概念之一。Vue 组件允许你将用户界面分割成独立、可复用的部分。这里我会更详细地解释 Vue 的全局组件和局部组件&#xff0c;包括它们的定义、使用方式以及适用场景。 Vue 全局组件&#xff1a; 全局组件是在整个 Vue 应用…

Pytorch-day05-可视化-checkpoint

PyTorch 可视化 1、模型结构可视化2、训练过程可视化3、模型评估可视化 #导入常用包 import os import numpy as np import torch from torch import nn from torch.utils.data import Dataset, DataLoader from torchvision.transforms import transforms import torchvis…

文件四剑客

目录 前言 一、正则表达式 二、grep 三、find 四、sed 五、awk 前言 文件四剑客是指在计算机领域中常用的四个命令行工具&#xff0c;包括awk、find、grep和sed。它们在处理文本文件和搜索文件时非常强大和实用。 1. awk是一种强大的文本处理工具&#xff0c;它允许用户根据指…

【前端】深入理解CSS盒子模型与浮动

目录 一、前言二、盒子模型1、盒子模型组成1.1、border边框1.1.1、边框的三部分组成1.1.2、边框复合简写1.1.3、边框分开写1.1.4、表格的细线边框 1.2、padding内边距1.3、margin外边距1.3.1、外边距水平居中1.3.2、外边距合并1.3.3、嵌套块元素垂直 外边距的塌陷1.3.3.1、解决…

设计模式之门面模式(Facade)的C++实现

1、门面模式提出 在组件的开发过程中&#xff0c;某些接口之间的依赖是比较紧密的&#xff0c;如果某个接口发生变化&#xff0c;其他的接口也会跟着发生变化&#xff0c;这样的代码违背了代码的设计原则。门面设计模式是在外部客户程序和系统程序之间添加了一层中间接口&…

Unity脚本常用生命周期

Unity脚本在Unity引擎运行时会经历多个阶段的变化。如创建&#xff0c;初始化&#xff0c;按帧执行&#xff0c;固定执行&#xff0c;绘制&#xff0c;禁用&#xff0c;销毁等等。具体如下图所示&#xff1a; 我们创建脚本时都是默认继承了MonoBehaviour类&#xff0c;而MonoBe…

【算法系列篇】二分查找——这还是你所知道的二分查找算法吗?

文章目录 前言什么是二分查找算法1.二分查找1.1 题目要求1.2 做题思路1.3 Java代码实现 2.在排序数组中查找元素的第一个和最后一个位置2.1 题目要求2.2 做题思路2.3 Java代码实现 3.搜索插入位置3.1 题目要求3.2 做题思路3.3 Java代码实现 4.x的平方根4.1 题目要求4.2 做题思路…

SpringMVC 反射型跨站点脚本攻击

解决方案&#xff1a; 服务端校验&#xff0c;添加拦截器 配置web,xml <filter><filter-name>xssFilter </filter-name><filter-class>com.fh.filter.XssFilter </filter-class></filter> XssFilter package com.fh.filter;import com…

TikTok Shop内容规则更新,禁止达人进行多平台联播

01.TikTok Shop禁止达人进行多平台联播 TikTok Shop更新了《TikTok Shop内容规则》&#xff0c;公告显示&#xff0c;TikTok Shop高度重视平台用户的安全&#xff0c;为保障用户体验并保护买家免受潜在的误导性广告的影响&#xff0c;在电商直播活动中&#xff0c;达人不得同时…

0基础入门C++之类和对象上篇

目录 1.面向过程和面向对象初步认识2.类的引入3.类的定义3.1类的两种定义方式:3.2成员变量命名规则的建议 4.类的访问限定符及封装4.1访问限定符4.2封装 5.类的作用域6.类的实例化7.类对象模型7.1如何计算类对象的大小7.2 类对象的存储方式猜测 8.this指针8.1this指针的引出8.2…

使用qsqlmysql操作mysql提示Driver not loaded

环境: win10 IDE: qt creator 编译器: mingw32 这里简单的记录下。我遇到的情况是在IDE使用debug和release程序都是运行正常&#xff0c;但是当我编译成发布版本之后。老是提示Driver not load。 这就很奇诡了。 回顾了下编译的时候是需要在使用qt先编译下libqsqlmysql.dll的…

marked在vue项目中改变超链接跳转方式和图片放大预览

marked在vue项目中改变超链接跳转方式和图片放大预览 这里我是另起一个js文件对marked的配置做了修改&#xff0c;参考如下 import marked from marked let renderer new marked.Renderer() const linkRenderer renderer.link const imgRenderer renderer.image // 超链接…

深入了解Unity的Physics类:一份详细的技术指南(七)(下篇)

接着上一篇深入了解Unity的Physics类(上篇)&#xff0c;我们继续把Physics类剩余的属性和方法进行讲解 碰撞检测和忽略: (这些方法和属性涉及查询和处理物体之间的碰撞) Physics.CheckBox: 检查给定位置的盒子是否与任何碰撞器接触或者位于任何碰撞器内部。 Physics.CheckCapsu…

16.遍历二叉树,线索二叉树

目录 一. 遍历二叉树 &#xff08;1&#xff09;三种遍历方式 &#xff08;2&#xff09;递归遍历算法 &#xff08;3&#xff09;非递归遍历算法 &#xff08;4&#xff09;层次遍历算法 二. 基于递归遍历算法的二叉树有关算法 &#xff08;1&#xff09;二叉树的建立 …