本帖最后由 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 仿真图像 |
@lllxxx111 :嗯嗯 好的
@21小跑堂 :我是首发,然后申请原创
点赞
@21小跑堂 :嗯嗯,可以的,刚开始不会弄,不知道咋回事发了两遍。
@lllxxx111 :嗯嗯嗯,您前面两篇文章标题不同,但看起来内容是一样的呀!若果是原创首发的话就给您审一篇了哈。
@21小跑堂 :好的,好的我补充上。
您好,咱是要申请原创吗?原创申请文章需要是原创并首发且文字接近800字(不含代码)。https://bbs.21ic.com/icview-3279072-1-1.html这个您可以详细看下哦~ 您补充下文化在那个可以再@21小跑堂一遍哦