📜 ⬆️ ⬇️

FPGA Debug Board - Frankenstein. Christmas tree controller

Another series about FPGA and debugging board Frankie. Previous series 1 , 2 , 3 .


Making a controller of Christmas tree garlands is not easy, but very simple! Hello World on FPGA is a blinking LED. A "Happy New Year" on the FPGA is a flash of several LEDs. The principle is simple, as in previous articles: create a counter that divides the frequency of the clock generator, select bits from the counter word, to get the desired speed. A few bits of this word will give us a specific display step (depending on the number of selected bits of 1, 2, 4, 8, etc. steps). Depending on the step number, set the values ​​for N LEDs.


To control a real garland, you can take some kind of shield with an electromagnetic relay. I found myself like this , on 8 relays. Wiring diagram Schematic diagram .



The basis of the project


module epm7064_test(clk, leds); input wire clk; //    output wire [7:0] leds; // 8   / reg [31:0] cnt; //         always @(posedge clk) cnt <= cnt + 1'b1; //      assign leds = ... //      endmodule 

Normal alternation


With the usual alternation of light bulbs, we light the even light bulbs in the first step, and the odd light bulbs in the second step. Steps 2, so we only need one bit from the counter word. The numbers of light bulbs at each step will be given by the word - constant.


 ... wire [7:0] variant1 = (cnt[24]) ? 8'b01010101 : 8'b10101010; assign leds = variant1; ... 

Running light


A light to run through 8 light bulbs needs 8 steps. To do this, you need to select 3 bits from the counter word (2 ^ 3 = 8). It is worth noting that the output we get is inverted, because to turn on the relay, we have to issue 0.


 ... wire [7:0] variant2 = (cnt[24:22] == 3'd0) ? 8'b11111110 : (cnt[24:22] == 3'd1) ? 8'b11111101 : (cnt[24:22] == 3'd2) ? 8'b11111011 : (cnt[24:22] == 3'd3) ? 8'b11110111 : (cnt[24:22] == 3'd4) ? 8'b11101111 : (cnt[24:22] == 3'd5) ? 8'b11011111 : (cnt[24:22] == 3'd6) ? 8'b10111111 : (cnt[24:22] == 3'd7) ? 8'b01111111 : 8'b11111111; assign leds = variant2; ... 

Normal Alternation v2


The same as in the first version, just combine the bulbs in pairs.


 ... wire [7:0] variant3 = (cnt[24]) ? 8'b00110011 : 8'b11001100; assign leds = variant3; ... 

Double running lights


This is a variation of a single running light, but here it will take two times less steps.


 ... wire [7:0] variant4 = (cnt[24:23] == 2'd0) ? 8'b11001100 : (cnt[24:23] == 2'd1) ? 8'b01100110 : (cnt[24:23] == 2'd2) ? 8'b00110011 : (cnt[24:23] == 2'd3) ? 8'b10011001 : 8'b11111111; assign leds = variant4; ... 

Random lights


This is the most interesting part. In order to generate pseudo-random sequencing, I used LFSR . Code samples can be directly taken from this link . I took on the least amount of bits. The algorithm is already proven, but for some reason he did not want to work! The reason was that the register should not have a zero value, and when you turn on the FPGA, it turns out zero in each bit. But I applied the Initial section !!! In general, for not love to read the documentation, the truth came through the experiments. On the FPGA of the EPM7000 series, the initial sections do not work. The same problem, by the way, was on Lattice 4064. All this suggests that in larger FPGAs of the Cyclone class, initial blocks are generated into some kind of additional hardware piece. And in order to do the initialization in EPM, I added another counter to generate a reset signal. When this signal arrives, the pseudo-random sequence generator register is assigned the original value. After that, the "generator" earned.


For reasons of economy, I did not create a generator for every bit. Most likely, there would not be enough resources. The fact is that the generator can produce the next value on a cad cycle, and we need to update the light bulbs not on each cycle, so one generator is used to fill in the values ​​of all the light bulbs.


 ... reg [2:0] res_gen_reg; //    wire reset = ~(res_gen_reg==3'b111); // ,    1,      8 always @(posedge clk) begin //    ,    ,     //  .  ,        //         .   //     res_gen_reg <= (res_gen_reg==3'b111) ? res_gen_reg : res_gen_reg + 1'b1; end reg [7:0] variant5; //        ,    reg [7:0] d; //      always @(posedge clk) begin if (reset) begin d <= 1; //    end else begin if (cnt[20:0]==21'd0) begin //      d <= { d[5:0], d[6] ^ d[5] }; //     //          variant5[cnt[23:21]] <= d[5]; //    8    end end end assign leds = variant5; ... 

Putting it all together


We still have FPGA resources, so we can take the high bits of the counter and use them to switch the type of running lights. It’s easier when there are 2, 4, 8 types, but we have five of them. Therefore, I will sort through 4 of them, and in the intervals between them I will insert the fifth version (or rather, the first). In general, there is a field for experimentation. There are still free resources, because 58 cells out of 64x were spent.


 assign leds = (cnt[29:27] == 3'd1) ? variant2 : (cnt[29:27] == 3'd3) ? variant3 : (cnt[29:27] == 3'd5) ? variant4 : (cnt[29:27] == 3'd7) ? variant5 : variant1; 

completely
 module epm7064_test(clk, leds); input wire clk; output wire [7:0] leds; reg [31:0] cnt; initial cnt <= 32'd0; always @(posedge clk) cnt <= cnt + 1'b1; wire [7:0] variant1 = (cnt[24]) ? 8'b01010101 : 8'b10101010; wire [7:0] variant2 = (cnt[24:22] == 3'd0) ? 8'b11111110 : (cnt[24:22] == 3'd1) ? 8'b11111101 : (cnt[24:22] == 3'd2) ? 8'b11111011 : (cnt[24:22] == 3'd3) ? 8'b11110111 : (cnt[24:22] == 3'd4) ? 8'b11101111 : (cnt[24:22] == 3'd5) ? 8'b11011111 : (cnt[24:22] == 3'd6) ? 8'b10111111 : (cnt[24:22] == 3'd7) ? 8'b01111111 : 8'b11111111; wire [7:0] variant3 = (cnt[24]) ? 8'b00110011 : 8'b11001100; wire [7:0] variant4 = (cnt[24:23] == 2'd0) ? 8'b11001100 : (cnt[24:23] == 2'd1) ? 8'b01100110 : (cnt[24:23] == 2'd2) ? 8'b00110011 : (cnt[24:23] == 2'd3) ? 8'b10011001 : 8'b11111111; reg [2:0] res_gen_reg; wire reset = ~(res_gen_reg==3'b111); always @(posedge clk) begin res_gen_reg <= (res_gen_reg==3'b111) ? res_gen_reg : res_gen_reg + 1'b1; end reg [7:0] variant5; reg [7:0] d; always @(posedge clk) begin if (reset) begin d <= 1; end else begin if (cnt[20:0]==21'd0) begin d <= { d[5:0], d[6] ^ d[5] }; variant5[cnt[23:21]] <= d[5]; end end end assign leds = (cnt[29:27] == 3'd1) ? variant2 : (cnt[29:27] == 3'd3) ? variant3 : (cnt[29:27] == 3'd5) ? variant4 : (cnt[29:27] == 3'd7) ? variant5 : variant1; endmodule 


findings


It would seem a meaningless project, but allowed me to learn about such nuances as the inoperability of initial on this series. I used to think that this is generally a feature of the manufacturer (Lattice, Xilinx or Altera). And from the comments it turned out that the number of flashing this FPGA is only about 100 times. New knowledge comes, it means all this is not in vain!


')

Source: https://habr.com/ru/post/318726/


All Articles