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

news2024/11/22 6:17:05

本文章主要针对沁恒科技的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};   // 2048

static 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-15
	n = 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))
#endif

typedef 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++)
    {
        //push
        fifo->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++)
    {
        //push
        fifo->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++)
    {
        //pop
        data[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++)
    {
        //pop
        data[0] = fifo->data[fifo->begin & fifo->size_mask];
        fifo->begin++;
    }
    return APP_DRV_FIFO_RESULT_SUCCESS;
}

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

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

相关文章

【LLM数据篇】预训练数据集+指令生成sft数据集

note 在《Aligning Large Language Models with Human: A Survey》综述中对LLM数据分类为典型的人工标注数据、self-instruct数据集等优秀的开源sft数据集&#xff1a;alpaca_data、belle、千言数据集、firefly、moss-003-sft-data多轮对话数据集等 文章目录 note构造指令实例…

k8s扩缩容与滚动更新

使用kubectl run创建应用 kubectl run kubernetes-bootcamp \> --imagedocker.io/jocatalin/kubernetes-bootcamp:v1 \> --port8080 端口暴露出去 kubectl expose pod kubernetes-bootcamp --type"NodePort" --port 8080 使用kubectl create创建应用 kubect…

该产品与此版 VMware Workstation 不兼容,因此无法使用

目录 VMware虚拟机开机报错 解决错误 VMware虚拟机开机报错 配置文件“D:\Users\tyn\Documents\Virtual Machines\Ubuntu16 的克隆\Ubuntu16 的克隆.vmx”是由 VMware 产品创建&#xff0c;但该产品与此版 VMware Workstation 不兼容&#xff0c;因此无法使用。 无法打开配…

VMware 虚拟机三种网络模式详解

文章目录 前言桥接模式(Bridged)桥接模式特点: 仅主机模式 (Host-only)仅主机模式 (Host-only)特点: NAT网络地址转换模式(NAT)仅主机模式 (Host-only)特点: 前言 很多同学在初次接触虚拟机的时候对 VMware 产品的三种网络模式不是很理解,本文就 VMware 的三种网络模式进行说明…

线上异常的处理

一、线上问题的排查 进程ID 简称为PID free -m 查看内存使用情况 iostat 查看磁盘读写活动情况 netstat 查看网络连接情况 df -h 查看磁盘空间使用情况 du -sh 查看文件大小情况 1.1、top 命令查看CPU占用情况 top -n num 查看CPU占用最高的num个进程top -Hp PID 或 top -H -p…

Vulnhub系列靶机--- Hackadmeic.RTB1

系列&#xff1a;Hackademic&#xff08;此系列共2台&#xff09; 难度&#xff1a;初级 信息收集 主机发现 netdiscover -r 192.168.80.0/24端口扫描 nmap -A -p- 192.168.80.143访问80端口 使用指纹识别插件查看是WordPress 根据首页显示的内容&#xff0c;点击target 点击…

Java-类与对象(上)

什么是面向对象 Java是一门纯面向对象的语言(Object Oriented Program&#xff0c;简称OOP)&#xff0c;在面向对象的世界里&#xff0c;一切皆为对象。 面向对象是解决问题的一种思想&#xff0c;主要依靠对象之间的交互完成一件事情。 以面向对象方式来进行处理&#xff0c;就…

宏病毒的实践

一、实验目的&#xff1a; 1、了解梅丽莎宏病毒基本概念 2、自己实验梅丽莎宏病毒 二、预备知识&#xff1a; 1.什么是word宏 宏是一个批处理程序命令&#xff0c;正确地运用它可以提高工作效率。微软的office软件运行用户自己编写&#xff0c;叫VBA的脚本来增加其灵活性&…

12. 登录拦截器

由于论坛中的所有功能接口都需要在用户登录的情况下才能访问&#xff0c;所以要做统一的登录身份校验。 1. 在 interceptor 包下创建 LoginInterceptor Component // 交给 Spring 管理 public class LoginInterceptor implements HandlerInterceptor {// 从配置文件中读取配…

ChatGPT和Claude的能力全测评

创造性思维/语言 提示&#xff1a;“写一首 4 行诗&#xff0c;每行只有 3 个词&#xff0c;描写重庆” ChatGPT写诗&#x1f447; Claude写诗&#x1f447; 仁者见仁&#xff0c;您怎么看谁更强&#xff1f; 提示&#xff1a; "如果你随机选择这个问题的答案&#xff0c;…

postgresql 的递归查询

postgresql 的递归查询功能很强大&#xff0c;可以实现传统 sql 无法实现的事情。那递归查询的执行逻辑是什么呢&#xff1f;在递归查询中&#xff0c;我们一般会用到 union 或者 union all&#xff0c;他们两者之间的区别是什么呢&#xff1f; 递归查询的执行逻辑 递归查询的…

⛳ TCP 协议面试题

目录 ⛳ TCP 协议面试题&#x1f43e; 一、为什么关闭连接的需要四次挥⼿&#xff0c;⽽建⽴连接却只要三次握⼿呢&#xff1f;&#x1f3ed; 二、为什么连接建⽴的时候是三次握⼿&#xff0c;可以改成两次握⼿吗&#xff1f;&#x1f463; 三、为什么主动断开⽅在TIME-WAIT状态…

shell 简单且常用的几种

目录 一、配置环境的shell脚本 二、系统资源脚本 一、要求 二、脚本内容 三、脚本解析 四、赋权并验证 一、配置环境的shell脚本 systemctl stop firewalld systemctl disable firewalld systemctl stop NetworkManager systemctl disable NetworkManager setenforce…

动物IT

动物是地球上最丰富和多样化的生物群体之一。它们包括鱼类、鸟类、爬行动物、两栖动物和哺乳动物等各种类型。动物在地球上有着不同的生态角色和生活习性。 动物对于维持生态平衡和生态系统的稳定性至关重要。它们在食物链中扮演着重要的角色&#xff0c;通过捕食和被捕食来保…

【李沐】3.5、softmax回归的从0开始实现

注意&#xff1a; 把每个像素位置看作⼀个特征 # 导入PyTorch库 import torch # 从IPython库中导入display模块&#xff0c;用于在交互式环境中显示内容 from IPython import display # 从d2l.torch模块中导入torch作为d2l的别名&#xff0c;方便后续使用d2l库中的功能 from d…

阿里云轻量应用服务器和云服务器有什么区别?2023更新

阿里云轻量应用服务器和云服务器ECS有什么区别&#xff1f;ECS是专业级云服务器&#xff0c;轻量应用服务器是轻量级服务器&#xff0c;轻量服务器使用门槛更低&#xff0c;适合个人开发者或中小企业新手使用&#xff0c;可视化运维&#xff0c;云服务器ECS适合集群类、高可用、…

ForkJoin框架

1. ForkJoin框架概述 ForkJoin模式先把一个大任务分解成许多个独立的子任务&#xff0c;然后开启多个线程并行去处理这些子任务。有可能子任务还是很大而需要进一步分解&#xff0c;最终得到足够小的任务。ForkJoin模式的任务分解和执行过程大致如下图所示。 ForkJoin模式借助…

NSS [CISCN 2019初赛]Love Math

NSS [CISCN 2019初赛]Love Math 开题直接给源码 <?php error_reporting(0); //听说你很喜欢数学&#xff0c;不知道你是否爱它胜过爱flag if(!isset($_GET[c])){show_source(__FILE__); }else{//例子 c20-1$content $_GET[c];if (strlen($content) > 80) {die("…

差值结构的复合底部

( A, B )---3*30*2---( 1, 0 )( 0, 1 ) 让网络的输入只有3个节点&#xff0c;AB训练集各由6张二值化的图片组成&#xff0c;让A 中有3个点&#xff0c;B中有1个点&#xff0c;且不重合&#xff0c;统计迭代次数并排序。 其中有20组数据 让迭代次数与排斥能成反比&#xff0c;排…

1、Spring_IOC

IOC 1.概述 IOC&#xff1a;Inversion of Control 控制反转&#xff0c;可以让容器负责对象的创建以及销毁操作&#xff0c;对象在容器中叫 bean 2.回顾问题 问题&#xff1a;写了太多与业务无关的代码 耦合度非常高&#xff0c;写了很多和业务无关的代码不利于项目的升级迭…