diff --git a/7Segment_Lattice_ice40_UltraPlus/.gitignore b/7Segment_Lattice_ice40_UltraPlus/.gitignore new file mode 100644 index 0000000..bebbe55 --- /dev/null +++ b/7Segment_Lattice_ice40_UltraPlus/.gitignore @@ -0,0 +1,3 @@ +*.blif +*.asc +*.bin diff --git a/7Segment_Lattice_ice40_UltraPlus/Makefile b/7Segment_Lattice_ice40_UltraPlus/Makefile new file mode 100644 index 0000000..cec9334 --- /dev/null +++ b/7Segment_Lattice_ice40_UltraPlus/Makefile @@ -0,0 +1,24 @@ +filename = top +pcf_file = io.pcf + +RPI_USER=pi +RPI_IP=192.168.10.90 +RPI_DIR=/home/pi/ice40/build2 + +build: + yosys -p "synth_ice40 -blif $(filename).blif" $(filename).v + arachne-pnr -d 5k -P sg48 -p $(pcf_file) $(filename).blif -o $(filename).asc + icepack $(filename).asc $(filename).bin + +prog: #for sram + iceprog -S $(filename).bin + +prog_flash: + iceprog $(filename).bin + +rpi_prog: build + scp $(filename).bin $(RPI_USER)@$(RPI_IP):$(RPI_DIR) + ssh $(RPI_USER)@$(RPI_IP) "cd $(RPI_DIR); iceprog $(filename).bin" + +clean: + rm -rf $(filename).blif $(filename).asc $(filename).bin diff --git a/7Segment_Lattice_ice40_UltraPlus/README.md b/7Segment_Lattice_ice40_UltraPlus/README.md new file mode 100644 index 0000000..89fe28a --- /dev/null +++ b/7Segment_Lattice_ice40_UltraPlus/README.md @@ -0,0 +1,9 @@ +# 7-Segment-Display to show Counter Value + +The goal of this example is to display a counter output on a 7-segment connected to the fpga. + +For used IOs check out io.pcf. + +To Upload use Makefile, Project IceStorm is needed for this to work. + +I uploaded with RPI4, look at make rpi_prog diff --git a/7Segment_Lattice_ice40_UltraPlus/bcd_to_7seg.v b/7Segment_Lattice_ice40_UltraPlus/bcd_to_7seg.v new file mode 100755 index 0000000..f80876a --- /dev/null +++ b/7Segment_Lattice_ice40_UltraPlus/bcd_to_7seg.v @@ -0,0 +1,34 @@ +//transforms 4bits numbers to a 7seg display +// +// --a-- +// | | +// f b +// | | +// --g-- +// | | +// e c +// | | +// --d-- DP +// +// 7'gfedcba (a = LSB) +module bcd_to_7seg(input [3:0] bcd_in, output [6:0] seg_out); + + assign seg_out = (bcd_in==4'h0) ? 7'b0111111 : + (bcd_in==4'h1) ? 7'b0000110 : + (bcd_in==4'h2) ? 7'b1011011 : + (bcd_in==4'h3) ? 7'b1001111 : + (bcd_in==4'h4) ? 7'b1100110 : + (bcd_in==4'h5) ? 7'b1101101 : + (bcd_in==4'h6) ? 7'b1111101 : + (bcd_in==4'h7) ? 7'b0000111 : + (bcd_in==4'h8) ? 7'b1111111 : + (bcd_in==4'h9) ? 7'b1101111 : + (bcd_in==4'ha) ? 7'b1110111 : + (bcd_in==4'hb) ? 7'b1111100 : + (bcd_in==4'hc) ? 7'b0111001 : + (bcd_in==4'hd) ? 7'b1011110 : + (bcd_in==4'he) ? 7'b1111001 : + (bcd_in==4'hf) ? 7'b1110001 : + 7'b0110110; //does a H, default shouldn't happen + +endmodule diff --git a/7Segment_Lattice_ice40_UltraPlus/clocks.v b/7Segment_Lattice_ice40_UltraPlus/clocks.v new file mode 100644 index 0000000..b574d50 --- /dev/null +++ b/7Segment_Lattice_ice40_UltraPlus/clocks.v @@ -0,0 +1,43 @@ +// generate clocks + +module clocks +#( + parameter PRE_PWM = 28'd12, + parameter PRE_7SEG = 28'd12, + parameter PRE_COUNTER = 28'd12 +) +( + input clk, output clk_pwm, output clk_7seg, output clk_counter +); + + reg [27:0] counter = 28'd0; + reg [27:0] counter_7seg = 28'd0; + reg [27:0] counter_counter = 28'd0; + reg clk_pwm; + reg clk_7seg; + reg clk_counter; + + always @(posedge clk) + begin + counter <= counter + 28'd1; + if(counter >= (PRE_PWM-1)) + counter <= 28'd0; + clk_pwm <= ( counter < PRE_PWM/2) ? 1'b1 : 1'b0; + end + + always @(posedge clk) + begin + counter_7seg <= counter_7seg + 28'd1; + if(counter_7seg >= (PRE_7SEG-1)) + counter_7seg <= 28'd0; + clk_7seg <= ( counter_7seg < PRE_7SEG/2) ? 1'b1 : 1'b0; + end + + always @(posedge clk) + begin + counter_counter <= counter_counter + 28'd1; + if(counter_counter >= (PRE_COUNTER-1)) + counter_counter <= 28'd0; + clk_counter <= ( counter_counter < PRE_COUNTER/2) ? 1'b1 : 1'b0; + end +endmodule diff --git a/7Segment_Lattice_ice40_UltraPlus/counter.v b/7Segment_Lattice_ice40_UltraPlus/counter.v new file mode 100644 index 0000000..43de511 --- /dev/null +++ b/7Segment_Lattice_ice40_UltraPlus/counter.v @@ -0,0 +1,23 @@ +////////////////////////////////////////////////////////////// +// 20-bit loadable up-down counter ////// +////////////////////////////////////////////////////////////// + +module counter(clk, rst, data, updown, load, data_out); + + input clk, rst, load; + input updown; + input [19:0] data; + + output reg [19:0] data_out; + + always @(posedge clk) + begin + if(rst) + data_out <= 20'b0; + else if(load) + data_out <= data; + else + data_out <= ((updown)?(data_out + 1'b1):(data_out -1'b1)); + end + +endmodule diff --git a/7Segment_Lattice_ice40_UltraPlus/digit_driver.v b/7Segment_Lattice_ice40_UltraPlus/digit_driver.v new file mode 100644 index 0000000..f45d00b --- /dev/null +++ b/7Segment_Lattice_ice40_UltraPlus/digit_driver.v @@ -0,0 +1,48 @@ +`include "bcd_to_7seg.v" + + +module digit_driver +#( + parameter D = 28'd0 +) +( + input clk, input [19:0] number, input dot, output [7:0] segs, output [4:0] digs +); + + // io for 7seg + reg [2:0] active_digit; + wire [4:0] buf_digs; + + wire [19:0] number; + wire [3:0] a_number; + wire [6:0] seg_out; + + bcd_to_7seg bcd_to_7seg_inst( + .bcd_in(a_number), + .seg_out(seg_out) + ); + + // see bcd_to_7seg.v for segments placement + // common anode ~seg_out[], common cathode seg_out[] + + assign segs = { dot, seg_out }; + + assign buf_digs = (number > 20'hFFFF) ? 5'b11111 : + (number > 20'hFFF) ? 5'b01111 : + (number > 20'hFF) ? 5'b00111 : + (number > 20'hF) ? 5'b00011 : + 5'b00001; // default shouldn't happen + + assign digs = buf_digs & (1'b1 << active_digit); + assign a_number = (number & (4'b1111 << (active_digit*4))) >> (active_digit*4); + + always @(posedge clk) + begin + active_digit <= active_digit + 1'b1; + if(active_digit > 3'd3) + active_digit <= 1'b0; + end + + + +endmodule \ No newline at end of file diff --git a/7Segment_Lattice_ice40_UltraPlus/io.pcf b/7Segment_Lattice_ice40_UltraPlus/io.pcf new file mode 100755 index 0000000..cad5709 --- /dev/null +++ b/7Segment_Lattice_ice40_UltraPlus/io.pcf @@ -0,0 +1,33 @@ +# For the iCE40 UltraPlus (iCE40UP5K-QFN) Breakout Board +# 12 MHz Clock +set_io clk 35 + +set_io LED_R 41 +set_io LED_G 40 +set_io LED_B 39 +set_io SW[0] 23 +set_io SW[1] 25 +set_io SW[2] 34 +set_io SW[3] 43 + +# bank 0,segments +set_io seg_b 26 # IOT_39A +set_io seg_a 27 # IOT_38B +set_io seg_p 28 # IOT_41A +set_io seg_f 31 # IOT_42B +set_io seg_g 32 # IOT_43A +set_io seg_e 37 # IOT_45A_G1 +set_io seg_d 42 # IOT_51A +set_io seg_c 38 # IOT_50B +# bank1 digit +set_io dig_1 21 # IOT_23B +set_io dig_2 20 # IOT_25B_G3 +set_io dig_3 19 # IOT_29B +set_io dig_4 18 # IOT_31B +set_io dig_5 11 # IOT_20A + +#spi +set_io SPI_SS 16 +set_io SPI_SCK 15 +set_io SPI_MOSI 17 +set_io SPI_MISO 14 \ No newline at end of file diff --git a/7Segment_Lattice_ice40_UltraPlus/pwm.v b/7Segment_Lattice_ice40_UltraPlus/pwm.v new file mode 100644 index 0000000..d764039 --- /dev/null +++ b/7Segment_Lattice_ice40_UltraPlus/pwm.v @@ -0,0 +1,24 @@ +//pwm module, outputs a pulse width according to the value written +//max width 255 cycles + +module pwm(input clk, input en, input [7:0] value_input, output out); + reg [7:0] counter; + reg [7:0] value; //max 255 + + assign out = (counter < value); + + initial begin + counter = 0; + value = 255; + end + + always @(posedge clk) + begin + counter <= counter + 1; + + if(en == 1'b1) + value <= value_input; + else + value <= 0; + end +endmodule diff --git a/7Segment_Lattice_ice40_UltraPlus/top.v b/7Segment_Lattice_ice40_UltraPlus/top.v new file mode 100755 index 0000000..a34dc20 --- /dev/null +++ b/7Segment_Lattice_ice40_UltraPlus/top.v @@ -0,0 +1,90 @@ +`include "digit_driver.v" +`include "pwm.v" +`include "clocks.v" +`include "counter.v" + +// A verilog module transforms a 4-bit number into a displayable 7-bit value. +// This number is incremented every ~0.25sec. +module top( input clk, + output LED_R, output LED_G, output LED_B, + output seg_b, output seg_a, output seg_f, + output seg_g, output seg_d, output seg_e, + output seg_c, output seg_p, input [3:0] SW, + output dig_1, output dig_2, output dig_3, output dig_4, output dig_5 +); + + wire clk_pwm; + wire clk_7seg; + wire clk_counter; + + clocks #(.PRE_PWM(28'd12), .PRE_7SEG(28'd12000), .PRE_COUNTER(28'd12000)) clocks_inst + ( + .clk(clk), + .clk_pwm(clk_pwm), + .clk_7seg(clk_7seg), + .clk_counter(clk_counter) + ); + + wire rst; + wire updown; + wire load; + reg [19:0] data = 20'h1337; + wire [19:0] data_out; + + assign rst = SW[0]; + assign updown = SW[1]; + assign load = SW[2]; + + counter TIM1 ( + .clk(clk_counter), + .rst(rst), + .data(data), + .updown(updown), + .load(load), + .data_out(data_out) + ); + + wire pwm_en_write; + assign pwm_en_write = SW[3]; + wire [7:0] pwm_brightness; + reg [7:0] led_brightness; + assign pwm_brightness = led_brightness; + + wire pwm_out; + pwm pwm_inst(.clk(clk_pwm), .en(pwm_en_write), .value_input(pwm_brightness), .out(pwm_out)); + + // active low, color white + assign LED_R = ~pwm_out; + assign LED_G = ~pwm_out; + assign LED_B = ~pwm_out; + + wire [19:0] number; + assign number = data_out; + assign dot = rst; + + wire [7:0] segs; + assign seg_a = segs[0]; + assign seg_b = segs[1]; + assign seg_c = segs[2]; + assign seg_d = segs[3]; + assign seg_e = segs[4]; + assign seg_f = segs[5]; + assign seg_g = segs[6]; + assign seg_p = segs[7]; + + wire [4:0] digs; + assign dig_1 = digs[0]; + assign dig_2 = digs[1]; + assign dig_3 = digs[2]; + assign dig_4 = digs[3]; + assign dig_5 = digs[4]; + digit_driver dig_inst(.clk(clk_7seg), .number(number), .dot(dot), .segs(segs), .digs(digs)); + + initial begin + led_brightness = 10; + end + + + + +endmodule