前言
这是本人第一次使用FPGA,感谢小眼睛科技公司以及elefans提供的每日一练和每周一练的机会,本人将借助这次机会入门FPGA,了解一下FPGA的神奇之处。
1 开发环境
官方工作人员提供了如下开发工具包:
1K2K链接:https://pan.baidu.com/s/18EBJd9TYyTuXH4MlEh2qZA
提取码:tknh
PDS软件Lite版本(免License)链接:https://pan.baidu.com/s/1hY0XZtZcntyVp87nd9HUWA
提取码:6abm
这里需要说明一点的就是,“1K2K链接”下面提供了pango Design Suite的开发包,但是是需要license的,需要向紫光同创申请,所以为了最好安装PDS软件Lite版本,用Lite版本开发,已经足够我们学习使用了。
环境安装就不多说了,直接安装“PDS软件Lite版本(免License)链接”下面提供的软件即可。
2 开发学习
参考“1K2K链接”下面提供的“MES2KG”,里面有示例代码和说明,我们可以参考这些入门。
下面就是我实现流水灯的过程。
2.1 新建工程
PDS使用教程可以参考资料包里面的文档《PDS快速使用手册.docx》。
到了如下一步之后选择如下,因为我们的板子是PGC1KG-6LPG100:
芯片型号一定要选对,不然的话烧录器是连接不上的,最开始我使用官方Demo就一直连不上烧录器JTAG,最后找了很久才发现是芯片型号不对。
2.2 软件编写
本人也是第一次使用FPGA,所以基本上还是参考官方提供的Demo来实现的,同时也为了入门FPGA。
2.2.1 代码分析
下面是对官方提供的代码的分析:
`timescale 1ns / 1ps
设置时间单位,时间单位是ns,精度是ps。
module water_led(
input clk,
input rstn,
output [7:0] led
);
上述代码定义了输入输出端口。
- clk是时钟输入;
- rstn是低电平有效的复位输入;
- led是8位输出端口,连接LED。
reg [25:0] led_light_cnt;
reg [ 7:0] led_status;
- 定义一个26位的寄存器led_light_cnt,用来做定时计数。
- 定义一个8位的寄存器led_status,用来记录LED点亮状态
always @(posedge clk)
begin
if(!rstn)
led_light_cnt <= `UD 26'd0;
else if(led_light_cnt == 26'd19_999_999)
led_light_cnt <= `UD 26'd0;
else
led_light_cnt <= `UD led_light_cnt + 26'd1;
end
在时钟上升沿的时候时触发上述代码。使用led_light_cnt实现计数功能:
- 复位时将寄存器led_light_cnt清零;
- 当寄存器记满19999999时,将寄存器led_light_cnt清零;
- 如果寄存器没有记满19999999,则计数值加1
always @(posedge clk)
begin
if(!rstn)
led_status <= `UD 8'b0000_0001;
else if(led_light_cnt == 25'd19_999_999)
led_status <= `UD {led_status[6:0],led_status[7]};
end
在始终上升沿的时候触发上述代码。
- 复位时将寄存器led_status复位为1;
- 当led_light_cnt计数满19999999时,将寄存器led_status向左移一位;这样就得到了LED状态的循环左移。
assign led = led_status;
最后寄存器led_status复制给led输出。
2.2.2 代码更改
按照题目要求,流水灯频率为0.5s,因为晶振频率为50MHz,所以修改计时值为24999999,并且我在此基础上增加了流水灯功能,修改为了左移流水灯移动完成之后,再直接右移,右移完成再左移,来回左右移动流水灯。
改良后的代码如下:
`timescale 1ns / 1ps
`define UD #1
module water_led(
input clk,
input rstn,
output [7:0] led
);
//==============================================================================
//reg and wire
reg [25:0] led_light_cnt;
reg [ 7:0] led_status;
reg led_dir;
reg [3:0] led_shift;
// time counter
always @(posedge clk)
begin
if(!rstn)
led_light_cnt <= `UD 26'd0;
else if(led_light_cnt == 26'd24_999_999)
led_light_cnt <= `UD 26'd0;
else
led_light_cnt <= `UD led_light_cnt + 26'd1;
end
// led status change
always @(posedge clk)
begin
if(!rstn) begin
led_status <= `UD 8'b0000_0001;
led_dir <= `UD 1'b1;
led_shift <= `UD 3'd0;
end
else if(led_light_cnt == 25'd24_999_999) begin
if (led_dir)
led_status <= `UD {led_status[6:0],led_status[7]};
else
led_status <= `UD {led_status[0], led_status[7:1]};
led_shift <= `UD led_shift + 3'd1;
if (led_shift == 3'd6) begin
led_dir <= `UD ~led_dir;
led_shift <= `UD 3'd0;
end
end
end
assign led = led_status;
endmodule
2.3 代码下载
- 连接JTAG烧录器
如果连接不上,可以查看一下芯片型号是否选对,芯片选择不对则也连接不上
-
点击菜单栏下载按钮:
-
然后弹出的下载窗口中点击连接按钮:
-
成功连接之后,会弹出一个文件对话框,选择编译好的sbit文件,双击即可:
-
然后右键单击右窗口PANGO图标,点击Program:
3 实验效果
效果如下,经过多次调试,终于成功实现目的了: