From fb5c786be539f508e5c311183b6a8610ba3c8908 Mon Sep 17 00:00:00 2001 From: shylie Date: Sat, 6 Sep 2025 23:52:09 -0400 Subject: [PATCH] Add spi.sv, update display.sv and top.sv --- Makefile | 6 +- display.sv | 490 ++++++++++++++++++++++++++++----------------------- spi.sv | 33 ++++ testbench.sv | 6 - top.sv | 40 +++-- 5 files changed, 337 insertions(+), 238 deletions(-) create mode 100644 spi.sv diff --git a/Makefile b/Makefile index 1f44757..9710a38 100644 --- a/Makefile +++ b/Makefile @@ -4,15 +4,18 @@ ICEPACK = icepack DFU_UTIL = dfu-util BIN2UF2 = bin2uf2 IVERILOG = iverilog +ICETIME = icetime VVP = vvp RTL = top.sv spi.sv display.sv -all: gateware.bin iverilog.vcd +all: gateware.bin clean: $(RM) *.json *.asc *.bin *.uf2 *.vcd *.vvp +sim: iverilog.vcd + prog: gateware.bin $(DFU_UTIL) -d 1209:b1c0 -a 1 -D gateware.bin @@ -23,6 +26,7 @@ gateware.bin: $(RTL) $(YOSYS) -q -p "read_verilog -sv $(RTL); synth_ice40 -top top -json $*.json" $(NEXTPNR) -q --randomize-seed --up5k --package sg48 --pcf constraints.pcf --json $*.json --asc $*.asc $(ICEPACK) $*.asc $@ + $(ICETIME) $*.asc -mtd up5k iverilog.vcd: testbench.sv $(RTL) $(IVERILOG) -g2012 -Wall -o $*vvp.vvp testbench.sv $(RTL) diff --git a/display.sv b/display.sv index d6a404a..d766746 100644 --- a/display.sv +++ b/display.sv @@ -3,6 +3,13 @@ module display( input wire nreset, input wire clk, + input wire [5:0] red, // + input wire [5:0] green, // current pixel + input wire [5:0] blue, // + output wire [7:0] x, // current pixel x + output wire [7:0] y, // current pixel y + output wire frame, // new frame indicator + output wire pixel, // new pixel indicator output wire sck, output wire cs, output wire mosi, @@ -35,7 +42,9 @@ localparam STATE_INIT_WAIT_AFTER_SET_DISPLAY_MODE = 22; localparam STATE_INIT_TURN_ON_DISPLAY = 23; localparam STATE_INIT_WAIT_AFTER_TURN_ON_DISPLAY = 24; localparam STATE_SEND_DISPLAY_CONTENTS_COMMAND = 25; -localparam STATE_SEND_DISPLAY_CONTENTS = 26; +localparam STATE_SEND_DISPLAY_CONTENTS_RED = 26; +localparam STATE_SEND_DISPLAY_CONTENTS_GREEN = 27; +localparam STATE_SEND_DISPLAY_CONTENTS_BLUE = 28; wire next; @@ -47,6 +56,12 @@ logic [20:0] wait_counter_r; logic [4:0] state; +logic [7:0] x_r; +logic [7:0] y_r; + +logic frame_r; +logic pixel_r; + spi spi_inst( .nreset(nreset), .clk(clk), @@ -60,6 +75,8 @@ spi spi_inst( always_ff @(posedge clk) begin if (nreset) begin send_data_r <= 0; + frame_r <= 0; + pixel_r <= 0; case (state) STATE_INIT_WAIT : begin @@ -77,7 +94,7 @@ always_ff @(posedge clk) begin spi_data_r <= 8'h01; if (next) begin - wait_counter_r <= 150000 * 12; // 150 ms wait + wait_counter_r <= 150000 * 48; // 150 ms wait state <= STATE_INIT_WAIT_AFTER_RESET; end end @@ -97,7 +114,7 @@ always_ff @(posedge clk) begin spi_data_r <= 8'h11; if (next) begin - wait_counter_r <= 10000 * 12; // 10 ms wait + wait_counter_r <= 10000 * 48; // 10 ms wait state <= STATE_INIT_WAIT_AFTER_STOP_SLEEP; end end @@ -115,240 +132,279 @@ always_ff @(posedge clk) begin STATE_INIT_SET_FORMAT : begin send_data_r <= 1; dc_r <= 0; - spi_data_r <= 8'h3A; + spi_data_r <= 8'h3A; - if (next) begin - state <= STATE_INIT_SET_FORMAT_PARAM1; + if (next) begin + state <= STATE_INIT_SET_FORMAT_PARAM1; + end end - end - STATE_INIT_SET_FORMAT_PARAM1 : begin - send_data_r <= 1; - dc_r <= 1; - spi_data_r <= 8'h66; + STATE_INIT_SET_FORMAT_PARAM1 : begin + send_data_r <= 1; + dc_r <= 1; + spi_data_r <= 8'h06; - if (next) begin - state <= STATE_INIT_WAIT_AFTER_SET_FORMAT; - wait_counter_r <= 10000 * 12; // 10ms wait + if (next) begin + state <= STATE_INIT_WAIT_AFTER_SET_FORMAT; + wait_counter_r <= 10000 * 48; // 10ms wait + end end - end - STATE_INIT_WAIT_AFTER_SET_FORMAT : begin - wait_counter_r <= wait_counter_r - 1; - - if (wait_counter_r == 0) begin - wait_counter_r <= 0; - - state <= STATE_INIT_SET_COLUMN_ADDRESS_RANGE; - end - end - - STATE_INIT_SET_COLUMN_ADDRESS_RANGE : begin - send_data_r <= 1; - dc_r <= 0; - spi_data_r <= 8'h2A; - - if (next) begin - state <= STATE_INIT_SET_COLUMN_ADDRESS_RANGE_PARAM1; - end - end - - STATE_INIT_SET_COLUMN_ADDRESS_RANGE_PARAM1 : begin - send_data_r <= 1; - dc_r <= 1; - spi_data_r <= 8'h00; - - if (next) begin - state <= STATE_INIT_SET_COLUMN_ADDRESS_RANGE_PARAM2; - end - end - - STATE_INIT_SET_COLUMN_ADDRESS_RANGE_PARAM2 : begin - send_data_r <= 1; - dc_r <= 1; - spi_data_r <= 8'h35; - - if (next) begin - state <= STATE_INIT_SET_COLUMN_ADDRESS_RANGE_PARAM3; - end - end - - STATE_INIT_SET_COLUMN_ADDRESS_RANGE_PARAM3 : begin - send_data_r <= 1; - dc_r <= 1; - spi_data_r <= 8'h00; - - if (next) begin - state <= STATE_INIT_SET_COLUMN_ADDRESS_RANGE_PARAM4; - end - end - - STATE_INIT_SET_COLUMN_ADDRESS_RANGE_PARAM4 : begin - send_data_r <= 1; - dc_r <= 1; - spi_data_r <= 8'hBB; - - if (next) begin - state <= STATE_INIT_SET_ROW_ADDRESS_RANGE; - end - end - - STATE_INIT_SET_ROW_ADDRESS_RANGE : begin - send_data_r <= 1; - dc_r <= 0; - spi_data_r <= 8'h2B; - - if (next) begin - state <= STATE_INIT_SET_ROW_ADDRESS_RANGE_PARAM1; - end - end - - STATE_INIT_SET_ROW_ADDRESS_RANGE_PARAM1 : begin - send_data_r <= 1; - dc_r <= 1; - spi_data_r <= 8'h00; - - if (next) begin - state <= STATE_INIT_SET_ROW_ADDRESS_RANGE_PARAM2; - end - end - - STATE_INIT_SET_ROW_ADDRESS_RANGE_PARAM2 : begin - send_data_r <= 1; - dc_r <= 1; - spi_data_r <= 8'h28; - - if (next) begin - state <= STATE_INIT_SET_ROW_ADDRESS_RANGE_PARAM3; - end - end - - STATE_INIT_SET_ROW_ADDRESS_RANGE_PARAM3 : begin - send_data_r <= 1; - dc_r <= 1; - spi_data_r <= 8'h01; - - if (next) begin - state <= STATE_INIT_SET_ROW_ADDRESS_RANGE_PARAM4; - end - end - - STATE_INIT_SET_ROW_ADDRESS_RANGE_PARAM4 : begin - send_data_r <= 1; - dc_r <= 1; - spi_data_r <= 8'h17; - - if (next) begin - state <= STATE_INIT_SET_ADDRESSING_MODE; - end - end - - STATE_INIT_SET_ADDRESSING_MODE : begin - send_data_r <= 1; - dc_r <= 0; - spi_data_r <= 8'h36; - - if (next) begin - state <= STATE_INIT_SET_ADDRESSING_MODE_PARAM1; - end - end - - STATE_INIT_SET_ADDRESSING_MODE_PARAM1 : begin - send_data_r <= 1; - dc_r <= 1; - spi_data_r <= 8'hC0; - - if (next) begin - state <= STATE_INIT_SET_DISPLAY_INVERSION; - end - end - - STATE_INIT_SET_DISPLAY_INVERSION : begin - send_data_r <= 1; - dc_r <= 0; - spi_data_r <= 8'h21; - - if (next) begin - state <= STATE_INIT_SET_DISPLAY_MODE; - end - end - - STATE_INIT_SET_DISPLAY_MODE : begin - send_data_r <= 1; - dc_r <= 0; - spi_data_r <= 8'h13; - - if (next) begin - wait_counter_r <= 10000 * 12; // 10ms wait - state <= STATE_INIT_WAIT_AFTER_SET_DISPLAY_MODE; - end - end - - STATE_INIT_WAIT_AFTER_SET_DISPLAY_MODE : begin - wait_counter_r <= wait_counter_r - 1; - - if (wait_counter_r == 0) begin - wait_counter_r <= 0; - - state <= STATE_INIT_TURN_ON_DISPLAY; - end - end - - STATE_INIT_TURN_ON_DISPLAY : begin - send_data_r <= 1; - dc_r <= 0; - spi_data_r <= 8'h29; - - if (next) begin - wait_counter_r <= 10000 * 12; // 10ms wait - state <= STATE_INIT_WAIT_AFTER_TURN_ON_DISPLAY; - end - end - - STATE_INIT_WAIT_AFTER_TURN_ON_DISPLAY : begin - wait_counter_r <= wait_counter_r - 1; - - if (wait_counter_r == 0) begin - wait_counter_r <= 0; - - state <= STATE_SEND_DISPLAY_CONTENTS_COMMAND; - end - end - - STATE_SEND_DISPLAY_CONTENTS_COMMAND : begin - send_data_r <= 1; - dc_r <= 0; - spi_data_r <= 8'h2C; - - if (next) begin - wait_counter_r <= 97200; // 240 * 135 * 3 - state <= STATE_SEND_DISPLAY_CONTENTS; - end - end - - STATE_SEND_DISPLAY_CONTENTS : begin - send_data_r <= 1; - dc_r <= 1; - spi_data_r <= 8'b11111100; - - if (next) begin + STATE_INIT_WAIT_AFTER_SET_FORMAT : begin wait_counter_r <= wait_counter_r - 1; - if (wait_counter_r == 1) begin + + if (wait_counter_r == 0) begin + wait_counter_r <= 0; + + state <= STATE_INIT_SET_COLUMN_ADDRESS_RANGE; + end + end + + STATE_INIT_SET_COLUMN_ADDRESS_RANGE : begin + send_data_r <= 1; + dc_r <= 0; + spi_data_r <= 8'h2A; + + if (next) begin + state <= STATE_INIT_SET_COLUMN_ADDRESS_RANGE_PARAM1; + end + end + + STATE_INIT_SET_COLUMN_ADDRESS_RANGE_PARAM1 : begin + send_data_r <= 1; + dc_r <= 1; + spi_data_r <= 8'h00; + + if (next) begin + state <= STATE_INIT_SET_COLUMN_ADDRESS_RANGE_PARAM2; + end + end + + STATE_INIT_SET_COLUMN_ADDRESS_RANGE_PARAM2 : begin + send_data_r <= 1; + dc_r <= 1; + spi_data_r <= 8'h35; + + if (next) begin + state <= STATE_INIT_SET_COLUMN_ADDRESS_RANGE_PARAM3; + end + end + + STATE_INIT_SET_COLUMN_ADDRESS_RANGE_PARAM3 : begin + send_data_r <= 1; + dc_r <= 1; + spi_data_r <= 8'h00; + + if (next) begin + state <= STATE_INIT_SET_COLUMN_ADDRESS_RANGE_PARAM4; + end + end + + STATE_INIT_SET_COLUMN_ADDRESS_RANGE_PARAM4 : begin + send_data_r <= 1; + dc_r <= 1; + spi_data_r <= 8'hBB; + + if (next) begin + state <= STATE_INIT_SET_ROW_ADDRESS_RANGE; + end + end + + STATE_INIT_SET_ROW_ADDRESS_RANGE : begin + send_data_r <= 1; + dc_r <= 0; + spi_data_r <= 8'h2B; + + if (next) begin + state <= STATE_INIT_SET_ROW_ADDRESS_RANGE_PARAM1; + end + end + + STATE_INIT_SET_ROW_ADDRESS_RANGE_PARAM1 : begin + send_data_r <= 1; + dc_r <= 1; + spi_data_r <= 8'h00; + + if (next) begin + state <= STATE_INIT_SET_ROW_ADDRESS_RANGE_PARAM2; + end + end + + STATE_INIT_SET_ROW_ADDRESS_RANGE_PARAM2 : begin + send_data_r <= 1; + dc_r <= 1; + spi_data_r <= 8'h28; + + if (next) begin + state <= STATE_INIT_SET_ROW_ADDRESS_RANGE_PARAM3; + end + end + + STATE_INIT_SET_ROW_ADDRESS_RANGE_PARAM3 : begin + send_data_r <= 1; + dc_r <= 1; + spi_data_r <= 8'h01; + + if (next) begin + state <= STATE_INIT_SET_ROW_ADDRESS_RANGE_PARAM4; + end + end + + STATE_INIT_SET_ROW_ADDRESS_RANGE_PARAM4 : begin + send_data_r <= 1; + dc_r <= 1; + spi_data_r <= 8'h17; + + if (next) begin + state <= STATE_INIT_SET_ADDRESSING_MODE; + end + end + + STATE_INIT_SET_ADDRESSING_MODE : begin + send_data_r <= 1; + dc_r <= 0; + spi_data_r <= 8'h36; + + if (next) begin + state <= STATE_INIT_SET_ADDRESSING_MODE_PARAM1; + end + end + + STATE_INIT_SET_ADDRESSING_MODE_PARAM1 : begin + send_data_r <= 1; + dc_r <= 1; + spi_data_r <= 8'hC0; + + if (next) begin + state <= STATE_INIT_SET_DISPLAY_INVERSION; + end + end + + STATE_INIT_SET_DISPLAY_INVERSION : begin + send_data_r <= 1; + dc_r <= 0; + spi_data_r <= 8'h21; + + if (next) begin + state <= STATE_INIT_SET_DISPLAY_MODE; + end + end + + STATE_INIT_SET_DISPLAY_MODE : begin + send_data_r <= 1; + dc_r <= 0; + spi_data_r <= 8'h13; + + if (next) begin + wait_counter_r <= 10000 * 48; // 10ms wait + state <= STATE_INIT_WAIT_AFTER_SET_DISPLAY_MODE; + end + end + + STATE_INIT_WAIT_AFTER_SET_DISPLAY_MODE : begin + wait_counter_r <= wait_counter_r - 1; + + if (wait_counter_r == 0) begin + wait_counter_r <= 0; + + state <= STATE_INIT_TURN_ON_DISPLAY; + end + end + + STATE_INIT_TURN_ON_DISPLAY : begin + send_data_r <= 1; + dc_r <= 0; + spi_data_r <= 8'h29; + + if (next) begin + wait_counter_r <= 10000 * 48; // 10ms wait + state <= STATE_INIT_WAIT_AFTER_TURN_ON_DISPLAY; + end + end + + STATE_INIT_WAIT_AFTER_TURN_ON_DISPLAY : begin + wait_counter_r <= wait_counter_r - 1; + + if (wait_counter_r == 0) begin + wait_counter_r <= 0; + state <= STATE_SEND_DISPLAY_CONTENTS_COMMAND; end end - end + + STATE_SEND_DISPLAY_CONTENTS_COMMAND : begin + send_data_r <= 1; + dc_r <= 0; + spi_data_r <= 8'h2C; + + if (next) begin + x_r <= 0; + y_r <= 0; + wait_counter_r <= 32400; // 240 * 135 + state <= STATE_SEND_DISPLAY_CONTENTS_RED; + end + end + + STATE_SEND_DISPLAY_CONTENTS_RED : begin + send_data_r <= 1; + dc_r <= 1; + spi_data_r <= {red, 2'b00}; + + if (next) begin + state <= STATE_SEND_DISPLAY_CONTENTS_GREEN; + end + end + + STATE_SEND_DISPLAY_CONTENTS_GREEN : begin + send_data_r <= 1; + dc_r <= 1; + spi_data_r <= {green, 2'b00}; + + if (next) begin + state <= STATE_SEND_DISPLAY_CONTENTS_BLUE; + end + end + + STATE_SEND_DISPLAY_CONTENTS_BLUE : begin + send_data_r <= 1; + dc_r <= 1; + spi_data_r <= {blue, 2'b00}; + + if (next) begin + x_r <= x_r + 1; + if (x_r == 134) begin + x_r <= 0; + y_r <= y_r + 1; + end + wait_counter_r <= wait_counter_r - 1; + if (wait_counter_r == 1) begin + frame_r <= 1; + state <= STATE_SEND_DISPLAY_CONTENTS_COMMAND; + end else begin + pixel_r <= 1; + state <= STATE_SEND_DISPLAY_CONTENTS_RED; + end + end + end endcase end else begin - spi_data_r <= 0; + spi_data_r <= 0; send_data_r <= 0; wait_counter_r <= 10; dc_r <= 0; state <= STATE_INIT_WAIT; + x_r <= 0; + y_r <= 0; + frame_r <= 0; + pixel_r <= 0; end end assign cs = ~send_data_r; assign dc = dc_r; +assign x = x_r; +assign y = y_r; +assign frame = frame_r; +assign pixel = pixel_r; endmodule diff --git a/spi.sv b/spi.sv new file mode 100644 index 0000000..7e6bc3c --- /dev/null +++ b/spi.sv @@ -0,0 +1,33 @@ +`timescale 1ps / 1ps + +module spi( + input wire nreset, + input wire clk, + input wire [7:0] data, + input wire send_data, + output wire sck, + output wire mosi, + output wire next +); + +logic [2:0] current_bit; + +always_ff @(posedge clk) begin + if (send_data == 1) begin + current_bit <= current_bit + 1; + if (current_bit == 3'b111) begin + current_bit <= '0; + end + end + + if (nreset == 1'b0) begin + current_bit <= '0; + end +end + +assign mosi = send_data == 1 ? data[7 - current_bit] : 0; +assign next = current_bit == 3'b110; // one bit early to allow for a response in time + +assign sck = clk; + +endmodule diff --git a/testbench.sv b/testbench.sv index ccd0bc2..9ae1407 100644 --- a/testbench.sv +++ b/testbench.sv @@ -3,9 +3,6 @@ module testbench; reg clk; -wire r; -wire g; -wire b; wire sck; wire mosi; wire cs; @@ -13,9 +10,6 @@ wire dc; top t( .CLK(clk), - .LED_R(r), - .LED_G(g), - .LED_B(b), .DISPLAY_SCK(sck), .DISPLAY_MOSI(mosi), .DISPLAY_CS(cs), diff --git a/top.sv b/top.sv index e915989..8aa2a4c 100644 --- a/top.sv +++ b/top.sv @@ -2,24 +2,35 @@ module top( input CLK, - output LED_R, - output LED_G, - output LED_B, output DISPLAY_SCK, output DISPLAY_MOSI, output DISPLAY_CS, output DISPLAY_DC ); -localparam N = 18; - -logic [N:0] counter; - logic nreset_r = 0; +logic [5:0] red_r; +logic [5:0] green_r; +logic [5:0] blue_r; + +wire frame; +wire pixel; +wire [7:0] x; +wire [7:0] y; + +logic [5:0] counter; + display display_inst( .nreset(nreset_r), .clk(CLK), + .red(red_r), + .green(green_r), + .blue(blue_r), + .x(x), + .y(y), + .frame(frame), + .pixel(pixel), .sck(DISPLAY_SCK), .cs(DISPLAY_CS), .mosi(DISPLAY_MOSI), @@ -28,16 +39,17 @@ display display_inst( always_ff @(posedge CLK) begin if (nreset_r) begin - counter <= counter + 1; + if (frame) begin + counter <= counter - 1; + end + red_r <= y[7:2] + counter[5:0]; + green_r <= 6'b000000; + blue_r <= 6'b000000; end else begin - counter <= '0; - nreset_r <= 1; + + counter <= 0; end end -assign LED_R = 1'b1; -assign LED_G = counter[N]; -assign LED_B = 1'b1; - endmodule