超级精简系列之十九:超级精简的循环FIFO池,C实现

原创 嵌入式Lee 2024-03-21 08:00

一. 前言

前面我们实现了循环缓冲区FIFO:https://mp.weixin.qq.com/s/MvL9eDesyuxD60fnbl1nag.

在串口驱动:https://mp.weixin.qq.com/s/vzjWu2LxpVGZw-msCooh8Q.

PWM音频采集与播放:https://mp.weixin.qq.com/s/nCSw743V5iZjGzrV1oQK4Q

等应用场景都有应用。

但是以上循环缓冲区FIFO还有一些应用场景并不能很方便和高效的使用。

比如在音频应用场景,除了PWM音频采集与播放可能还会涉及到算法处理,此时应用场景是采集-算法-输出, 多了算法处理的过程,此时上述FIFO就显得不是很适用。

我们来看这种应用场景对FIFO的需求:

1.数据链路加长,尽量避免数据拷贝带来的开销和占用系统总线带宽显得很重要。原来的FIFO实现都是从FIFO拷贝到用户存储再去使用,拷贝次数较多。

2.充分利用硬件DMA的特性,原来的FIFO方式,每次写入的位置不一定是对齐的,且可能绕回不是一片连续的空间不适合应用DMA等。

3.效率很重要,缓冲区大小一般是固定值,比如音频算法可能一次处理10ms的数据量,那么就可以以这个颗粒度进行采集,运算和输出。此时使用池比原来的环形FIFO更合适。

综合以上应用场景和需求,我们继续造一个满足不同应用场景的FIFO的轮子,我们就叫做FIFO_POOLFIFO池。

二. 实现

数据结构还是和原来的环形FIFO一样,但是存储空间分为固定大小的分块,不再和原来一样可以任意大小,这样每一次inout的数据块都是连续的,并且可以配置为固定对齐,这样硬件DMA等可以直接使用,不需要搬运到buffer中。

然后还有一个大的不同是状态更新和空间使用时间维度分离了,原来是inout搬运完数据,同时就更新完相关状态(in,out指针,有效数据量等)。现在是获取到当前inout的位置,然后使用这一片空间,使用完后再更新相关状态。

2.1数据结构

和原来的FIFO实现类似

/** * \struct fifo_pool_st * FIFO_POOL缓冲区结构. */typedef struct {  uint32_t in;          /**< 写入索引        */   uint32_t out;         /**< 读出索引        */   uint32_t pool_cnt;    /**< 有效数据块数    */   uint32_t pool_len;    /**< 每个块长度      */   uint32_t pool_num;    /**< 最大块数        */   uint8_t* buffer;      /**< 缓存,用户分配   */
} fifo_pool_st;

2.2接口

In相关接口

/** * \fn fifo_pool_in * 往fifo pool里写数据 * \param[in] dev \ref fifo_pool_st * \param[in] buffer 待写入的数据 * \param[in] len 待写入的长度 * \retval 返回实际写入的数据量 */uint32_t fifo_pool_in(fifo_pool_st* dev, uint8_t* buffer, uint32_t len);
/** * \fn fifo_pool_getinaddr * 获取fifo pool当前可写入地址 * \param[in] dev \ref fifo_pool_st * \retval 返回可写入地址 */uint8_t* fifo_pool_getinaddr(fifo_pool_st* dev);
/** * \fn fifo_pool_incinaddr * 递增写入指针 * \param[in] dev \ref fifo_pool_st */void fifo_pool_incinaddr(fifo_pool_st* dev);

Out相关接口

/** * \fn fifo_pool_out * 从fifo pool读出数据 * \param[in] dev \ref fifo_pool_st * \param[in] buffer 存读出的数据 * \param[in] len 需要读出的数据长度 * \retval 返回实际读出的数据量 返回0表示满 */uint32_t fifo_pool_out(fifo_pool_st* dev, uint8_t* buffer, uint32_t len);
/** * \fn fifo_pool_getoutaddr * 获取fifo pool当前可读出地址 * \param[in] dev \ref fifo_pool_st * \retval 返回可读出地址, 返回0表示空 */uint8_t* fifo_pool_getoutaddr(fifo_pool_st* dev);
/** * \fn fifo_pool_incoutaddr * 递增读出指针 * \param[in] dev \ref fifo_pool_st */void fifo_pool_incoutaddr(fifo_pool_st* dev);

获取当前有效数据块数

/** * \fn fifo_pool_getpoolnum * 获取有效的数据块数 * \param[in] dev \ref fifo_pool_st */uint32_t fifo_pool_getpoolnum(fifo_pool_st* dev);

2.3代码

#include #include "fifo_pool.h"
#define FIFO_POOL_PARAM_CHECK 0
/** * 往fifo pool里写数据 */uint32_t fifo_pool_in(fifo_pool_st* dev, uint8_t* buffer, uint32_t len){  uint8_t* p;  #if FIFO_POOL_PARAM_CHECK  /* 参数检查 */  if((dev == 0) || (buffer == 0) || (len == 0))  {    return 0;  }  if(dev->buffer == 0)  {    return 0;  }  if(len > dev->pool_len)  {    return 0;  }  #endif
  if(dev->pool_cnt >= dev->pool_num)  {      /* 满 */      return 0;  }  else  {      p = dev->buffer + dev->in * dev->pool_len;      memcpy(p,buffer,len);      dev->in++;      if(dev->in >= dev->pool_num) /* 用减法代替取余 */      {        dev->in -= dev->pool_num;      }      dev->pool_cnt++;  }  return len;}
/** * 获取fifo pool当前可写入地址 */uint8_t* fifo_pool_getinaddr(fifo_pool_st* dev){  #if FIFO_POOL_PARAM_CHECK  /* 参数检查 */  if(dev == 0)  {    return 0;  }  #endif
  if(dev->pool_cnt >= dev->pool_num)  {      /* 满 */      return 0;  }  else  {      return (dev->buffer + dev->in * dev->pool_len);  }}
/** * 递增写入指针 */void fifo_pool_incinaddr(fifo_pool_st* dev){  #if FIFO_POOL_PARAM_CHECK  /* 参数检查 */  if(dev == 0)  {    return;  }  #endif
  if(dev->pool_cnt >= dev->pool_num)  {      /* 满 */  }  else  {      dev->in++;      if(dev->in >= dev->pool_num) /* 用减法代替取余 */      {        dev->in -= dev->pool_num;      }      dev->pool_cnt++;  }}
/** * 从fifo pool读出数据 */uint32_t fifo_pool_out(fifo_pool_st* dev, uint8_t* buffer, uint32_t len){  uint8_t* p;  #if FIFO_POOL_PARAM_CHECK  /* 参数检查 */  if((dev == 0) || (buffer == 0) || (len == 0))  {    return 0;  }  if(dev->buffer == 0)  {    return 0;  }  if(len > dev->pool_len)  {    return 0;  }  #endif
  if(dev->pool_cnt == 0)  {      /* 空 */      return 0;  }  else  {      p = dev->buffer + dev->out * dev->pool_len;      memcpy(buffer, p, len);      dev->out++;      if(dev->out >= dev->pool_num) /* 用减法代替取余 */      {        dev->out -= dev->pool_num;      }      dev->pool_cnt--;  }  return len;}
/** * 获取fifo pool当前可读出地址 */uint8_t* fifo_pool_getoutaddr(fifo_pool_st* dev){  #if FIFO_POOL_PARAM_CHECK  /* 参数检查 */  if(dev == 0)  {    return 0;  }  #endif
  if(dev->pool_cnt == 0)  {      /* 空 */      return 0;  }  else  {      return (dev->buffer + dev->out * dev->pool_len);  }}
/** * 递增读出指针 */void fifo_pool_incoutaddr(fifo_pool_st* dev){  #if FIFO_POOL_PARAM_CHECK  /* 参数检查 */  if(dev == 0)  {    return;  }  #endif
  if(dev->pool_cnt == 0)  {      /* 空 */  }  else  {      dev->out++;      if(dev->out >= dev->pool_num)  /* 用减法代替取余 */      {        dev->out -= dev->pool_num;      }      dev->pool_cnt--;  }}

三. 典型应用

下图是原来的采集-发送的应用场景,采集需要先采集到BUFFER然后拷贝到FIFO,发送需要先从FIFO拷贝出来到BUFFER才能发送。

如果是采集-处理-发送的应用场景,就需要两个FIFO,如下图

而我们使用FIFO_POOL可以减少图中红色部分,即两个BUFFERBUFFERFIFO之间的拷贝,即直接使用FIFO_POOL中的空间而无需BUFFER中转。

使用FIFO_POOL更详细的一个应用场景如下

四. 总结

注意以上仅仅实现FIFO本身,实际应用在多线程,或者前后台(中断和主循环)中访问FIFO,需要考虑临界段保护,这一点要特别小心,可以根据具体环境具体处理。

从实际应用来看,我们设计的FIFO_POOL满足了我们的应用需求,效率高且方便,可减少内存的拷贝,移植性也很好可以方便的移植到不同场景使用。




评论
  • 习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习笔记&记录学习习笔记&记学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记
    youyeye 2024-12-11 17:58 75浏览
  • 铁氧体芯片是一种基于铁氧体磁性材料制成的芯片,在通信、传感器、储能等领域有着广泛的应用。铁氧体磁性材料能够通过外加磁场调控其导电性质和反射性质,因此在信号处理和传感器技术方面有着独特的优势。以下是对半导体划片机在铁氧体划切领域应用的详细阐述: 一、半导体划片机的工作原理与特点半导体划片机是一种使用刀片或通过激光等方式高精度切割被加工物的装置,是半导体后道封测中晶圆切割和WLP切割环节的关键设备。它结合了水气电、空气静压高速主轴、精密机械传动、传感器及自动化控制等先进技术,具有高精度、高
    博捷芯划片机 2024-12-12 09:16 72浏览
  • 近日,搭载紫光展锐W517芯片平台的INMO GO2由影目科技正式推出。作为全球首款专为商务场景设计的智能翻译眼镜,INMO GO2 以“快、准、稳”三大核心优势,突破传统翻译产品局限,为全球商务人士带来高效、自然、稳定的跨语言交流体验。 INMO GO2内置的W517芯片,是紫光展锐4G旗舰级智能穿戴平台,采用四核处理器,具有高性能、低功耗的优势,内置超微高集成技术,采用先进工艺,计算能力相比同档位竞品提升4倍,强大的性能提供更加多样化的应用场景。【视频见P盘链接】 依托“
    紫光展锐 2024-12-11 11:50 65浏览
  • 在智能化技术快速发展当下,图像数据的采集与处理逐渐成为自动驾驶、工业等领域的一项关键技术。高质量的图像数据采集与算法集成测试都是确保系统性能和可靠性的关键。随着技术的不断进步,对于图像数据的采集、处理和分析的需求日益增长,这不仅要求我们拥有高性能的相机硬件,还要求我们能够高效地集成和测试各种算法。我们探索了一种多源相机数据采集与算法集成测试方案,能够满足不同应用场景下对图像采集和算法测试的多样化需求,确保数据的准确性和算法的有效性。一、相机组成相机一般由镜头(Lens),图像传感器(Image
    康谋 2024-12-12 09:45 68浏览
  • 习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习笔记&记录学习习笔记&记学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记
    youyeye 2024-12-10 16:13 113浏览
  • 我的一台很多年前人家不要了的九十年代SONY台式组合音响,接手时只有CD功能不行了,因为不需要,也就没修,只使用收音机、磁带机和外接信号功能就够了。最近五年在外地,就断电闲置,没使用了。今年9月回到家里,就一个劲儿地忙着收拾家当,忙了一个多月,太多事啦!修了电气,清理了闲置不用了的电器和电子,就是一个劲儿地扔扔扔!几十年的“工匠式”收留收藏,只能断舍离,拆解不过来的了。一天,忽然感觉室内有股臭味,用鼻子的嗅觉功能朝着臭味重的方向寻找,觉得应该就是这台组合音响?怎么会呢?这无机物的东西不会腐臭吧?
    自做自受 2024-12-10 16:34 163浏览
  • 天问Block和Mixly是两个不同的编程工具,分别在单片机开发和教育编程领域有各自的应用。以下是对它们的详细比较: 基本定义 天问Block:天问Block是一个基于区块链技术的数字身份验证和数据交换平台。它的目标是为用户提供一个安全、去中心化、可信任的数字身份验证和数据交换解决方案。 Mixly:Mixly是一款由北京师范大学教育学部创客教育实验室开发的图形化编程软件,旨在为初学者提供一个易于学习和使用的Arduino编程环境。 主要功能 天问Block:支持STC全系列8位单片机,32位
    丙丁先生 2024-12-11 13:15 60浏览
  • 时源芯微——RE超标整机定位与解决详细流程一、 初步测量与问题确认使用专业的电磁辐射测量设备,对整机的辐射发射进行精确测量。确认是否存在RE超标问题,并记录超标频段和幅度。二、电缆检查与处理若存在信号电缆:步骤一:拔掉所有信号电缆,仅保留电源线,再次测量整机的辐射发射。若测量合格:判定问题出在信号电缆上,可能是电缆的共模电流导致。逐一连接信号电缆,每次连接后测量,定位具体哪根电缆或接口导致超标。对问题电缆进行处理,如加共模扼流圈、滤波器,或优化电缆布局和屏蔽。重新连接所有电缆,再次测量
    时源芯微 2024-12-11 17:11 104浏览
  • 一、SAE J1939协议概述SAE J1939协议是由美国汽车工程师协会(SAE,Society of Automotive Engineers)定义的一种用于重型车辆和工业设备中的通信协议,主要应用于车辆和设备之间的实时数据交换。J1939基于CAN(Controller Area Network)总线技术,使用29bit的扩展标识符和扩展数据帧,CAN通信速率为250Kbps,用于车载电子控制单元(ECU)之间的通信和控制。小北同学在之前也对J1939协议做过扫盲科普【科普系列】SAE J
    北汇信息 2024-12-11 15:45 104浏览
  • RK3506 是瑞芯微推出的MPU产品,芯片制程为22nm,定位于轻量级、低成本解决方案。该MPU具有低功耗、外设接口丰富、实时性高的特点,适合用多种工商业场景。本文将基于RK3506的设计特点,为大家分析其应用场景。RK3506核心板主要分为三个型号,各型号间的区别如下图:​图 1  RK3506核心板处理器型号场景1:显示HMIRK3506核心板显示接口支持RGB、MIPI、QSPI输出,且支持2D图形加速,轻松运行QT、LVGL等GUI,最快3S内开
    万象奥科 2024-12-11 15:42 81浏览
  • 全球知名半导体制造商ROHM Co., Ltd.(以下简称“罗姆”)宣布与Taiwan Semiconductor Manufacturing Company Limited(以下简称“台积公司”)就车载氮化镓功率器件的开发和量产事宜建立战略合作伙伴关系。通过该合作关系,双方将致力于将罗姆的氮化镓器件开发技术与台积公司业界先进的GaN-on-Silicon工艺技术优势结合起来,满足市场对高耐压和高频特性优异的功率元器件日益增长的需求。氮化镓功率器件目前主要被用于AC适配器和服务器电源等消费电子和
    电子资讯报 2024-12-10 17:09 95浏览
  • 首先在gitee上打个广告:ad5d2f3b647444a88b6f7f9555fd681f.mp4 · 丙丁先生/香河英茂工作室中国 - Gitee.com丙丁先生 (mr-bingding) - Gitee.com2024年对我来说是充满挑战和机遇的一年。在这一年里,我不仅进行了多个开发板的测评,还尝试了多种不同的项目和技术。今天,我想分享一下这一年的故事,希望能给大家带来一些启发和乐趣。 年初的时候,我开始对各种开发板进行测评。从STM32WBA55CG到瑞萨、平头哥和平海的开发板,我都
    丙丁先生 2024-12-11 20:14 61浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦