FPGA0

记录我的FPGA学习之路-可控线性序列机

感谢小梅哥的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种不同的可控线性序列机设计

  1. 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即可。

  1. 暗0.25s,亮0.5s,暗0.75s,亮1s,循环

总时间现在变为2.5s,即312,500,000个cycle 将判断点改为MCNT/10, MCNT3/10,MCNT6/10,MCNT即可

  1. 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
  1. 除了八个状态外, 每一个状态的时间也由用户控制。
  • 必然需要添加一个输入信号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
  1. 实现两个led灯独立控制
  • 只需要将led改为[1:0],然后添加一个Ctrl2([7:0])即可。
  1. 在进行周期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信号不好输入啊,以我目前的实力还做不到😭,仿真足以。

爽爽爽🐶

Licensed under CC BY-NC-SA 4.0
啊啊啊啊啊啊啊
使用 Hugo 构建
主题 StackJimmy 设计