前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何做到一套FPGA工程无缝兼容两款不同的板卡?

如何做到一套FPGA工程无缝兼容两款不同的板卡?

作者头像
单片机点灯小能手
发布2023-11-11 19:52:20
2930
发布2023-11-11 19:52:20
举报
文章被收录于专栏:电子电路开发学习

试想这样一种场景,有两款不同的FPGA板卡,它们的功能代码90%都是一样的,但是两个板卡的管脚分配完全不同,一般情况下,我们需要设计两个工程,两套代码,之后还需要一直维护两个版本。

那么有没有一种自动化的方式,实现一个工程,编译出一个程序文件,下载到这两个不同的板卡上,都可以正常运行呢?

本文以开发板A和开发板B为例,介绍如何实现一套FPGA工程无缝兼容两款管脚不同的板卡?

两款开发板的时钟信号分别为clk_a和clk_b,分别位于两个不同的芯片管脚,两个开发板的FPGA型号完全一致,外部时钟的频率也一样。

首先需要判断当前是哪款板卡?实现方式是通过两个计数器,分别对时钟信号进行计数,由于两款板子的时钟信号分别位于不同的管脚,所以只有一个计数器会累加,并达到目标值,这样就实现了板卡型号的自动区分。

具体代码如下:

代码语言:javascript
复制
/*********************************************************************
 * Copyright © blog.csdn.net/whik1194
 * ModuleName : board_sel.v 
 * CreateTim  : 2023年11月5日 19:16:48
 * Author     : mcu149
 * Function   : function
 * Version    : v1.0
 *      Version | Modify
 *      ----------------------------------
 *       v1.0   | first version
 *********************************************************************/

module board_sel(
    //Inputs
    input clk_a,        //100MHz
    input clk_b,        //100MHz

    //Outputs
    output reg [1:0] sel = 2'd0,
    output reg rst_n = 1'b0
);

//1.parameter 
// parameter LATCH_TIME = 10_000_000 / 10;     //10ms
// parameter RESET_TIME = 100_000_000 / 10;    //100ms
// for simulation
parameter LATCH_TIME = 5_000 / 10;     //simulation, 5 us
parameter RESET_TIME = 10_000 / 10;    //simulation, 10 us

//2.localparam 
localparam BOARD_A = 2'd1;
localparam BOARD_B = 2'd2;

//3.reg
reg [31:0] cnt_a = 0;
reg [31:0] cnt_b = 0;

//4.wire 

//5.assign

//6.always 
always @ (posedge clk_a) begin
    if(cnt_a < LATCH_TIME + RESET_TIME)
        cnt_a <= cnt_a + 1;
end

always @ (posedge clk_b) begin
    if(cnt_b < LATCH_TIME + RESET_TIME)
        cnt_b <= cnt_b + 1;
end

always @ (*) begin
    if(cnt_a == LATCH_TIME)
        sel <= BOARD_A; 
    else if(cnt_b == LATCH_TIME)
        sel <= BOARD_B;
end

always @ (*) begin
    if((cnt_a == LATCH_TIME + RESET_TIME) || (cnt_b == LATCH_TIME + RESET_TIME))
        rst_n <= 1;
end

//7.instance

endmodule   //board_sel end

这里的代码,使用了寄存器定义时赋初值0的一个小技巧,一般工程不建议这么使用。

板卡区分之后,再根据区分的结果即sel的值对输出、输入分别进行选择。

具体实现如下:

代码语言:javascript
复制
/*********************************************************************
 * Copyright © blog.csdn.net/whik1194
 * ModuleName : board_sel.v 
 * CreateTim  : 2023年11月5日 19:40:48
 * Author     : mcu149
 * Function   : function
 * Version    : v1.0
 *      Version | Modify
 *      ----------------------------------
 *       v1.0   | first version
 *********************************************************************/

module board_dock(
    //Inputs
    input [1:0] sel,       

    input clk_a,
    input clk_b,
    input uart_txd,
    input led1,

    //Outputs
    output clk,
    output uart_txd_a,
    output uart_txd_b,
    output led1_a,
    output led1_b
);

//1.parameter 

//2.localparam 
localparam BOARD_A = 2'd1;
localparam BOARD_B = 2'd2;
localparam DEFAULT_OUT_VALUE = 1'b1;

//3.reg

//4.wire 

//5.assign
assign clk        = (sel == 2'd0   ) ? DEFAULT_OUT_VALUE : ((sel == BOARD_B) ? clk_b : clk_a );
assign uart_txd_a = (sel == BOARD_A) ? uart_txd : DEFAULT_OUT_VALUE;
assign uart_txd_b = (sel == BOARD_B) ? uart_txd : DEFAULT_OUT_VALUE;
assign led1_a     = (sel == BOARD_A) ? led1     : DEFAULT_OUT_VALUE;
assign led1_b     = (sel == BOARD_B) ? led1     : DEFAULT_OUT_VALUE;

//6.always 

//7.instance

endmodule   //board_dock end

仿真文件:

代码语言:javascript
复制
`timescale 1ns/1ps

`define BRD_A
// `define BRD_B

module top_tb;

localparam PERIOD = 10;      //10ns
localparam BOARD_A = 2'd1;
localparam BOARD_B = 2'd2;

reg clk_a;
reg clk_b;
reg uart_txd;
reg led1;

wire [1:0] sel;
wire rst_n;

`ifdef BRD_A
    always #(PERIOD/2) clk_a <= !clk_a;
`endif

`ifdef BRD_B
    always #(PERIOD/2) clk_b <= !clk_b;
`endif

initial begin
    $display("testbench: %s", "top_tb");

    clk_a = 0;
    clk_b = 0;
    uart_txd = 0;
    led1 = 0;

end

always #(500_000) uart_txd <= !uart_txd;
always #(200_000) led1 <= !led1;

board_sel board_sel_ut0(
    //Inputs
    .clk_a(clk_a),        //100MHz
    .clk_b(clk_b),        //100MHz

    //Outputs
    .sel(sel),
    .rst_n(rst_n)
);

board_dock board_dock_ut0(
    //Inputs
    .sel(sel),      
    .clk_a(clk_a),
    .clk_b(clk_b),
    .uart_txd(uart_txd),
    .led1(led1),

    //Outputs
    .clk(clk),
    .uart_txd_a(uart_txd_a),
    .uart_txd_b(uart_txd_b),
    .led1_a(led1_a),
    .led1_b(led1_b)
);

endmodule   //top_tb end

总结

本文所提出的方式,可以在某些应用场景对板卡实现一定的兼容性,比如用来固件在线升级所使用的Golden镜像工程,不同的板子共用此工程,以后只需要维护一套代码即可。

当然这种方式也有一定的局限性,比如需要两款板卡的FPGA芯片型号一致、晶振频率一致,比如同样为XC7K325T,外部输入单端50M时钟。

也可以根据需要做到部分兼容,比如公用一套RTL代码,但是因为芯片型号不同,需要创建两个不同的工程,比如XC7K325T和XC7A75T。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-11-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 电子电路开发学习 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档