记录我的FPGA学习之路-可控线性序列机
使用ZYNQ-Z2开发板
- 该开发板基于Xilinx Zynq-7000 SoC,集成了ARM处理器和FPGA逻辑单元,适合嵌入式系统开发和硬件加速应用。(即PS+PL架构,processing system + programmable logic)
- 板子具体型号:ZYNQ-Z2 (XC7Z020-1CLG400C)
- ps: 时钟频率50MHz,最高支持650MHz?
- pl: 时钟频率125MHz,直接使用H16引脚,可独立使用。
6种不同的可控线性序列机设计
- 0.5s暗灯,0.5s亮灯
1s/125MHz= 8nm/cycle
考虑到1s太长,将仿真时间缩短1000倍,期望看到0.5ms暗灯,0.5ms亮灯
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
30
31
|
// simple counter LED module, as basic template, latter will build on it
module counter_led_0(
Clk,
Reset_n,
Led
)
input Clk;
input Reset_n;
output reg Led;
reg [26:0] counter; // 27 bits to count up to 125,000,000
parameter MCNT = 125000000 // 在testbench中可以修改该参数来缩短1000倍仿真时间
always @(posedge Clk or negedge Rst_n)
begin
if (!Rst_n)
counter <= 0;
else if (counter == MCNT - 1)
counter <= 0;
else
counter <= counter + 1;
end
always @(posedge Clk or negedge Rst_n)
begin
if (!Rst_n)
Led <= 0;
else if (counter == MCNT/2 - 1)
Led <= 1;
else if (counter == MCNT - 1)
Led <= 0;
end
endmodule
|
如果需要暗0.25s,亮0.75s,只需要将MCNT/2改为MCNT/4即可。
- 暗0.25s,亮0.5s,暗0.75s,亮1s,循环
总时间现在变为2.5s,即312,500,000个cycle
将判断点改为MCNT/10, MCNT3/10,MCNT6/10,MCNT即可
- 8个0.25s,状态由用户控制。
添加一个输入信号Ctrl([7:0]),表示8种状态开关,将判断点分为MCNT/8,MCNT*2/8,…,MCNT即可。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
// 补充一个case语法(和if-else功能相同)
always@(posedge Clk or negedge Reset_n)
begin
if (!Reset_n)
Led <= 0;
else case(counter)
MCNT/8 -1 : Led <= Ctrl[0];
MCNT*2/8 -1 : Led <= Ctrl[1];
MCNT*3/8 -1 : Led <= Ctrl[2];
MCNT*4/8 -1 : Led <= Ctrl[3];
MCNT*5/8 -1 : Led <= Ctrl[4];
MCNT*6/8 -1 : Led <= Ctrl[5];
MCNT*7/8 -1 : Led <= Ctrl[6];
MCNT -1 : Led <= Ctrl[7];
default: Led <= Led;
endcase
end
|
- 除了八个状态外, 每一个状态的时间也由用户控制。
- 必然需要添加一个输入信号Time([31:0]),来代替固定的MCNT,这个信号表示一个小周期的时钟次数,考虑到2.5s的时间才需要312,500,000个时钟周期,因此32位足以。
- 同时需要引入一个计数器,用于设置当前的状态是第几个小周期,记位counter2([2:0]).
- 每次counter达到Time-1的时候,counter归0,同时counter2加1,当counter2达到8的时候,自动归0。
- 简而言之就是Time控制时间长度,counter计时,counter2计数当前状态。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
always @(posedge Clk or negedge Reset_n)
begin
if (!Reset_n)
counter <= 0;
else if (counter == Time - 1)
counter <= 0;
else
counter <= counter + 1;
end
always @(posedge Clk or negedge Reset_n)
begin
if (!Reset_n)
counter2 <= 0;
else if (counter == Time - 1)
counter2 <= counter2 + 1;
end
// 后面把case的参数改为counter2即可,然后值换成0,1,2,3,4,5,6,7
|
- 实现两个led灯独立控制
- 只需要将led改为[1:0],然后添加一个Ctrl2([7:0])即可。
- 在进行周期8状态转化结束的时候设置一个10ms的休息状态,然后重新开始。
a easy quiz to exercise your verilog skill.🐶
- 感觉可以设置一个新的状态量state,0表示工作,1表示休息。
- 当counter2等于7并且counter等于Time-1的时候,state变成1,同时counter和counter2归0。
- 当state等于1的时候,跳过其他分支,直接计数counter,10ms是1250000个cycle,当counter等于1250000-1的时候,state变成0,同时counter归0,重新开始工作。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
reg state; // 0 for work, 1 for rest
always @(posedge Clk or negedge Reset_n)
begin
if (!Reset_n)
state <= 0;
else if (state == 0 && counter2 == 7 && counter == Time -1)
state <= 1;
else if (state == 1 && counter == 1250000 -1)
state <= 0;
end
// state对counter的逻辑没有影响(其实有,一开始踩坑了😆)
// 在counter的逻辑中修改
else if (counter == Time - 1 && state == 0)
counter <= 0;
else if (counter == 1250000 -1 && state == 1)
counter <= 0;
// 在counter2的逻辑中添加
else if (state == 1)
counter2 <= 0;
// 在led的逻辑中添加
else if (state == 1)
Led <= 0;
|
- 最后也是成功仿真出来了😇
- 如何在板子上跑?恐怕很难,毕竟32位的Time和8位的Ctrl信号不好输入啊,以我目前的实力还做不到😭,仿真足以。
爽爽爽🐶