|
|
我想使用 DOUT A输出最大电压4.095V, 但是测量到的总是2.04V,不知道为什么? 下面是代码,使用内部参考源2.04V
module tlv5638_chA_1hz (
input wire clk, // 系统时钟(默认50MHz)
input wire rst_n, // 异步复位(低有效)
output reg [11:0] voltage_data,
output reg sclk, // TLV5638 SPI时钟(1MHz)
output reg din, // TLV5638 串行数据(MSB先行)
output reg cs_n // TLV5638 片选(低有效)
);
// ===========================================================================
// 核心参数定义(基于手册规则,内部参考2.048V)
// ===========================================================================
localparam SYS_CLK_FREQ = 50_000_000; // 系统时钟频率(50MHz)
localparam SPI_CLK_FREQ = 1_000_000; // SPI目标时钟频率(1MHz)
localparam DAC_RESOLUTION = 12; // TLV5638为12位DAC
localparam UPDATE_FREQ = 1; // 电压更新频率(1Hz)
localparam INT_REF_VOLTAGE = 2048; // 内部参考电压(2.048V,单位:毫伏)
localparam TARGET_STEP_V = 500; // 目标电压步进(0.5V,单位:毫伏)
localparam OUTPUT_GAIN = 2; // 输出缓冲固定×2增益
// 关键参数计算
localparam FULL_SCALE_V = OUTPUT_GAIN * INT_REF_VOLTAGE; // 满量程输出(4096mV=4.096V)
localparam SPI_CLK_DIV = SYS_CLK_FREQ / (2 * SPI_CLK_FREQ); // SCLK分频系数(25)
localparam UPDATE_CNT = SYS_CLK_FREQ / UPDATE_FREQ; // 1秒计数阈值(50_000_000)
localparam SHIFT_CYCLES = 16; // 需传输16位数据(4控制+12数据)
// 0.5V对应的12位数字量步进(手册公式:ΔD=(TARGET_STEP_V×4096)/FULL_SCALE_V)
localparam VOLTAGE_STEP = (TARGET_STEP_V * 4096) / FULL_SCALE_V; // (500×4096)/4096=500
// ===========================================================================
// 控制字定义(根据手册修正 - D15:R1, D14:SPD, D13 WR, D12:R0)
// ===========================================================================
// 配置控制寄存器:R1=1,R0=1→控制寄存器,SPD=0,PWR=0,REF1=1,REF0=1→内部2.048V参考
localparam [15:0] CONTROL_REF_CONFIG = 16'b1100_0000_0000_0010;
// 写入DAC A寄存器:R1=1,R0=0→DAC A,SPD=0,PWR=0
localparam [3:0] CMD_DAC_A_WRITE = 4'b1001;
// 状态机定义
localparam IDLE = 3'd0; // 空闲(复位初始化)
localparam CONFIG_REF = 3'd1; // 配置CONTROL寄存器(激活内部参考)
localparam SHIFT_START = 3'd2; // 拉低片选+准备DAC数据移位
localparam SHIFT_RUN = 3'd3; // 串行移位(SCLK翻转+数据输出)
localparam DELAY_1S = 3'd4; // 移位完成后1秒延时
// ===========================================================================
// 内部信号定义
// ===========================================================================
reg [2:0] curr_state; // 当前状态
reg [2:0] next_state; // 下一状态
reg [15:0] dac_data; // 16位串行控制字(4控制+12数据)
reg [3:0] shift_cnt; // 移位计数器(0~15)
reg [31:0] sclk_cnt; // SCLK分频计数器
reg [31:0] delay_cnt; // 1秒延时计数器
reg ref_config_done; // 参考配置完成标志
// ===========================================================================
// 1. 状态机时序逻辑
// ===========================================================================
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
curr_state <= IDLE;
end else begin
curr_state <= next_state;
end
end
// ===========================================================================
// 2. 状态机组合逻辑
// ===========================================================================
always @(*) begin
next_state = curr_state;
case (curr_state)
IDLE: begin
next_state = CONFIG_REF; // 复位后首先配置内部参考
end
CONFIG_REF: begin
// 参考配置完成 → 进入延时准备第一次DAC输出
if (ref_config_done) begin
next_state = DELAY_1S;
end
end
SHIFT_START: begin
next_state = SHIFT_RUN; // 准备完成后立即进入移位
end
SHIFT_RUN: begin
// 16位移位完成 → 进入1秒延时
if (shift_cnt == SHIFT_CYCLES - 1'b1 && sclk_cnt == SPI_CLK_DIV - 1'b1) begin
next_state = DELAY_1S;
end
end
DELAY_1S: begin
// 1秒延时完成 → 回到DAC数据准备(循环输出)
if (delay_cnt == UPDATE_CNT - 1'b1) begin
next_state = SHIFT_START;
end
end
default: begin
next_state = IDLE;
end
endcase
end
// ===========================================================================
// 3. SCLK生成逻辑(符合手册时序:空闲高电平,占空比50%)
// ===========================================================================
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
sclk_cnt <= 32'd0;
sclk <= 1'b1; // 手册:SCLK空闲状态为高电平
end else begin
// 仅在"参考配置"和"DAC移位"阶段生成SCLK
if (curr_state == CONFIG_REF || curr_state == SHIFT_RUN) begin
if (sclk_cnt == SPI_CLK_DIV - 1'b1) begin
sclk_cnt <= 32'd0;
sclk <= ~sclk; // 计数到阈值翻转,确保占空比50%
end else begin
sclk_cnt <= sclk_cnt + 1'b1;
end
end else begin
sclk_cnt <= 32'd0;
sclk <= 1'b1; // 非移位阶段保持高电平
end
end
end
// ===========================================================================
// 4. 核心控制逻辑
// ===========================================================================
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cs_n <= 1'b1; // 复位时片选拉高
din <= 1'b0; // 数据默认低电平
shift_cnt <= 4'd0; // 移位计数器清零
voltage_data <= 12'd0; // 初始DAC数据(0V)
delay_cnt <= 32'd0; // 延时计数器清零
dac_data <= 16'd0; // 控制字初始化
ref_config_done <= 1'b0; // 参考配置标志清零
end else begin
case (curr_state)
IDLE: begin
cs_n <= 1'b1;
din <= 1'b0;
ref_config_done <= 1'b0;
end
// --------------------------
// 状态1:配置CONTROL寄存器(激活内部2.048V参考)
// D15-D12: 1100 (R1=1,R0=1→控制寄存器, SPD=0, PWR=0)
// D1-D0: 11 (REF1=1,REF0=1→内部2.048V参考)
// --------------------------
CONFIG_REF: begin
cs_n <= 1'b0; // 拉低片选
dac_data <= CONTROL_REF_CONFIG; // 16'b1100_0000_0000_0011
// SCLK上升沿:输出当前位数据(MSB先行)
if (sclk_cnt == 32'd0 && sclk == 1'b0) begin
din <= dac_data[15 - shift_cnt];
end
// SCLK下降沿:移位计数
if (sclk_cnt == SPI_CLK_DIV - 1'b1 && sclk == 1'b1) begin
if (shift_cnt < SHIFT_CYCLES - 1'b1) begin
shift_cnt <= shift_cnt + 1'b1;
end else begin
// 16位传输完成,置位配置标志
ref_config_done <= 1'b1;
shift_cnt <= 4'd0; // 为下一次传输准备
end
end
end
// --------------------------
// 状态2:准备DAC数据(通道A)
// D15-D12: 1000 (R1=1,R0=0→DAC A, SPD=0, PWR=0)
// D11-D0: 12位电压数据
// --------------------------
SHIFT_START: begin
cs_n <= 1'b0; // 拉低片选
shift_cnt <= 4'd0; // 复位移位计数器
// 16位控制字:修正的控制位 + 12位电压数据
dac_data <= {CMD_DAC_A_WRITE, voltage_data}; // {4'b1000, 12位电压数据}
// 提前输出最高位(确保第一个SCLK上升沿时有有效数据)
if (sclk_cnt == 32'd0) begin
din <= dac_data[15];
end
end
// --------------------------
// 状态3:串行移位(传输DAC数据)
// --------------------------
SHIFT_RUN: begin
cs_n <= 1'b0; // 保持片选有效
// SCLK上升沿:输出当前位数据
if (sclk_cnt == 32'd0 && sclk == 1'b0) begin
din <= dac_data[15 - shift_cnt];
end
// SCLK下降沿:移位计数器递增
if (sclk_cnt == SPI_CLK_DIV - 1'b1 && sclk == 1'b1) begin
if (shift_cnt < SHIFT_CYCLES - 1'b1) begin
shift_cnt <= shift_cnt + 1'b1;
end
end
end
// --------------------------
// 状态4:1秒延时+电压数据递增
// --------------------------
DELAY_1S: begin
cs_n <= 1'b1; // 拉高片选(结束本次移位)
if (delay_cnt == UPDATE_CNT - 1'b1) begin
delay_cnt <= 32'd0;
// 电压数据递增:每次+500(对应0.5V),溢出后循环
if (voltage_data + VOLTAGE_STEP >= 4096) begin
voltage_data <= 12'd0;
end else begin
voltage_data <= voltage_data + VOLTAGE_STEP;
end
end else begin
delay_cnt <= delay_cnt + 1'b1;
end
end
default: begin
cs_n <= 1'b1;
din <= 1'b0;
shift_cnt <= 4'd0;
end
endcase
end
end
endmodule
|
|