1.开发环境
评估资源:x*0.6;
选择合适的逻辑量;
RAM资源;
关注特殊资源;
2.LED
a.PLL锁相环:时钟分频器、倍频器、调整相位
b.IP核:厂商提供
c.时间分频器:PLL都是M级别,需要自己设计合适的时钟
d.LED的输出:亮或者灭
e.I/O物理约束:绑定具体的控制引脚。像我所使用的板子晶振引脚u18,灯T14;
f.上板验证
设计点亮LED:先画模块图,输入8MHZ,分频获得1KHZ的时钟,连接到LED驱动,最后输出。
注意事项:1.小灯个数;2.LED的翻转时间(这里设定为1ms);3.LED点亮的电平(高或者低)
按位取反和非的区别:一个是每位取反,另一个低字节取反(逻辑取反)
分频器的设计:
4分频:计数为2时取反;
8分频:计数为4取反;以此类推
但这里要注意的是,不要用除法(/),而是用移位算法。右移几位就是除以2的几次方。
例如:100(4)>>1=010(2)
另,值得注意的:设计模块时,需要自上而下;写代码时,需要从下到上;
所以点亮LED:
设计第一部分:LED_DRIVER
module LED_Drive#(
parameter P_LED_NUMBER =1,
parameter p_LED_CNT =1000,// LED翻转时间 ms
parameter p_LED_ON =1
)(
input i_clk,//1k的时钟,
input i_rst,//复位高有效
output [P_LED_NUMBER-1:0] o_led
);
顶层参数:方便后续的改动(类似C语言中的宏定义),定义LED 1s翻转一次。
声明端口以及名称;
这里格式较为固定,特别输入信号和复位信号。
reg [P_LED_NUMBER-1:0] ro_led; //LED输出寄存器
reg [15:0] r_cnt;
声明两个寄存器。reg类型为寄存器,wire类型就是电线;
wire w_clk_1KHZ;
assign o_led = ro_led;
assign 组合逻辑功能:可以理解成绑定;
always@(posedge w_clk_1KHZ, posedge i_rst)
begin
if(i_rst)
r_cnt<=0;
else if(r_cnt == p_LED_CNT-1)
r_cnt<= 0;
else
r_cnt<=r_cnt+1;
end
计数部分:在开头定义,LED1000ms翻转一次。因为数电中起始位是0,所以p_LED_CNT-1,而且if...else if()....else..格式相对固定;复位时,计数参数为0。计满时,清零;其余的情况就是在加1计数。
always@(posedge w_clk_1KHZ)
begin
if(i_rst)
ro_led<=0;
else if(r_cnt == p_LED_CNT-1)
ro_led<=~ro_led;
else
ro_led<=ro_led;
end
控制LED亮灭部分:
因为LED翻转,所以用计数器部分控制LED的亮灭。这里很清晰的可以看出,复位,LED灭;计数到999,LED翻转;其他的时候,就保持。(计数器在这里控制LED亮灭)
设计第二部分:CLK_DIV_module
这部分主要是把我们IP核PLL的频率设置成我们期望的。
第一步:依旧是设置顶层参数,以及声明定义端口
module CLK_DIV_module#(
parameter p_CLK_DIV_CNT = 2//16位宽:最大65535
)(
input i_clk,
input i_rst,
output o_clk_div
);
reg ro_o_clk_div;
reg [15:0] r_cnt;
定义两个寄存器
一个是输出频率的寄存器;一个是计数的寄存器
assign o_clk_div = ro_o_clk_div;
绑定引脚
always@(posedge i_clk,posedge i_rst) //分频计数器
begin
if(i_rst)
r_cnt<=0;
else if(r_cnt == (p_CLK_DIV_CNT >> 1)-1)
r_cnt<=0;
else
r_cnt<=r_cnt+1;
end
分频计数器设定:计数器格式几乎一致。复位,计满都清零,其余的情况都在计数。这里的条件是我们需要分频到P_CLK_DIV_CNT的2分频
always@(posedge i_clk,posedge i_rst)//控制时钟翻转
begin
if(i_rst)
ro_o_clk_div<=0;
else if(r_cnt ==(p_CLK_DIV_CNT >> 1)-1)
ro_o_clk_div<=~ ro_o_clk_div;
else
ro_o_clk_div<=ro_o_clk_div;
end
控制时钟翻转:只有当计数的寄存器在和分频相等时,时钟开始翻转;复位,清零;其余时间,则是保持不变。
设计第三部分:顶层设计以及连线。
第一步:声明定义端口;
module LED_TOP(
input i_clk,
output [1:0] o_led
);
wire w_clk_8MHZ;
wire w_clk_locked;
电线的声明,定义。
CLK_PLL CLK_PLL_u0
(
.clk_in1 (i_clk),
// Clock out ports
.clk_out1 (w_clk_8MHZ), // output clk_out1
// Status and control signals
.locked (w_clk_locked) // output locked
// Clock in ports
); // input clk_in1
LED_Drive#(
. P_LED_NUMBER (1 ),
. p_LED_CNT (1000),// LED翻转时间 ms
. p_LED_ON (1 )
)
LED_Drive_u0
(
.i_clk (w_clk_8MHZ ) ,//1k的时钟,
.i_rst (~w_clk_locked ) ,//复位高有效
.o_led (o_led[0] )
);
第二部分:连线。
fpga中连线用.在各个端口前。而端口后的()的值是可以随便修改。这种修改方式仅是在所调用的模块里修改,不是全局修改;全局修改一般是用defparam。注意区分。
连线注意事项:
1.顶层参数的连线;
2.例化模块名称,连线;这里注意看LED_Driver模块的操作;
3.调用IP核设置,vivado中IP核调用设置。一是频率设置(根据片子选择);二是要参与计数的频率设置。
没点亮的原因:一是在控制led翻转那里端口取反写错了。二是分频计数器那里写错了