0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

实现稳健的微控制器到FPGA SPI接口: 双缓冲区!

得捷电子DigiKey 来源:得捷电子DigiKey 2024-05-16 09:36 次阅读

问:实现稳健的微控制器FPGA SPI 接口: 双缓冲区

在介绍双缓冲器之前,我们将简要探讨Verilog 脉宽调制器 (PWM) 的工作原理。这一点很重要,因为双缓冲区最好被看作是硬件模块 (如 PWM) 的可寻址接口。

PWM 的回顾

PWM 模块的顶层接口在这个 Verilog 代码片段中描述。观察该模块使用了位宽参数,并建立了最小和最大占空比限制。最后,观察PWM模块有一个[B - 1:0]输入矢量来设置占空比。没有显示的是在每个 PWM 占空比开始时读取输入的事实。

module PWM #(parameter

B = 12,

D_MIN_PERCENT = 0,

D_MAX_PERCENT = 95

)

(

input wire clk,

input wire enable,

input wire [B -1:0] d_in,

output reg PWM,

output reg [B -1:0] cnt

);

同步数据呈现

PWM 设计用于在更大的 uC 到 FPGA SPI 系统中工作。回想一下,SPI自然地使用字节宽度的数据元素进行操作。这与使用B定义的数据宽度操作的PWM形成鲜明对比。为了方便,我们假设 PWM 以16位的位宽度(B)实例化。

当系统更新与 PWM 输入相关的寄存器时,会出现一个问题。如果没有适当的注意,PWM 可能会在更新过程中执行读取操作。其结果是驱动器字节被分割成一个旧字节和一个新字节。这可能导致占空比的显著跃升,持续一个 PWM 周期。如果 PWM 用于LED 指示灯,则可能不会注意到这一点。在更复杂的系统中,故障相当于一个强脉冲,并可能导致系统响铃或变得不稳定,具体取决于错误发生的时间和频率。

解决方案是实现以下三篇文章中提到的双缓冲方案,后面将进行深入讨论。

第1 部分介绍了指导大型系统开发的 Verilog 设计理念。这是介绍寄存器传输电平 (RTL) 设计准则的关键部分,如时钟边界、频闪器的使用和双缓冲区的必要性。

第2部分介绍了 SPI 协议。回想一下,所选协议改编自802.3以太网帧,具有可变有效载荷长度和循环冗余校验 (CRC) 等概念,以提供数据完整性的度量。

第3部分介绍了 uC 到 FPGA 接口的高级视图。那篇文章中最重要的部分是这里重复的框图。

使用一组寄存器来捕获单个字节。当收集到完整的n字节数据时,更新第二个更宽的寄存器。第二个寄存器-双缓冲区-然后用于驱动其他模块,如代表性的 PWM。

双缓冲模块

双缓冲模块的框图如图1所示。在内部,它由四个主要部分组成。最重要的是输出寄存器。在这个例子中,它是16位宽,使其适合驱动16位 PWM。输出寄存器由单个8位寄存器驱动,在本例中它们被标记为 LSB 和 MSB。注意,所有的寄存器更新都是由双缓冲区的控制部分发起的。这是一个同步操作,其中所有元素响应主 100mhz时钟的滴答声。

04f2c404-12c9-11ef-a297-92fbcf53809c.png

1:双缓冲区的框图,显示了单个8位缓冲区与输出缓冲区之间的关系。

重要的是要理解,每个双缓冲区模块都是用特定的地址和特定的字节宽度实例化的,如下面的代码清单所示。注意,16位地址、8位数据和写频闪都涉及到加载缓冲区。当16位地址输入与实例化地址匹配时,数据传输就开始了。

module

double_buffer #(

parameterBYTE_WIDTH = 2,

parameterBASE_ADDRESS = 16'h0200

) (

input wire clk,

input wire [7:0]data,

input wire [15:0]address,

input wirewrite_strobe,

output reg [((8 *BYTE_WIDTH) - 1): 0] double_buffer_out,

output regnew_data_strobe

);

如图1所示,这个 uC 到 FPGA 接口有一个底层的8位传输过程。在这文章中首先介绍的命令帧中也隐含了一个连续写入操作。为了方便起见,这里将命令帧重复为图2。作为一个例子,让我们假设 PWM 和相关的双缓冲区以地址0x0200实例化。命令帧的写地址将被设置为0x0200,负载的前两个字节将保持所需的16位 PWM 值。

05166148-12c9-11ef-a297-92fbcf53809c.png

2:构成uC到FPGA SPI协议基础的命令和响应帧。

当接收并验证命令帧时,MSG 写块将断言地址0x0200,该地址指向 PWM 的双缓冲区。它将把第一个有效载荷字节放到数据总线上。最后,它将为一个时钟周期断言写频闪。这将加载如图1所示的 MSB (大端)。

继续进行连续写入,MSG 写入器向前推进地址,断言下一个数据字节,然后脉冲写入频闪,从而将 LSB 加载到双缓冲区中。这个过程对命令帧中的每个字节继续进行,由帧的字节长度字段控制。

从本质上讲,消息编写器并不了解相关的双缓冲区的长度。它只关心断言地址、数据和写频闪的三步过程。这取决于双缓冲区模块来理解它们何时被寻址,以及何时接收到 BYTE_WIDTH 参数指定的必要字节数。

由于双级缓冲区的基址和字节宽度在实例化时是已知的,因此很容易确定何时接收到所有字节。在这个 PWM 示例中,双缓冲器计数到2,然后发送一个频闪来加载输出寄存器。

技术贴士: 数据可能首先访问最高有效字节 (MSB) 或最低有效字节 (LSB)。描述顺序的术语是“端序” (endian)。如果 MSB 先出现,则系统为大端序。如果 LSB 是第一个,则系统是小端序的。本文描述的双缓冲区和关联帧是大端序。

双缓冲区代码

双缓冲区的 Verilog 代码附在本注释的末尾。代码紧跟图2的框图,理解它可以扩展到n字节的宽度。这可以通过更改 BYTE_WIDTH 参数来实现。

这段代码的关键是 Verilog 生成操作符的使用。回想一下,generate特性允许迭代地生成硬件。它的运作方式就像一个制造小部件的工厂。

除了,在这种情况下,我们正在制作8位寄存器,其程序集的总数等于 BYTE_WIDTH 参数。我们可以在 Vivado 分层设计窗口中看到这一点,如图3所示。这些“制造”的块与它们在生成循环中定义的连续命名方案一起出现。

0536e7b0-12c9-11ef-a297-92fbcf53809c.png

3:在双缓冲区实例化中可以看到生成的字节宽度寄存器。

观察每个生成的9位寄存器都包含一个对应的 local_write_strobe。这是一个重要的设计方面,因为 “control”部分使用它来加载相关的8位寄存器。

除了寄存器之外,生成循环还制造一个8位矢量,每个8位寄存器的输出都连接到这个矢量上。然后将这些N × 8位的包连接起来并传递到n字节输出寄存器。

代码的最后一部分确定n字节何时被收集。然后它更新输出寄存器并发送一个new_data_strobe。

控制部分有三个基本功能:

当基址与实例化地址匹配时激活模块。

维护一个计数器指向“制造的”8位寄存器。这个计数器对于连续写入是必不可少的。

对相关的8位寄存器进行频闪。

当N个8位寄存器被填满时,对输出缓冲区进行频闪。

技术贴士:矢量是导线的一维数组。一个例子是“input wire [15:0] address”,它定义了一个16位的名为 address 的矢量。

结语

最后,虽然这段代码确实很复杂,但 Verilog 生成操作符提供了很大的灵活性。它消除了为每个期望的字节宽度构建独立模块的需要。


审核编辑:刘清
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 寄存器
    +关注

    关注

    31

    文章

    5262

    浏览量

    119476
  • 缓冲器
    +关注

    关注

    6

    文章

    1905

    浏览量

    45372
  • LED指示灯
    +关注

    关注

    2

    文章

    94

    浏览量

    12574
  • SPI接口
    +关注

    关注

    0

    文章

    258

    浏览量

    34266
  • 脉宽调制器
    +关注

    关注

    1

    文章

    50

    浏览量

    16969

原文标题:实现MCU到FPGA SPI接口有一个好选项:用双缓冲器!

文章出处:【微信号:得捷电子DigiKey,微信公众号:得捷电子DigiKey】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    基于宏高效实现环形缓冲区教程

    来源 | 小麦大叔 循环缓冲区是嵌入式软件工程师在日常开发过程中的关键组件。 多年来,互联网上出现了许多不同的循环缓冲区实现和示例。我非常喜欢这个模块,可以GitHub上找到这个开源的 CBUF.h
    的头像 发表于 09-02 09:24 6660次阅读
    基于宏高效<b class='flag-5'>实现</b>环形<b class='flag-5'>缓冲区</b>教程

    SPI接口如何实现微控制器之间的通信

    微控制器接口侧配有一个通用同步和异步收发 (USART)、一个 I2C 兼容型双线接口 (TWI) 和 SPI。USART 可配置为第
    发表于 08-02 11:24 2566次阅读
    <b class='flag-5'>SPI</b><b class='flag-5'>接口</b>如何<b class='flag-5'>实现</b><b class='flag-5'>微控制器</b>之间的通信

    采用FT245BM和FPGA实现USB接口设计

    USB数据与并行I/O口数据的交换缓冲区。FIFO实现与外界(微控制器FPGA或其它器件)的接口,主要通过8根数据线D0~D7、读写
    发表于 04-22 07:00

    采用FT245BM和FPGA实现USB接口设计

    USB数据与并行I/O口数据的交换缓冲区。FIFO实现与外界(微控制器FPGA或其它器件)的接口,主要通过8根数据线D0~D7、读写
    发表于 04-26 07:00

    基于ARM和FPGA的环形缓冲区接口设计方案

    CPU用户手册,在FPGA端编写相应的接口代码来配合ARM CPU2端的读写时序实现。 下面重点介绍环形缓冲区接口的软件
    发表于 05-30 05:00

    UART缓冲技术:友好中断

    UART对于业余和专业项目都是很好的传输协议,但是在时间紧迫的系统中,UART可能很棘手。UART(通用异步接收传输)是微控制器在其他微控制器和计算机之间进行接口的一种流行协议。使用高速微控制
    发表于 09-19 08:32

    请问如何实现微控制器FPGA接口设计?

    基于FPGA的MCU设计有两种基本实现方式如何实现微控制器FPGA接口设计
    发表于 05-06 10:05

    什么是缓冲区模式?

    什么是缓冲区模式?
    发表于 12-08 07:05

    什么是缓冲区模式?

    什么是缓冲区模式?
    发表于 02-28 10:09

    环形缓冲区实现原理

    在通信程序中,经常使用环形缓冲区作为数据结构来存放通信中发送和接收的数据。环形缓冲区是一个先进先出的循环缓冲区,可以向通信程序提供对缓冲区的互斥访问。
    的头像 发表于 03-22 10:03 7433次阅读
    环形<b class='flag-5'>缓冲区</b>的<b class='flag-5'>实现</b>原理

    缓冲区是啥意思 STM32串口数据接收之环形缓冲区

    缓冲区顾名思义是缓冲数据用的。实现缓冲区最简单的办法时,定义多个数组,接收一包数据数组A,就把接收数据的地址换成数组B,每个数据有个标记字
    的头像 发表于 07-22 15:33 1.1w次阅读

    STM32微控制器上的Octo-SPI接口

    STM32微控制器上的Octo-SPI接口
    发表于 11-21 08:11 4次下载
    STM32<b class='flag-5'>微控制器</b>上的Octo-<b class='flag-5'>SPI</b><b class='flag-5'>接口</b>

    环形缓冲区实现思路

    单片机程序开发一般都会用到UART串口通信,通过通信来实现上位机和单片机程序的数据交互。通信中为了实现正常的收发,一般都会有对应的发送和接收缓存来暂存通信数据。这里使用环形缓冲区的方式来设计数据收发的缓存,即
    的头像 发表于 01-17 15:07 1507次阅读

    SPI控制器驱动层功能介绍

    SPI 控制器驱动层 SPI 控制器驱动层负责最底层的数据收发,主要有以下功能: 申请必要的硬件资源,比如中断、DMA 通道、DMA 内存缓冲区
    的头像 发表于 07-25 10:58 1078次阅读
    <b class='flag-5'>SPI</b><b class='flag-5'>控制器</b>驱动层功能介绍

    C++环形缓冲区设计与实现

    的存储空间。环形缓冲区的特点是其终点和起点是相连的,形成一个环状结构。这种数据结构在处理流数据和实现数据缓存等场景中具有广泛的应用。 环形缓冲区的主要作用是存储和管理数据
    的头像 发表于 11-09 11:21 1480次阅读
    C++环形<b class='flag-5'>缓冲区</b>设计与<b class='flag-5'>实现</b>