1、上课知识
今天是AMD的工程师来深大进行FPGA创新短课讲课的第一天,学到了很多东西
LUT(查找表)全称为look up table
FIFO为frist in first out先进先出
上课的时候讲了怎么设计一个4位加法器:
1 2 3 4 5 6 7 8 9 10 11 12 13
| module addrer( input [3:0] a, input [3:0] b, output carry, output [3:0] sum );
wire [4:0] total; assign total=a+b; assign sum=total[3:0]; assign carry=total[4];
endmodule
|
2、串口通信
2.1 UART基础知识
UART为通用异步收发传输器
UART 通信只需要两根线(TX 发送数据、RX 接收数据),不需要额外的时钟线(CLK)。这减少了硬件复杂度和成本。
依赖协议:双方依靠预先约定好的波特率(Baud Rate) 来同步数据。接收方会在检测到起始位后,在预期的中间点采样数据,以此保证读取的正确性。
与之相对的是 “同步”通信(如 SPI、I2C),它们需要一根额外的时钟线来告诉对方何时读取数据。
同步通信的核心特点是:通信双方共享一个统一的时钟信号(CLK)。发送方根据这个时钟来发送数据,接收方也根据这个时钟来采样数据,双方步调高度一致。
一帧数据包含什么:
1、起始位 1位
总是逻辑 0(低电平),用于通知接收方“数据开始了”,是帧同步的起点。
2、数据位 5-9位
核心的有效数据。最常用的是 8位(一个字节),与计算机系统的基本数据单位一致。
3、奇偶校验位 0或1位
可选。用于简单的错误检测(检错,但不能纠错)。如果不用,这一位就不存在。
4、停止位 1、1.5或2位
总是逻辑 1(高电平),用于表示“数据结束”。最常用的是 1位。
再来说一下奇偶校验是什么:
奇偶校验是一种最简单的单比特错误检测方法,通过添加1个校验位,使数据中“1”的个数满足奇/偶性。
- 奇校验:使“1”的总数(数据+校验位)为奇数,①数据有4个“1”(偶),校验位补1 → 总数5(奇)。 ②数据有3个“1”(偶),校验位补0 → 总数3(奇)
- 偶校验:使“1”的总数(数据+校验位)为偶数 ①数据有3个“1”(奇),校验位补1 → 总数4(偶)。② 数据有4个“1”(偶),校验位补0 → 总数4(偶)
- 发送端:计算数据位“1”的个数 → 按规则补校验位 → 发送。接收端:接收后重新计算“1”的个数 → 与约定规则比对 → 一致则接受,不一致则丢弃。
- 奇偶校验只负责检验,不负责纠正。
波特率(Baud):是指从一设备发到另一设备的波特率,即每秒钟可以通信的数据比特个数。典型的波特率有 300, 1200, 2400, 9600, 19200, 115200 等。一般通信两端设备都要设为相同的波特率,但有些设备也可设置为自动检测波特率。
最常用的配置是18N1(即一个起始位、八个数据位、无奇偶校验、一个停止位),
3、高云初使用
初使用设计了一个闪烁的LED灯
在 50MHz 的时钟频率下,FPGA 中要实现 1秒 的精确定时,需要一个位宽为 26位(即 reg [25:0])的计数器。该计数器需要从 0 开始计数,直到达到终值 49,999,999(即共计 5千万 个时钟周期),此时刚好耗时1秒,之后计数器归零并重新开始。简而言之,50MHz的时钟每秒钟会产生5千万个周期,因此计满5千万次就是1秒。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| module led_flash( input clk, input rst, output reg led );
reg [25:0] counter;
always@(posedge clk or negedge rst) begin if(!rst) counter<=0; else if(counter==26'd49_999_999) counter<=0; else counter<=counter+1'b1; end
always@(posedge clk or negedge rst) begin if(!rst) led<=0; else if(counter==26'd49_999_999) led<=~led; else led<=led; end
endmodule
|
测试文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| `timescale 1ns/1ns
module led_flash_tb;
reg rst; reg clk; wire led;
initial clk=1; always #10 clk=!clk;
initial begin rst=0; #201; rst=1; #1000000000; end
led_flash led_flash_inst( .rst(rst), .clk(clk), .led(led) );
endmodule
|
4、FPGA设计流程
FPGA 设计核心流程(精简版)
1.PROJECT MANAGER 工程管理 建仓库、备料:创建项目,添加代码文件、设置约束(引脚、时钟)。
2.IP INTEGRATOR IP集成 乐高拼装:用现成的功能模块(IP核)快速搭建系统。
3.SIMULATION 功能仿真 电脑彩排:在烧录前,用软件模拟运行代码,检查逻辑对不对。
4.SYNTHESIS 逻辑综合 翻译蓝图:把代码(Verilog/VHDL)“编译”成由基本电路单元组成的电路图(网表)。生成电路网表
5.IMPLEMENTATION 布局布线 芯片施工:把电路图映射到真实的FPGA芯片上,决定每个元件的位置并连线。
6.PROGRAM AND DEBUG 编程调试 烧录验收:生成最终文件(比特流)并下载到芯片中运行,同时可在线调试。
工作流程口诀:管理 → 集成 → 仿真 → 综合 → 实现 → 编程
5、使用参数化设计实现计数器
ACG525开发板上的LED 状态每500ms翻转一次。ACG525开发板上晶振为50MHz,也就是说时钟周期为 20ns,这样可以计算得出 500ms = 500_000_000ns/20ns = 25_000_000,即需要计数器计数 25_000_000 次,也就是需要一个至少 25 位的计数器(2^25>25_000_000>2^24)。且每当计数次数达到需要清零并重新计数。
因为计数器是从 0 开始计数而不是 1,因此在计数值计数到 25’d24_999_999 时清零而不是计数到 25’d25_000_000时清零,这里计数器最大值使用 parameter 进行参数化定义表示,使用参数化定义的好处是通过修改 parameter 中定义最大值的数值可以全部修改设计中用到的这个参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| module led_flash( input clk, input rst, output reg led ); parameter CNT=25'd24_999_999 ;
reg [25:0] counter;
always@(posedge clk or negedge rst) begin if(!rst) counter<=0; else if(counter==CNT) counter<=0; else counter<=counter+1'b1; end
always@(posedge clk or negedge rst) begin if(!rst) led<=0; else if(counter==CNT) led<=~led; else led<=led; end
endmodule
|
测试文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| `timescale 1ns/1ns `define CLOCK_PERIOD 20
module led_flash_tb;
reg rst; reg clk; wire led;
initial clk=1; always #(`CLOCK_PERIOD/2) clk=~clk;
initial begin rst=0; #(`CLOCK_PERIOD*10+1); rst=1; #2000000000; $stop; end
led_flash led_flash_inst( .rst(rst), .clk(clk), .led(led) );
endmodule
|
在进行上述的功能仿真时可以发现电脑需要运行的时间较长,这是由于计数器的计数值太大。可以通过更改仿真计数的最大值来缩短仿真时间。这里介绍两种更改方式,第一种方式是将设计文件 bin_counter.v 中使用 parameter 进行参数化定义的计数值最大值修改为 24_999,具体代码如下。
1
| parameter MCNT = 24_999;
|
我们可以使用defparam的方式修改参数值,比较简单
1
| defparam bin_counter_inst.MCNT = 24_999;
|
可以使用`define 某个变量的形式去定义
在使用的时候就直接`CLK_PERIOD,在定义的变量前面加上
`符号即可
!为逻辑取反,~为按位取反,逻辑取反的意思就是只是判断0和1,如果一个数字大于0,!后就为0,但是按位取反~不一样,他是每一位都在取反的
在markdown中使用\来解引用,例如可以使用`来解引用,否则就变成代码的形式变换格式了