通过comp sci major,意外输出编程FPGA的问题

时间:2017-11-09 21:38:36

标签: verilog fpga

上下文
我是计算机科学专业,填补了我们计算机工程专家留下的空白。我在学校,这是我的高级项目的一部分。我正在尝试编程FPGA,用于我的小组创建的电子棋盘游戏。 FPGA只是Raspberry Pi的IO扩展器,可以控制所有逻辑。下面的verilog代码在Altera Max V 570 devkit上运行,目的是为生产单元迁移到Max V 40。每个FPGA将控制一组4个游戏区块,最终产品将有4组区块。

问题:
我正在创建一个FPGA,它将与覆盆子pi连接,以控制我们系统中的MOSFET(现在是LED)。我遇到的问题是,无论我发送给磁贴的命令是什么,LED都会像这样切换:

对于tile0,只有第0个LED将切换 对于tile1,只有第一个LED将切换 对于tile2,只有第二个LED会切换 对于tile3,只有第3个LED会切换

以下是此行动照片的链接:
https://drive.google.com/open?id=0B7P773tnBnRybHhGRmZMX3hScGFrNXpKUDN2c0tBbkFZaTVJ
(忽略每组中的最终LED,将从电容式传感器输入)

LED切换命令(下面的代码中为2&b; b11)和电磁阀切换(以下代码中的2' b01)都是如此。

在使用Altera ModelSim进行仿真时,一切都运行良好!但是所有东西都连接到面包板上,我看到了上面的情况。

我对这个问题的看法
我最初认为问题在于分配给我正在阅读的同一个寄存器,但我添加了另一步(随意...)来读取寄存器,然后分配,但我看到更糟糕的行为(LED不会切换)。救命! :)

这是我的verilog代码:

module comm_protocol(clock, bus, t0, t1, t2, t3, t0cap, t1cap, t2cap, t3cap, capOut);

parameter [1:0] my_address = 2'b11;


input clock;
input [3:0] bus;

output reg [4:0] t0;
output reg [4:0] t1;
output reg [4:0] t2;
output reg [4:0] t3;

input wire t0cap, t1cap, t2cap, t3cap;
output reg capOut;

reg start;
reg [1:0] tickCounter;

reg gotFpgaAddress;
reg [1:0] fpgaAddress;
reg[1:0] tileAddress;

reg gotCommand;
reg [3:0] command;

initial begin

    start <= 0;

    t0 <= 5'b11111;
    t1 <= 5'b11111;
    t2 <= 5'b11111;
    t3 <= 5'b11111;

end


always @ (posedge clock) begin

    // check if we have recieved the start condition, which is just a positive edge on the clock
    if (~start) begin

        start <= 1;
        tickCounter <= 0;
        gotFpgaAddress <= 0;
        gotCommand <= 0;

    end
    else begin // we have received the start condition, so continue into the logic

        // increment the counter
        // this counter controls when a reset of the logic is performed
        // the entire protocol should take place in 4 cycles, so when our counter hits 3 we are done
        tickCounter <= tickCounter + 1;
        if (tickCounter == 3) begin

            start <= 0;

        end
        else begin // no reset, continue into logic

            // here, we will read the address of the fpga the pi is talking to
            // first check if we have recieved the address or not
            if (~gotFpgaAddress) begin

                fpgaAddress <= bus[3:2]; //[3:0];
                tileAddress <= bus[1:0];

                gotFpgaAddress <= 1;
                //gotTileAddress <= 1;

            end
            else begin // we got the address, now compare it to see if it matches our address

                if (fpgaAddress == my_address) begin

                    // the message is intended for us, so next we check if the command has been received
                    if (~gotCommand) begin

                        //tileAddress <= bus[3:0];
                        command <= bus;
                        gotCommand <= 1;

                    end
                    else begin  // we have received the command, now decode it and perform the action

                        // decode the command that has been sent
                        // leading 11xx : toggle an led specified by the 2 least significant bits
                        // leading 00xx : read from the capactive sensor and write it onto the bus
                        // leading 01xx : toggle the solenoid for the popup

                        // implement logic to toggle leds
                        if (command[3:2] == 2'b11) begin

                            // route to appropriate tile
                            case (tileAddress)

                                // tile 0
                                2'b00: begin 
                                    case (command[1:0])
                                        2'b00: t0[0] <= ~t0[0];
                                        2'b01: t0[1] <= ~t0[1];
                                        2'b10: t0[2] <= ~t0[2];
                                        2'b11: t0[3] <= ~t0[3];
                                    endcase
                                end 
                                // tile 1
                                2'b01: begin
                                    case (command[1:0])
                                        2'b00: t1[0] <= ~t1[0];
                                        2'b01: t1[1] <= ~t1[1];
                                        2'b10: t1[2] <= ~t1[2];
                                        2'b11: t1[3] <= ~t1[3];
                                    endcase
                                end 
                                // tile 2
                                2'b10: begin
                                    case (command[1:0])
                                        2'b00: t2[0] <= ~t2[0];
                                        2'b01: t2[1] <= ~t2[1];
                                        2'b10: t2[2] <= ~t2[2];
                                        2'b11: t2[3] <= ~t2[3];
                                    endcase
                                end
                                // tile 3
                                2'b11: begin
                                    case (command[1:0])
                                        2'b00: t3[0] <= ~t3[0];
                                        2'b01: t3[1] <= ~t3[1];
                                        2'b10: t3[2] <= ~t3[2];
                                        2'b11: t3[3] <= ~t3[3];
                                    endcase
                                end

                            endcase

                        end
                        // implement logic to read from the capacitive sensor and write it onto the bus
                        else if (command[3:2] == 2'b00) begin

                            case (tileAddress)

                                2'b00: capOut <= t0cap;
                                2'b01: capOut <= t1cap;
                                2'b10: capOut <= t2cap;
                                2'b11: capOut <= t3cap;

                            endcase

                        end
                        // implement logic to toggle the solenoid
                        else if (command[3:2] == 2'b01) begin

                            case (tileAddress)

                                2'b00: t0[4] <= ~t0[4];
                                2'b01: t1[4] <= ~t1[4];
                                2'b10: t2[4] <= ~t2[4];
                                2'b11: t3[4] <= ~t3[4];

                            endcase

                        end

                    end

                end

            end

        end

    end    

end


endmodule

奖金
目前我已经消耗了42个逻辑元素,如果有人能指出如何将其减少到恰好40 LE或更少,我将永远感激不尽!没什么大不了的,80元Max V仅比MaxV40高出70美分

2 个答案:

答案 0 :(得分:1)

很高兴你在你的python代码中发现了这个问题。可能有一点帮助的是添加一个输入引脚作为对总线进行采样的限定符。否则将需要确保所有FPGA完全同步。

现在提出你的红利问题:

通过将start转换为gotFpgaAddress,您无需更改代码的任何行为即可消除3个触发器(gotCommandtickCountertickCounter)以及一小部分逻辑门FSM。我注意到当localparam INIT=2'b0, GETADDR=2'b01, GETCMD=2'b10, TOGGLELED=2'b11; reg [1:0] state; reg [1:0] fpgaAddress; reg [1:0] tileAddress; reg [3:0] command; initial begin state = INIT; // Note: initial blocks should use blocking statements t0 = 5'b11111; t1 = 5'b11111; t2 = 5'b11111; t3 = 5'b11111; end always @ (posedge clock) begin case(state) INIT : begin state <= GETADDR; // technically this is a dummy state, but needed to match behavior end GETADDR : begin state <= GETCMD; fpgaAddress <= bus[3:2]; tileAddress <= bus[1:0]; end GETCMD : begin state <= TOGGLELED; /* No output is effected in this state, * so it doesn't matter what the address is. * Preventing assignment to command would add logic. */ command <= bus; end TOGGLELED : begin state <= INIT; // Here we care about the address if (fpgaAddress == MY_ADDRESS) begin // ... your assignments to t0-t3 here ... /* There are tricks to reduce the number of lines of code here, * but nothing I can immanently think of that will reduce gate count. */ end end endcase end 为0时,您始终处于初始/重置状态。当它为1时,您将获得该地址。当它为2时,如果它是目标fpga地址,您可以收集命令。当它为3时,如果在目标fpga地址处,则切换LED。

INIT

如果确实想要挤压该区域,可以通过删除GETCMDbus状态将其降低到两种状态。请记住,command现在是TOGGLELED状态的if (start_fsm) begin state <= NEXT_STATE ; /*... other stuff ...*/ end else begin state <= CURRENT_STATE; end。另请注意,这会将您的设计从4个周期更改为2个周期。所以你需要改变刺激(你的python代码)。

如果你添加我上面提到的限定符输入引脚,那么它是对状态赋值的调整(例如:output [4:0] t0;)。

另一个主题是,您的模块标题是以一种名为Non-ANSI的过时样式编写的。 Verilog-1995需要更严格的非ANSI版本(前reg[4:0] t0; output reg[4:0] t0;而不是module comm_protocol #(parameter [1:0] MY_ADDRESS = 2'b11) ( input clock, input [3:0] bus, output reg [4:0] t0, output reg [4:0] t1, output reg [4:0] t2, output reg [4:0] t3, input wire t0cap, t1cap, t2cap, t3cap, output reg capOut ); ),但自从Verilog-2001得到广泛支持以来,它已经失去了知名度。现代标题样式称为ANSI。使用ANSI样式,您在同一行上声明端口顺序,方向和类型(其中非ANSI需要2到3个单独的行)。它更清洁,更不容易出现错别字。

function excelRound(n, e) {
  let f = Math.pow(10, e);
  return Math.round(n * f) / f;
}

console.log(31283700000, -6, excelRound(31283700000, -6));
console.log(60204605, -4, excelRound(60204605, -4));

答案 1 :(得分:0)

发现问题,用python代码控制整个该死的东西。我重复使用变量发送地址,并错误地将其作为命令发送......

但它工作!!