嵌入式开源组件——LwRB(RingBuffer)的移植和应用

news2024/11/20 3:25:39

说明:记录自己学习的过程,如有理解上的错误或者不恰当的地方请原谅。

一、简介

LwRB 是一个针对嵌入式系统优化的通用FIFO(先进先出)缓冲区库,之前的名称叫做RingBuffe 

,不知道作者在V2.0.0版本时,修改名称为了LwRB。以下为主要的一些特性:

  • 用 C (C11) 编写,兼容size_t 数据类型

  • 平台无关,无特定架构的代码

  • 实现 FIFO(先进先出)缓冲区

  • 无动态内存分配,数据为静态数组

  • 使用优化的内存复制,而不是循环来读取/写入内存中的数据

  • 作为管道使用时,线程安全,只有单个写入和单个读取条目

  • 作为管道使用时,单写和单读条目的中断安全

  • 适用于从内存到内存的 DMA 传输,缓冲区和应用内存之间零拷贝开销

  • 支持数据查看、读取跳过和写入时提前

  • 实现对事件通知的支持

  • 用户友好的 MIT 许可证

我们重点关注里面标记红色特性,在把LwRB用于串口接收和发送时,零拷贝开销,特别高。

二、相关资料和链接

直接挂上作者写的文档链接,里面有详细的使用技巧介绍、原理讲解,非常生动形象。主页上还有作者开发发的各种其他嵌入式开源小组件。

https://docs.majerle.eu/projects/lwrb/en/latest/index.html

三、移植注意事项

移值平台:DMK5  GD32F303系列芯片(其实和芯片平台无关)

3.1 源码获取

GitHub地址 https://github.com/MaJerle/lwrb 这里我们拉取main分支的代码,他是最新稳定的版本分支。不建议使用develop分支代码,应为为开发状态。

3.2 源码文件介绍

主要关注docs文件和lwrb文件。

docs/examples_src文件重点关注,详细的说明了各个用法例子。docs文件下有许多后缀rst的文件(是一种用于文本数据的文件格式,主要用于Python 编程语言社区的技术文档),这个直接在github网页上就可以了。

docs/lwrb/src文件。我们直接把里面的lwrb.h和lwrb.c文件拎出来,移植就用这两个文件。

3.3 需要修改的地方

把上述的lwrb.h和lwrb.c文件加入工程中。最新稳定V3.0.0版本支持了STDATOMIC 功能,保证数据的原子访问,需要支持这个特性的话,编译器需要支持C11,需要的keil 是AC6的支持。你懂的AC6太麻烦了,我们还是用AC5吧。直接编译会报错:

..\..\User\components\lwrb\lwrb.h(53): error:  #5: cannot open source input file "stdatomic.h": No such file or directory

在lwrb.h上直接定义一个LWRB_DISABLE_ATOMIC,表明不使用atomic即可。

#define LWRB_DISABLE_ATOMIC
#ifdef LWRB_DISABLE_ATOMIC
typedef unsigned long lwrb_ulong_t;
#else
#include <stdatomic.h>
typedef atomic_ulong lwrb_ulong_t;
#endif

可能大家这里就会有疑问了,不使用atomic有什么问题吗?答案是没有的,因为size_t 类型在Cortex-M 上是 32 位,我们使用的GD32或者STM32是 32 位在一个周期内写入的。

3.4 最小示例代码

移植完成后,就可以使用了,只是官网的一个最小使用示例:

#include "lwrb/lwrb.h"

/* Declare rb instance & raw data */
lwrb_t buff;
uint8_t buff_data[8];

/* Application variables */
uint8_t data[2];     /* Application working data */

/* Application code ... */
lwrb_init(&buff, buff_data, sizeof(buff_data)); /* Initialize buffer */

/* Write 4 bytes of data */
lwrb_write(&buff, "0123", 4);

/* Print number of bytes in buffer */
printf("Bytes in buffer: %d\r\n", (int)lwrb_get_full(&buff));

/* Will print "4" *

四、LwRB实现原理

主要参考官方给的文档,文档展示了几种不同的缓冲区使用情况,来提供给我们理解内部是如何管理数据,这里自己搬运一下,配合上自己的理解。https://docs.majerle.eu/projects/lwrb/en/latest/user-manual/how-it-works.html

先明确一下这几个缩写的含义:

  • R: 代表读指针。在读取/写入操作时读取。仅在读取操作时修改
  • W: 代表写指针。在进行读/写操作时读取。仅在写操作时修改
  • S: 代表缓冲区大小。在初始化的时候就固定了
  • W和R指针的值位于0到S-1之间。例如上述图中定义了一个大小为8的缓冲区作为数组,W 和 R 指针的有效数值范围为 0 - 7。
    • R 和 W 将在在 S 处溢出,因此R 和 W有效范围总是 0、1、2、3、......、S - 2、S - 1、0、1、2、3、......、S - 2、S - 1、0、......
    • 当S为4时,R和W的取值范围为:0、1、2、3、0、1、2、3、0、1.............
  • 缓冲区可容纳的最大字节数总是 S - 1,因此缓冲区最多可容纳 7 个字节
  • R 和 W 指针总是指向下一个读/写操作
  • 当 W == R 时,缓冲区为空
  • 当 W == R - 1 时,缓冲区被认为是满的
    • W == R - 1 只有在 W 和 R 溢出缓冲区大小 S 时才有效。
    • 总是将 S 加到计算出的数字上,然后使用模数 S 得出最终值

具体的模数应该怎么计算呢?

//假设S为4 
2 - 3 = (2 - 3 + S) % S = (2 - 3 + 4) % 4 = (-1 + 4) % 4 = 3

我们来看具体的情况:

  • 示例A:缓冲区为空,因为 W == R = 0 
  • 示例B:缓冲区有 W - R = 4 - 0 = 4 个字节,因为 W > R
  • 示例C:缓冲区满,因为 W == R - 1 或 7 == 0 - 1 ,也就是上面说到模数计算公式R代入0,来进行计算 ,7 = (0 - 1 + S) % S = (0 - 1 + 8) % 8 = (-1 + 8) % 8 = 7
  • 示例D:缓冲区保存有 S - (R - W) = 8 - (5 - 3) = 6 个字节,因为 R > W
  • 示例E:缓冲区满,因为 W == R - 1 或者叫(4 = 5 - 1) ,也就是 S - (R - W) = 8 - (5 - 4) ) = 7 字节。

注意:这里我们重点区分一下,缓冲区满的C和E的情况不同,C示例的缓冲区满,是W>R的条件下,直接用R-1计算是负数,需要进行取模计算公式来满足W==R-1。而E示例的缓冲区满R>W的条件下的,相当于缓冲区到了尾部后又重新到了头部,所以直接利用R-1计算可以得到满足W==R-1,这个时候的利用 S - (R - W)来计算出缓冲区内大小为7字节,缓冲区满了。

五、应用

我主要用于串口数据的接收和发送上面,配置DMA接收半满中断、串口IDLE中断、DAM发送完成中断,可以实现高效的串口数据发送和接收,后续会出两篇博文详细介绍这方面的使用和原理。

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

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

相关文章

C++11线程库简介

前言 在c11之前涉及多线程的问题都是和平台相关的&#xff0c;比如windows和linux都有一套自己的接口&#xff0c;这使得代码的可移植性变差。C11中最重要的特性就是对线程进行了支持&#xff0c;使得C在编程时不再依赖第三方库&#xff0c;而且原子操作中还引入了原子类的概念…

消息队列(六):服务器设计

紧接着上一章没说完的进行服务器的补充。 推送给消费者消息的基本实现思路 让 brokerServer 把哪些消费者管理好收到对应的消息&#xff0c;把消息推送给消费者 消费者是以队列为维度来订阅消息的&#xff0c;一个队列可以有多个消费者&#xff08;此处我们约定按照轮询的方…

HTTP协议(超级详细)

HTTP协议介绍 基本介绍&#xff1a; HTTP&#xff1a;超文本传输协议&#xff0c;是从万维网服务器传输超文本到本地浏览器的传送协议HTTP是一种应用层协议&#xff0c;是基于TCP/IP通信协议来传送数据的&#xff0c;其中 HTTP1.0、HTTP1.1、HTTP2.0 均为 TCP 实现&#xff0…

激光焊接汽车PP塑料配件透光率测试仪

随着汽车主机厂对车辆轻量化的需求越来越强烈&#xff0c;汽车零部件轻量化设计、制造也成为汽车零部件生产厂商的重要技术指标。零部件企业要实现产品的轻量化&#xff0c;在材料指定的情况下&#xff0c;要通过产品设计优化、产品壁厚减小和装配方式的优化来解决。使用PP材料…

React 把useState变成响应式 ,今天又可以早点下班了

Ⅰ、前言 我们知道 React 中 , 要想修改 「状态」 > 必须要「state &#xff0c; setState」 useState() 中「setState」 去修改 > 「state」那么如果用 Proxy > 去改造 useState&#xff0c;那么 「摸鱼的时间」又增加啦 &#xff1f; Ⅱ、proxy 改造 useState 首…

数据结构与算法之Floyd算法-最短路径问题

Floyd算法-最短路径问题 Floyd算法-最短路径问题算法结束算法思想算法效率分析 Floyd算法-最短路径问题 算法结束 Floyd算法&#xff1a;求出每一对顶点之间的最短路径 核心&#xff1a;使用动态规划思想&#xff0c;将问题的求解分为多个阶段&#xff1a; 对于n个顶点的图…

数据结构---绪论

&#x1f31e;欢迎来到数据结构的世界 &#x1f308;博客主页&#xff1a;卿云阁 &#x1f48c;欢迎关注&#x1f389;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f31f;本文由卿云阁原创&#xff01; &#x1f4c6;首发时间&#xff1a;&#x1f339;2023年9月17日&…

HTTP代理反爬虫技术详解

HTTP代理是一种网络技术&#xff0c;它可以将客户端的请求转发到目标服务器&#xff0c;并将服务器的响应返回给客户端。在网络安全领域中&#xff0c;HTTP代理经常被用来反爬虫&#xff0c;以保护网站的正常运营。 HTTP代理反爬虫的原理是通过限制访问者的IP地址、访问频率、U…

typeScript 类型推论

什么是类型推论&#xff1f; 类型推论是 TypeScript 中的一个特性&#xff0c;它允许开发人员不必显式地指定变量的类型。相反&#xff0c;开发人员可以根据变量的使用情况让 TypeScript 编译器自动推断出类型。例如&#xff0c;如果开发人员将一个字符串赋值给一个变量&#…

【自然语言处理】【大模型】RWKV:基于RNN的LLM

相关博客 【自然语言处理】【大模型】RWKV&#xff1a;基于RNN的LLM 【自然语言处理】【大模型】CodeGen&#xff1a;一个用于多轮程序合成的代码大语言模型 【自然语言处理】【大模型】CodeGeeX&#xff1a;用于代码生成的多语言预训练模型 【自然语言处理】【大模型】LaMDA&a…

MySQL数据库详解 三:索引、事务和存储引擎

文章目录 1. 索引1.1 索引的概念1.2 索引的作用1.3 如何实现索引1.4 索引的缺点1.5 建立索引的原则依据1.6 索引的分类和创建1.6.1 普通索引1.6.2 唯一索引1.6.3 主键索引1.6.4 组合索引1.6.5 全文索引 1.7 查看索引1.8 删除索引 2. 事务2.1 事务的概念2.2 事务的ACID特性2.2.1…

Java 高频疑难问题系列一

​​​​​​​ 目录 ​编辑​​​​​​​ 1.零长度 2.redis的有序集的排序 3.Unsafe类 4.带资源的try语句 5.Spring如何实现计划任务 6.Java中普通代码块,构造代码块,静态代码块执行顺序 7.MyBatis缓存机制 8.Redis Java 2种类型操作转换 9.CAS底层原理和问题 1…

【数据分享】2006-2021年我国城市级别的市容环境卫生相关指标(20多项指标)

《中国城市建设统计年鉴》中细致地统计了我国城市市政公用设施建设与发展情况&#xff0c;在之前的文章中&#xff0c;我们分享过基于2006-2021年《中国城市建设统计年鉴》整理的2006—2021年我国城市级别的市政设施水平相关指标、2006-2021年我国城市级别的各类建设用地面积数…

【pytorch】模型常用函数(conv2d、linear、loss、maxpooling等)

1、二维卷积函数——cnv2d(): in_channels (int): 输入通道数 out_channels (int): 输出通道数 kernel_size (int or tuple): 卷积核大小 stride (int or tuple, optional): 步长 Default: 1 padding (int, tuple or str, optional): 填充 Default: 0 padding_mode (str, optio…

计算机是如何工作的下篇

操作系统&#xff08;Operating System ) 操作系统是一组做计算机资源管理的软件的统称。目前常见的操作系统有&#xff1a;Windows系列、Unix系列、Linux系列、OSX系列、Android系列、iOS系列、鸿蒙等. 操作系统由两个基本功能&#xff1a; 对下,要管理硬件设备. 对上,要给…

数据标注赋能机器学习进行内容审核

数据标注一直以来都是人工智能的基础&#xff0c;是机器学习得以训练的不可或缺的步骤。随着互联网的兴起&#xff0c;如何创建和维护一个健康的网络环境将成为互联网平台不断解决的问题&#xff0c;但对于与日俱增的用户增长和铺天盖地的网络信息&#xff0c;人工审核内容变得…

【牛客网】BC146 添加逗号

一.题目描述 牛客网题目链接:添加逗号_牛客题霸_牛客网 描述: 对于一个较大的整数 N(1<N<2,000,000,000) 比如 980364535&#xff0c;我们常常需要一位一位数这个数字是几位数&#xff0c;但是如果在这 个数字每三位加一个逗号&#xff0c;它会变得更加易于朗读。 因此&a…

指针扩展之——函数指针

前言&#xff1a;小伙伴们好久不见&#xff0c;本篇文章我们继续讲解一个指针的扩展——函数指针。 一.何为函数指针 我们通过对指针的学习已经知道&#xff0c;凡是叫什么什么指针的&#xff0c;都是指指向这个东西的指针。 所以所谓函数指针&#xff0c;也就是指向函数的指…

001 linux 导学

前言 本文建立在您已经安装好linux环境后&#xff0c;本文会向您介绍Shell的一些常用指令 什么是linux Linux是一种自由和开放源代码的类UNIX操作系统&#xff0c;该操作系统的内核由林纳斯托瓦兹在1991年首次发 布&#xff0c;之后&#xff0c;在加上用户空间的应用程序之后…

TypeScript 从入门到进阶之基础篇(一) ts类型篇

系列文章目录 文章目录 系列文章目录前言一、安装必要软件二、TypeScript 基础类型1.基础类型之 数字类型 number2.基础类型之 字符串类型 string3.基础类型之 布尔类型 boolean4.基础类型之 空值类型 void5.基础类型之 null 、undefined类型6.基础类型之 任意类型 any &#x…