newStep.v

This commit is contained in:
2025-11-27 04:28:54 +03:00
parent a84b8fcfde
commit 6e38a6c1af
85 changed files with 25646 additions and 6801 deletions

156
RTL/DEVICES/SSD1351_1331.v Normal file
View File

@@ -0,0 +1,156 @@
// femtorv32, a minimalistic RISC-V RV32I core
// Bruno Levy, 2020-2021
//
// This file: driver for SSD1351 and SSD1331 OLED display
// Reference: https://www.crystalfontz.com/controllers/SolomonSystech/SSD1351/
//
// TODO: we could use wmask to write directly 16 bits or 32 bits of data
// (we could even have a 'fast clear' option that writes a number
// of zeroes).
`ifdef NRV_IO_SSD1331
`define NRV_IO_SSD1351_1331
`endif
`ifdef NRV_IO_SSD1351
`define NRV_IO_SSD1351_1331
`endif
module SSD1351_clk #(
parameter width=1
)(
input wire clk, // input system clock
output wire CLK, // SSD1351 clock
output wire CLK_falling_edge // pulses at each falling edge of CLK
);
reg [width-1:0] slow_cnt;
always @(posedge clk) begin
slow_cnt <= slow_cnt + 1;
end
assign CLK = slow_cnt[width-1];
assign CLK_falling_edge = (slow_cnt == (1 << width)-1);
endmodule
module SSD1351(
input wire clk, // system clock
input wire wstrb, // write strobe (use one of sel_xxx to select dest)
input wire sel_cntl, // wdata[0]: !CS; wdata[1]: RST
input wire sel_cmd, // send 8-bits command to display
input wire sel_dat, // send 8-bits data to display
input wire sel_dat16, // send 16-bits data to display
input wire [31:0] wdata, // data to be written
output wire wbusy, // asserted if the driver is busy sending data
// SSD1351 pins
output DIN, // data in
output CLK, // clock
output reg CS, // chip select (active low)
output reg DC, // data (high) / command (low)
output reg RST // reset (active low)
);
initial begin
DC = 1'b0;
RST = 1'b0;
CS = 1'b1;
end
/********* The clock ****************************************************/
// Note: SSD1351 expects the raising edges of the clock in the middle of
// the data bits.
// TODO: try to have a 'waveform' instead, that is shifted (simpler and
// more elegant).
// Page 52 of the doc: 4-wire SPI timing:
// Unclear what 'Clock Cycle Time' (220 ns) means,
// Clock Low Time (20ns) + Clock High Time (20ns) = 40ns
// max freq = 1/(40ns) = 25 MHz
// experimentally, seems to work up to 30 Mhz (but not more)
wire CLK_falling_edge;
generate
if(`NRV_FREQ <= 60) begin // Divide by 2-> 30 MHz
SSD1351_clk #(
.width(1)
)slow_clk(
.clk(clk),
.CLK(CLK),
.CLK_falling_edge(CLK_falling_edge)
);
end else if(`NRV_FREQ <= 120) begin // Divide by 4
SSD1351_clk #(
.width(2)
)slow_clk(
.clk(clk),
.CLK(CLK),
.CLK_falling_edge(CLK_falling_edge)
);
end else begin // Divide by 8
SSD1351_clk #(
.width(3)
)slow_clk(
.clk(clk),
.CLK(CLK),
.CLK_falling_edge(CLK_falling_edge)
);
end
endgenerate
// Currently sent bit, 1-based index
// (0000 config. corresponds to idle)
reg[4:0] bitcount = 5'b0000;
reg[15:0] shifter = 0;
wire sending = (bitcount != 0);
assign DIN = shifter[15];
assign wbusy = sending;
/*************************************************************************/
always @(posedge clk) begin
if(wstrb) begin
if(sel_cntl) begin
CS <= !wdata[0];
RST <= wdata[1];
end
if(sel_cmd) begin
RST <= 1'b1;
DC <= 1'b0;
shifter <= {wdata[7:0],8'b0};
bitcount <= 8;
CS <= 1'b1;
end
if(sel_dat) begin
RST <= 1'b1;
DC <= 1'b1;
shifter <= {wdata[7:0],8'b0};
bitcount <= 8;
CS <= 1'b1;
end
if(sel_dat16) begin
RST <= 1'b1;
DC <= 1'b1;
shifter <= wdata[15:0];
bitcount <= 16;
CS <= 1'b1;
end
end else begin
// detect falling edge of slow_clk
if(CLK_falling_edge) begin
if(sending) begin
if(CS) begin // first tick activates CS (low)
CS <= 1'b0;
end else begin // shift on falling edge
bitcount <= bitcount - 5'd1;
shifter <= {shifter[14:0], 1'b0};
end
end else begin // last tick deactivates CS (high)
CS <= 1'b1;
end
end
end
end
endmodule