TLC5615 DA转换 verilog FSM

管脚

在这里插入图片描述
在这里插入图片描述
输入数字数据格式,精度是10bit的数据大小,但是是串行输入的,所以要根据协议去传数据。
在这里插入图片描述
fpga向芯片串行发送,TLC5615芯片读完12bits之后,芯片进行内部转换,然后输出模拟电压

具体协议

在这里插入图片描述
1、sclk串行移位时钟的最快频率限制:该值有spi传输协议限制,一般取决于Tsclk的高低电平的最小值之和。由手册可知,tw(CH)=tw(CL)=25ns(最小值),则fsclk_max=1/50ns=20MHz,留有一定空间,故fsclk不能过大,手册给出经验值14MHz,设计时按照此值即可。

如果用50MHz的时钟,需要降频,四个50M的时钟做一个ad_clk,降成12.5MHz即可。

2、dac输出极限频率限制:

手册中有个概念,名为Setting time(注意不是建立时间setting up time),其义为:当输入的数字16进制码(12bit)从000变化到3ff(或者从3ff变化到000),dac输出电压保持稳定在目标电压的±0.5LSB范围内的时间,也可以称之为广义的建立时间。按这样定义的话,这个参数决定了dac的输出频率,因为这个时间概念是一个范围概念,其包括了很多个时间之和(隐含从000à001的时间以及001à010的时间等等,他是这之间所有变换的时间之和),则fo_max=1/(2*12.5us)=40KHz,很多资料说是80KHz(只取12.5us,这里的意思是全范围内的输出的更新率,如从0V输出到5V输出,这个时间间隔是12.5us,那么输出正弦波的频率就应该小于40KHz)

状态机控制状态转换
在这里插入图片描述

code

Step1:调用rom_ip生成数据源,预先用mif文件初始化rom,这部分网上可以自行百度,其后,需要简单写一个data_init的module,用来从rom调度数据输出,这时调度的间隔对应输出频率。

Step2:sclk的生成,采用20ns*4的周期(tf_sclk最小为50ns,技术文档中有说明),在cs_n拉低后,应该是输出12个时钟(tlc5615的12bit方式),这里,注意细节:若采用sclk=~sclk的方式,最后容易产生不标准的sclk信号(多一次翻转,或者在cs_n拉高后sclk变成高)。解决的办法是:sclk_cnt为1和3时输出对应态,不采用取反方式。

Step3: 移位

step4: 如果目标需要上升沿的数据读取,那么就应该在下降沿将数据写入(对应上文中的移位输出),这样就能够在上升沿稳定读取到目标数据了。充分体现了相异边沿对数据的写入和读取的思想

module da(
    clk    ,
    rst_n  ,
    //INPUT
    DA_data,
    Send_start,
    //OUT
    Da_clk,
    Da_din,
    Da_cs_n,
    Send_finish
    );

    //参数定义
    parameter      DATA_W =        10;

    //输入信号定义
    input               clk         ;
    input               rst_n       ;
    input[DATA_W-1:0]   DA_data     ;
    input               Send_start  ;

    //输出信号定义
    output              Da_din           ;
    output              Da_clk           ;
    output              Da_cs_n          ;
    output              Send_finish      ;


    //中间信号定义
    reg[2:0]          state;
    reg[2:0]          state_n;
    parameter IDLE = 3'b000;
    parameter START = 3'b001;
    parameter WRITE = 3'b010;
    parameter FINISH = 3'b011;

    //
    reg[4:0] bit_cnt;
    reg [3:0] sclk_cnt;
    //cs_n
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            Da_cs_n<=1;
        end
        else if(state==START)begin
            Da_cs_n<=0;
        end
        else if(state==FINISH) begin
            Da_cs_n<=1;            
        end
        else begin
            Da_cs_n<=Da_cs_n;
        end
    end
    //sclk_cnt 4个50MHz 12.5Mhz的adclk
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            sclk_cnt<=0;
        end
        else if(Da_cs_n||sclk_cnt==3)begin
            sclk_cnt<=0;
        end
        else if(Da_cs_n==0)begin
            sclk_cnt<=sclk_cnt+1;            
        end
    end
    //Da_clk
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            Da_clk<=0;
        end
        else if(Da_cs_n==0)begin//START 和WRITE期间
            if(sclk_cnt==1)
                Da_clk<=1;
            else if(sclk_cnt==3)
                Da_clk<=0;                
        end
        else 
                Da_clk<=0;           
    end
    //wait_time 3个时钟,60ns
    reg [1:0] wait_cnt;
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            wait_cnt<=0;
        end
        else if(state_n!=state||wait_cnt==2)begin
            wait_cnt<=0;
        end
        else if(state==START||state==FINISH) 
            wait_cnt<=wait_cnt+1;            
    end
    //状态机
    always @ (posedge clk, negedge rst_n) begin
    	if (!rst_n)
	    	state <= IDLE;
    	else
	    	state <= state_n;
    end

    always@(*)begin
        case
            IDLE:begin
				if (Send_start)
					state_n = START;
				else
					state_n = state;
            end
            START:begin
                if(wait_cnt==2)//等待三个时钟
					state_n = WRITE;
				else
					state_n = state;
            end
            WRITE:begin
 				if (bit_cnt == 12)
 					state_n = FINISH;
 				else
 					state_n = state;
 			end

     end
            FINISH:begin
                if(wait_cnt==2)//等待三个时钟
 					state_n = IDLE;
 				else
 					state_n = state;                    
            end
            default:state_n=IDLE;
        endcase
    end

    //bit_cnt
    always@(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            bit_cnt<=0;
        end
        else if(bit_cnt == 12) begin
            bit_cnt <=0;
        end
    	else if (state == WRITE && sclk_cnt == 4'd3)//下降沿,如果写adclk=0就慢了一个时钟
	    	bit_cnt <= bit_cnt + 1'b1;
        else 
	    	bit_cnt <= bit_cnt  ;
    end
    //shift_reg
    reg[11:0] shift_reg;
    reg[11:0] shift_reg_buff;    
    //shift_reg_buff
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            shift_reg_buff<=0;
        end
        else if(Send_start)begin
            shift_reg_buff<=DA_data;
        end
    end
    //shift_reg
    always  @(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            shift_reg<=0;
        end
        else if((state==START||state==WRITE)&&sclk_cnt==0)begin
            shift_reg<=shift_reg_buff<<bit_cnt;
        end
    end
    assign Da_din= shift_reg[11];		//将移位寄存器的最高位赋值给DA_DIN
    assign Send_finish=(state== IDLE);
    endmodule


发布了466 篇原创文章 · 获赞 279 · 访问量 75万+

猜你喜欢

转载自blog.csdn.net/qq_35608277/article/details/105458014
FSM
今日推荐