安路Anlogic FPGA从入门到放弃-Anlogic-安路社区-FPGA CPLD-ChipDebug

安路Anlogic FPGA从入门到放弃

8个用户LED被74HC595芯片驱动且高电平点亮LED,如下图所示。74HC595芯片由8位移位寄存器和8位锁存器组成,通过控制CLK、LATCH、DIN三个信号即可控制8个LED的状态,因此,采用该芯片可节省FPGA用户管脚的使用。
b52280707f171700

74HC595的驱动时序图如下所示,串行输入数据在移位时钟的上升沿被读进移位寄存器;移位寄存器的值在锁存时钟的上升沿被锁存输出。

8eca489633171729

需要考虑时钟和信号之间的建立时间和保持时间,如下图所示,由于芯片电压为3.3V且室温在25℃~85℃之间,故输入数据对移位时钟上升沿的最小建立时间和保持时间分别为50ns和5ns,而移位时钟上升沿对锁存时钟上升沿的最小建立时间为70ns。
93a463aebb171744

此外,移位时钟的最大频率为10MHz,如下图所示。由于AN88开发板的晶振时钟频率为24MHz,可以通过计数器分频产生6MHz(即166.67ns)的移位时钟,则输入数据的建立时间和保持时间都为83.33ns,移位时钟上升沿对锁存时钟上升沿的建立时间为83.33ns,很显然满足74HC595芯片的时序要求。

ff16a3025b171758

本设计通过驱动74HC595芯片实现流水灯功能,设计框图如下所示,由两个子模块组成,其中led_ctrl模块实现流水灯功能,driver_74hc595模块驱动74HC595芯片。

2e7c0c72c7171814

打开Anlogic TD软件。选择菜单“Project”—>“New Project…”新建工程,如下所示。

1021341721171834

在弹出的对话框中输入工程名run_water_led、选择工程路径以及选择FPGA器件EG4S20NG88,如下所示:

4b823de2e4171849

建立工程后,选择菜单“Source”—>“New Source…”新建源文件,如下所示。

cbb74f6116171901

在弹出的对话框选择文件类型、输入文件名run_water_led以及文件保存路径,如下所示。

8be5868117171912

用上述方法新建源文件led_ctrl.v和driver_74hc595.v。
led_ctrl模块的RTL设计:(1)由于输入时钟clk为24MHz,则计数12_000_000个时钟周期可得到0.5s的时间片段;(2)每完成0.5s的计数,则对LED值进行一次循环移位处理,如下图所示。
b2beac8a1e171939

module led_ctrl
(
input wire clk , // 24MHz
input wire rst_n ,
output reg [7:0] led_data ,
output reg led_data_valid
);
//----------------------------------------------------------------------
localparam C_CNT_VALUE = 28'd12_000_000; // 0.5s
reg [27:0] cnt;

always @(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
cnt <= 28'b0;
else
begin
if(cnt < C_CNT_VALUE - 1'b1)
cnt <= cnt + 1'b1;
else
cnt <= 28'b0;
end
end

wire cnt_done_flag;
assign cnt_done_flag = (cnt == C_CNT_VALUE - 1'b1) ? 1'b1 : 1'b0;

always @(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
led_data <= 8'b0000_0001;
led_data_valid <= 1'b0;
end
else
begin
if(cnt_done_flag == 1'b1)
begin
led_data <= {led_data[6:0],led_data[7]};
led_data_valid <= 1'b1;
end
else
begin
led_data <= led_data;
led_data_valid <= 1'b0;
end
end
end

endmodule

driver_74hc595模块的RTL设计。

module driver_74hc595
(
    input  wire                 clk             ,   //  24MHz
    input  wire                 rst_n           ,
    input  wire     [7:0]       led_data        ,
    input  wire                 led_data_valid  ,
    output reg                  shift_clock     ,
    output reg                  latch_clock     ,
    output reg                  serial_data     
);
//----------------------------------------------------------------------
localparam C_CNT     = 3'd2;                        //  83.333ns
localparam C_CNT_NUM = 5'd17;

localparam S_IDLE      = 1'b0;
localparam S_SEND_DATA = 1'b1;

reg             [1:0]           state;
reg             [7:0]           led_data_tmp;
reg             [2:0]           cnt;
reg             [4:0]           cnt_num;

always @(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        state <= S_IDLE;
    else
    begin
        case(state)
            S_IDLE : 
            begin
                if(led_data_valid == 1'b1)
                    state <= S_SEND_DATA;
                else
                    state <= S_IDLE;
            end
            S_SEND_DATA : 
            begin
                if((cnt == C_CNT - 1'b1)&&(cnt_num == C_CNT_NUM - 1'b1))
                    state <= S_IDLE;
                else
                    state <= S_SEND_DATA;
            end
        endcase
    end
end

always @(posedge clk)
begin
    if((state == S_IDLE)&&(led_data_valid == 1'b1))
        led_data_tmp <= led_data;
    else
        led_data_tmp <= led_data_tmp;
end

always @(posedge clk)
begin
    if(state == S_SEND_DATA)
    begin
        if(cnt < C_CNT - 1'b1)
            cnt <= cnt + 1'b1;
        else
            cnt <= 3'b0;
    end
    else
        cnt <= 3'b0;
end

always @(posedge clk)
begin
    if(state == S_SEND_DATA)
    begin
        if(cnt == C_CNT - 1'b1)
            cnt_num <= cnt_num + 1'b1;
        else
            cnt_num <= cnt_num;
    end
    else
        cnt_num <= 5'b0;
end

always @(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        shift_clock <= 1'b0;
    else
    begin
        if(state == S_SEND_DATA)
        begin
            shift_clock <= cnt_num[0];
        end
        else
            shift_clock <= 1'b0;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        latch_clock <= 1'b0;
    else
    begin
        if((state == S_SEND_DATA)&&(cnt_num == C_CNT_NUM - 1'b1))
            latch_clock <= 1'b1;
        else
            latch_clock <= 1'b0;
    end
end

always @(posedge clk)
begin
    if(state == S_SEND_DATA)
        serial_data <= led_data_tmp >> cnt_num[4:1];
    else
        serial_data <= 1'b0;
end

endmodule
run_water_led模块作为顶层模块,用于例化led_ctrl和driver_74hc595。
run_water_led
(
    input  wire                 clk_24m     ,
    output wire                 shift_clock ,
    output wire                 latch_clock ,
    output wire                 serial_data
);
//----------------------------------------------------------------------
reg             [3:0]           delay_cnt = 4'd0;

always@(posedge clk)
begin
    if(delay_cnt < 4'hf)
        delay_cnt <= delay_cnt + 1'b1;
    else
        delay_cnt <= delay_cnt;
end

wire                            rst_n;
assign rst_n = (delay_cnt == 4'hf)? 1'b1 : 1'b0;

//----------------------------------------------------------------------
wire            [7:0]           led_data;
wire                            led_data_valid;

led_ctrl u_led_ctrl
(
    .clk            (clk_24m        ),
    .rst_n          (rst_n          ),
    .led_data       (led_data       ),
    .led_data_valid (led_data_valid )
);

//----------------------------------------------------------------------
driver_74hc595 u_driver_74hc595
(
    .clk            (clk_24m        ),
    .rst_n          (rst_n          ),
    .led_data       (led_data       ),
    .led_data_valid (led_data_valid ),
    .shift_clock    (shift_clock    ),
    .latch_clock    (latch_clock    ),
    .serial_data    (serial_data    )
);

endmodule

run_water_led模块作为顶层模块,用于例化led_ctrl和driver_74hc595。

run_water_led
(
    input  wire                 clk_24m     ,
    output wire                 shift_clock ,
    output wire                 latch_clock ,
    output wire                 serial_data
);
//----------------------------------------------------------------------
reg             [3:0]           delay_cnt = 4'd0;

always@(posedge clk)
begin
    if(delay_cnt < 4'hf)
        delay_cnt <= delay_cnt + 1'b1;
    else
        delay_cnt <= delay_cnt;
end

wire                            rst_n;
assign rst_n = (delay_cnt == 4'hf)? 1'b1 : 1'b0;

//----------------------------------------------------------------------
wire            [7:0]           led_data;
wire                            led_data_valid;

led_ctrl u_led_ctrl
(
    .clk            (clk_24m        ),
    .rst_n          (rst_n          ),
    .led_data       (led_data       ),
    .led_data_valid (led_data_valid )
);

//----------------------------------------------------------------------
driver_74hc595 u_driver_74hc595
(
    .clk            (clk_24m        ),
    .rst_n          (rst_n          ),
    .led_data       (led_data       ),
    .led_data_valid (led_data_valid ),
    .shift_clock    (shift_clock    ),
    .latch_clock    (latch_clock    ),
    .serial_data    (serial_data    )
);

endmodule

完成RTL设计之后,还需要对其功能进行仿真,以确保满足设计需求。仿真结果如下所示,很显然符合预期。

18975475dd172128

5ed6a881fe172144

接下来进行管脚约束和时序约束,在工程目录下新建文件夹sdc,且在文件夹下新建文件run_water_led.adc(用于管脚约束)和run_water_led.sdc(用于时序约束)。

e11ad1fc9e172157

将run_water_led.adc添加到工程,如下所示。

 

88a34a1057172231

在run_water_led.adc中编写管脚约束:
set_pin_assignment { clk_24m } { LOCATION = P13; }
set_pin_assignment { shift_clock } { LOCATION = P59; }
set_pin_assignment { serial_data } { LOCATION = P45; }
set_pin_assignment { latch_clock } { LOCATION = P57; }
将run_water_led.sdc添加到工程,如下所示。

 

e0cd200cbc172315

在run_water_led.sdc中编写时序约束:

create_clock -name clk_24m -period 41.667 [get_ports {clk_24m}]
双击HDL2Bit Flow即可对设计进行综合、实现以及生成bit文件,如下图所示。

2fba5e4bbe172326

用下载器连接AN88开发板和电脑,并给AN88开发板上电。选择菜单“Tools”—>“Download”打开目标文件烧录界面,通过点击“Add”添加run_water_led.bit,然后点击“Run”开始烧录,如下所示。

3aacaf95b1172335

完成烧录后,在AN88开发板上可以看到8个LED像流水一样流动,每隔0.5秒流动一次。

请登录后发表评论