Skip to content

Instantly share code, notes, and snippets.

@gregdavill
Created June 25, 2018 21:55
Show Gist options
  • Save gregdavill/daf0b92debd8b19757b1f58d72d0bae3 to your computer and use it in GitHub Desktop.
Save gregdavill/daf0b92debd8b19757b1f58d72d0bae3 to your computer and use it in GitHub Desktop.
Simple iPod Nano MIPI Verilog module
module top();
wire disp_clk_en, disp_clkp_bias_en, disp_clkn_bias_en;
wire disp_datap_bias_en, disp_datan_bias_en;
wire disp_data0, disp_data1;
wire disp_clk_tri,disp_data_tri;
wire disp_reset;
simpleLCD slcd (
.resetn( resetn),
.clk( clk),
.lcd_clk_en(disp_clk_en),
.lcd_clkp_bias_en(disp_clkp_bias_en),
.lcd_clkn_bias_en(disp_clkn_bias_en),
.lcd_clk_tri(disp_clk_tri),
.lcd_data_0(disp_data0),
.lcd_data_1(disp_data1),
.lcd_datap_bias_en(disp_datap_bias_en),
.lcd_datan_bias_en(disp_datan_bias_en),
.lcd_data_tri(disp_data_tri),
.lcd_reset(disp_reset)
);
wire disp_clk = clk_90 & disp_clk_en;
OBZ disp_clk_obz [1:0] (
.O ( DISP_CLK ),
.I ({!disp_clk,disp_clk}),
.T (!disp_clk_tri)
);
wire [1:0] disp_ddr_data;
ODDRX1F disp_data_DDR [1:0] (
.SCLK(clk),
.RST(!resetn),
.D0({!disp_data0,disp_data0}), // data sent on next edge
.D1({!disp_data1,disp_data1}), // data sent on following edge
.Q(disp_ddr_data)
);
OBZ disp_data [1:0] (
.O ( DISP_DATA ),
.I (disp_ddr_data),
.T (!disp_data_tri)
);
assign DISP_CLKP_BIAS = !disp_clkp_bias_en;
assign DISP_CLKN_BIAS = !disp_clkn_bias_en;
assign DISP_DATAP_BIAS = !disp_datap_bias_en;
assign DISP_DATAN_BIAS = !disp_datan_bias_en;
assign DISP_RESET = disp_reset;
endmodule
module simpleLCD (
input resetn,
input clk,
output reg lcd_clk_en,
output reg lcd_clkp_bias_en,
output reg lcd_clkn_bias_en,
output reg lcd_clk_tri,
output lcd_data_0,
output lcd_data_1,
output reg lcd_datap_bias_en,
output reg lcd_datan_bias_en,
output reg lcd_data_tri,
output reg lcd_reset
);
/* Clock out data continously
* data_in and data_byte_en latch in new data.
* data_sr shifts by two every rising edge for DDR.
*/
assign lcd_data_0 = data_sr[0];
assign lcd_data_1 = data_sr[1];
reg [7:0] data_in;
reg data_byte_en;
reg [7:0] data_sr;
always @(posedge clk) begin
if(!resetn) begin
data_sr <= 0;
end else begin
data_sr <= {2'b0, data_sr[7:2]};
if(data_byte_en) begin
data_sr <= data_in;
end
end
end
/* Divide clock by 4
* a divided signal enables our state machine to update every 4 clocks
* 4-clks represent 1 byte of DDR data. */
reg [1:0] div_sr;
always @(posedge clk) begin
if(!resetn) begin
div_sr <= 0;
end else begin
div_sr <= div_sr + 1;
end
end
/* Control State Machine
* Handle power up Reset
* Handle High speed entry / exit */
reg [15:0] state;
reg [15:0] counter;
reg [15:0] line_counter;
reg [7:0] cmd_data [0:27];
reg [7:0] line_data [0:479];
initial $readmemh("display_line_cmd.list", cmd_data);
initial $readmemh("display_line_data.list", line_data);
parameter state_INIT=0, state_RESET=1, state_CLK_HS_start=2, state_RUNNING=3;
wire clk4 = (div_sr == 2'b11);
always @(posedge clk4) begin
if(!resetn) begin
state <= 0;
counter <= 0;
end else begin
counter <= counter + 1;
case (state)
state_INIT: begin
lcd_reset <= 0;
if(counter == 10000) begin
state <= state_RESET;
counter <= 0;
end
end
state_RESET: begin
lcd_reset <= 1;
if(counter == 10000) begin
state <= state_CLK_HS_start;
counter <= 0;
end
end
state_CLK_HS_start: begin
if(counter == 100) begin
state <= state_RUNNING;
end
end
state_RUNNING: begin
end
endcase
end
end
reg [8:0] HS_clk_counter;
reg [8:0] HS_clk_state;
parameter state_clk_WAIT=0, state_clk_CLKP_BIAS_LOW=1, state_clk_CLKN_BIAS_LOW=2, state_clk_DRIVE_EN=3, state_clk_CLK_EN=4;
always @(posedge clk4) begin
if(!resetn) begin
HS_clk_state <= state_clk_WAIT;
HS_clk_counter <= 0;
end else begin
case (HS_clk_state)
state_clk_WAIT: begin
lcd_clk_en <= 0;
lcd_clkp_bias_en <= 0;
lcd_clkn_bias_en <= 0;
lcd_clk_tri <= 0;
if(state == state_CLK_HS_start) begin
HS_clk_state <= state_clk_CLKP_BIAS_LOW;
end
end
state_clk_CLKP_BIAS_LOW: begin
HS_clk_counter <= HS_clk_counter + 1;
lcd_clkp_bias_en <= 1;
if(HS_clk_counter == 10) begin
HS_clk_state <= state_clk_CLKN_BIAS_LOW;
HS_clk_counter <= 0;
end
end
state_clk_CLKN_BIAS_LOW: begin
HS_clk_counter <= HS_clk_counter + 1;
lcd_clkn_bias_en <= 1;
if(HS_clk_counter == 10) begin
HS_clk_state <= state_clk_DRIVE_EN;
HS_clk_counter <= 0;
end
end
state_clk_DRIVE_EN: begin
HS_clk_counter <= HS_clk_counter + 1;
lcd_clk_tri <= 1;
if(HS_clk_counter == 10) begin
HS_clk_state <= state_clk_CLK_EN;
HS_clk_counter <= 0;
end
end
state_clk_CLK_EN: begin
lcd_clk_en <= 1;
end
endcase
end
end
reg [8:0] data_cmd_counter;
reg [8:0] data_line_counter;
reg [15:0] data_counter;
reg [8:0] data_state;
parameter state_data_INIT=0,state_data_WAIT=1, state_data_DATAP_BIAS_LOW=2, state_data_DATAN_BIAS_LOW=3, state_data_EN=4, state_data_START=5,state_data_DISPLAY = 6, state_data_END = 7, state_data_FRAME_WAIT=8;
always @(posedge clk) begin
if(!resetn) begin
data_state <= state_data_INIT;
data_counter <= 0;
end else begin
data_byte_en <= 0;
if(clk4) begin
case (data_state)
state_data_INIT: begin
lcd_datap_bias_en <= 0;
lcd_datan_bias_en <= 0;
lcd_data_tri <= 0;
if(lcd_clk_en)
data_state <= state_data_WAIT;
end
state_data_WAIT: begin
data_counter <= data_counter + 1;
if(data_counter > 10) begin
data_state <= state_data_DATAP_BIAS_LOW;
data_counter <= 0;
end
end
state_data_DATAP_BIAS_LOW: begin
data_counter <= data_counter + 1;
lcd_datap_bias_en <= 1;
if(data_counter > 10) begin
data_state <= state_data_DATAN_BIAS_LOW;
data_counter <= 0;
end
end
state_data_DATAN_BIAS_LOW: begin
data_counter <= data_counter + 1;
lcd_datan_bias_en <= 1;
if(data_counter > 10) begin
data_state <= state_data_EN;
data_counter <= 0;
end
end
state_data_EN: begin
data_counter <= data_counter + 1;
lcd_data_tri <= 1;
if(data_counter > 10) begin
data_state <= state_data_START;
data_counter <= 0;
data_cmd_counter <= 0;
end
end
state_data_START: begin
data_counter <= data_counter + 1;
data_byte_en <= 1;
data_cmd_counter <= data_cmd_counter + 1;
data_in <= cmd_data[data_cmd_counter];
if(line_counter > 0 && data_cmd_counter == 21)
data_in <= 8'h3c;
if(data_counter == 21) begin
data_state <= state_data_DISPLAY;
data_counter <= 0;
end
end
state_data_DISPLAY: begin
data_counter <= data_counter + 1;
data_byte_en <= 1;
data_line_counter <= data_line_counter + 1;
//data_in <= line_data[data_line_counter];
data_in <= data_line_counter;
if(data_counter == 479) begin
data_state <= state_data_END;
data_counter <= 0;
end
end
state_data_END: begin
data_counter <= data_counter + 1;
data_byte_en <= 1;
data_cmd_counter <= data_cmd_counter + 1;
data_in <= cmd_data[data_cmd_counter];
if(data_counter == 5) begin
line_counter <= line_counter + 1;
data_counter <= 0;
if(line_counter >= 239)
data_state <= state_data_FRAME_WAIT;
else
data_state <= state_data_INIT;
end
end
state_data_FRAME_WAIT: begin
data_counter <= data_counter + 1;
lcd_datap_bias_en <= 0;
lcd_datan_bias_en <= 0;
lcd_data_tri <= 0;
line_counter <= 0;
data_line_counter <= 0;
if(data_counter == 10000) begin
data_state <= state_data_WAIT;
data_counter <= 0;
end
end
endcase
end
end
end
endmodule
B8
15
29
00
0F
15
11
00
25
15
36
80
12
15
3A
55
02
39
E1
01
0B
2C
00
00
FF
FF
FF
FF
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
3F
00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment