| 
 
| 本帖最后由 lllxxx111 于 2023-1-31 17:29 编辑 
 [url=home.php?mod=space&uid=760190]@21小跑堂 #有奖活动#[/url] #申请原创#
 一:MMCM配置差分对讲解
 在开发过程中,FPGA的板载时钟为差分信号,然后AD8403的时钟输入为单端晶振,这时候就不能简单的把差分信号当一般的时钟晶振去使用了,需要Vivado里面的clock IP核去配置,配置方法很简单,直接在Vivado 软件编程页面左侧点击IP,然后在搜索框里输入clock点击搜索就行,如图1.
 
 图1 clock IP核配置打开之后里面有MMCM和PLL 这两个都可以通过Xilinx的原语把差分信号分成不同频率的单端信号,这里我选择的是用MMCM然后在Port Name中输入差分对(差分对有P/N两个管脚,一般可以理解为P为+管脚,N为-管脚)的P管脚名称,在Input Frequency(Mhz)里面输入差分对的频率。我这里是100MHz,之后在SOURce里面选择Differential clock 如图2,其他的选项则不需要改变。 
 图2  IP核配置设置之后点击Output Clocks(输出时钟配置选项),在clk_out1前面点击对号,在Output Freq(MHz)列输入想要的单端时钟的频率,为了方便我把最下面的复位管脚等等都取消了如图3。这时候就可以看见自动生成的代码了如图4。 
 图3 配置输出频率页面找到.veo文件可以看见里面有自动生成的代码,这里的代码不需要改动,直接复制到主程序里面即可,代码如下 //----------- Begin Cut here for INSTANTIATION Template ---// INST_TAG
 clk_wiz_0 instance_name
 (
 // Clock out ports
 .clk_out1(clk_out1),     // output clk_out1
 // Clock in ports
 .clk_in1_p(clk_in1_p),    // input clk_in1_p
 .clk_in1_n(clk_in1_n));    // input clk_in1_n
 // INST_TAG_END ------ End INSTANTIATION Template --------
 
 图 4  自动生成的代码把代码拷贝到主程序里面,进行配置代码如下,要注意的是要把instance_name改成自己需要的名字。 /*锁相环锁差分时钟输出50Mhz 单时钟*/
 wire clk_50Mhz=0;
 clk_wiz_0 clk_50M_out
 (
 // Clock out ports
 .clk_out1(clk_50Mhz),     // output clk_out1
 // Clock in ports
 .clk_in1_p(clk32M_p),    // input clk_in1_p这是FPGA板上的32Mhz差分对的P端
 .clk_in1_n(clk32M_n)
 );    // input clk_in1_n
 /**/
 二:SPI通信协议讲解及其实现
 AD8403通过SPI协议与FPGA通信,SPI需要完成9位数据的发送,SPI为全双工串行通信协议,在串行发送数据的时候,数据位的低位处于后面,高位处于前面,SPI在电路中可以通过四根线来实现,一般主机和子机连接方式如图
 
   图5  SPI接口图(不能交叉连接)  从上往下介绍:
 CS管脚:为使能管脚,从图上可以看出是主Master控制从Slave的,这也就意味着在代码里面定义主机CS时候有定为输出管脚,从机代码里面CS要定义为输入模式。
 SCK管脚:就是传统的CLK时钟管脚,和CS类似也是主机SCK为输出模式,从机SCK为输入模式,所有主机的SCK都有主机发出,共用主机的SCK。
 MOSI:为主机发送 从机接收线,需要把主机的MOSI设置为输出模式,从机的MOSI设置为输入模式。
 MISO:为主机接收 从机发送线,所以在定义变量的时候需要把主机里面的MISO设置成输入模式,从机里面的MISO设置成输出模式。
 根据手册这里SCK设置成在上升沿采样,主机在MISO处接收从机数据同理,从机在MOSI处采样,所以在一个时钟周期内会有1bit的数据交换,如图6.
 
 如图 6  一个周期内有1bit数据交换代码实现如下 //所要发送的数据A1 A0 D7 D6 D5 D4 D3 D2 D1 (2进制) 11_1010_0101  A5
 reg[9:0] Send_Data = 10'b11_1010_0101;
 /*构造状态机*/
 reg[4:0] Data_State = 5'd0;
 parameter D0_State = 5'd0;//发送最低位数据-状态
 parameter D1_State = 5'd2;
 parameter D2_State = 5'd4;
 parameter D3_State = 5'd6;
 parameter D4_State = 5'd8;
 parameter D5_State = 5'd10;
 parameter D6_State = 5'd12;
 parameter D7_State = 5'd14;
 parameter D8_State = 5'd16;
 parameter D9_State = 5'd18; //发送最高位数据-状态
 always@(posedge clk_50Mhz or posedge CLK_50M or negedge RST_N )
 // CLK_50M 和RST_N为激励晶振or posedge CLK_50M  or negedge RST_N
 begin
 if(RST_N == 0)//复位
 begin
 SCK <= 1'b0;    //SCK初始电平为低
 CS <= 1'b1;     //CS初始电平为高
 MOSI <= 1'b0;   //MOSI初始电平为低
 end
 else//产生SPI时序
 begin
 CS <= 0;//CS拉低准备数据传输
 case(Data_State)
 5'd1,
 5'd3,
 5'd5,
 5'd7,
 5'd9,
 5'd11,
 5'd13,
 5'd15,
 5'd17,
 5'd19://每次放置数据完毕后 在此拉高时钟线,便于下次的下降沿产生1111 奇数拉高
 begin
 SCK <= 1'b1;//准备在下降沿放置数据,提前将SCK拉高 CLK1 SCK为高读取数据
 Data_State <= Data_State + 4'd1;//切换为数据放置状态(每发完1bit数据进入此一次,将时钟线拉高)
 End
 之后每一位数据都是在下降沿放置数据,然后在切换状态
 举一个例子第0位数据的发送
 5'd20:
 begin
 SCK<=1'b0;
 CS<=1'b1;
 MOSI <= 1'b0;
 end
 D0_State://第0位数据发送状态 -- CLK0 SCK为低放置数据
 begin
 MOSI <= Send_Data[9];//A1数据
 SCK <= 1'b0;//在下降沿放置数据
 //CS<=1'b1;
 Data_State <= Data_State + 4'd1;//切换状态
 end
 之后的8位数据类似。写完激励代码,然后仿真出来如图5,达到了预期的效果(未完待续)。
 
 图7   仿真图像 | 
 
×本帖子中包含更多资源您需要 登录 才可以下载或查看,没有账号?注册 
  评论 |