如果其他工程的外部器件需要用到一个SCLK,并且该外部器件的时序图可通过序列机实现(如DAC_TLV5618),则可以通过稍微改动来产生一个可变的时钟SCLK。
//************************************************************ // DAC_TLV5618模块中的任意偶数频率分频 //************************************************************* module DAC_TLV5618( Clk, Rst_n, Start, DAC_data, // DAC_state Set_done, SCLK, CS, DIN ); input Clk; input Rst_n; input Start; // 模块使能信号 input [15:0] DAC_data; //控制器,控制字,高4位为控制字,低12位为数据位 output reg Set_done; //更新 DAC 完成标志,每次完成更新产生一个高电平脉冲,脉冲宽度为 1 个时钟周期 output reg SCLK; //TLV5618 的 SCLK 接口 output reg CS; //TLV5618 的 CS 接口 output reg DIN; //TLV5618 的 DIN 接口 // output DAC_state; //模块状态标识,低电平时为忙标志,高电平为空闲状态 parameter DIV_param = 2; //实际上这里的SCLK为CLK的4分频, DIV_param = 3,SCLK为CLK的6分频...... //reg define reg EN; //转换使能信号 reg SCLK2X; //2倍SCLK时钟频率 reg [7:0] DIV_cnt; //分频计数器 //reg [7:0] DIV_param; //可调分频参数 reg [5:0] SCLK2X_cnt; //对SCLK2X脉冲进行计数,用于计数产生序列机所需的脉冲数 //EN使能信号仅在数据传输时有效,传输完毕时无效 always@(posedge Clk or negedge Rst_n)begin if(!Rst_n) EN <= 1'b0; else if(Start) EN <= 1'b1; else if(Set_done) EN <= 1'b0; else EN <= EN; end //生成2倍SCLK使能时钟计数器 always@(posedge Clk or negedge Rst_n)begin if(!Rst_n) DIV_cnt <= 8'd0; else if(EN)begin if(DIV_cnt == (DIV_param - 1'b1)) DIV_cnt <= 8'd0; else DIV_cnt <= DIV_cnt + 1'b1; end else DIV_cnt <= 8'd0; end //生成SCLK2X时钟,高电平仅为一个clk周期的时间 always@(posedge Clk or negedge Rst_n)begin if(!Rst_n) SCLK2X <= 1'b0; else if(EN && (DIV_cnt == (DIV_param - 1'b1))) SCLK2X <= 1'b1; else SCLK2X <= 1'b0; end //对SCLK2X高电平进行计数,由DAC写入时序图得知,该序列机需要计数34个数 always@(posedge Clk or negedge Rst_n)begin if(!Rst_n) SCLK2X_cnt <= 6'd0; else if(EN) begin if(EN && SCLK2X) begin if(SCLK2X_cnt == 6'd33) SCLK2X_cnt <= 6'd0; else SCLK2X_cnt <= SCLK2X_cnt + 1'b1; end else SCLK2X_cnt <= SCLK2X_cnt; end else SCLK2X_cnt <= 6'd0; end //通过case语句,生成SCLK时钟频率,并且在对应的SCLK上升沿把数据送到DIN数据线上 always@(posedge Clk or negedge Rst_n)begin if(!Rst_n)begin SCLK <= 1'b0; CS <= 1'b1; DIN <= 1'b1; Set_done <= 1'b0; end else if(!Set_done && SCLK2X)begin case(SCLK2X_cnt) 0 : begin SCLK <= 1'b1; DIN <= DAC_data[15] ; CS <= 1'b0; end 2 : begin SCLK <= 1'b1; DIN <= DAC_data[14] ; end 4 : begin SCLK <= 1'b1; DIN <= DAC_data[13] ; end 6 : begin SCLK <= 1'b1; DIN <= DAC_data[12] ; end 8 : begin SCLK <= 1'b1; DIN <= DAC_data[11] ; end 10 : begin SCLK <= 1'b1; DIN <= DAC_data[10] ; end 12 : begin SCLK <= 1'b1; DIN <= DAC_data[9] ; end 14 : begin SCLK <= 1'b1; DIN <= DAC_data[8] ; end 16 : begin SCLK <= 1'b1; DIN <= DAC_data[7] ; end 18 : begin SCLK <= 1'b1; DIN <= DAC_data[6] ; end 20 : begin SCLK <= 1'b1; DIN <= DAC_data[5] ; end 22 : begin SCLK <= 1'b1; DIN <= DAC_data[4] ; end 24 : begin SCLK <= 1'b1; DIN <= DAC_data[3] ; end 26 : begin SCLK <= 1'b1; DIN <= DAC_data[2] ; end 28 : begin SCLK <= 1'b1; DIN <= DAC_data[1] ; end 30 : begin SCLK <= 1'b1; DIN <= DAC_data[0] ; end 32 : begin SCLK <= 1'b1; end 1 ,3 , 5 , 7 , 9 , 11 , 13 , 15 , 17 , 19 , 21 , 23 , 25 , 27 , 29 , 31 : SCLK <= 1'b0; 33 : begin SCLK <= 1'b0; CS <= 1'b1; Set_done <= 1'b1; end default : ; endcase end else ; end endmodule
上述代码的仿代码:
//************************************************************ // DAC_TLV5618_tb模块 //************************************************************* `timescale 1ns/1ps `define clk_period 20 module DAC_TLV5618_tb; reg sys_clk; reg sys_rst_n; reg Start; reg [15:0] DAC_data; wire SCLK; wire CS; wire Set_done; wire DIN; //模块例化 DAC_TLV5618 #(.DIV_param(3)) DAC_TLV5618( //仿真设置的是将CLK进行6分频得到时钟SCLK .Clk(sys_clk), .Rst_n(sys_rst_n), .Start(Start), .DAC_data(DAC_data), // .DAC_state(DAC_state), .Set_done(Set_done), .SCLK(SCLK), .CS(CS), .DIN(DIN) ); initial sys_clk = 1'b1; always #(`clk_period/2) sys_clk = ~sys_clk; initial begin sys_rst_n = 1'b0; Start = 1'b0; #10; sys_rst_n = 1'b1; Start = 1'b1; DAC_data = 16'd43690; #18_000; Start = 1'b0; #1000; Start = 1'b1; #18_000; Start = 1'b0; $stop; end endmodule
仿真图(CLK6分频):