跳至正文

Verilog功能模块–SPI主机和从机(06)–MAX31865 Demo SPI驱动实测

MAX31865Driver_Demo

前言

书接上文,为进一步验证所设计的Verilog功能模块——SPI主机在实际硬件环境中的功能,本文对MAX31865芯片进行实测。测试证明此SPI主机模块在实际硬件场景中工作正常。

本文仅为验证SPI主机,故仅进行了读写配置寄存器与故障阈值寄存器的试验,并非是完整的MAX31865驱动实验。

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

一、MAX31865简介

MAX31865 是一款易于使用的电阻-数字转换器,专为铂电阻温度检测器(RTD)优化设计。通过一个外部电阻设置所用RTD的灵敏度,精密的Δ-Σ ADC将RTD电阻与参考电阻的比值转换为数字形式。MAX31865的输入端可防护高达±45V的过压故障。该器件还集成了可编程的RTD及电缆开路、短路检测功能。

MAX31865特点:

  • 集成降低了系统成本,简化了设计工作,并缩短了设计周期。

    • 简单地将铂电阻温度计的电阻转换为数字值。
    • 处理100Ω至1kΩ(在0°C时)的铂电阻温度计(PT100到PT1000)
    • 兼容2线、3线和4线传感器连接
    • SPI兼容接口
    • 20引脚TQFN和SSOP封装
  • 高精度便于满足误差预算

    • 15位ADC分辨率;名义温度分辨率为0.03125℃(由于RTD非线性而变化)
    • 所有操作条件下的总精度:0.5℃(满量程的0.05%)最大值
    • 完全差分VREF输入
    • 转换时间为21毫秒(最大值)
  • 集成故障检测提高了系统的可靠性

    • ±45V输入保护
    • 故障检测(开路RTD元件、RTD短接到超出范围电压或RTD元件短路)

二、MAX31865驱动设计思路

  • 1.MAX31865通过SPI写入/读取寄存器来完成对芯片的配置和数据读取

  • 2.MAX31865需要先进行配置, 再进行数据读取

  • 3.配置分为两种类型, 一为配置寄存器(读地址8’h00, 写地址8’h80), 包括:

    • 启用或禁用偏置VBIAS

    • 设置转换模式:自动或常态关闭

    • 设置是否开启单次触发

    • 选择 RTD 连接方式:三线或四线

    • 清除故障状态寄存器

    • 选择滤波器频率

  • 4.二为配置故障阈值寄存器,包括:

    高故障阈值寄存器MSB (读地址8’h03, 写地址8’h83)

    高故障阈值寄存器LSB (读地址8’h04, 写地址8’h84)

    低故障阈值寄存器MSB (读地址8’h05, 写地址8’h85)

    低故障阈值寄存器LSB (读地址8’h06, 写地址8’h86)

  • 5.芯片工作时如果有故障会更新故障状态寄存器的值, 上层模块在遇到芯片故障时需读取故障寄存器值, 判断故障类型并对外输出

  • % 驱动错误

    * drive_error_code[2:0]: 表示发生了某项驱动错误

    * 2’b00: 表示配置寄存器读出数据不等于前一步骤写入的数据, 可能是SPI时序问题, 或者芯片本身的响应问题

    * 2’b01: 表示故障阈值寄存器读出数据不等于前一步骤写入的数据, 可能原因同上

三、MAX31865的SPI时序分析

  • 1.时序特性参考: 数据手册–交流电气特性:SPI接口
  • 2.MAX31865的SCLK频率最大为5MHz, 实际使用建议最大fSCLK设定为4MHz, 占空比固定为50%
  • 3.SCLK空闲时为高电平, 对应 CPOL=1
  • 4.MAX31865在SCLK的上升沿采样SDI引脚上的数据, 结合SCLK空闲高电平, 即在第二个时钟边沿采样, 对应CPHA = 1
  • 5.综合来看 SPI_MODE = {CPOL, CPHA} = 2’b11 = 3
  • 6.tCC: CS_N下降沿到SCLK的第一个下降沿, 最小值为400ns
  • 7.tCCH: 最后一个SCLK上升沿到CS_N上升沿, 最小值100ns
  • 8.tCWH: CS_N无效时间, CS_N低电平有效到下一次低电平有效的时间, 最小值为400ns
  • 9.tCDZ: CS_N上升沿到SDO引脚高阻的时间, 最大值40ns
  • 10.SPI的读写时序是确定的, 芯片SDI先接收8位数据, 根据地址值决定是读还是写:
  • 如果是读, 则芯片SDO输出16位数据
  • 如果是写, 则芯片SDI接收16位数据
  • 单次通讯结束

四、MAX31865驱动模块

4.1 模块框图

MAX31865Driver_Demo

4.2 信号接口

4.2.1 参数列表

参数名 类型 默认值 说明
SCLK_PERIOD_CLK_NUM integer 100 fSCLK, SCLK周期对应CLK数, 必须为偶数, 最小为2
CS_EDGE_TO_SCLK_EDGE_CLK_NUM integer 50 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 50 TCWH, CS_N低电平后保持高电平的时间对应CLK数, 最小为2
CLK_FREQ_MHZ integer 100 模块工作时钟, 常用100/120,100MHz对应单周期10ns

4.2.2 信号列表

信号分组 信号名 方向 说明
外部控制信号 MAX31865_begin input 上升沿有效, 进行一次配置寄存器和故障阈值寄存器的读写
MAX31865_is_busy output 高电平指示芯片正在工作, 此时不响应begin信号
max31865_config_data[7:0] input 待写入配置寄存器的值, 在有效的begin上升沿锁存
max31865_rd_config_data[7:0] output 读出的配置寄存器的值
max31865_rd_config_data_valid output 指示读出的配置寄存器的值有效, 高电平有效, 只会持续一个时钟周期的高电平
max31865_high_threshold[15:0] input 写入的高故障阈值
max31865_low_threshold[15:0] input 写入的低故障阈值
max31865_rd_high_threshold[15:0] output 读取的高故障阈值
max31865_rd_low_threshold[15:0] output 读取的低故障阈值
max31865_rd_threshold_valid output 读取的故障阈值有效信号, 高电平有效, 只会持续一个时钟的高电平
SPI硬线链接 spi_cs_n output 片选, 低电平有效
spi_sclk output SPI时钟, 主机提供
spi_mosi output 主机输出从机输入
spi_miso input 主机输入从机输出
时钟与复位 clk input 模块工作时钟
rstn input 模块复位, 低电平有效

4.3 驱动部分代码

4.3.1 寄存器读写地址

//++ 寄存器读写地址 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
/* 配置寄存器 读写*/
localparam [7:0] CONFIG_REG_RADDR = 8'h00// 配置寄存器读地址
localparam [7:0] CONFIG_REG_WADDR = CONFIG_REG_RADDR + 8'h80// 配置寄存器写地址

/* 故障阈值寄存器 读写*/
localparam [7:0] HIGH_FAULT_THRESHOLD_MSB_REG_RADDR = 8'h03// 高故障阈值MSB读地址
localparam [7:0] HIGH_FAULT_THRESHOLD_LSB_REG_RADDR = 8'h04// 高故障阈值LSB读地址
localparam [7:0] LOW_FAULT_THRESHOLD_MSB_REG_RADDR = 8'h05// 低故障阈值MSB读地址
localparam [7:0] LOW_FAULT_THRESHOLD_LSB_REG_RADDR = 8'h06// 低故障阈值LSB读地址
localparam [7:0] HIGH_FAULT_THRESHOLD_MSB_REG_WADDR = HIGH_FAULT_THRESHOLD_MSB_REG_RADDR
                                                    + 8'h80// 高故障阈值MSB写地址
localparam [7:0] HIGH_FAULT_THRESHOLD_LSB_REG_WADDR = HIGH_FAULT_THRESHOLD_LSB_REG_RADDR
                                                    + 8'h80// 高故障阈值LSB写地址
localparam [7:0] LOW_FAULT_THRESHOLD_MSB_REG_WADDR = LOW_FAULT_THRESHOLD_MSB_REG_RADDR
                                                   + 8'h80// 低故障阈值MSB写地址
localparam [7:0] LOW_FAULT_THRESHOLD_LSB_REG_WADDR = LOW_FAULT_THRESHOLD_LSB_REG_RADDR
                                                   + 8'h80// 低故障阈值LSB写地址
//-- 寄存器读写地址 ------------------------------------------------------------

4.3.2 读写配置与故障阈值寄存器

//++ 读写配置与故障阈值寄存器 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
(* mark_debug *)reg [3:0] spi_end_cnt; // spi_end计数, 作为下一次spi_begin的开始
always @(posedge clk) begin
  if (~rstn)
    spi_end_cnt <= 'd0;
  else if (max31865_is_busy)
    if (spi_end)
      spi_end_cnt <= spi_end_cnt + 1'b1;
    else
      spi_end_cnt <= spi_end_cnt;
  else
    spi_end_cnt <= 'd0;
end

localparam SPI_END_CNT_MAX = 9;
assign max31865_end = spi_end && spi_end_cnt == SPI_END_CNT_MAX;

always @(posedge clk) begin
  if (~rstn)
    spi_begin <= 1'b0;
  else if (max31865_begin_pedge && ~max31865_is_busy)
    spi_begin <= 1'b1;
  else if (spi_end && spi_end_cnt < SPI_END_CNT_MAX)
    spi_begin <= 1'b1;
  else
    spi_begin <= 1'b0;
end

// spi写入
always @(*) begin
  if (~rstn)
    spi_master_tx_data = 'd0;
  else
    case (spi_end_cnt)
      0: spi_master_tx_data = {CONFIG_REG_WADDR, max31865_config_data};
      1: spi_master_tx_data = {CONFIG_REG_RADDR, max31865_config_data};
      2: spi_master_tx_data = {HIGH_FAULT_THRESHOLD_MSB_REG_WADDR, max31865_high_threshold[15:8]};
      3: spi_master_tx_data = {HIGH_FAULT_THRESHOLD_MSB_REG_RADDR, max31865_high_threshold[15:8]};
      4: spi_master_tx_data = {HIGH_FAULT_THRESHOLD_LSB_REG_WADDR, max31865_high_threshold[7:0]};
      5: spi_master_tx_data = {HIGH_FAULT_THRESHOLD_LSB_REG_RADDR, max31865_high_threshold[7:0]};
      6: spi_master_tx_data = {LOW_FAULT_THRESHOLD_MSB_REG_WADDR, max31865_low_threshold[15:8]};
      7: spi_master_tx_data = {LOW_FAULT_THRESHOLD_MSB_REG_RADDR, max31865_low_threshold[15:8]};
      8: spi_master_tx_data = {LOW_FAULT_THRESHOLD_LSB_REG_WADDR, max31865_low_threshold[7:0]};
      9: spi_master_tx_data = {LOW_FAULT_THRESHOLD_LSB_REG_RADDR, max31865_low_threshold[7:0]};
      default: ;
    endcase
end

// 读取配置数据
always @(posedge clk) begin
  if (~rstn)
    max31865_rd_config_data <= 'd0;
  else if (spi_end)
    case (spi_end_cnt)
      1: max31865_rd_config_data <= spi_master_rx_data[7:0];
      default: ;
    endcase
  else
    max31865_rd_config_data <= max31865_rd_config_data;
end

assign max31865_rd_config_data_valid = spi_end && spi_end_cnt == 'd1;

// 读取高故障阈值
always @(posedge clk) begin
  if (~rstn)
    max31865_rd_high_threshold <= 'd0;
  else if (spi_end)
    case (spi_end_cnt)
      3: max31865_rd_high_threshold[15:8] <= spi_master_rx_data[7:0];
      5: max31865_rd_high_threshold[7:0]  <= spi_master_rx_data[7:0];
      default: ;
    endcase
  else
    max31865_rd_high_threshold <= max31865_rd_high_threshold;
end

// 读取低故障阈值
always @(posedge clk) begin
  if (~rstn)
    max31865_rd_low_threshold <= 'd0;
  else if (spi_end)
    case (spi_end_cnt)
      7: max31865_rd_low_threshold[15:8] <= spi_master_rx_data[7:0];
      9: max31865_rd_low_threshold[7:0]  <= spi_master_rx_data[7:0];
      default: ;
    endcase
  else
    max31865_rd_low_threshold <= max31865_rd_low_threshold;
end

assign max31865_rd_threshold_valid = spi_end && spi_end_cnt == 'd9;
//-- 读写配置与故障阈值寄存器 ------------------------------------------------------------

五、MAX31865驱动顶层模块

在顶层模块功能:

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

部分代码如下:

配置寄存器设置:

//++ 设置配置寄存器值 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
/*
* 配置寄存器位定义:
*   D7: V_BIAS       - 偏置电压(1:开启, 0:关闭)
*   D6: CONV_MODE    - 转换模式(1:自动, 0:正常关闭)
*   D5: SINGLE_SHOT  - 单次触发(1:1-shot, 0:无)
*   D4: WIRE_MODE    - 线制选择(1:三线, 0:四线)
*   D3: FAULT_DETECT_H - 故障检测周期高位(与D2组合)
*   D2: FAULT_DETECT_L - 故障检测周期低位(见表3)
*   D1: FAULT_CLR    - 故障清除(1:清除状态, 0:无操作)
*   D0: FILTER_SEL   - 工频滤波(1:60Hz, 0:50Hz)
*/

/*
* 故障检测周期控制 (D3-D2):
*   00: 无操作                        | 读取: 故障检测完成
*   01: 带自动延迟的故障检测             | 读取: 自动故障检测仍在运行
*   10: 带手动延迟的故障检测(周期 1)    | 读取: 手动周期1仍在运行;等待用户写入11
*   11: 带手动延迟的故障检测(周期 2)    | 读取: 手动周期2仍在运行
*/

localparam [00] V_BIAS         = 1'b1;
localparam [00] CONV_MODE      = 1'b0;
localparam [00] SINGLE_SHOT    = 1'b1;
localparam [00] WIRE_MODE      = 1'b1;
localparam [00] FAULT_DETECT_H = 1'b0;
localparam [00] FAULT_DETECT_L = 1'b0;
localparam [00] FAULT_CLR      = 1'b0;
localparam [00] FILTER_SEL     = 1'b0;
assign max31865_config_data = {
  V_BIAS,
  CONV_MODE,
  SINGLE_SHOT,
  WIRE_MODE,
  FAULT_DETECT_H,
  FAULT_DETECT_L,
  FAULT_CLR,
  FILTER_SEL
};
//-- 设置配置寄存器值 ------------------------------------------------------------

生成begin信号:

//++ 生成MAX31865驱动demo控制信号 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
localparam MAX31865_SAMPLE_FREQ_HZ = 10;
localparam MAX31865_BEGIN_CLK_CNT_MAX = CLK_FREQ_MHZ * 1000 * 1000 / MAX31865_SAMPLE_FREQ_HZ;
reg [$clog2(MAX31865_BEGIN_CLK_CNT_MAX+1)-1 : 0] max31865_begin_clk_cnt;
always @(posedge clk) begin
  if (~rstn)
    max31865_begin_clk_cnt <= 'd0;
  else if (max31865_begin_clk_cnt < MAX31865_BEGIN_CLK_CNT_MAX)
    max31865_begin_clk_cnt <= max31865_begin_clk_cnt + 1'b1;
  else
    max31865_begin_clk_cnt <= 'd0;
end

always @(posedge clk) begin
  if (~rstn)
    max31865_begin <= 1'b0;
  else if (max31865_begin_clk_cnt == MAX31865_BEGIN_CLK_CNT_MAX && ~max31865_is_busy)
    max31865_begin <= 1'b1;
  else
    max31865_begin <= 1'b0;
end
//-- 生成MAX31865驱动demo控制信号 ------------------------------------------------------------

六、MAX31865驱动的ILA实测波形

Verilog功能模块--SPI主机和从机(06)--MAX31865 Demo SPI驱动实测-2

一次SPI写入同时读取16bit数据,前8位为写/读寄存器地址,后8位为写/读寄存器的值。

实测表明MAX31865驱动功能正常,进一步验证了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

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

Verilog功能模块--SPI主机和从机(06)--MAX31865 Demo SPI驱动实测-3

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

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

451078

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


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

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


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

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