实现稳健的微控制器到FPGA SPI接口:双缓冲区机制详解
实现稳健的微控制器到FPGA SPI接口:双缓冲区机制详解
在嵌入式系统设计中,微控制器(uC)与现场可编程门阵列(FPGA)之间的SPI接口常常需要处理数据同步和稳定性问题。本文将详细介绍如何通过双缓冲区机制实现稳健的微控制器到FPGA SPI接口,特别是在脉宽调制(PWM)模块的应用中。
PWM模块回顾
在深入探讨双缓冲区之前,我们先简要回顾一下Verilog PWM模块的工作原理。PWM模块的顶层接口如以下Verilog代码片段所示:
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模块有一个[B - 1:0]输入矢量来设置占空比。
同步数据呈现的挑战
PWM设计通常需要在更大的uC到FPGA SPI系统中工作。SPI协议自然地使用字节宽度的数据元素进行操作,这与使用B定义的数据宽度操作的PWM形成对比。假设PWM以16位的位宽度(B)实例化。
当系统更新与PWM输入相关的寄存器时,如果没有适当的注意,PWM可能在更新过程中执行读取操作。这可能导致驱动器字节被分割成一个旧字节和一个新字节,从而引起占空比的显著跃升,持续一个PWM周期。这种问题在更复杂的系统中可能导致系统不稳定。
双缓冲模块设计
为了解决上述问题,我们引入双缓冲方案。双缓冲模块的框图如图1所示:
图 1 :双缓冲区的框图,显示了单个8位缓冲区与输出缓冲区之间的关系。
双缓冲模块由四个主要部分组成:输出寄存器、8位寄存器(LSB和MSB)、控制部分和时钟信号。输出寄存器由两个8位寄存器驱动,在本例中它们被标记为LSB和MSB。所有的寄存器更新都是由双缓冲区的控制部分发起的,这是一个同步操作,所有元素响应主100MHz时钟的滴答声。
双缓冲模块的Verilog代码如下:
module double_buffer #(parameter
BYTE_WIDTH = 2,
BASE_ADDRESS = 16'h0200
)
(
input wire clk,
input wire [7:0] data,
input wire [15:0] address,
input wire write_strobe,
output reg [((8 * BYTE_WIDTH) - 1): 0] double_buffer_out,
output reg new_data_strobe
);
双缓冲区代码实现
双缓冲区的Verilog代码利用了Verilog的生成操作符,可以灵活地扩展到n字节的宽度。通过更改BYTE_WIDTH参数,可以调整缓冲区的宽度。在Vivado的分层设计窗口中,可以看到生成的字节宽度寄存器,如图3所示:
图 3 :在双缓冲区实例化中可以看到生成的字节宽度寄存器。
控制部分有三个基本功能:
- 当基址与实例化地址匹配时激活模块。
- 维护一个计数器指向“制造的”8位寄存器。
- 对相关的8位寄存器进行频闪。
- 当N个8位寄存器被填满时,对输出缓冲区进行频闪。
结语
虽然这段代码确实很复杂,但Verilog生成操作符提供了很大的灵活性。它消除了为每个期望的字节宽度构建独立模块的需要。通过使用双缓冲区机制,可以有效地解决uC到FPGA SPI接口中的数据同步问题,确保系统的稳定性和可靠性。