1.引言
此驱动程序已经完成很久了,花了2个星期的时间,主要是提升程序运行的效率。最近整理文件的时候又看到了,记录一下。文章来源:https://www.toymoban.com/news/detail-691575.html
2.程序框架分解
module adc7254_Ctrl(
input sys_clk, //system clkc 50M
input reset_n, //reset flag
input iData_a_in, //ADC to fpga
input iData_b_in,
output sclk_out, //to ADC
output cs_out, //to ADC
output sdin, //to ADC
output [11:0] oData_a, //get data
output [11:0] oData_b //get data
);
wire clk_200M; //PLL驱动
AD_PLL AD_PLL_inst(
.inclk0(sys_clk),
.c0(Clk_200M),
.c1(sclk_out)
);
wire En_conv,En_send; //定义ADC发送和接收程序的状态切换时间
adc_test adc_test_inst(
.iRst_n(reset_n),
.iDclk(sclk_out),
.iSend_down(Send_down),
.oAdc_rst_n(adc_rst_n),
.oEn_conv(En_conv),
.oEn_send(En_send)
);
wire Send_down; //ADC指令发送部分
adc_in_send adc_in_send_inst
(
.iClk_200M(Clk_200M),
.iRst_n(adc_rst_n),
.iDcLK(sclk_out),
.iEn_send(En_send),
.oSDATA(sdin),
.oSend_down(Send_down)
);
wire Conv_down;
adc_out_conv adc_out_conv_inst //ADC数据采样部分
(
.iClk_200M ( Clk_200M ),
.iRst_n ( adc_rst_n ),
.iEn_conv ( En_conv ),
.iDcLK ( sclk_out ),
.iData_a_in ( iData_a_in ),
.iData_b_in ( iData_b_in ),
.oData_a ( oData_a ),
.oData_b ( oData_b ),
.oConv_down ( Conv_down )
);
assign cs_out = Conv_down & Send_down; //状态完成
endmodule
3.子任务分解
(1)状态控制程序
其主要是以空状态,写状态,读状态三个状态顺序执行的。文章来源地址https://www.toymoban.com/news/detail-691575.html
module adc_test(
input iRst_n,
input iDclk,
input iSend_down,
output oAdc_rst_n,
output reg oEn_send,
output reg oEn_conv
);
reg [1:0] state;
reg [5:0] sclk_cnt;
localparam state_IDLE = 2'd0;
localparam state_Write = 2'd1;
localparam state_Read = 2'd3;
assign oAdc_rst_n = (iRst_n & state);
always @(posedge iDclk or negedge iRst_n) begin
if(!iRst_n)begin
sclk_cnt <= 6'd0;
state <= state_IDLE;
oEn_conv = 1'd0;
oEn_send = 1'd0;
end else begin
case(state)
state_IDLE:
begin
if (sclk_cnt > 6'd30 ) begin
sclk_cnt <= 6'd0;
state <= state_Write;
oEn_conv = 1'd0;
oEn_send = 1'd1;
end else begin
sclk_cnt <= sclk_cnt + 1'd1;
state <= state_IDLE;
oEn_conv = 1'd0;
oEn_send = 1'd0;
end
end
state_Write:
begin
if (iSend_down == 1'd1 && sclk_cnt > 6'd30 ) begin
sclk_cnt <= 0;
state <= state_Read;
oEn_conv = 1'd1;
oEn_send = 1'd0;
end else begin
sclk_cnt <= sclk_cnt + 1'd1;
state <= state_Write;
oEn_conv = 1'd0;
oEn_send = 1'd1;
end
end
state_Read:
begin
state <= state_Read;
sclk_cnt <= 1'd0;
oEn_conv = 1'd1;
oEn_send = 1'd0;
end
endcase
end
end
endmodule
(2)写命令程序部分
module adc_in_send(
input iClk_200M, //200M
input iRst_n,
input iDcLK, //最小T>60ns
input iEn_send,
output oSDATA,
output oSend_down
);
//==================使能接收标志位en==================//
//一旦启动不会突然停止除非复位信号到来
reg en;
reg [5:0] sclk_cnt;
always @(posedge iDcLK or negedge iRst_n ) begin
if (!iRst_n) begin
en <= 1'd0;
sclk_cnt <= 6'd0;
end else if ( iEn_send == 1'd1 && sclk_cnt == 6'd0 ) begin
en <= 1'd1;
sclk_cnt <= 6'd32;
end else if ( sclk_cnt > 6'd1 ) begin
en <= en;
sclk_cnt <= sclk_cnt - 1'd1;
end else if (oSend_down == 1'd1 && sclk_cnt == 6'd1 ) begin
en <= 1'd0;
sclk_cnt <= sclk_cnt - 1'd1;
end else begin
en <= en;
sclk_cnt <= sclk_cnt;
end
end
//==================使能接收标志位en==================//
//==================SDATA输出操作=========================//
reg [15:0]CFR_16bit_data = 16'h8840; //需要写入寄存器中的数据
assign oSDATA = (en > 1'd0) ? ((sclk_cnt > 6'd17) ? CFR_16bit_data[sclk_cnt-6'd17] : 0 ): 0;
//==================SDATA操作=========================//
//==================oSend_down操作======================//
assign oSend_down = (sclk_cnt > 6'd1) ? 0 : 1;
//==================oSend_down操作======================//
endmodule
(3)读数据程序部分
module adc_out_conv(
input iClk_200M, //200M
input iRst_n,
input iData_a_in,
input iData_b_in,
input iDcLK, //最小T=60ns
input iEn_conv,
output reg [11:0] oData_a,
output reg [11:0] oData_b,
output oConv_down //T>70ns
);
//下降沿接收
//==================使能接收标志位en==================//
//一旦启动不会突然停止除非复位信号到来
reg en;//接收使能标志位
reg [5:0] sclk_cnt;
always @(posedge iDcLK or negedge iRst_n ) begin
if (!iRst_n) begin
en <= 1'd0;
sclk_cnt <= 5'd0;
end else if (iEn_conv == 1'd1 && sclk_cnt == 4'd0) begin
en <= 1'd1;
sclk_cnt <= 6'd17;
end else if (sclk_cnt > 4'd1) begin
en <= en;
sclk_cnt <= sclk_cnt - 1'd1;
end else if (oConv_down == 1'd1 && sclk_cnt == 4'd1)begin
en <= 1'd0;
sclk_cnt <= sclk_cnt - 1'd1;
end else begin
en <= en;
sclk_cnt <= sclk_cnt;
end
end
//==================使能接收标志位en==================//
//==================dclk时钟采样==================//
reg [6:0] dclk;
always@(posedge iClk_200M or negedge iRst_n) begin
if(!iRst_n) begin
dclk <= 7'd0;
end else if(!en) begin
dclk <= 7'd0;
end else begin
dclk <= {dclk[5:0],iDcLK};
end
end
//==================dclk时钟采样==================//
//==================状态切换==================//
reg [1:0] state;
parameter state_IDLE = 2'd0;
parameter state_Read = 2'd1;
parameter state_Write = 2'd2;
always@(posedge iClk_200M or negedge iRst_n) begin
if(!iRst_n ) begin
state <= state_IDLE;
end else if(!en) begin
state <= state_IDLE;
end else if(dclk[1] == 1 & dclk[2] == 0) begin
state <= state_Read;
end else if (dclk[1] == 0 & dclk[2] == 1) begin
state <= state_Write;
end else begin
state <=state;
end
end
//==================状态切换==================//
//==================data串行转并行==================//
reg [2:0] Data_a_in_temp,Data_b_in_temp;//保证7次采样有4次为1
reg [11:0] Data_a_temp,Data_b_temp;
always@(posedge iClk_200M or negedge iRst_n)
begin
if(!iRst_n ) begin
Data_a_temp <= 12'd0;
Data_b_temp <= 12'd0;
Data_a_in_temp <= 3'd0;
Data_b_in_temp <= 3'd0;
end else if(sclk_cnt > 6'd16)begin
Data_a_in_temp <= 3'd0;
Data_b_in_temp <= 3'd0;
Data_a_temp <= 12'd0;
Data_b_temp <= 12'd0;
end else if(sclk_cnt > 6'd3 ) begin
if(state == state_Read && dclk[6] == 0 ) begin
Data_a_in_temp <= Data_a_in_temp + iData_a_in;
Data_b_in_temp <= Data_b_in_temp + iData_b_in;
Data_a_temp <= Data_a_temp;
Data_b_temp <= Data_b_temp;
end else if(state == state_Write && dclk[0]!=dclk[1])begin
Data_a_in_temp <= 3'd0;
Data_b_in_temp <= 3'd0;
Data_a_temp <= {Data_a_temp[10:0],Data_a_in_temp[2]};
Data_b_temp <= {Data_b_temp[10:0],Data_b_in_temp[2]};
end else begin
Data_a_in_temp <= Data_a_in_temp;
Data_b_in_temp <= Data_b_in_temp;
Data_a_temp <= Data_a_temp;
Data_b_temp <= Data_b_temp;
end
end else begin
Data_a_in_temp <= Data_a_in_temp;
Data_b_in_temp <= Data_b_in_temp;
Data_a_temp <= Data_a_temp;
Data_b_temp <= Data_b_temp;
end
end
//==================data串行转并行==================//
//==================oConv_down操作======================//
assign oConv_down = (sclk_cnt > 6'd1) ? 0 : 1;
//==================oConv_down操作======================//
//==================数据按帧输出==================//
always@(posedge iClk_200M or negedge iRst_n)
begin
if(!iRst_n )
begin
oData_a <= 12'd0;
oData_b <= 12'd0;
end
else if( oConv_down == 1'd1)
begin
oData_a <= Data_a_temp;
oData_b <= Data_b_temp;
end
else
begin
oData_a <= oData_a;
oData_b <= oData_b;
end
end
//==================数据按帧输出==================//
endmodule
到了这里,关于FPGA SPI 驱动程序的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!