跳至正文

Verilog功能模块–SPI主机和从机(05)–ADX112 SPI驱动实测

adx112Driver

前言

前文已经进行了SPI主从机回环试验的功能仿真,验证了主从机基本通信功能的正确性。然而在实际应用中,绝大部分场景FPGA均是作为SPI主机使用,PCB板上的其它器件(如传感器、ADC、DAC、存储器等)则作为SPI从机。

为进一步验证所设计的Verilog功能模块——SPI主机在实际硬件环境中的功能,本系列后续文章将在实际的FPGA板卡上运行该SPI主机模块,驱动多个实际SPI从机芯片。选用的测试从机包括:

  1. ADX112: analogysemi(类比半导体)推出的16位、4路单端/2路差分、8~860SPS的ADC,内部集成晶振、参考电压源与PGA,数据接口为SPI接口;
  2. MAX31865: ADI公司推出的用于铂电阻温度检测(RTD)的专用芯片,数据接口为SPI接口;

本文对ADX112芯片进行实测。

测试证明此SPI主机模块在实际硬件场景中工作正常。

本文最后开源了所有Verilog源码。

一、ADX112简介

ADX112(Q)超小尺寸、超低功耗SPI接口16位高精度ΔΣ ADC(内置基准电压源和振荡器)。

  • AEC-Q100认证(仅ADX112Q具备)

  • 超小尺寸QFN封装:2mm×1.5mm×0.4mm

  • 小型3mm×3mm MSOP封装

  • 宽供电电压范围:2V至5.5V

  • 低电流消耗:

    连续模式:仅145μA

    单脉冲模式:自动断电

  • 可编程数据速率:8SPS至860SPS

  • 单周期建立时间

  • 内部低漂移电压基准

  • 内部振荡器

  • 兼容SPI接口

  • 内部可编程增益放大器(PGA)

  • 4个单端输入或2个差分输入

  • 工作温度范围:-40°C至125°C

二、ADX112驱动设计思路

思路:

  • 1.此芯片数字接口为SPI接口, 故只需编写驱动SPI通用主机模块的外层逻辑即可

  • 2.此芯片的SPI有两种读取方式:

    • 一次读32位, 这时dout的前16位为转换结果, 后16位为配置寄存器数据

    • 一次读16位, 这时dout只输出转换结果

  • 3.din用于设置配置寄存器, 如果不需要更改配置寄存器, 那么保持din=全0或者全1即可

三、ADX112 SPI时序分析

% 此芯片SPI时序

  • 1.SCLK时钟周期最小为250ns, 对应最大频率为4MHz
  • 2.CS下降沿到第一个SCLK上升沿的延迟, 最小为100ns
  • 3.SCLK空闲为低电平,即CPOL=0
  • 4.最后一个SCLK下降沿到CS上升沿的延迟, 最小为100ns
  • 5.CS高电平持续时间, 最小为200ns
  • 6.SCLK低电平持续28ms后, 芯片SPI接口将被复位
  • 7.din有效到sclk下降沿的时间, 最小为50ns, 此为建立时间, 意味着芯片在sclk下降沿采样
  • 8.sclk下降沿是时钟的第二个边沿, 故CPHA=1, 所以SPI_MODE={CPOL, CPHA}=2‘b01=1
  • 9.sclk下降沿之后, din保持有效的时间, 最小值为50ns, 此为保持时间
  • 10.CS下降沿到DOUT输出有效的延迟, 最大为100ns
  • 11.SCLK上升沿到new dout有效的延迟, 最大为50ns
  • 12.CS上升沿到DOUT高阻态的延迟, 最大为100ns

四、ADX112驱动模块

4.1 模块框图

adx112Driver

4.2 信号接口

4.2.1 参数列表

参数名 类型 默认值 说明
SCLK_PERIOD_CLK_NUM integer 100 fSCLK, SCLK周期对应CLK数, 必须为偶数, 最小为2
CS_EDGE_TO_SCLK_EDGE_CLK_NUM integer 20 TCC, CS_N下降沿到SCLK的第一个边沿对应CLK数, 最小为1
SCLK_EDGE_TO_CS_EDGE_CLK_NUM integer 20 TCCH, 最后一个SCLK边沿到CS_N上升沿对应CLK数, 最小为3
CS_KEEP_HIGH_CLK_NUM integer 40 TCWH, CS_N低电平后保持高电平的时间对应CLK数, 最小为2
CLK_FREQ_MHZ integer 100 模块工作时钟, 常用100/120,100MHz对应单周期10ns

4.2.2 信号列表

信号分组 信号名 方向 说明
外部控制信号 adx112_begin input 上升沿有效,使芯片读取一次数据
adx112_is_busy output 高电平指示芯片正在工作, 此时不响应begin信号
adx112_config_value[15:0] input 待写入配置寄存器的值, 在有效的begin上升沿锁存
adx112_dout[15:0] output 芯片输出, 16bit
adx112_dout_valid output 芯片输出有效指示, 高电平有效, 只会持续一个时钟周期的高电平
adx112_rd_config_value output 回读的配置寄存器值
SPI硬线链接 spi_cs_n output 片选, 低电平有效
spi_sclk output SPI时钟, 主机提供
spi_mosi output 主机输出从机输入
spi_miso input 主机输入从机输出
时钟与复位 clk input 模块工作时钟
rstn input 模块复位, 低电平有效

4.3 驱动部分代码

//++ SPI读写控制 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
reg adx112_begin_r1;
always @(posedge clk) begin
  adx112_begin_r1 <= adx112_begin;
end

wire adx112_begin_pedge = adx112_begin && ~adx112_begin_r1;

localparam integer DATA_WIDTH = 32;  // 单次通信发送或接收数据的位宽, 16/32(默认)

wire spi_begin;
// wire spi_end;
wire spi_is_busy;
wire [DATA_WIDTH-1:0] spi_master_tx_data;
wire [DATA_WIDTH-1:0] spi_master_rx_data;
wire        spi_master_rx_data_valid;

assign spi_begin = adx112_begin_pedge && ~spi_is_busy;
assign adx112_is_busy = spi_is_busy;
assign adx112_dout = spi_master_rx_data[DATA_WIDTH-1:DATA_WIDTH-16];
assign adx112_dout_valid = spi_master_rx_data_valid;
assign spi_master_tx_data = {adx112_config_value, 16'b0};

assign adx112_rd_config_value = spi_master_rx_data[DATA_WIDTH-17:DATA_WIDTH-32];
//-- SPI读写控制 ------------------------------------------------------------


//++ 实例化SPI主机模块 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mySPI_4Wire_Master #(
  .SPI_MODE                     (1                           ),
  .DATA_WIDTH                   (DATA_WIDTH                  ),
  .SCLK_PERIOD_CLK_NUM          (SCLK_PERIOD_CLK_NUM         ),
  .CS_EDGE_TO_SCLK_EDGE_CLK_NUM (CS_EDGE_TO_SCLK_EDGE_CLK_NUM),
  .SCLK_EDGE_TO_CS_EDGE_CLK_NUM (SCLK_EDGE_TO_CS_EDGE_CLK_NUM),
  .CS_KEEP_HIGH_CLK_NUM         (CS_KEEP_HIGH_CLK_NUM        ),
  .CLK_FREQ_MHZ                 (CLK_FREQ_MHZ                )
) mySPI_4Wire_Master_u0 (
  .spi_begin                (spi_begin               ),
  .spi_end                  (                        ),
  .spi_is_busy              (spi_is_busy             ),
  .spi_master_tx_data       (spi_master_tx_data      ),
  .spi_master_rx_data       (spi_master_rx_data      ),
  .spi_master_rx_data_valid (spi_master_rx_data_valid),
  .spi_cs_n                 (spi_cs_n                ),
  .spi_sclk                 (spi_sclk                ),
  .spi_mosi                 (spi_mosi                ),
  .spi_miso                 (spi_miso                ),
  .clk                      (clk                     ),
  .rstn                     (rstn                    )
);
//-- 实例化SPI主机模块 ------------------------------------------------------------

五、ADX112驱动顶层模块

在顶层模块功能:

  • 实例化PLL
  • 生成复位信号
  • 实例化ADX112驱动
  • 设定配置寄存器值
  • 提供驱动begin信号

部分代码如下:

配置寄存器设置:

//++ 配置寄存器设置 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
/*
* 工作状态或单次转换启动
* 该位决定器件的工作状态。
* 仅在掉电状态下可写入工作状态,在转换进行时写入无效。
* 写入时:
* 0 = 无效果
* 1 = 启动单次转换(在掉电状态下)
* 读取时:
* 0 = 器件当前正在执行转换
* 1 = 器件当前未执行转换(默认)
*/

localparam [0:0] SS = 1'b1//* 对配置寄存器的设置值只关注写入, 下同

/*
* 输入多路复用器配置
* 这些位配置输入多路复用器。
* 000 = 正输入端为AIN0,负输入端为AIN1(默认)
* 001 = 正输入端为AIN0,负输入端为AIN3
* 010 = 正输入端为AIN1,负输入端为AIN3
* 011 = 正输入端为AIN2,负输入端为AIN3
* 100 = 正输入端为AIN0,负输入端为地
* 101 = 正输入端为AIN1,负输入端为地
* 110 = 正输入端为AIN2,负输入端为地
* 111 = 正输入端为AIN3,负输入端为地
*/

localparam [2:0] MUX = 3'b100;

/*
* 可编程增益放大器配置
* 这些位配置可编程增益放大器。
* 000 = 满量程为±6.144V(1)
* 001 = 满量程为±4.096V(1)
* 010 = 满量程为±2.048V(默认)
* 011 = 满量程为±1.024V
* 100 = 满量程为±0.512V
* 101 = 满量程为±0.256V
* 110 = 满量程为±0.256V
* 111 = 满量程为±0.256V
*/

localparam [2:0] PGA = 3'b001;

/*
* 器件工作模式
* 该位控制ADX112(Q)的工作模式。
* 0 = 连续转换模式
* 1 = 掉电和单次模式(默认)
*/

localparam [0:0] MODE = 1'b1;

/*
* 数据速率
* 这些位控制数据速率设置。
* 000 = 8SPS
* 001 = 16SPS
* 010 = 32SPS
* 011 = 64SPS
* 100 = 128SPS(默认)
* 101 = 250SPS
* 110 = 475SPS
* 111 = 860SPS
*/

localparam [2:0] DR = 3'b100;

/*
* 温度传感器模式
* 该位配置ADC是转换温度信号还是输入信号。
* 0 = ADC模式(默认)
* 1 = 温度传感器模式
*/

localparam [0:0] TS_MODE = 1'b0;

/*
* 上拉使能
* 仅当CS为高电平时,该位使能DOUT/DRDY引脚上的弱内部上拉电阻。
* 使能时,一个内部400kΩ电阻将总线连接到电源;禁用时,DOUT/DRDY引脚浮空。
* 0 = DOUT/DRDY引脚上拉电阻禁用
* 1 = DOUT/DRDY引脚上拉电阻使能(默认)
*/

localparam [0:0] PULL_UP_EN = 1'b1;

/*
* 无操作
* NOP[1:0]位控制是否向配置寄存器写入数据。
* 要向配置寄存器写入数据,NOP[1:0]位必须为“01”;其他任何值都将产生NOP命令。
* 在SCLK脉冲期间,DIN可保持高电平或低电平,且不会有数据写入配置寄存器。
* 00 = 无效数据,不更新配置寄存器内容
* 01 = 有效数据,更新配置寄存器(默认)
* 10 = 无效数据,不更新配置寄存器内容
* 11 = 无效数据,不更新配置寄存器内容
*/

localparam [1:0] NOP = 2'b01;

/*
* 保留位
* 向该位写入0或1均无效果,读取时始终为1
*/

localparam [0:0] RESERVED = 1'b1;

assign adx112_config_value = {
  SS,
  MUX,
  PGA,
  MODE,
  DR,
  TS_MODE,
  PULL_UP_EN,
  NOP,
  RESERVED
};

/*
* 如果不设置仅读取配置寄存器则会读到其默认值 = 16'h858B
* 手册里写的是058B, 经分析是错误的, 最高位SS应读到1, 表示器件当前未执行转换(默认)
*/

// assign adx112_config_value = 'd0;
//-- 配置寄存器设置 ------------------------------------------------------------

生成begin信号:

//++ ADX112控制 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
localparam ADX112_BEGIN_DELAY_CNT_MAX = CLK_FREQ_MHZ * 1000 * 1000 / 128;
reg [$clog2(ADX112_BEGIN_DELAY_CNT_MAX+1)-1 : 0] adx112_begin_delay_cnt;
always @(posedge clk) begin
  if (~rstn)
    adx112_begin_delay_cnt <= 'd0;
  else if (adx112_begin_delay_cnt < ADX112_BEGIN_DELAY_CNT_MAX)
    adx112_begin_delay_cnt <= adx112_begin_delay_cnt + 1'b1;
  else
    adx112_begin_delay_cnt <= 'd0;
end

always @(posedge clk) begin
  if (~rstn)
    adx112_begin <= 1'b0;
  else if (~adx112_is_busy && adx112_begin_delay_cnt == ADX112_BEGIN_DELAY_CNT_MAX)
    adx112_begin <= 1'b1;
  else
    adx112_begin <= 1'b0;
end
//-- ADX112控制 ------------------------------------------------------------

六、ADX112驱动的ILA实测波形

SPI主机和从机(05)--ADX112 SPI驱动实测-2

一次SPI读取32bit数据,前16位为ADC码,后16位为配置寄存器读取值。

写入配置寄存器的值为16’hc38b,最高位SS写入1表示开始一次转换。

读出配置寄存器的值为16’h438b,最高位SS读出0表示芯片转换已经完成。

实测表明ADX112驱动功能正常,进一步验证了Verilog功能模块–SPI主机的正确性。

七、分享

源码在Gitee与Github开源,两平台同步:

Gitee:Verilog功能模块–SPI主机和从机: Verilog功能模块–SPI主机和从机 https://gitee.com/xuxiaokang/verilog-function-module–SPI-Master-Slave

Github:zhengzhideakang/Verilog–SPI-Master-Slave: verilog-function-module–SPI-Master-Slave https://github.com/zhengzhideakang/Verilog–SPI-Master-Slave

仓库中包含ADX112数据手册及其中文翻译版。

SPI主机和从机(05)--ADX112 SPI驱动实测-3

测试工程分享,BX71-ADX112Driver Vivado 2024.2 20250810.7z。

欢迎大家关注我的微信公众号:徐晓康的博客,回复以下6位数字获取网盘链接。

451078

建议复制过去不会码错字!


如果本文对你有所帮助,欢迎点赞、转发、收藏、评论让更多人看到,赞赏支持就更好了。

如果对文章内容有疑问,请务必清楚描述问题,留言评论或私信告知我,我看到会回复。


徐晓康的博客持续分享高质量硬件、FPGA与嵌入式知识,软件,工具等内容,欢迎大家关注。

0 0 投票数
文章评分
订阅评论
提醒
0 评论
内联反馈
查看所有评论
目录
0
希望看到您的想法,请您发表评论x