精华内容
下载资源
问答
  • 数字系统重要指标-吞吐率吞吐率被定义为数字电路单位时间内传输数据的量或单位时间完成的工作量。传输的数据越多或做的工作越多,则吞吐率越高。吞吐率有时候和性能、带宽可以互换使用。对于CPU来说...

     

    c05e941f2d1c269f8ab893d850a85462.png

    数字系统重要指标-吞吐率

    吞吐率被定义为数字电路单位时间内传输数据的量或单位时间完成的工作量。传输的数据越多或做的工作越多,则吞吐率越高。吞吐率有时候和性能、带宽可以互换使用。对于CPU来说,吞吐率定义为单位时间内能够执行的指令数。对于DDR存储器来说,吞吐率定义 为从存储器中写入或读取的数据量。

    经常和吞吐率一起出现的术语是延迟,我们会发现,延迟和吞吐率是两个不同的概念(后面会介绍延迟)。当谈论吞吐率的时候,我们一般谈论的是支持多大的吞吐率。为了获得吞吐率,我们需要测量—段时间内传输的数据量或执行的指令数。这是一个平均数值而不是瞬时数值。

    延迟是指从加入激励到得到第一个输出结果需要的最短时间。例如,你种植一棵柠檬树,等待它结出果实,它可能过了一年才结出第一批果实。你对降低延迟(一年)无能为力。但是,你可以通过种植10棵树来增加柠檬的产量,你会得到10倍的果实,但是你还是要等一年才能得到第一批水果对于多数设计来说,有一些方法可以降低延迟,但大多数情况下是无能为力的。下面我们将讨论降低延迟的方法。

    在一些应用中,吞吐率至关重要,而在一些情况下,降低延迟是设计的重点。例如,当对DRAM写人大量的数据时,具有高吞吐率就很重要。而另一方面,对类似于在线翻译服务器这类设备来说,用户需要快速获得返回结果,降低延迟就变得更为重要。

    增加吞吐率的方法

    当我们设计一个系统或一个芯片的架构时,希望尽力获得高吞吐率。提高吞吐率涉及多个关键技术点,假如我们能够理解这些关键技术点是如何工作的,以及它们之间存在怎样的关联,那么我们就能把这些关键技术点以最好的方式组合起来以实现期望的目标。下面将对 影响吞吐率的关键技术点进行逐一分析。

    更高的频率

    当今的数字系统以同步系统为主,都需要一个或多个时钟。一个增加数据传输速率或指令执行速度的常用方法是使用更高频率的时钟,在时钟频率增加的情况下,系统的处理能力就会得到不断提升,处理器设计中通常采用这种方法。然而,这种方式会有负面效应,原因 记功率消耗和时钟频率成正比例关系。假如设计的是低功耗电路,通过增加频率来满足吞吐率的要求并不是很好的方法,此时可能需要考虑其他的技术手段。当前流行的处理器设计趋势并不是仅仅把处理器时钟频率的提高作为目标。例如,通过设计多核系统和采用多通道存 储器可以在不提高主频的情况下提高处理能力。

    更宽的数据通道

    设计者可以通过增加数据总线的位宽来提高数据吞吐率。在时钟频率不变的情况下,增加数据总线的位宽可以增加数据吞吐率,就像四车道的公路比两车道的公路单位时间内可以通过更多的车辆一样。例如,PCIe总线可以连接1个通道、2个通道直至32个通道。假设需要 设计一个SA SPCIe控制卡,或一个PCIe SSD卡,那么需要用多少个通道的PCIe总线呢?首先,需要计算HDD或SSD读写需要的带宽,然后选择一个xl,x2x4或甚至x8的PCIe连接器。所选择的PCIe总线连接器的带宽需要与存储器的访问带宽相同或比后者大。另外设计时要考虑到PCIe协议的开销,和任何协议一样,PCIe上并不是所有的时钟周期都可以用来传输用户数据。

    在实际设计中,通常需要对总线的工作时钟频率和总线的位宽进行折中考虑。在给定系统所需传输带宽的情况下,需要选择合适的数据线的宽度和工作频率。例如,64位、800MHz,128位、400MHz和256位、200MHz的总线具有相同的带宽,应如何选择呢?增大总线宽度会使接插件变得更大,芯片引脚更多,从而增加设备的硬件成本;提高总线频率会增加系统设计难度,需要更多地考虑高频信号中常出现的电磁兼容和信号传输质量问题。

    我们可以假定一个这样的场景:我们选择64位数据通道进行背靠背的数据包传输,在一个时钟周期里可以并行发送4字节,它们分属于不同的数据包。在这种情况下,使用一个低速时钟进行数据处理是非常烦琐的。此外,低速时钟意味着更大的延迟(进行数据处理需 要的时间更长)。如果一个设计占用的逻辑门资源不多,对延迟也不敏感,那么使用较为早期的低端工艺进行芯片设计就可以满足需求。如果希望降低延迟,同时预算充足,可以采用最为先进的工艺,使用更高的时钟频率和更窄的数据通道。

    流水线

    所有当前先进的处理器都采用流水线结构来增加吞吐率。假如一条指令需要n个步骤才能完成执行,那么它需要n级流水线。当第一条指令开始执行第二个步骤时,一条新的指令可以开始执行第一个步骤,后续的指令依次不断进人流水线。当第一条指令完成n个步骤之后,每个时钟周期都会有一条指令执行完成。假如不使用流水线,那么需要等一条指令执行完之后才开始另一条指令,效率就只有原来的1/n。流水线的概念不仅适用于处理器,在许多系统中都有应用。一个PCIe IO扩展卡可以向主存储器发起读操作命令,该指令的操作需要一定的时间和操作步骤,扩展卡可以在前一条指令尚未完成时就发出后续的指令,以此来提高总线的吞吐率。设计者还可以利用此概念设计高速流水线结构的加法器和乘法器。当我们设计一个协议时,可以考虑采用流水线来增加吞吐率。

    并行处理

    并行处理与流水线不同,在并行处理中,会同时用到更多的资源。现代处理器中常常会同时存在多个线程,其中每一个线程以流水线方式工作。每条线程在一个时钟周期内执行一条指令或每秒钟执行m条指令。当有n条线程时,一秒内可以执行m x n条指令。

    并行处理过程可以用超级市场出口处的收银-打包台来类比。每个出口处需要两名工作人员,一个收银,一个进行商品装袋打包,两个人构成一条简单的流水线,多个收银-打包出口构成多个并行的线程。商场可以根据客流量调整出口的数量。

    无序执行(乱序执行)

    一个晴朗的周六早晨,我的妻子给我布置了六件无序的工作(列在一张纸上)。只要在一定时间内把六件事都完成她就会很开心。她并不关心我先做哪件事后做哪件事,除非它们前后有依赖关系。我看了看清单,记下了需要去的几个地方,列出了一个处理顺序,然后完 成它们。我重新将它们排序可以基于总路程最短,或根据我的喜好,把喜欢做的事放在最前面,讨厌的放在后面。此时处理顺序可能不是最有效率的,但我可能更喜欢这样做。

    不需要按照严格的顺序执行n项任务为在尽可能短的时间内完成全部任务提供了优化的可能,这也就增加了电路的吞吐率。SATA和SAS协议支持的NCQ(Native Command Queuing)就是这样一种优化技术。操作系统向磁盘发送一组读写操作命令,数据存储在磁盘中,根 读/写磁头和数据的相对位置,单个命令花费的时间是不同的,磁盘驱动电路分析所有的操作命令,根据一些算法(如最少搜寻算法)确定内部的执行顺序,从而提高整体读写效率。

    当前的处理器将指令分解成若干微代码,发送到指令池中。然后,微代码以无序的方式执行然而从外部看,这些指令完成的顺序和指令取出的顺序是相同的。例如,指令1和指令2两条指令先后进入指令池进行乱序执行,如果指令2的所有微代码都已执行完毕,但是指 令1中仍然有一条微代码尚未完成。在这种情况下,指令2必须等待指令1完成后才能完成并返冋执行结果。从整体上看,虽然存在内部等待,但以无序方式执行微代码可以提高整体效率,因此具有更高的吞吐率。

    另外一个是存储器控制器的例子。一个PCIe卡能够向主存储器发送多个存储器读操作命令。存储器控制器可以重新对存储器读操作命令进行排序(基于被读取数据所在的存储区域)。存储器控制器返回的读出数据的输出顺序和PCIe卡发岀的读操作命令的顺序可能不同,PCIe会确保系统的正常工作。如果PCIe卡在某些情况下需要保证读出顺序,那么它必须等待该数据被读出后才发出后续的操作命令。从整体上说,存储器控制器的这种乱序工作方式可以提高存储访问的吞吐率。

    高速缓存(cache)

    处理器经常利用cache来提高系统性能。系统启动之后,操作系统和用户程序从硬盘加载到内存(RAM)中。所有的命令都保留在RAM中,当处理器要执行某个指令时,它会从内存中读取该指令。类似地,处理器也会对RAM进行数据读写。理论上,这就是计算机的运行 方式,但是存在一个问题,那就是RAM的读写时间比较长,需要多个时钟周期(或者说指令周期)才能完成。

    为了改进性能,处理器使用一个容量较小的存储器,将部分指令和数据存入其中,这个更小的存储器称为cache(高速缓存)。高速缓存离CPU更近,运行速度更快,几乎和CPU内核的速度是一样的。当处理器需要读入指令和数据时,它会首先读取缓存而不是存储器。只 有当需要的指令和数据不在缓存中时,才会去内存中读取。这种方式可以减少内存访问的次数,提高系统性能。目前的高性能处理器中通常采用两级cache(L1 cache和L2 cache)。

    高速缓存的概念可以进行推广,当一个系统的两个部分在运行速度方面差别较大时,可以在快速设备和慢速设备之间插入cache,一些硬件设备,如硬盘等,读写速度相对较慢,此时硬盘驱动电路中可以使用一个本地缓存来存储从磁盘读取的数据,当读操作指令到达硬 盘驱动电路时,它能很快地从本地缓存中返回数据,而不是花费更长的时间读取磁盘中的数据。cache也用来提高写入的性能,当CPU向主存储区写数据时,它会花费很长的时间。这时CPU处于空置状态不能执行其他指令。此时可以设置一个写缓存,CPU将需要写入的数据写入cache中即可,此后CPU继续执行其他指令,驱动电路负责将cache中的数据以较低的速度写入存储器中。

    固态盘(Solid-State Drive),如Flash存储器的驱动电路中也使用本地缓存提高写和读的性能。固态盘的一个特点是读/擦除的次数是受限的。固态盘的写缓存在数据写入时先将数据缓存下来,向CPU发出ACK确认信息,然后再将数据写入存储器。采用写缓存还有一个优点,假如存在对同一个地址的多次写操作,那么固态盘驱动电路只将最后一个数据真正写入存储器中,这就减少了闪存写入的次数,提高了固态盘的使用寿命。

    cache并不只在硬件设i十中使用,在软件设计中也经常用到。搜索引擎在网络中查找并在本地存储所需要的信息,当用户进行网络搜索时.可以直接在搜索引擎所存储的数据中进行查找,而不是到Internet中进行搜索,这样就可以提高搜索速度。

    预读取

    数据预读取的含义是在缓存区中预先存入比当前需求更多的数据由于实际应用屮许多数据是连续存储和使用的,提前读入一些数据到缓存区中可以减少对存储介质的访问,从而提高读取速度。

    多核

    现代的处理器经常采用多核(例如,8核或16核)结构。每个核都是一个完整的CPU多个CPU能并行地进行数据处理。’

    在一个高性能存储器控制器中,可能存在多个DDR控制器,它们独立地连接不同的DDR存储器。同样,高性能的SSD控制器同时存在多个Flash控制器,它们也能独立地同时进行Flash读写。

    时延

    时延,如前所述,是从操作或命令开始执行到获得数据或结果的最短时间。时延和吞吐量是两个常用概念,是一个系统的两个不同方面。通常两者相互独立,但也存在着一些相互关联和影响。在同步通信中,时延决定着一个独立工作流的吞吐量。

    以CPU访问存储器为例,假如CPU希望从主存储器中读取数据,那么它会发出存储器读指令以读取64字节数据(64字行通常被称为一个cache line)。假如读取数据的前8字节耗时0.5us,那么时延就为0.5us。我们再举一个PCIe网卡从主存储器中以DMA方式读取数据的例子,该读操作大概需要2us时间,此时时延即为2us.如果PCIe网卡支持背靠背的存储器读操作,那么就能够增加吞吐量。此时,获得读取的第一个数据包需要2us,但是后来的数据包会连续到达。如果我们在一个相对较长的时间内连续进行数据读写,那么时延就不会对吞吐量产生明显的影响。

    在一些情况下,时延会影响到吞吐量。在使用一些具有互控机制的通信协议时(如处理器之间的通信),一些指令只有在收到完整的数据之后才能执行,此时吞吐率就会直接受到时延的影响。在这种情况下,我们需要尽量减小时延。另外,对于在线业务或计算机处理的 股票交易中,时延也是非常重要的。假如根据用户的查询要求,设备需从存储器中读取4K字节节的数据,那么系统设计者需要考虑尽可能快地返冋需要的数据,使得时延越小越好。

    降低时延的方法

    有没有降低时延的有效方法呢?毫无疑问是有的。在很多应用中需要使用FIFO(First In First Out,先入先出存储器),FIFO会引入时延。在FIFO中,先到达的数据会先被读出,如果写入端的速度高于读出端,FIFO的可用存储空间就会减小到零。如果一个对时延敏感的包到了一个FIFO队列中,由于其排列在FIFO队列中的后面,因此必须等前面的数据被读出后才能读出该数据,这就会带来时延。在进行芯片架构设计时,会常常用到异步FIFO进行跨时钟域数据传递,而有时采用简单的握手机制就可以进行跨时钟域的数据传递,这有利于减少延迟。

    芯片的时钟频率也会直接影响时延,对于同一个电路来说,时钟频率高时,可以更迅速地进行数据处理和操作。以PCIe交换电路为例,其目标是使输入的数据包快速地被交换到输出端。此时,使用高频内部时钟可以提高数据包转发速度并能够降低时延。

    在以太网交换电路或PCIe交换电路中,可以使用直接透明分组转发模式替代存储转发模式来降低时延。目前,在大多数应用中,数据以包的形式进行转发。在以太网交换电路中,当数倨包到达输入端后,先存储在缓冲区中。由于以太网帧中的CRC校验域在帧的末尾,在 接收数据的过程中,本地CRC校验电路一边接收数据,一边进行CRC校验计算,当完整的帧接收完毕后,将本地的CRC计算结果和接收的校验结果进行比较,如果二者相同,则接收此帧;如果不同,则丢弃此帧。

    根据CRC校验的工作机制,只有一个帧被完整地接收后才可以判断该帧是否存在错误,因此接收延迟与帧长有直接关系。采取存储转发机制时,对整个交换机而言,数据帧从输入到输出的时延与帧长冇关,对于整个系统而言,端到端的延迟还与数据帧所经过的交换机数量有关。

    采用直接透明分组转发模式时,交换电路可以在包到达输入端的时候就开始进行转发,这样可以大大降低时延。采用这种方式时,如果发生了CRC校验错误应该怎样处理呢?此时,可以将CRC检错功能放到终端中进行,当链路误码率非常低时,这种工作方式可以有效地降 低延迟。

    降低时延还有许多其他的方法,下面介绍其中的一种。例如,CPU需要读取存储器中从地址8到地址15的8字节数据。考虑到读取的效率,存储器控制器从存储器中连续取64字节(1个cache line),而不是8字节。此时,存储器控制器从地址0到地址63连续读出了64字节的数据。此后,存储器控制器可以将地址0到地址63的64字节交给CPU如果CPU希望快速读取字节8~15,存储器控制器可以从地址8开始读取数据,当地址到达63后,再读出地址0到地址7所存储的数据。

    5f9920b6e660b34e313177441734661e.gif

    NOW

    学习Xilinx FPGA最好的资料其实就是官方手册,下表总结了部分手册的主要介绍内容,关注我,持续更新中......

    文件名主标题内容简单介绍是否有中文版
    UG4767 Series FPGAs GTX/GTH  TransceiversGTX和GTH介绍,PCIe、serdes等学习必备
    UG4717 Series FPGAs SelectIO Resources描述 7 系列 FPGA 中可用的 SelectIO资源。
    UG1114PetaLinux Tools DocumentatonPetaLinux 工具文档 参考指南是,V2019.2
    UG949UltraFAST 设计方法指南(适用于 Vivado  Design Suite)赛灵思® UltraFast™  设计方法是用于为当今器件优化设计进程的一套最佳实践。这些设计的规模与复杂性需要执行特定的步骤与设计任务,从而确保设计每一个阶段的成功开展。依照这些步骤,并遵循最佳实践,将帮助您以最快的速度和最高的效率实现期望的设计目标是,V2018.1
    IP手册pg057FIFO GeneratorFIFO生成器IP使用手册
    pg104Complex Multiplier复数乘法器IP使用手册
    pg122RAM-Based Shift Register 移位寄存器IP使用手册

    d2ba026b2252ff5128df6feac6f07611.png

    推荐阅读

    【Vivado那些事】如何查找官网例程及如何使用官网例程

    【Vivado使用误区与进阶】总结篇

    【Vivado那些事】Vivado中常用的快捷键(二)其他常用快捷键

    SystemVerilog数字系统设计_夏宇闻 PDF

    图书推荐|ARM Cortex-M0 全可编程SoC原理及实现

    简谈:如何学习FPGA

    1202年了,还在使用虚拟机吗?Win10安装Ubuntu子系统及图形化界面详细教程

    Github 上有哪些优秀的 VHDL/Verilog/FPGA 项目

    AD936x+ZYNQ搭建收音机(一)

    AD936x+ZYNQ搭建OpenWIFI

    无招胜有招-Vivado非工程模式下的详细设计

    面试中经常会遇到的FPGA基本概念,你会几个?

    Xilinx FPGA MIPI 接口简单说明

    Vivado ML(机器学习) 2021尝鲜

    推荐一些可以获取免费的国外的原版书籍(电子版)网站

    【Vivado那些事】FPGA的配置方式

    FPGA 的重构

    浅析FPGA局部动态可重构技术

    ISP(图像信号处理)算法概述、工作原理、架构、处理流程

    国产CPU概括

    从电子游戏历史看IC发展的助推剂

    80年代电子游戏及电脑游戏的发展历史

    PCIe总线的基础知识

    万字长文带你回顾电子游戏的七十多年历史(完整版)

    FPGA中异步复位,同步释放的理解

    OpenFPGA系列文章总结

    用Verilog设计一个16 位 RISC 处理器

    介绍一些新手入门FPGA的优秀网站(新增)

    Verilog数字系统基础设计-CR

    FPGA 的布局规划艺术

    Verilog数字系统基础设计-奇偶校验

    建立和保持时间及时序简单理解

    (Xilinx)FPGA中LVDS差分高速传输的实现

    Xilinx Multiboot实例演示

    高速串行通信常用的编码方式-8b/10b编码/解码
    Verilog计时(微秒、毫秒和秒)脉冲的产生及同步整形电路

    再说System Verilog 与 Verilog 的关系

    图书推荐|一本图像/视频处理的强大工具书

    Verilog HDL-同步技术

    再说System Verilog 与 Verilog 的关系

    数模混合信号建模语言Verilog-AMS

    展开全文
  • 1.3.1 LE 1M PHY 最大数据吞吐率 1.3.2 LE 2M PHY 最大数据吞吐率 1.4 如何同步数据的生产与发送? 二、如何设置广播连接参数以满足低功耗需求? 更多文章: 我们开发的BLE 设备多数都有两点要求:一是低功耗,电池...

    我们开发的BLE 设备多数都有两点要求:一是低功耗,电池供电需要持续工作数周甚至数个月;二是将BLE peripheral产生的数据快速传送给central,传输数据功耗较高,提高传输速率缩短传输时间也有利于降低平均功耗。我们该如何设置广播参数与连接参数以达到我们要求的功耗呢?该如何设置连接参数与报文长度(PDU / MTU)以尽可能达到最大传输速率呢?

    一、如何提高BLE 数据传输速率?

    BLE 数据传输相关的服务中有一个比较基础的串口透传服务,本文以nRF5_SDK_17.0.2 中的ble_app_uart 工程为例,展示如何提高BLE 的数据传输速率。

    在尝试提高BLE 数据传输速率前,需要先获得两个信息:

    1. 当前使用的BLE 协议栈支持的理论最大数据吞吐率是多少?
    2. 如何获知当前的BLE 数据传输速率是多少?

    1.1 Nordic BLE 最大数据吞吐率是多少?

    对于第一个问题,我们可以从Nordic 协议栈规格说明书中获知,比如使用s132 softdevice 可以参考文档:S132 SoftDevice SoftDevice Specification v7.1,查阅Bluetooth Low Energy data throughput 章节,数据传输速率使用下面的公式:

    #define OPCODE_LENGTH        1
    #define HANDLE_LENGTH        2
    
    Throughput_bps = num_packets * (ATT_MTU - OPCODE_LENGTH - HANDLE_LENGTH) * 8 / seconds
    

    这里统计的传输数据指的是应用数据,ATT_MTU 减去Attribute protocol PDU Opcode 和Attribute Handle 字段长度,剩下的就是Attribute Value 字段(也即有效的应用数据)。每个字节占8 比特,下表中的传输速率单位是kbps(如果要换算成 KB/s 需要除以8),下表Connection interval 与Connection Event Length 相等:
    S132 softdevice data throughput
    从上表可知,跟传输速率相关的因素主要有ATT MTU size、Connection interval、Connection Event Length、Communication Mode、LE PHY speed 等。比如ATT MTU size 为23、Connection interval 与Connection Event Length 取7.5 ms、Communication Mode 为Send Notification、LE 1M PHY 的最大速率为24 KB/s;ATT MTU size 为247、Connection interval 与Connection Event Length 取50 ms、Communication Mode 为Send Notification、LE 2M PHY 的最大速率为165.94 KB/s。

    1.2 如何获知BLE 当前数据吞吐率?

    一般BLE peripheral 作为GATT Server 向BLE central 也即GATT Client 传输数据,想获得BLE 当前的数据吞吐率,一般有三种方式:

    1. BLE peripheral 端统计单位时间内发送出去的数据量;
    2. BLE central 端统计单位时间内接收到的数据量;
    3. BLE sniffer 抓取单位时间内传输的报文中有效数据量。

    Nordic 手机端的应用并没有提供显示当前数据吞吐率的功能,我们开发GATT Server 应用再去修改BLE central 代码比较麻烦。BLE sniffer 抓包分析倒是比较方便,wireshark + nRF sniffer 抓包方案容易丢包也没有直接统计数据吞吐率指标,专业的蓝牙分析仪Ellisys Bluetooth Explorer 倒是可以直接统计数据吞吐率,蓝牙分析仪成本太高。因此,本文选择第一种方案,在BLE peripheral 代码中添加统计数据发送量的功能,并通过RTT Log 打印出来。

    我们在.\nRF5_SDK_17.0.2_d674dde\examples\ble_peripheral\ble_app_uart 示例工程的基础上添加统计单位时间内数据发送量的代码,Nordic UART Service 我们在博文:如何实现扫码连接BLE 设备的功能? 中已经介绍过了,二者主要的代码逻辑差不多,主要有两点不同:

    • ble_app_uart 工程在GAP 阶段作为Advertiser,在函数advertising_init 中初始化广播包内容、广播间隔、广播超时时间等,然后在函数advertising_start 中开始广播;ble_app_uart_c 工程在GAP 阶段作为Scanner 和Initiator,在函数scan_init 中设置扫描过滤条件、注册scan_evt_handler 等,然后在函数scan_start 中开始扫描周围的广播设备;
    • ble_app_uart 工程在GATT 阶段作为GATT Server,在函数services_init --> ble_nus_init 中添加NUS service(包括RX Characteristic、TX Characteristic)、注册nus_data_handler 等,其中NUS 为Primary Service 对外提供串口透传服务;ble_app_uart_c 工程在GATT 阶段作为GATT Client,在函数db_discovery_init 和nus_c_init 中发现对端设备提供了哪些services(特别是NUS 服务)、注册db_disc_handler 和ble_nus_c_evt_handler 等,发现NUS 服务后就可以访问该服务了。

    本文就不展开介绍ble_app_uart 工程代码逻辑了,我们重点关心的是GATT Server 如何使用NUS 服务向GATT Client 发送数据。从函数uart_event_handle 代码可以看出,使用函数ble_nus_data_send 可以通过NUS 服务向对端设备发送数据,该函数的声明如下:

    // .\nRF5_SDK_17.0.2_d674dde\components\ble\ble_services\ble_nus\ble_nus.h
    
    /**@brief   Function for sending a data to the peer.
     *
     * @details This function sends the input string as an RX characteristic notification to the
     *          peer.
     *
     * @param[in]     p_nus       Pointer to the Nordic UART Service structure.
     * @param[in]     p_data      String to be sent.
     * @param[in,out] p_length    Pointer Length of the string. Amount of sent bytes.
     * @param[in]     conn_handle Connection Handle of the destination client.
     *
     * @retval NRF_SUCCESS If the string was sent successfully. Otherwise, an error code is returned.
     */
    uint32_t ble_nus_data_send(ble_nus_t * p_nus,
                               uint8_t   * p_data,
                               uint16_t  * p_length,
                               uint16_t    conn_handle);
    

    既然是统计单位时间内GATT Server 发送出去的数据量,自然需要一个定时器资源,我们选用低功耗的app_timer。为了提高数据发送速率,我们选择Send Notification 模式。为了少做无用功,我们在NUS Notification enable 的情况下再开始发送数据,当连接断开后便停止发送数据。新增用于统计BLE data throughput 的代码如下:

    // .\nRF5_SDK_17.0.2_d674dde\examples\ble_peripheral\ble_app_uart\main.c
    
    /**@brief Resources related to throughput testing.
     */
    #define DATA_THROUGHPUT_INTERVAL            APP_TIMER_TICKS(5)                   /**< data throughput interval (ticks). */
    APP_TIMER_DEF(m_timer_throughput_id);
    
    uint32_t m_data_sent_length = 0;
    uint8_t m_data_array[BLE_NUS_MAX_DATA_LEN] = {0};
    
    /**@brief Data generation timer timeout handler function.
     */
    static void data_throughput_timeout_handler(void * p_context)
    {
        UNUSED_PARAMETER(p_context);
        
        static uint32_t timeout_count = 0;
        ret_code_t err_code;
        
        timeout_count++;
    
        do
        {
            uint16_t length = BLE_NUS_MAX_DATA_LEN;
            err_code = ble_nus_data_send(&m_nus, m_data_array, &length, m_conn_handle);
            if ((err_code != NRF_ERROR_INVALID_STATE) &&
                (err_code != NRF_ERROR_RESOURCES) &&
                (err_code != NRF_ERROR_NOT_FOUND))
            {
                APP_ERROR_CHECK(err_code);
            }
    
            if(err_code == NRF_SUCCESS)
            {
                m_data_sent_length += length;
                m_data_array[0]++;
                m_data_array[length-1]++;
            }
        } while (err_code == NRF_SUCCESS);
    
        // Timer interval 5 ms, when the timer reaches 1 second 
        if(timeout_count == 200)
        {
            // Send m_data_sent_length bytes of data within 1 second, which is equal to m_data_sent_length * 8 / 1024 kilobits of data
            NRF_LOG_INFO("****** BLE data throughput: %d kbps ******", m_data_sent_length >> 7);
            m_data_sent_length = 0;
            timeout_count = 0;
        }
    }
    
    /**@brief Function for initializing the timer module.
     */
    static void timers_init(void)
    {
        ......
        // Create a data generation timer for testing throughput.
        err_code = app_timer_create(&m_timer_throughput_id, 
                                    APP_TIMER_MODE_REPEATED, 
                                    data_throughput_timeout_handler);
        APP_ERROR_CHECK(err_code);
    }
    
    /**@brief Function for handling the data from the Nordic UART Service.
     */
    static void nus_data_handler(ble_nus_evt_t * p_evt)
    {
    
        if (p_evt->type == BLE_NUS_EVT_RX_DATA) {
            ......
        } else if(p_evt->type == BLE_NUS_EVT_COMM_STARTED) {
            // Start data throughput timers.
            ret_code_t err_code;
            err_code = app_timer_start(m_timer_throughput_id, 
                                       DATA_THROUGHPUT_INTERVAL,
                                       NULL);
            APP_ERROR_CHECK(err_code);
        }
    }
    
    /**@brief Function for handling BLE events.
     */
    static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
    {
        uint32_t err_code;
    
        switch (p_ble_evt->header.evt_id)
        {
            case BLE_GAP_EVT_CONNECTED:
                ......
            case BLE_GAP_EVT_DISCONNECTED:
                ......
                // Stop data throughput timers.
                err_code = app_timer_stop(m_timer_throughput_id);
                APP_ERROR_CHECK(err_code);
                break;
    
            case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
            ......
        }
    }
    

    上述代码主要包含两部分:

    1. app_timer 资源的创建、开始与结束,包括超时回调函数的注册。当NUS Notification enable 事件发生时开始定时器,当连接断开时停止定时器;
    2. 超时回调函数data_throughput_timeout_handler 的实现,主要有两个任务:一是调用函数ble_nus_data_send 发送数据(参照函数uart_event_handle 内调用函数ble_nus_data_send 并检查返回值的代码,仅当返回NRF_SUCCESS 时才计入已发送数据);二是通过RTT Log 打印1 秒内发送出去的数据量。

    值得一提的是,每个定时周期可以发送不止一个数据包,博文链路层空口报文设计 中提到LE 1M PHY 发送最大PDU 约需2.3 ms,上面的代码设置的定时周期为5 ms,因此每个定时周期可以发送多个数据包,我们将ble_nus_data_send 放到循环体内,当返回值为NRF_SUCCESS 时继续循环发送下一个数据包。

    通过RTT Log 打印当前BLE 数据吞吐量的代码已经实现了,编译工程 --> 将代码烧录到nRF52 DK 内,PC 端打开J-Link RTT Viewer,手机端打开nRF Connect for mobile。点击Enable CCCDs 或者Tx Characteristic 右边的图标使能NUS Notification,nRF52 DK 开始通过BLE 向手机端发送数据,nRF Connect --> Show log 可以查看接收到的数据,J-Link RTT Viewer 开始打印当前的BLE 数据吞吐率:
    RTT Log 打印BLE 数据吞吐量

    1.3 如何提高BLE 数据传输速率?

    上图展示的BLE 数据吞吐率只有41 kbps,远低于nordic softdevice 支持的最大数据吞吐率,这是怎么回事呢?

    BLE 数据吞吐率的计算公式:

    Throughput_kbps = num_packets * (ATT_MTU - 3) * 8 / 1000				// num_packets 为单位时间也即 1 秒内发送的数据包个数
    				= (num_packets_interval / CONN_INTERVAL) * (ATT_MTU - 3) * 8 / 1000			// num_packets_interval 为单个连接间隔内发送的数据包个数,CONN_INTERVAL 为连接间隔,单位是秒
    

    1.3.1 LE 1M PHY 最大数据吞吐率

    上述工程默认的ATT_MTU 值为247,CONN_INTERVAL 为20 ~ 75 ms,由Throughput_kbps 等于41 kbps 可反推出num_packets_interval 等于1(CONN_INTERVAL 取中间值47.5 ms)。一个连接间隔只发送出去一个数据包,这大概是BLE 数据吞吐率这么低的主要原因吧,该如何提高BLE Throughput_kbps 呢?
    BLE Connection event
    前面也谈到,影响BLE Throughput_kbps 的因素主要有ATT MTU size、Connection interval、Connection Event Length、Communication Mode、LE PHY speed 等,ATT MTU size 已经设置为BLE 支持的最大值247,Connection Event 值为7.5 ms,也即一个连接周期最多只有Connection Event 时间传输数据,这个值远小于Connection interval,我们需要让Connection Event 占满Connection interval。为便于跟nordic softdevice 规格说明书中的值对比,这里设置连接参数如下:

    // .\nRF5_SDK_17.0.2_d674dde\examples\ble_peripheral\ble_app_uart\main.c
    #define MIN_CONN_INTERVAL               MSEC_TO_UNITS(50, UNIT_1_25_MS)             /**< Minimum acceptable connection interval (20 ms), Connection interval uses 1.25 ms units. */
    #define MAX_CONN_INTERVAL               MSEC_TO_UNITS(50, UNIT_1_25_MS)             /**< Maximum acceptable connection interval (75 ms), Connection interval uses 1.25 ms units. */
    
    // .\nRF5_SDK_17.0.2_d674dde\examples\ble_peripheral\ble_app_uart\pca10040\s132\config\sdk_config.h
    #define NRF_SDH_BLE_GAP_EVENT_LENGTH 40				// The time set aside for this connection on every connection interval in 1.25 ms units.
    
    #define NRF_SDH_BLE_GAP_DATA_LENGTH 251
    #define NRF_SDH_BLE_GATT_MAX_MTU_SIZE 247
    

    编译工程 --> 烧录到nRF52 DK,J-Link RTT Viewer 打印RTT Log 信息如下:
    RTT Log NRF_ERROR_NO_MEM
    在执行函数sd_ble_enable 时返回NRF_ERROR_NO_MEM,也即分配给softdevice 的RAM 空间不足,需要为softdevice 预留更多的空间(也即缩减application 可用RAM 空间)。我们按照RTT Log 调整RAM_Start 和RAM_Size 如下:
    调整RAM_START与RAM_SIZE
    重新编译工程并烧录代码,nRF Connect for mobile 使能notification 或CCCDs,J-Link RTT Viewer 打印的BLE 数据吞吐率如下:
    RTT Log BLE data throughput 2
    BLE 最大数据吞吐率已经达到697 kbps了,很接近nordic softdevice 规格说明书中的702.8 kbps(也即87.85 KB/s),多打印会儿是可以看到BLE data throughput 达到七百以上的,BLE 数据传输速率达到了softdevice 支持的最大值。

    如果已知Throughput_kbps 值为702.8 kbps,ATT_MTU 值为247,CONN_INTERVAL 值为50 ms,可以通过公式反求出单个连接间隔内发送出去的数据包个数为18,也即每个数据包以send notification 模式发送出去所需的平均时间为2.78 ms(包括radio 启动和切换时间、协议栈调度时间等)。

    1.3.2 LE 2M PHY 最大数据吞吐率

    从nordic softdevice 规格说明书可知,还可以使用BLE 5.0 新增的LE 2M PHY 特性进一步提高数据吞吐率。链路层使用LE 2M PHY,可以在更短的时间发送完等长度的数据包,也即在一个连接间隔可以发送更多的数据包,实现更大的传输速率。

    当Connection interval 与Connection event 均为50 ms,ATT_MTU size 为247,采用Send Notification 通信模式和LE 2M PHY 物理链路,可以达到的Throughput_kbps 值为1327.5 kbps,通过公式可反求出单个连接间隔内发送出去的数据包个数为34,也即每个数据包以send notification 模式发送出去所需的平均时间为1.47 ms(由于radio 启动与切换时间、协议栈调度时间基本固定,因此发送单个数据包使用LE 2M PHY 比LE 1M PHY 所需时间的一半略多)。如何启用LE 2M PHY 呢?

    前面通过修改宏变量值就可以更新Data Length 和Connection Parameters,这些更新过程在链路层有相应的控制报文交互(参阅博文:Link Layer Control Protocol),对于PHY Update 也有对应的链路层控制报文交互。
    上述工程ble_app_uart 代码中跟PHY Update 相关的主要代码如下:

    // .\nRF5_SDK_17.0.2_d674dde\examples\ble_peripheral\ble_app_uart\main.c
    /**@brief Function for handling BLE events.
     */
    static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
    {
        uint32_t err_code;
    
        switch (p_ble_evt->header.evt_id)
        {
            ......
            case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
            {
                NRF_LOG_DEBUG("PHY update request.");
                ble_gap_phys_t const phys =
                {
                    .rx_phys = BLE_GAP_PHY_AUTO,
                    .tx_phys = BLE_GAP_PHY_AUTO,
                };
                err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
                APP_ERROR_CHECK(err_code);
            } break;
            ......
        }
    }
    
    // .\nRF5_SDK_17.0.2_d674dde\components\softdevice\s132\headers\ble_gap.h
    /**@defgroup BLE_GAP_PHYS GAP PHYs
     * @{ */
    #define BLE_GAP_PHY_AUTO                         0x00    /**< Automatic PHY selection. Refer @ref sd_ble_gap_phy_update for more information.*/
    #define BLE_GAP_PHY_1MBPS                        0x01    /**< 1 Mbps PHY. */
    #define BLE_GAP_PHY_2MBPS                        0x02    /**< 2 Mbps PHY. */
    #define BLE_GAP_PHY_CODED                        0x04    /**< Coded PHY. */
    #define BLE_GAP_PHY_NOT_SET                      0xFF    /**< PHY is not configured. */
    
    /**@brief Supported PHYs in connections, for scanning, and for advertising. */
    #define BLE_GAP_PHYS_SUPPORTED  (BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_2MBPS) /**< All PHYs except @ref BLE_GAP_PHY_CODED are supported. */
    

    上面的代码是处理BLE_GAP_EVT_PHY_UPDATE_REQUEST 事件的,从BLE_GAP_PHYS_SUPPORTED 可以看出nRF52 DK 是支持BLE_GAP_PHY_2MBPS 的,变量phys 的值如果设置为BLE_GAP_PHY_1MBPS 或BLE_GAP_PHY_2MBPS 则强制选择相应的PHY,上述代码phys 设置为BLE_GAP_PHY_AUTO 则会自动选择当前最合适的PHY。如果在BLE central 端请求使用LE 2M PHY,BLE peripheral 端也会更新到LE 2M PHY(前提是BLE central 端与peripheral 端均支持LE 2M PHY,且peripheral 端未强制指定PHY)。

    手机端是否支持LE 2M PHY,可以从nRF connect for mobile --> Device information 界面查看“High speed(PHY 2M) supported” 项为“YES” 表示支持LE 2M PHY。nRF connect for mobile 连接到nRF52 DK 广播名NORDIC_UART 后,点击“Enable CCCDs”使能NUS Notification,点击"Set preferred PHY" Tx/Rx PHY 均选择“LE 2M(Double speed)”。PC 端J-Link RTT Viewer 打印的BLE 数据吞吐率如下:
    LE 2M PHY 数据吞吐率
    我们看到了很奇怪的现象,理论上切换到LE 2M PHY,BLE 数据吞吐率应该提高近一倍的,实际情况却是大幅下降,这是怎么回事呢?

    我们也是在每个定时周期循环发送数据包,直到函数ble_nus_data_send 的返回值不为NRF_SUCCESS 或者函数data_throughput_timeout_handler 被更高优先级的中断抢占(协议栈softdevice 事件的优先级高于application 中断的优先级)。同样的代码LE 1M PHY 可以接近最大数据吞吐率,切换到LE 2M PHY 数据吞吐率反而下降了,我们可以合理猜测循环发送数据包的过程出问题了,也即函数ble_nus_data_send 的返回值不是NRF_SUCCESS 而过早的退出了循环。该如何验证并解决该问题呢?

    这里选用的Send Notification 通信模式,server 可以连续向Client 发送多个数据包而不需要等待response 或Confirmation 报文(Client 可能来不及处理数据包而直接丢弃),因此可以达到较高的数据吞吐率:
    BLE notification
    调用函数ble_nus_data_send,实际上是将应用层待发送数据指针传给softdevice 协议栈,放入到radio FIFO 中,当radio 将数据包成功发送出去后,softdevice 协议栈会返回BLE_GATTS_EVT_HVN_TX_COMPLETE 事件通知应用层数据包已成功发送出去。NUS 服务则会返回BLE_NUS_EVT_TX_RDY 事件通知应用层数据包已通过NUS 服务成功发送出去。

    前面的问题既然猜测是由函数ble_nus_data_send 返回值非NRF_SUCCESS 而过早退出循环导致每个定时周期发送的数据包太少引起的,我们可以在每次触发BLE_NUS_EVT_TX_RDY 事件时再次循环调用函数ble_nus_data_send 发送下一个数据包。每成功发送一个数据包触发一次BLE_NUS_EVT_TX_RDY 事件,调用一次函数ble_nus_data_send,理论上应该能解决上述问题,我们添加如下代码:

    // .\nRF5_SDK_17.0.2_d674dde\examples\ble_peripheral\ble_app_uart\main.c
    
    /**@brief Function for handling the data from the Nordic UART Service.
     */
    static void nus_data_handler(ble_nus_evt_t * p_evt)
    {
    
        if (p_evt->type == BLE_NUS_EVT_RX_DATA) {
            ......
        } else if(p_evt->type == BLE_NUS_EVT_COMM_STARTED) {
            // Start data throughput timers.
            ......
        } else if (p_evt->type == BLE_NUS_EVT_TX_RDY) {
            ret_code_t err_code;
            
            do {
            	uint16_t length = BLE_NUS_MAX_DATA_LEN;
                err_code = ble_nus_data_send(&m_nus, m_data_array, &length, m_conn_handle);
                if ((err_code != NRF_ERROR_INVALID_STATE) &&
                    (err_code != NRF_ERROR_RESOURCES) &&
                    (err_code != NRF_ERROR_NOT_FOUND))
                {
                    APP_ERROR_CHECK(err_code);
                }
            
                if(err_code == NRF_SUCCESS)
                {
                    m_data_sent_length += length;
                    m_data_array[0]++;
                    m_data_array[length-1]++;
                }
            } while (err_code == NRF_SUCCESS);
        }
    }
    

    重新编译工程并烧录代码,nRF Connect for mobile 点击“Enable CCCDs”使能NUS Notification,点击"Set preferred PHY" Tx/Rx PHY 均选择“LE 2M(Double speed)”,J-Link RTT Viewer 打印的BLE 数据吞吐率如下:
    LE 2M PHY 最大吞吐率
    切换到LE 2M PHY 后,BLE 数据吞吐率果然大幅提升,上图显示吞吐率可以达到1220 kbps (也即152.5 KB/s),已经比较接近nordic softdevice 支持的最大吞吐率1327.5 kbps 了,多打印会儿是可以看到BLE data throughput 达到一千三以上的,BLE 数据传输速率达到了softdevice 支持的最大值。

    1.4 如何同步数据的生产与发送?

    前面的代码直接对数组首尾字节自增后发送,实际应用场景中都是将断开连接期间暂时保存在本设备的数据或者sensor 实时产生的数据,在BLE 建立连接后分包发送给BLE Central 设备。如何保证数据包的有序发送呢?

    我们很容易想到,可以借助FIFO 缓冲队列实现数据包的有序发送,这里使用nordic 提供的queue 库,生产出来的待发送数据有序入队,要发送的数据从队列中取用即可。

    我们将上述持续发送BLE 数据包的代码修改为使用queue 的形式,首先需要将目录 .\nRF5_SDK_17.0.2_d674dde\components\libraries\queue 下的源文件和头文件路径添加进工程中,再在main.c 文件中包含"nrf_queue.h" 头文件,在main.c 中添加或修改如下代码:

    // .\nRF5_SDK_17.0.2_d674dde\examples\ble_peripheral\ble_app_uart\main.c
    ......
    #include "nrf_queue.h"
    ......
    #define QUEUE_ELEMENT_NUMBERS               32
    #define PKGS_PER_TIMER_PERIOD               8
    
    uint8_t m_data_array[QUEUE_ELEMENT_NUMBERS][BLE_NUS_MAX_DATA_LEN] = {0};
    typedef struct
    {
        uint8_t * p_data;
        uint16_t length;
    } m_element_t;
    
    NRF_QUEUE_DEF(m_element_t, m_buf_queue, QUEUE_ELEMENT_NUMBERS, NRF_QUEUE_MODE_NO_OVERFLOW);
    ......
    /**@brief Use queue to send ble data.
     */
    void ble_data_send_with_queue(void)
    {
        ret_code_t err_code;
        m_element_t data_item;
        uint16_t length = BLE_NUS_MAX_DATA_LEN;
    
        while(!nrf_queue_is_empty(&m_buf_queue))
        {
            err_code = nrf_queue_pop(&m_buf_queue, &data_item);
            APP_ERROR_CHECK(err_code);
    
            length = MIN(length, data_item.length);
            err_code = ble_nus_data_send(&m_nus, data_item.p_data, &length, m_conn_handle);
            if ((err_code != NRF_ERROR_INVALID_STATE) &&
                (err_code != NRF_ERROR_RESOURCES) &&
                (err_code != NRF_ERROR_NOT_FOUND))
            {
                APP_ERROR_CHECK(err_code);
            }
            if(err_code == NRF_SUCCESS)
                m_data_sent_length += length;
            else
                break;
        }
    }
    
    /**@brief Data generation timer timeout handler function.
     */
    static void data_throughput_timeout_handler(void * p_context)
    {
        UNUSED_PARAMETER(p_context);
        
        static uint32_t timeout_count = 0;
        ret_code_t err_code;
    
        static uint8_t value = 0;
        m_element_t data_item;
        uint16_t length = BLE_NUS_MAX_DATA_LEN;
        uint8_t pkgs = PKGS_PER_TIMER_PERIOD;
        
        timeout_count++;
    
        while (!nrf_queue_is_full(&m_buf_queue) && pkgs--)
        {
            m_data_array[value % QUEUE_ELEMENT_NUMBERS][0] = value;
            m_data_array[value % QUEUE_ELEMENT_NUMBERS][length-1] = value;
    
            data_item.p_data = &m_data_array[value % QUEUE_ELEMENT_NUMBERS][0];
            data_item.length = length;
    
            err_code = nrf_queue_push(&m_buf_queue, &data_item);
            APP_ERROR_CHECK(err_code);
    
            value++;
        }
    
        ble_data_send_with_queue();
    
        // Timer interval 5 ms, when the timer reaches 1 second 
        if(timeout_count == 200)
        {
            // Send m_data_sent_length bytes of data within 1 second, which is equal to m_data_sent_length * 8 / 1024 kilobits of data
            NRF_LOG_INFO("****** BLE data throughput: %d kbps ******", m_data_sent_length >> 7);
            m_data_sent_length = 0;
            timeout_count = 0;
            value = 0;
        }
    }
    ......
    /**@brief Function for handling the data from the Nordic UART Service.
     */
    static void nus_data_handler(ble_nus_evt_t * p_evt)
    {
    
        if (p_evt->type == BLE_NUS_EVT_RX_DATA) {
            ......
        } else if(p_evt->type == BLE_NUS_EVT_COMM_STARTED) {
            ......
        } else if(p_evt->type == BLE_NUS_EVT_TX_RDY) {
            ble_data_send_with_queue();
        }
    }
    

    使用queue 同步数据的产生与发送,队列未满时将生产的数据入队,队列非空时从队列中取出下一个元素通过调用函数ble_nus_data_send 将其发送出去。

    编译工程报错,提示nrf_queue 函数未定义,我们需要在sdk_config.h 文件中启用NRF_QUEUE 模块相关的宏变量如下:

    // .\nRF5_SDK_17.0.2_d674dde\examples\ble_peripheral\ble_app_uart\pca10040\s132\config\sdk_config.h
    
    #define NRF_QUEUE_ENABLED 1
    

    重新编译工程并烧录代码,nRF Connect for mobile 点击“Enable CCCDs”使能NUS Notification,点击"Set preferred PHY" Tx/Rx PHY 均选择“LE 2M(Double speed)”,J-Link RTT Viewer 打印的BLE 数据吞吐率如下:
    use queue measure ble data throughput
    使用queue 同步数据产生与发送,PHY 使用LE 1M 时最大数据吞吐率为726 kbps,PHY 切换到LE 2M 时最大数据吞吐率为1334 kbps,均略高于nordic softdevice 支持的最大值,达到了我们预期的效果。

    二、如何设置广播连接参数以满足低功耗需求?

    我们开发的BLE peripheral 多数都有低功耗要求,由电池供电,如何满足电池续航需求呢?

    Nordic 提供了nRF 芯片理论功耗计算网页Online Power Profiler for BLE,我们可以在该页面修改参数,看理论功耗是否满足我们的设计要求。如果已经试产出产品了,也可以借助Power Profiler KitPower Profiler Kit II 测量产品的真实功耗。

    假设我们使用CR2032 纽扣电池(额定容量为220 mAh,额定电压3.0 V)供电,使用寿命一年,每天平均连接两个小时,其余时间处于idle 空闲状态,我们该如何设置广播参数与连接参数,以满足我们的设计续航要求呢?

    假设我们选用nRF52832 芯片,Idle current 为2 uA,全年待机共消耗电量 = 365 * 24 * 2 uAh = 17.52 mAh。在产品寿命期间,BLE 连接通信时间约730 小时,可供BLE 连接消耗的电量约200 mAh,BLE 连接的平均功耗为274 uA。电池并不仅仅为BLE 通信供电,还为必要的传感器与外设工作供电,考虑到传感器与外设工作的时间比BLE 连接通信的时间更长,我们假设仅电池电量的1/3 供BLE 广播连接通信使用,其余2/3 为传感器和芯片外设工作供电,因此BLE 广播连接通信的平均功耗应控制在90 uA 左右。我们在Online Power Profiler for BLE 页面配置如下参数:
    BLE Advertising interval
    芯片选择nRF52832、CR2032 的额定电压为3.0 V、穿戴设备Radio Tx Power 选择 0 dBm 可以满足传输距离需求(可根据BLE 在空气中的路径损耗公式,结合通讯距离要求选择合适的Tx Power)。

    DC/DC regulator 是一种效率很高的稳压器,原理是DC->AC->DC,既可以升压也可以降压。与之相比,还有一种低成本的LDO (Low Dropout regulator) 稳压器,效率比DC/DC 低些,只能降压使用且对输入输出电压差有限制。如果想达到更低的功耗,可以选择DC/DC,如果想进一步降低成本,可以选择LDO。这里我们选择更高效率的DC/DC regulator。

    BLE 芯片通常需要两个时钟信号,比如nRF52 DK 上高频晶振频率为32 MHz、低频晶振频率为32.768 KHz,高频晶振驱动MCU 和高速外设工作,低频晶振可以大幅降低芯片的待机功耗(idle 或sleep 状态耗电的高频时钟关闭,仅保留低频时钟方便计时和唤醒)。高频时钟信号都需要外部晶振提供,低频时钟信号既可以外部晶振提供也可以使用MCU 内部的RC 振荡器获得。如果使用MCU 内部的RC 振荡器作为低频时钟则需要定期对其进行校准,需要大概 1.0 uA 的校准电流,且时钟精度略低些(较低的时钟精度也会增加BLE 通讯功耗)。

    配置低频时钟信号的代码如下(工程ble_app_uart 默认选择的外部晶振作为低频时钟信号,若想选择MCU 内部振荡器作为低频时钟,修改sdk_config.h 中如下的四个宏变量值即可,本文选择默认的外部晶振):

    // .\nRF5_SDK_17.0.2_d674dde\components\softdevice\common\nrf_sdh.c
    
    /**@brief Function for requesting to enable the SoftDevice, is called in the function ble_stack_init.
     */
    ret_code_t nrf_sdh_enable_request(void)
    {
        ......
        nrf_clock_lf_cfg_t const clock_lf_cfg =
        {
            .source       = NRF_SDH_CLOCK_LF_SRC,
            .rc_ctiv      = NRF_SDH_CLOCK_LF_RC_CTIV,
            .rc_temp_ctiv = NRF_SDH_CLOCK_LF_RC_TEMP_CTIV,
            .accuracy     = NRF_SDH_CLOCK_LF_ACCURACY
        };
        ......
    }
    
    // .\nRF5_SDK_17.0.2_d674dde\examples\ble_peripheral\ble_app_uart\pca10040\s132\config\sdk_config.h
    ......
    // <h> Clock - SoftDevice clock configuration
    //==========================================================
    // <o> NRF_SDH_CLOCK_LF_SRC  - SoftDevice clock source.
     
    // <0=> NRF_CLOCK_LF_SRC_RC 
    // <1=> NRF_CLOCK_LF_SRC_XTAL 
    // <2=> NRF_CLOCK_LF_SRC_SYNTH 
    
    #ifndef NRF_SDH_CLOCK_LF_SRC
    #define NRF_SDH_CLOCK_LF_SRC 1
    #endif
    
    // <o> NRF_SDH_CLOCK_LF_RC_CTIV - SoftDevice calibration timer interval. 
    #ifndef NRF_SDH_CLOCK_LF_RC_CTIV
    #define NRF_SDH_CLOCK_LF_RC_CTIV 0
    #endif
    
    // <o> NRF_SDH_CLOCK_LF_RC_TEMP_CTIV - SoftDevice calibration timer interval under constant temperature. 
    // <i> How often (in number of calibration intervals) the RC oscillator shall be calibrated
    // <i>  if the temperature has not changed.
    
    #ifndef NRF_SDH_CLOCK_LF_RC_TEMP_CTIV
    #define NRF_SDH_CLOCK_LF_RC_TEMP_CTIV 0
    #endif
    
    // <o> NRF_SDH_CLOCK_LF_ACCURACY  - External clock accuracy used in the LL to compute timing.
     
    // <0=> NRF_CLOCK_LF_ACCURACY_250_PPM 
    // <1=> NRF_CLOCK_LF_ACCURACY_500_PPM 
    // <2=> NRF_CLOCK_LF_ACCURACY_150_PPM 
    // <3=> NRF_CLOCK_LF_ACCURACY_100_PPM 
    // <4=> NRF_CLOCK_LF_ACCURACY_75_PPM 
    // <5=> NRF_CLOCK_LF_ACCURACY_50_PPM 
    // <6=> NRF_CLOCK_LF_ACCURACY_30_PPM 
    // <7=> NRF_CLOCK_LF_ACCURACY_20_PPM 
    // <8=> NRF_CLOCK_LF_ACCURACY_10_PPM 
    // <9=> NRF_CLOCK_LF_ACCURACY_5_PPM 
    // <10=> NRF_CLOCK_LF_ACCURACY_2_PPM 
    // <11=> NRF_CLOCK_LF_ACCURACY_1_PPM 
    
    #ifndef NRF_SDH_CLOCK_LF_ACCURACY
    #define NRF_SDH_CLOCK_LF_ACCURACY 7
    #endif
    

    BLE 广播通信阶段作为Advertising(connectable) role,假设TX payload 为31 bytes,当设置Advertising interval 为160 ms 时,Total average current 为87 uA,可满足我们的功耗需求,我们可以设置如下的宏变量(将Advertising interval 设置为160 ms):

    // .\nRF5_SDK_17.0.2_d674dde\examples\ble_peripheral\ble_app_uart\main.c
    ......
    #define APP_ADV_INTERVAL                256                                          /**< The advertising interval (in units of 0.625 ms. This value corresponds to 160 ms). */
    #define APP_ADV_DURATION                18000                                       /**< The advertising duration (180 seconds) in units of 10 milliseconds. */
    ......
    

    BLE 连接通信阶段作为Connection(peripheral) role,启用Data Packet Length Extension 和Connection Event Length Extension,假设TX payload per event 和RX payload per event 均为251 bytes,选择LE 1M PHY,我们在Online Power Profiler for BLE 页面配置如下参数:
    BLE connection interval and slave latency
    我们配置较小的Connection interval 可以在BLE peripheral 有数据传输需求时及时通知BLE central,配置较大的Slave latency 可以让BLE peripheral 在没有数据传输需求时跳过一定的连接事件以降低功耗。我们配置Connection interval 为25 ms、Slave latency 为 14 时,Total average current 为89 uA,可满足我们的功耗需求,我们可以设置如下的宏变量:

    // .\nRF5_SDK_17.0.2_d674dde\examples\ble_peripheral\ble_app_uart\main.c
    ......
    #define MIN_CONN_INTERVAL               MSEC_TO_UNITS(20, UNIT_1_25_MS)             /**< Minimum acceptable connection interval (20 ms), Connection interval uses 1.25 ms units. */
    #define MAX_CONN_INTERVAL               MSEC_TO_UNITS(30, UNIT_1_25_MS)             /**< Maximum acceptable connection interval (30 ms), Connection interval uses 1.25 ms units. */
    #define SLAVE_LATENCY                   14                                           /**< Slave latency. */
    #define CONN_SUP_TIMEOUT                MSEC_TO_UNITS(4000, UNIT_10_MS)             /**< Connection supervisory timeout (4 seconds), Supervision Timeout uses 10 ms units. */
    ......
    

    本工程源码下载地址:https://github.com/StreamAI/Nordic_nRF5_Project/tree/main/examples/ble_peripheral\ble_app_uart

    更多文章:

    展开全文
  • 怎么提高吞吐率

    2021-08-03 11:26:27
    1、吞吐率的概念: 数字电路单位时间内传输数据的量或单位时间完成的工作量。吞吐率有时候可以和性能、带宽互换使用。对于CPU来说,吞吐率定义为单位时间内能够执行的指令数。对于DDR存储器而言,吞吐率定义为从...

    1、吞吐率的概念:
    数字电路单位时间内传输数据的量或单位时间完成的工作量。吞吐率有时候可以和性能、带宽互换使用。对于CPU来说,吞吐率定义为单位时间内能够执行的指令数。对于DDR存储器而言,吞吐率定义为从存储器中写入或者读取的数据量。
    2、措施
    (1)更高的频率
    (2)更宽的数据通道
    (3)流水线
    (4)并行处理
    (5)无序执行(乱序执行)
    (6)高速缓存
    (7)预读取
    (8)多核

    展开全文
  • 流水线吞吐率和效率

    千次阅读 2021-01-22 23:05:55
    流水线吞吐率 = 指令数 / 指令总执行时间 = 4 / (6t + 3 * 3t) = 4/15t 流水线最大吞吐率 近似于 1/流水线周期 流水线效率 = 实际使用时空区/总时空区 = 4 * 6t/ 4 * 15t = 2/5 题目出自希赛网

    在这里插入图片描述
    流水线吞吐率 = 指令数 / 指令总执行时间 = 4 / (6t + 3 * 3t) = 4/15t

    流水线最大吞吐率 近似于 1/流水线周期

    流水线效率 = 实际使用时空区/总时空区 = 4 * 6t/ 4 * 15t = 2/5
    在这里插入图片描述
    题目出自希赛网

    展开全文
  • 它是衡量网络性能的重要指标,通常情况下,吞吐率用“字节数/秒”来衡量,当然,可以用“请求数/秒”和“页面数/秒”来衡量。其实,不管是一个请求还是一个页面,它的本质都是在网络上传输的数据,那么来表示数据的...
  • 一条指令流水线被分为k段,每一段时间都为Δt\Delta tΔt,连续输入n条...吞吐率记作TPTPTP: TP=nTk=nkΔt+(n−1)Δt TP= \frac{n}{T_k}=\frac{n}{k\Delta t+(n-1)\Delta t} TP=Tk​n​=kΔt+(n−1)Δtn​ n个任务.
  • 吞吐率 是指单位时间内流水线所完成的任务数量或输出的结果数量。 上图为例。 指令条数 = 100,流水线执行时间 = 203 吞吐率 = 100/203 最大吞吐率 理想状态的情况。忽略流水线建立时间,建立之后每个流水线周期...
  • 流水线吞吐率计算

    2021-03-30 20:01:52
  • 吞吐率一般分为实际吞吐率和最大吞吐率,下面我从两个案例来分别讲述: 实际吞吐率 按照上面的公式,指令条数为8条,流水线时间=(1+2+3+1) + (8-1) * 3=28,结果就显而易见是C了 最大吞吐率 我们列个一元二次...
  • 故我们需要在我们的业务功能中加上吞吐率吞吐率 < QPS)的限制, 当达到限制时让当前的请求等待到下一个可执行时间段执行。 吞吐率实现 吞吐率的限制是当前时段内(1S内)最多能处理的任务数量,超过限制必须...
  • 吞吐率: 单位时间内通过某个网络(或信道、接口)的数据量。 如果 测试工具: iperf (iperf 是一个网络性能测试工具)、Magic iPerf ,其实它就是iperf。 测试准备工作: wifi使用的板子、一台手机。板子需要...
  • 吞吐率是服务器并发处理能力的量化描述,单位是reqs/s,指的是某个并发用户数下单位时间内处理的请求数。 某个并发用户数下单位时间内能处理的最大的请求数,称之为最大吞吐率。 QPS、每秒查询率(Query Per Second...
  • 主要以下四点: 带宽、延时、吞吐率、PPS(Packet Per Second) 1.带宽 表示链路的最大传输速率,单位是 b/s (比特 / 秒),带宽越大,其传输能力就越强。 2.延时 表示请求数据包发送后,收到对端响应,所需要的时间...
  • 响应时间、并发用户数、吞吐率: 未到达最大并发用户数之前,在响应时间不变,系统吞吐率与并发用户数成线性关系; 到达最大并发用户数之后,吞吐率不变,响应时间随着并发用户数的增加而增大。 ...
  • 服务器的吞吐率对应什么配置 内容精选换一换弹性云服务器(Elastic Cloud Server)是一种可随时自动获取、计算能力可弹性伸缩的云服务器,可帮助您打造可靠、安全、灵活、高效的应用环境,确保服务持久稳定运行,提升...
  • Elasticsearch还有另一个有用的功能,称为自适应副本选择(ARS),它允许协调节点了解数据节点上的负载,并允许它选择最佳的分片副本来执行搜索,从而提高搜索吞吐量、降低延迟。 通过在查询时间内更均匀地分散负载...
  • 怎么说呢,本人菜鸟一枚,费了几天时间,终于做了一个用java获取JVM的CPU占用率、内存占用率、线程数及服务器的网口吞吐率、磁盘读写速率的实现。其中windows环境下获取jvm 的cpu占用率这里是参考网上别人的东西(在...
  • WGCLOUD-v2.3.6Wgcloud is a distributed monitoring platform based on Java language. Its core modules include: server cluster monitoring, ES cluster monitoring, CPU monitoring, memory monitoring, data ....
  • 指令——流水线和吞吐率 解析: (1)吞吐率有个公式:指令条数除以流水线时间 (2)流水线时间计算有个公式:一条指令所需时间+(指令条数-1)*时间最长的指令的一段 7+(8-1)*3 流水线: 流水线是指在...
  • 昨天优化了一下服务器的网络部分,测试了一下,在不考虑吞吐率的情况下,并发5W下面是俺的一些经验1.基本结构服务器结构如下图使用2个不同的线程池来分别来处理 网络数据包的发送接收 以及 消息的处理.这样可以避免繁重...
  • 吞吐率,表示单位时间内成功传输的数据量,单位是 b/s(比特 / 秒)或者 B/s(字节 / 秒),吞吐受带宽限制,带宽越大,吞吐率的上限才可能越高。 PPS,全称是 Packet Per Second(包 / 秒),表示以网络包为单位的...
  • 一、引言 使用工作队列的一个好处就是它能够并行的处理队列。如果堆积了很多任务,我们只需要添加更多的工作者(workers)就可以了,扩展很简单。本例使用多线程来创建多信道并绑定队列,达到多workers的目的。...
  • 操作:Ubuntu 18.04 硬件环境:Jetson Nano 通信模块:某厂商模块 测试网站:www.speedtest.net 当你在jetson Nano能够上网(ping通百度)的时候,然后数据这个测试网站www.speedtest.net,即可测试,测试......
  • 1.前言 本文简单介绍了LTE吞吐率问题的分析方法,并结合高通平台对分析方法做了详细说明。 关键词:MCS,RB,CQI,BLER,RSRP,SINR,天线平衡度,layer,TM,校准,QXDM log 2.协议相关 2.1 相关协议索引 与吞吐率...
  • 区块链 solana TPS吞吐率

    千次阅读 2021-12-02 19:44:48
    50000 号称以太坊杀手的Solana是什么? - 知乎
  • 这个公式里,有一个叫做CPI的指标,CPI的倒数,又叫作 IPC(Instruction Per Clock),也就是一个时钟周期里面能够执行的指令树,代表了CPU的吞吐率。那么,在反复优化流水线架构的CPU里面,能够达到多少呢? 答案...
  • logstash吞吐率优化

    2020-12-20 06:05:44
    问题一最近发现kibana的日志传的很慢,常常查不到日志,由于所有的日志收集都只传输到了一个logstash进行收集和过滤,于是怀疑是否是由于logstash的吞吐量存在瓶颈。一看,还真是到了瓶颈。优化过程经过查询logstash...
  • 吞吐率,表示单位时间内成功传输的数据量,单位是 b/s(比特 / 秒)或者 B/s(字节 / 秒),吞吐受带宽限制,带宽越大,吞吐率的上限才可能越高。 PPS,全称是 Packet Per Second(包 / 秒),表示以网络包为单位的...
  • 背景:在迁移上公有云迁移时,因目的端的ES集群开发、测试环境配置较低,导致在用logstash同步时会使得目的端的ES集群GC过高,从而导致集群不可用 策略:减低减少ES的写入,减少对目的端集群的影响 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 143,169
精华内容 57,267
关键字:

吞吐率

友情链接: ResNet50.zip