赞
踩
1.串行外设接口(SPI)是微控制器和外围IC(如传感器、ADC、DAC、移位寄存器、SRAM等)之间使用最广泛的接口之一。
2.SPI是一种同步、全双工、主从式接口。来自主机或从机的数据在时钟上升沿或下降沿同步。主机和从机可以同时传输数据。SPI接口可以是3线式或4线式。
SPI总线传输只需要4根线就能完成,这四根线的作用分别如下:
DAC8830是TI的TI一款DAC芯片,他支持16bit数据输入,同时建立时间为1us,支持标准的3线SPI接口,最快可支持50Mhz。
以下是接口定义
总线主设备将芯片选择信号CS拉低,表示要访问DAC模块。
在CS处于低电平状态时,总线主设备生成同步时钟信号SCLK,并将串行输入数据SDI按照时钟的下降沿进行传输。数据从总线主设备经由SDI线逐位地传输到DAC模块。
DAC模块在SCLK的下降沿时,将串行输入数据SDI的每一位依次存储到输入移位寄存器中。通常情况下,最高有效位(MSB)先传输,并在SCLK的上升沿锁存到输入移位寄存器中。
当CS由低电平变为高电平时,表示数据传输完成,并且同时更新输出。为了传输一个完整的数据,CS必须在16个SCLK后立即变为高电平。
输入信号:
clk
:时钟信号,模块在时钟上升沿执行。rst_n
:复位信号,低电平有效,当复位信号为低电平时,模块会清零输出数据,并将使能信号、DAC8830 时钟、数据和片选信号都输出为高电平。start
:开始信号,高电平有效,当开始信号为高电平时,模块会将输入数据赋值给输出数据,并将使能信号设置为高电平。data_in
:16位的输入数据信号,用于传输到 DAC8830 芯片。输出信号:
SCLK
:DAC8830 时钟信号,用于控制数据传输时序。DIN
:DAC8830 数据输入信号,传输到 DAC8830 芯片的串行数据。CS
:DAC8830 片选信号,用于选择 DAC8830 芯片。done
:传输完成信号,用于指示数据传输完成。en
是使能信号,由外部输入开始信号时,en
为高电平,数据开始传输;数据传输完成后done信号拉高,en变为低电平,停止传输。SCLK_CNT
是输出时钟计数器,用于计数时钟周期的数量。它在数据传输过程中递增,用于控制时钟信号的生成和数据的传输时机。cnt
是分频计数器,用于计数SCLK的时钟周期。当计数器的值达到一定数量(这里是10)时,cnt_flag置1。
cnt_flag
是计数标志,用于指示分频计数器的状态。当cnt_flag
为高电平时,表示已经传输了一位数据并且需要进行下一位数据的传输。- module SPI_drive(
- input clk, // 输入时钟
- input rst_n, // 复位信号
- input start, // 启动信号
- input [15:0] data_in, // 输入数据
-
- // DAC8830输入
- output reg SCLK, // 时钟信号
- output reg DIN, // 输入数据信号
- output reg CS, // 芯片选择信号
-
- output reg done // 完成信号
- );
-
- reg en; // 使能信号
- reg [3:0] cnt; // 分频计数
- reg [6:0] SCLK_CNT; // 输出时钟计数
- reg cnt_flag; // 计数标志
- reg [15:0] data_out; // 输出数据
-
- parameter cnt_threshold = 5;//时钟分频阈值,
- //输出时钟频率为输入时钟频率的1/(cnt_threshold+1)
-
- // 接收数据
- always @(posedge clk or negedge rst_n)
- begin
- if (!rst_n)
- data_out <= 16'b0;
- else if (en)
- data_out <= data_in; // 在启动时加载输入数据
- else
- data_out <= data_out;
- end
- // 使能信号
- always @(posedge clk or negedge rst_n)
- begin
- if (!rst_n)
- en <= 1'b0;
- else if (start)
- en <= 1'b1; // 在启动时使能信号为高电平
- else if (done)
- en <= 1'b0; // 在传输完成后禁用使能信号
- else
- en <= en;
- end
-
- // 分频计数
- always @(posedge clk or negedge rst_n)
- begin
- if (!rst_n)
- begin
- cnt <= 4'b0;
- cnt_flag <= 1'b0;
- end
- else if (en)
- begin
- if (cnt == cnt_threshold)
- begin
- cnt <= 4'b0; // 达到分频阈值时清零分频计数
- cnt_flag <= 1'b1; // 设置计数标志
- end
- else
- begin
- cnt <= cnt + 4'b1; // 增加分频计数
- cnt_flag <= 1'b0; // 清零计数标志
- end
- end
- else
- cnt <= 0; // 禁用时清零分频计数
- end
-
- // 输出时钟计数
- always @(posedge clk or negedge rst_n)
- begin
- if (!rst_n)
- SCLK_CNT <= 7'b0;
- else if (en)
- begin
- if (cnt_flag && (SCLK_CNT == 7'd32))
- SCLK_CNT <= 7'b0; // 达到输出时钟计数阈值时清零计数
- else if (cnt_flag)
- SCLK_CNT <= SCLK_CNT + 1'b1; // 增加输出时钟计数
- else
- SCLK_CNT <= SCLK_CNT; // 其他情况下保持输出时钟计数不变
- end
- else
- SCLK_CNT <= 0; // 禁用时清零输出时钟计数
- end
-
- // 开启数据传输,线性序列机,每个时钟周期按照固定的步骤依次执行
- always @(posedge clk or negedge rst_n)
- begin
- if (!rst_n)
- begin
- SCLK <= 1'b1;
- DIN <= 1'b1;
- CS <= 1'b1;
- end
- else if (en)
- begin
- if (cnt_flag)
- begin
- case (SCLK_CNT)
- 7'd0: begin SCLK <= 1'b0; DIN <= data_out[15]; CS <= 1'b0; end
- 7'd2: begin SCLK <= 1'b0; DIN <= data_out[14]; end
- 7'd4: begin SCLK <= 1'b0; DIN <= data_out[13]; end
- 7'd6: begin SCLK <= 1'b0; DIN <= data_out[12]; end
- 7'd8: begin SCLK <= 1'b0; DIN <= data_out[11]; end
- 7'd10: begin SCLK <= 1'b0; DIN <= data_out[10]; end
- 7'd12: begin SCLK <= 1'b0; DIN <= data_out[9]; end
- 7'd14: begin SCLK <= 1'b0; DIN <= data_out[8]; end
- 7'd16: begin SCLK <= 1'b0; DIN <= data_out[7]; end
- 7'd18: begin SCLK <= 1'b0; DIN <= data_out[6]; end
- 7'd20: begin SCLK <= 1'b0; DIN <= data_out[5]; end
- 7'd22: begin SCLK <= 1'b0; DIN <= data_out[4]; end
- 7'd24: begin SCLK <= 1'b0; DIN <= data_out[3]; end
- 7'd26: begin SCLK <= 1'b0; DIN <= data_out[2]; end
- 7'd28: begin SCLK <= 1'b0; DIN <= data_out[1]; end
- 7'd30: begin SCLK <= 1'b0; DIN <= data_out[0]; end
- 7'd1,7'd3,7'd5,7'd7,7'd9,7'd11,7'd13,7'd15,7'd17,
- 7'd19,7'd21,7'd23,7'd25,7'd27,7'd29,7'd31: begin SCLK <= 1'b1; end
- 7'd32: begin SCLK <= 1'b0;
- CS <= 1'b1; end // 全部数据输出后,cs信号马上拉高
- endcase
- end
- else ;
- end
- else
- begin
- SCLK <= 1'b1;
- DIN <= 1'b1;
- CS <= 1'b1;
- end
- end
- // 传输完成
- always @(posedge clk or negedge rst_n)
- begin
- if (!rst_n)
- done <= 1'b0;
- else if (cnt_flag && (SCLK_CNT == 7'd32))
- done <= 1'b1; // 达到输出时钟计数阈值时设置完成信号为高电平
- else
- done <= 1'b0;
- end
-
- endmodule

en信号一直为高是因为外部一直在给start信号
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。