FPGA_SPI驱动设计

ADC驱动原理

TLV1548型ADC芯片内部结构 ,TLV1544型只有4个模拟输入引脚。
TLV1548有8个。
在这里插入图片描述
A0~A7为8个模拟通道,REF±为2个参考电压通道,DATA_IN为SPI数据接口输入端,Samples and Hold Function 为采样和保持功能。Analog MUX为模拟多路器。10-bit ADC转换数据功能。
DSP(数字信号处理)。

使用FPGA模拟SPI接口

在这里插入图片描述
TLV1544通过SPI接口与控制器进行通信的时序图如下所示:
在这里插入图片描述

FPGA下降沿更新D1,上升沿写入AD/DA模块;FPAG上升沿读取D0,AD/DA模块下降沿更新D0.

DO为数信号,DI为模拟信号。

ADC驱动模块设计

在这里插入图片描述

CONTROL_DO为开始采样使能信号,ADC_SEL为4个模拟通道选择信号,TLV1544_SDO为输入给FPGA采样数据,ADC_DONE为此次转换完成信号,ADC_DATE为采样结果,TLV1544_SDI为输出给ADC模块地址信号。DATE_VALUE表示ADC_DATE数据有效刚好把所有的DO数据提取到ADC_DATE数据中。

ADC控制模块

module TLV1544_CONTROL(
  CLK,
  RST_N,
  CONTROL_DO,  //开始采样使能信号
  ADC_SEL,   //4个模拟通道选择信号
  TLV1544_SDO,  //ADC采样转化的数字信号
  TLV1544_EOC,   
  
  ADC_DONE,   //一次采样完成
  ADC_DATE,   //采样结果
  TLV1544_FS,   //SPI模式下默认高电平
  TLV1544_nCS,  //低电平有效
  TLV1544_CLOCK,
  DATE_VAUEL,   //ADC_DATE数据有效信号(ADC为转换之前)
  TLV1544_SDI
  );

 input CLK;
 input RST_N;
 input CONTROL_DO;  //开始采样使能信号
 input  [3:0] ADC_SEL;   //4个模拟通道选择信号
 input  TLV1544_SDO;  //ADC采样转化的数字信号
 input  TLV1544_EOC;   
  
 output reg ADC_DONE;   //一次采样完成
 output reg [9:0]ADC_DATE;   //采样结果
 output wire TLV1544_FS;   //SPI模式下默认高电平
 output reg TLV1544_nCS;  //低电平有效
 output reg TLV1544_CLOCK;
 output reg DATE_VAUEL;   //ADC_DATE数据有效信号(ADC为转换之前)
 output reg  TLV1544_SDI;  //地址信号位
 
 reg [7:0]count;
 reg [9:0]r_date;
 
 assign TLV1544_FS = 1'b1;
 
 //计数
always @(posedge CLK or negedge RST_N)
if(!RST_N)
 count <= 8'b0;
else  if((TLV1544_EOC ==1) && count <204 && (CONTROL_DO ==1 || count>0))
  count <= count + 8'b1;
else if((TLV1544_EOC ==0) && count <204)
  count <= count ;
else if((TLV1544_EOC ==1) && count ==204)
  count <= 8'b0; 

 //序列机
always @(posedge CLK or negedge RST_N)
if(!RST_N) begin
ADC_DONE <= 0;
ADC_DATE <= 0;
TLV1544_nCS <= 0;
TLV1544_CLOCK <= 0;
DATE_VAUEL <= 0;
r_date <= 10'b0;
end  else
  begin  
case(count)  
            0: begin    
				            TLV1544_CLOCK <=0; 
				            TLV1544_nCS <=1; 
				            TLV1544_SDI <= 0;
				            ADC_DONE <= 0;
								r_date <= 10'b0;
								DATE_VAUEL <= 0;
				   end
				1: begin    
				            TLV1544_CLOCK <=0; 
				            TLV1544_nCS <=0; 
				            TLV1544_SDI <= ADC_SEL[3];
				   end
				9: begin   
				            TLV1544_CLOCK <=1; 
				            r_date[9] <= TLV1544_SDO;
				   end
				19:
				   begin   
				            TLV1544_CLOCK <=0; 
				            TLV1544_SDI <= ADC_SEL[2];
				   end
				29:
				   begin   
				            TLV1544_CLOCK <=1; 
				            r_date[8] <= TLV1544_SDO;
				   end
				39:
				   begin   
				            TLV1544_CLOCK <=0; 
				            TLV1544_SDI <= ADC_SEL[1];
				   end
				49:
				   begin   
				            TLV1544_CLOCK <=1; 
				            r_date[7] <= TLV1544_SDO;
				   end
				59:
				   begin   
				            TLV1544_CLOCK <=0; 
				            TLV1544_SDI <= ADC_SEL[0];
				   end
				69:
				  begin   
				            TLV1544_CLOCK <=1; 
				            r_date[6] <= TLV1544_SDO;
				   end
				79: TLV1544_CLOCK <=0; 
				89:
				  begin   
				            TLV1544_CLOCK <=1; 
				            r_date[5] <= TLV1544_SDO;
				  end
				99:TLV1544_CLOCK <=0; 
				109:
				  begin   
				            TLV1544_CLOCK <=1; 
				            r_date[4] <= TLV1544_SDO;
				  end
				119:TLV1544_CLOCK <=0; 
				129:
				   begin   
				            TLV1544_CLOCK <=1; 
				            r_date[3] <= TLV1544_SDO;
				   end
				139:TLV1544_CLOCK <=0; 
				149:
				     begin   
				            TLV1544_CLOCK <=1; 
				            r_date[2] <= TLV1544_SDO;
				     end
				159:TLV1544_CLOCK <=0; 
				169:
				   begin   
				            TLV1544_CLOCK <=1; 
				            r_date[1] <= TLV1544_SDO;
				     end
				179:TLV1544_CLOCK <=0; 
				189:
				    begin    TLV1544_CLOCK <=1; 
				       	    if(TLV1544_EOC)
					          DATE_VAUEL <= 1;
						       else		 
						       DATE_VAUEL <= 0;
				           
				           ADC_DATE <= {r_date[9:1],TLV1544_SDO};
				     end
				199:
				    begin   
				            TLV1544_CLOCK <=0; 
				            TLV1544_nCS <= 1;
				     end
				204:     ADC_DONE <= 1'b1;
				
				default: DATE_VAUEL <= 0; 
			endcase
end				
				
endmodule 

ADC控制仿真模块

`timescale 1ns/1ns
`define Clk_period 20
module TLV1544_CONTROL_tb;


 reg CLK;
 reg RST_N;
 reg CONTROL_DO;  //开始采样使能信号
 reg  [3:0] ADC_SEL;   //4个模拟通道选择信号
 reg  [9:0]TLV1544_SDO;  //ADC采样转化的数字信号
 reg  TLV1544_EOC;   
  
 wire ADC_DONE;   //一次采样完成
 wire [9:0]ADC_DATE;   //采样结果
 wire TLV1544_FS;   //SPI模式下默认高电平
 wire TLV1544_nCS;  //低电平有效
 wire TLV1544_CLOCK;
 wire DATE_VAUEL;   //ADC_DATE数据有效信号(ADC为转换之前)
 wire [3:0] TLV1544_SDI;  //地址信号位

TLV1544_CONTROL TLV1544_CONTROL0(
  .CLK(CLK),
  .RST_N(RST_N),
  .CONTROL_DO(CONTROL_DO),  
  .ADC_SEL(ADC_SEL), 
  .TLV1544_SDO(TLV1544_SDO), 
  .TLV1544_EOC(TLV1544_EOC),   
  
  .ADC_DONE(ADC_DONE),   
  .ADC_DATE(ADC_DATE),   
  .TLV1544_FS(TLV1544_FS),  
  .TLV1544_nCS(TLV1544_nCS),  
  .TLV1544_CLOCK(TLV1544_CLOCK),
  .DATE_VAUEL(DATE_VAUEL),  
  .TLV1544_SDI(TLV1544_SDI)
  );
  
initial CLK =1;
always #(`CLK_period/2) CLK =~CLK;

initial  begin
RST_N = 0;
CONTROL_DO = 0;
ADC_SEL = 0;
TLV1544_SDO = 0;
TLV1544_EOC = 1;
#(`CLK_period*10);
RST_N = 1;
ADC_SEL = 0;

#(`CLK_period*2);
CONTROL_DO = 1;
#`CLK_period;
CONTROL_DO = 0;
@(posedge (TLV1544_CONTROL0.count==8'd189));
#(`CLK_period);
TLV1544_EOC=0;
#(`CLK_period*20+1);
TLV1544_EOC=1;
#(`CLK_period*1000);


#(`CLK_period*2);
CONTROL_DO = 1;
#`CLK_period;
CONTROL_DO = 0;
@(posedge (TLV1544_CONTROL0.count==8'd189));
#(`CLK_period);
TLV1544_EOC=0;
#(`CLK_period*20+1);
TLV1544_EOC=1;
#(`CLK_period*1000);
$stop;
end
initial begin  
forever begin
TLV1544_SDO = ~TLV1544_SDO;
#360;
end
end

endmodule

仿真结果

在这里插入图片描述

可以看到DO数据在TLV1544_CLOCK上升沿读取数据到r_date,在count位189时将r_date的值传输到ADC_DATE。

基于SPI的SSOP芯片驱动

SSOP是一款16 路恒流输出芯片。

设计图

根据芯片手册引脚说明与定义设计控制器端口框图。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
目前选择芯片真值表第一种状态。满足芯片手册端口信号条件。
在这里插入图片描述

时序设计图

为满足整个工程资源优化,SPI通信时钟选择10MHZ。
时序设计图如下:
在这里插入图片描述

工程文件

采用线性序列机的思想,以count计数为条件编写case语句。

`timescale 1ns / 1ps

    
module ssop_control(
            
    input                   clk         ,           //10MHZ
    input                   rst_n       ,
    input                   con_en      ,           //  pulse.  width>=0.1us
    input       [15:0]      con_data    ,   
    
    output      reg         ssop_sin    ,
    output      reg         ssop_oe     ,
    output      reg         ssop_le     ,
    output      reg         ssop_state  ,
    output      wire        ssop_clk                 //10MHZ
    
    );
    
    reg         [4:0]       count       ;
    reg         [15:0]      r_con_data  ;           
    reg         [15:0]      m_r_con_data;
    
assign      ssop_clk    =  ~ clk         ;

always @(posedge clk or negedge rst_n)
    if(!rst_n)
        r_con_data      <=      1'b0    ;
    else
        r_con_data      <=      con_data    ;
        
always @(posedge clk or negedge rst_n)
    if(!rst_n)
        m_r_con_data    <=      1'b0    ;
    else
        m_r_con_data    <=      r_con_data  ;



always @(posedge clk or negedge rst_n)
    if(!rst_n)
        count   <=      5'b0;
    else
    if(con_en   ||  (   count  > 5'b0  ))   
        begin
            if(count    ==  5'h10)                  //'d16
                count   <=  5'b0    ;
            else
                count   <=      count   +   1'b1;
        end
   

always @(posedge clk or negedge rst_n)
    if(!rst_n)
        begin
            ssop_sin        <=      1'b0;            
            ssop_oe         <=      1'b1;        
            ssop_le         <=      1'b0;        
            ssop_state      <=      1'b0;        
        end
    else
        begin
            case(count)
                
                5'h1:
                    begin
                        ssop_sin        <=      m_r_con_data[15];
                        ssop_oe         <=      1'b0;
                        ssop_le         <=      1'b1;
                        ssop_state      <=      1'b1;
                    end
        
                5'h2:
                        ssop_sin        <=      m_r_con_data[14];                
        
                5'h3:
                        ssop_sin        <=      m_r_con_data[13];          
        
                5'h4:
                        ssop_sin        <=      m_r_con_data[12];                
        
                5'h5:
                        ssop_sin        <=      m_r_con_data[11];
                    
                5'h6:
                        ssop_sin        <=      m_r_con_data[10];

                5'h7:
                        ssop_sin        <=      m_r_con_data[9]; 

                5'h8:
                        ssop_sin        <=      m_r_con_data[8];

                5'h9:
                        ssop_sin        <=      m_r_con_data[7];

                5'ha:
                        ssop_sin        <=      m_r_con_data[6];

                5'hb:
                        ssop_sin        <=      m_r_con_data[5];                 

                5'hc:
                        ssop_sin        <=      m_r_con_data[4];

                5'hd:
                        ssop_sin        <=      m_r_con_data[3];

                5'he:
                        ssop_sin        <=      m_r_con_data[2];

                5'hf:
                        ssop_sin        <=      m_r_con_data[1];

                5'h10:
                        ssop_sin        <=      m_r_con_data[0];
                
                default :   
                    begin
                        ssop_sin        <=      1'b0;
                        ssop_oe         <=      1'b1;
                        ssop_le         <=      1'b0;
                        ssop_state      <=      1'b0;
                    end
            endcase 
        end
endmodule

前仿真

仿真文件

模拟两次数据发送。

`timescale 1ns / 1ns
`define CLK_PER 100

module ssop_tb();

reg             rst_n           ;
reg             clk             ;
reg             con_en          ;
reg     [15:0]  con_data        ;

wire            ssop_sin        ;
wire            ssop_oe         ;
wire            ssop_le         ;
wire            ssop_state      ;
wire            ssop_clk        ;

initial clk = 1;
always  #(`CLK_PER/2) clk = ~ clk;

ssop_control    ssop_control_inst(
            
        .clk         (clk),           //10MHZ
        .rst_n       (rst_n),
        .con_en      (con_en),           //  pulse.  width>=0.1us
        .con_data    (con_data),   
        
        .ssop_sin    (ssop_sin  ),
        .ssop_oe     (ssop_oe   ),
        .ssop_le     (ssop_le   ),
        .ssop_state  (ssop_state),
        .ssop_clk    (ssop_clk  )             //10MHZ
    
    );

initial
begin
    rst_n   =   0;
    con_en  =   0;
    con_data=   0;
    #(`CLK_PER*5+1);    
    rst_n   =   1;
    //first send   data
    con_data=   16'hfaaa;
    #(`CLK_PER*2+1);
    con_en  =   1;    
    #(`CLK_PER*2+1); 
    con_en  =   0;
    #(`CLK_PER*200); 
    //second    send    data
    con_data=   16'hebdc;
    #(`CLK_PER+1);
    con_en  =   1;    
    #(`CLK_PER*2+1); 
    con_en  =   0;    
    #(`CLK_PER*600);    
    
    $stop;
end
endmodule

仿真结果

请添加图片描述
请添加图片描述
满足芯片手册时序要求。满足手册最小时间。请添加图片描述
请添加图片描述

  • 7
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值