spi通信相关内容大家可以找找,然后我以DAC7512,进行spi书写
下边是代码
module dac7512_dinayuan(
input clk, // 输入时钟
input rst_n, // 复位信号
input start, // 启动信号
input [15:0] data_in, // 输入数据
// DAC7512输入
output reg SCLK, // 时钟信号
output reg DIN, // 输入数据信号
output reg CS, // 芯片选择信号
//测试接口
//output reg en,
//output reg [6:0] SCLK_CNT,
//output reg cnt_flag,
output reg done // 完成信号
);
//reg done;
reg en; // 使能信号
reg [3:0] cnt; // 分频计数
reg [6:0] SCLK_CNT; // 输出时钟计数
reg cnt_flag; // 计数标志
reg [15:0] data_out; // 输出数据
reg en1; //使能信号寄存1
reg en2; //使能信号寄存2
wire pos; //抓取到的使能信号的上升沿
parameter cnt_threshold = 4;//时钟分频阈值,
//输出时钟频率为输入时钟频率的1/(cnt_threshold+1)
//使能信号上升沿检测
always @(posedge clk or negedge rst_n)
begin
if (!rst_n)begin
en1 <= 1'b0;
en2 <= 1'b0;
end
else begin
en1 <= en; // 使能信号锁存
en2 <= en1;
end
end
assign pos=en1&(!en2);
// 接收数据
always @(posedge clk or negedge rst_n)
begin
if (!rst_n)
data_out <= 16'b0;
else
data_out <= data_in; // 在启动时加载输入数据
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
// DIN <= 1'b1;
// CS <= 1'b1;
//end
// else if(pos)begin
//DIN <= data_out[15];
//CS <= 1'b0;
//end
//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 CS <= 1'b0; DIN <= data_out[15]; end//CS <= 1'b0;
7'd2: begin SCLK <= 1'b1; DIN <= data_out[14]; end
7'd4: begin SCLK <= 1'b1; DIN <= data_out[13]; end
7'd6: begin SCLK <= 1'b1; DIN <= data_out[12]; end
7'd8: begin SCLK <= 1'b1; DIN <= data_out[11]; end
7'd10: begin SCLK <= 1'b1; DIN <= data_out[10]; end
7'd12: begin SCLK <= 1'b1; DIN <= data_out[9]; end
7'd14: begin SCLK <= 1'b1; DIN <= data_out[8]; end
7'd16: begin SCLK <= 1'b1; DIN <= data_out[7]; end
7'd18: begin SCLK <= 1'b1; DIN <= data_out[6]; end
7'd20: begin SCLK <= 1'b1; DIN <= data_out[5]; end
7'd22: begin SCLK <= 1'b1; DIN <= data_out[4]; end
7'd24: begin SCLK <= 1'b1; DIN <= data_out[3]; end
7'd26: begin SCLK <= 1'b1; DIN <= data_out[2]; end
7'd28: begin SCLK <= 1'b1; DIN <= data_out[1]; end
7'd30: begin SCLK <= 1'b1; 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'b0; end
7'd32: begin SCLK <= 1'b1;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
代码是子模块,一些输入在顶层模块中,仿真过没问题。