Add spi.sv, update display.sv and top.sv

This commit is contained in:
shylie 2025-09-06 23:52:09 -04:00
parent 0485c1c845
commit fb5c786be5
5 changed files with 337 additions and 238 deletions

View File

@ -4,15 +4,18 @@ ICEPACK = icepack
DFU_UTIL = dfu-util DFU_UTIL = dfu-util
BIN2UF2 = bin2uf2 BIN2UF2 = bin2uf2
IVERILOG = iverilog IVERILOG = iverilog
ICETIME = icetime
VVP = vvp VVP = vvp
RTL = top.sv spi.sv display.sv RTL = top.sv spi.sv display.sv
all: gateware.bin iverilog.vcd all: gateware.bin
clean: clean:
$(RM) *.json *.asc *.bin *.uf2 *.vcd *.vvp $(RM) *.json *.asc *.bin *.uf2 *.vcd *.vvp
sim: iverilog.vcd
prog: gateware.bin prog: gateware.bin
$(DFU_UTIL) -d 1209:b1c0 -a 1 -D 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" $(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 $(NEXTPNR) -q --randomize-seed --up5k --package sg48 --pcf constraints.pcf --json $*.json --asc $*.asc
$(ICEPACK) $*.asc $@ $(ICEPACK) $*.asc $@
$(ICETIME) $*.asc -mtd up5k
iverilog.vcd: testbench.sv $(RTL) iverilog.vcd: testbench.sv $(RTL)
$(IVERILOG) -g2012 -Wall -o $*vvp.vvp testbench.sv $(RTL) $(IVERILOG) -g2012 -Wall -o $*vvp.vvp testbench.sv $(RTL)

View File

@ -3,6 +3,13 @@
module display( module display(
input wire nreset, input wire nreset,
input wire clk, 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 sck,
output wire cs, output wire cs,
output wire mosi, 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_TURN_ON_DISPLAY = 23;
localparam STATE_INIT_WAIT_AFTER_TURN_ON_DISPLAY = 24; localparam STATE_INIT_WAIT_AFTER_TURN_ON_DISPLAY = 24;
localparam STATE_SEND_DISPLAY_CONTENTS_COMMAND = 25; 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; wire next;
@ -47,6 +56,12 @@ logic [20:0] wait_counter_r;
logic [4:0] state; logic [4:0] state;
logic [7:0] x_r;
logic [7:0] y_r;
logic frame_r;
logic pixel_r;
spi spi_inst( spi spi_inst(
.nreset(nreset), .nreset(nreset),
.clk(clk), .clk(clk),
@ -60,6 +75,8 @@ spi spi_inst(
always_ff @(posedge clk) begin always_ff @(posedge clk) begin
if (nreset) begin if (nreset) begin
send_data_r <= 0; send_data_r <= 0;
frame_r <= 0;
pixel_r <= 0;
case (state) case (state)
STATE_INIT_WAIT : begin STATE_INIT_WAIT : begin
@ -77,7 +94,7 @@ always_ff @(posedge clk) begin
spi_data_r <= 8'h01; spi_data_r <= 8'h01;
if (next) begin 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; state <= STATE_INIT_WAIT_AFTER_RESET;
end end
end end
@ -97,7 +114,7 @@ always_ff @(posedge clk) begin
spi_data_r <= 8'h11; spi_data_r <= 8'h11;
if (next) begin 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; state <= STATE_INIT_WAIT_AFTER_STOP_SLEEP;
end end
end end
@ -115,240 +132,279 @@ always_ff @(posedge clk) begin
STATE_INIT_SET_FORMAT : begin STATE_INIT_SET_FORMAT : begin
send_data_r <= 1; send_data_r <= 1;
dc_r <= 0; dc_r <= 0;
spi_data_r <= 8'h3A; spi_data_r <= 8'h3A;
if (next) begin if (next) begin
state <= STATE_INIT_SET_FORMAT_PARAM1; state <= STATE_INIT_SET_FORMAT_PARAM1;
end
end end
end
STATE_INIT_SET_FORMAT_PARAM1 : begin STATE_INIT_SET_FORMAT_PARAM1 : begin
send_data_r <= 1; send_data_r <= 1;
dc_r <= 1; dc_r <= 1;
spi_data_r <= 8'h66; spi_data_r <= 8'h06;
if (next) begin if (next) begin
state <= STATE_INIT_WAIT_AFTER_SET_FORMAT; state <= STATE_INIT_WAIT_AFTER_SET_FORMAT;
wait_counter_r <= 10000 * 12; // 10ms wait wait_counter_r <= 10000 * 48; // 10ms wait
end
end end
end
STATE_INIT_WAIT_AFTER_SET_FORMAT : begin 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
wait_counter_r <= wait_counter_r - 1; 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; state <= STATE_SEND_DISPLAY_CONTENTS_COMMAND;
end end
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 endcase
end else begin end else begin
spi_data_r <= 0; spi_data_r <= 0;
send_data_r <= 0; send_data_r <= 0;
wait_counter_r <= 10; wait_counter_r <= 10;
dc_r <= 0; dc_r <= 0;
state <= STATE_INIT_WAIT; state <= STATE_INIT_WAIT;
x_r <= 0;
y_r <= 0;
frame_r <= 0;
pixel_r <= 0;
end end
end end
assign cs = ~send_data_r; assign cs = ~send_data_r;
assign dc = dc_r; assign dc = dc_r;
assign x = x_r;
assign y = y_r;
assign frame = frame_r;
assign pixel = pixel_r;
endmodule endmodule

33
spi.sv Normal file
View File

@ -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

View File

@ -3,9 +3,6 @@
module testbench; module testbench;
reg clk; reg clk;
wire r;
wire g;
wire b;
wire sck; wire sck;
wire mosi; wire mosi;
wire cs; wire cs;
@ -13,9 +10,6 @@ wire dc;
top t( top t(
.CLK(clk), .CLK(clk),
.LED_R(r),
.LED_G(g),
.LED_B(b),
.DISPLAY_SCK(sck), .DISPLAY_SCK(sck),
.DISPLAY_MOSI(mosi), .DISPLAY_MOSI(mosi),
.DISPLAY_CS(cs), .DISPLAY_CS(cs),

40
top.sv
View File

@ -2,24 +2,35 @@
module top( module top(
input CLK, input CLK,
output LED_R,
output LED_G,
output LED_B,
output DISPLAY_SCK, output DISPLAY_SCK,
output DISPLAY_MOSI, output DISPLAY_MOSI,
output DISPLAY_CS, output DISPLAY_CS,
output DISPLAY_DC output DISPLAY_DC
); );
localparam N = 18;
logic [N:0] counter;
logic nreset_r = 0; 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( display display_inst(
.nreset(nreset_r), .nreset(nreset_r),
.clk(CLK), .clk(CLK),
.red(red_r),
.green(green_r),
.blue(blue_r),
.x(x),
.y(y),
.frame(frame),
.pixel(pixel),
.sck(DISPLAY_SCK), .sck(DISPLAY_SCK),
.cs(DISPLAY_CS), .cs(DISPLAY_CS),
.mosi(DISPLAY_MOSI), .mosi(DISPLAY_MOSI),
@ -28,16 +39,17 @@ display display_inst(
always_ff @(posedge CLK) begin always_ff @(posedge CLK) begin
if (nreset_r) 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 end else begin
counter <= '0;
nreset_r <= 1; nreset_r <= 1;
counter <= 0;
end end
end end
assign LED_R = 1'b1;
assign LED_G = counter[N];
assign LED_B = 1'b1;
endmodule endmodule