Verilog code: `timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Company: // Engineer: // // Create Date: 22:19:51 05/06/2014 // Design Name: // Module Name: lcd // Project Name: // Target Devices: // Tool versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // ////////////////////////////////////////////////////////////////////////////////// module lcd(clk, reset, SF_D, LCD_E, LCD_RS, LCD_RW, SF_CE0); input clk; input reset; output[3:0] SF_D; output LCD_E; output LCD_RS; output LCD_RW; output SF_CE0; reg cur_state; reg[3:0] SF_D0; reg[3:0] SF_D1; reg LCD_E0; reg LCD_E1; reg mux; reg tx_state; reg[7:0] tx_byte; reg tx_init; reg tx_rdy; reg init_state; reg init_init; reg init_done; reg[19:0] i; // 20'b1011011100011011000 -> 750,000 reg[15:0] i2; // 16'b0000011111010000 -> 2,000 reg[16:0] i3; // 17'b10100000001010000 -> 82000 assign SF_CE0 = 1'b1; // disable strataflash assign LCD_RW = 1'b0; // write only reg s1; reg s2; reg s3; reg s4; reg s5; reg s6; reg s7; reg s8; reg done; reg init; reg idle; reg fifteenms; reg fortyus; reg oneus; reg high_hold; reg high_setup; reg low_setup; reg low_hold; reg char_A; reg function_set; reg entry_set; reg set_display; reg clr_display; reg set_addr; reg update; reg pause; // when to transmit a command/data and when not to always @ (function_set or entry_set or set_display or clr_display or set_addr or update ) begin case (cur_state) function_set: tx_init = 1'b1; entry_set : tx_init = 1'b1; set_display : tx_init = 1'b1; clr_display : tx_init = 1'b1; set_addr : tx_init = 1'b1; update : tx_init = 1'b1; default : tx_init = 1'b0; endcase end // control the bus always @ (init) begin case (cur_state) init : mux <= 1'b1; default : mux <= 1'b0; endcase end //control the initialization sequence always @ (init) begin case (cur_state) init : init_init <= 1'b1; default : init_init <= 1'b0; endcase end //register select assign LCD_RS = (cur_state == s1) ? 1'b0 : (cur_state == s2) ? 1'b0 : (cur_state == s3) ? 1'b0 : (cur_state == s4) ? 1'b0 : (cur_state == s5) ? 1'b0 : 1'b1; always @ (s1 or s2 or s3 or s4 or s5 or char_A) begin case (cur_state) s1 : tx_byte <= 8'b00101000; //function_set s2 : tx_byte <= 8'b00000110; //entry_set s3 : tx_byte <= 8'b00001100; //set_display s4 : tx_byte <= 8'b00000001; //clear_display s5 : tx_byte <= 8'b10000000; //set_addr char_A : tx_byte <= 8'b01000000; // character A endcase end always @ (clk or reset) begin : display if (reset == 1'b1) begin cur_state <= init; end else if (clk == 1'b1) begin case (cur_state) init : begin if (init_done == 1'b1) begin cur_state <= function_set; end else begin cur_state <= init; end end function_set : begin cur_state <= s1; end s1 : begin if (tx_rdy == 1'b1) begin cur_state <= entry_set; end else begin cur_state <= s1; end end entry_set : begin cur_state <= s2; end s2 : begin if (tx_rdy == 1'b1) begin cur_state <= set_display; end else begin cur_state <= s2; end end set_display : begin cur_state <= s3; end s3 : begin if (tx_rdy == 1'b1) begin cur_state <= clr_display; end else begin cur_state <= s3; end end clr_display : begin cur_state <= s4; end s4 : begin if (tx_rdy == 1'b1) begin cur_state <= pause; end else begin cur_state <= s4; end end pause : begin if (i3 == 17'b1011011100011011000) begin //82000ms cur_state <= set_addr; end else begin cur_state <= pause; i3 <= i3 + 1; end end set_addr : begin cur_state <= s5; end s5 : begin if (tx_rdy == 1'b1) begin cur_state <= update; end else begin cur_state <= s5; end end update : begin cur_state <= char_A; end char_A : begin if (tx_rdy == 1'b1) begin cur_state <= set_addr; end else begin cur_state <= char_A; end end done : begin cur_state <= done; end endcase end end assign SF_D = (mux == 1'b0) ? SF_D0 : SF_D1; //LCD_E0-transmit LCD_E1-initialize assign LCD_E = (mux == 1'b0) ? LCD_E0 : LCD_E1; //LCD_E0-transmit LCD_E1-initialize always @ (tx_rdy) begin case (tx_rdy) done : tx_rdy <= 1'b1; default : tx_rdy <= 1'b0; endcase end always @ (tx_state) begin case (tx_state) high_setup : LCD_E0 = 1'b0; oneus : LCD_E0 = 1'b0; low_setup : LCD_E0 = 1'b0; fortyus : LCD_E0 = 1'b0; done : LCD_E0 = 1'b0; high_hold : LCD_E0 = 1'b1; low_hold : LCD_E0 = 1'b1; endcase case (tx_state) high_setup : SF_D0 <= tx_byte[7:4]; oneus : SF_D0 <= tx_byte[7:4]; low_setup : SF_D0 <= tx_byte[3:0]; fortyus : SF_D0 <= tx_byte[3:0]; done : SF_D0 <= tx_byte[3:0]; high_hold : SF_D0 <= tx_byte[7:4]; low_hold : SF_D0 <= tx_byte[3:0]; endcase end //specified by datasheet always @ (clk or reset or tx_init) begin: transmit if (reset == 1'b1) begin tx_state <= done; end else if (clk == 1'b1) begin case (tx_state) high_setup : begin //40ns if (i2 == 16'b10) begin //i2=2 tx_state <= high_hold; i2 <= 16'b0; end else begin tx_state <= high_setup; i2 <= i2 + 1; end end high_hold : begin //230ns if (i2 == 16'b1100) begin //i2=12 tx_state <= oneus; i2 <= 16'b0; end else begin tx_state <= high_hold; i2 <= i2 + 1; end end oneus : begin if (i2 == 16'b110010) begin //i2=50 tx_state <= low_setup; i2 <= 16'b0; end else begin tx_state <= oneus; i2 <= i2 + 1; end end low_setup : begin if (i2 == 16'b10) begin //i2=2 tx_state <= low_hold; i2 <= 16'b0; end else begin tx_state <= low_setup; i2 <= i2 + 1; end end low_hold : begin if (i2 == 16'b1100) begin //i2=12 tx_state <= fortyus; i2 <= 16'b0; end else begin tx_state <= low_hold; i2 <= i2 + 1; end end fortyus : begin if (i2 == 16'b0000011111010000) begin tx_state <= done; i2 <= 16'b0; end else begin tx_state <= fortyus; i2 <= i2 + 1; end end done : begin if (tx_init == 1'b1) begin tx_state <= high_setup; i2 <= 16'b0; end else begin tx_state <= done; i2 <= 16'b0; end end endcase end end always @ (init_state) begin case (init_state) done : init_done <= 1'b1; default : init_done <= 1'b0; endcase case (init_state) s1 : SF_D1 <= 4'b0011; s2 : SF_D1 <= 4'b0011; s3 : SF_D1 <= 4'b0011; s4 : SF_D1 <= 4'b0011; s5 : SF_D1 <= 4'b0011; s6 : SF_D1 <= 4'b0011; default : SF_D1 <= 4'b0010; endcase case (init_state) s1 : LCD_E1 <= 1'b1; s3 : LCD_E1 <= 1'b1; s5 : LCD_E1 <= 1'b1; s7 : LCD_E1 <= 1'b1; default : LCD_E1 <= 1'b0; endcase end //specified by datasheet always @ (clk or reset or init_init) begin: power_on_initialize if (reset == 1'b1) begin init_state <= idle; end else if (clk == 1'b1) begin case (init_state) idle : begin if (init_init == 1'b1) begin init_state <= fifteenms; i <= 20'b0; end else begin init_state <= idle; i <= i + 1; end end fifteenms : begin if (i == 20'b1011011100011011000) begin //i=750000 init_state <= s1; i <= 20'b0; end else begin init_state <=fifteenms; i <= i + 1; end end s1 : begin if (i == 20'b1011) begin //i=11 init_state <= s2; i <= 20'b0; end else begin init_state <=s1; i <= i + 1; end end s2 : begin if (i == 20'b110010000011001000) begin //i=205,000 init_state <= s3; i <= 20'b0; end else begin init_state <=s2; i <= i + 1; end end s3 : begin if (i == 20'b1011) begin //i=11 init_state <= s4; i <= 20'b0; end else begin init_state <=s3; i <= i + 1; end end s4 : begin if (i == 20'b1001110001000) begin //i=5,000 init_state <= s5; i <= 20'b0; end else begin init_state <=s4; i <= i + 1; end end s5 : begin if (i == 20'b1011) begin //i=11 init_state <= s6; i <= 20'b0; end else begin init_state <=s5; i <= i + 1; end end s6 : begin if (i == 20'b11111010000) begin //i=2,000 init_state <= s7; i <= 20'b0; end else begin init_state <=s6; i <= i + 1; end end s7 : begin if (i == 20'b1011) begin //i=11 init_state <= s8; i <= 20'b0; end else begin init_state <=s7; i <= i + 1; end end s8 : begin if (i == 20'b11111010000) begin //i=2,000 init_state <= done; i <= 20'b0; end else begin init_state <=s8; i <= i + 1; end end done : begin init_state <= done; end endcase end end endmodule