OpenCores
URL https://opencores.org/ocsvn/forwardcom/forwardcom/trunk

Subversion Repositories forwardcom

[/] [forwardcom/] [trunk/] [lcd.sv] - Blame information for rev 22

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 4 Agner
//////////////////////////////////////////////////////////////////////////////////
2
// Engineer: Agner Fog
3
//
4
// Create Date:    2020-06-22
5
// Last modified:  2020-06-29
6
// Module Name:    decoder
7
// Project Name:   ForwardCom soft core
8
// Target Devices: Artix 7
9
// Tool Versions:  Vivado v. 2020.1
10
// License:        CERN-OHL-W v. 2 or later
11
// Description:    Driver for LCD displays
12
// Two LCD displays with each 4 lines x 20 characters
13
//////////////////////////////////////////////////////////////////////////////////
14
 
15
`include "defines.vh"
16
 
17
module lcd
18
  #(parameter numrows = 8,               // number of lines of combined displays (2 - 8)
19
    parameter numcolumns = 20,           // number of characters per line
20
    parameter rows_per_display = 4)      // number of rows per display unit
21
 (input       clock,                     // system clock 100 MHz
22
  input       reset,                     // reset and clear
23
  input [4:0] x,                         // column number (0 = left)
24
  input [2:0] y,                         // row number (0 = top)
25
  input [7:0] text[0:numcolumns-1],      // text for one line
26
  input [4:0] text_length,               // length of text
27
  input       start,                     // start writing
28
  input       eol,                       // pad with spaces until end of line
29
  output reg  lcd_rs,                    // LCD RS pin
30
        output reg  [1:0] lcd_e,               // enable pins for two LCD displays
31
        output reg  [3:0] lcd_data,            // LCD data, 4 bit bus
32
        output reg  ready                      // finished writing. ready for next line
33
);
34
 
35
localparam count_bits = 14;              // number of bits in clock divider counter
36
localparam count_max = (2**count_bits)-1;// maximum count
37
 
38
logic [7:0] rowaddress;                  // command for setting row address
39
reg [count_bits-1:0] counter = 0;        // clock divider
40
reg [7:0] delay;                         // delay counter
41
reg [3:0] state = 0;                     // state machine for initialization
42
                                         // 0  -  9: initialization sequence
43
                                         // 10 - 11: set x,y position
44
                                         // 12 - 13: write characters
45
                                         // 15:      finished
46
reg [7:0] text_buffer [0:numcolumns-1];  // copy of input text
47
reg [4:0] column;                        // text column
48
reg [2:0] row;                           // text row
49
reg [4:0] text_count;                    // count down characters in text
50
reg       eol_save;                      // copy of eol
51
 
52
/* initialization sequence:
53
The display can receive data in 4-bit or 8-bit mode. We are using 4-bit mode,
54
sending 4 bits at a time, with only the upper four bits connected.
55
First, we send 8'H3x three times to get into 8-bit mode. Then 8'H2x to get
56
into 4-bit mode. The remaining numbers are 8-bit pairs:
57
8'H28: multi-line mode (the first needs a long delay)
58
8'H01: reset (needs long delay)
59
8'H0C: display on, no cursor, no blink
60
//8'H06 forward direction
61
*/
62
reg [3:0] initialization_sequence [10] = {3, 3, 3, 2, 2, 8, 0, 1, 0, 12 };
63
 
64
always_comb begin
65
    // command to set row address
66
    if (rows_per_display == 4) begin
67
        case (row[1:0]) // 4 lines per display
68
        0: rowaddress = 8'H80 + column;
69
        1: rowaddress = 8'HC0 + column;
70
        2: rowaddress = 8'H80 + numcolumns + column;
71
        3: rowaddress = 8'HC0 + numcolumns + column;
72
        endcase
73
    end else begin
74
        case (row[0])   // 2 lines per display
75
        0: rowaddress = 8'H80 + column;
76
        1: rowaddress = 8'HC0 + column;
77
        endcase
78
    end
79
end
80
 
81
always_ff @(posedge clock) begin
82
    lcd_e <= 0;
83
 
84
    if (reset) begin
85
        // reset
86
        counter <= 0;
87
        delay <= 8'H80;
88
        state <= 0;
89
 
90
    end else if (start && state == 15) begin
91
        // write command received
92
        text_buffer <= text;
93
        column <= x;
94
        row <= y;
95
        text_count <= text_length;
96
        eol_save <= eol;
97
        counter <= 0;
98
        state <= 10;
99
 
100
    end else begin
101
        counter <= counter + 1; // 2**count_bits / 100MHz = 160 µs
102
        if (state < 10) begin
103
 
104
            // initialization sequence
105
            lcd_rs <= 0;
106
            if (delay > 0) begin
107
                if (counter == count_max) delay <= delay - 1;
108
            end else begin
109
                lcd_data <= initialization_sequence[state];
110
                lcd_e[0] <= counter[count_bits-1:count_bits-2] == 2'b01; // generate pulse for display unit 0
111
                lcd_e[1] <= counter[count_bits-1:count_bits-2] == 2'b01; // generate pulse for display unit 1
112
                if (counter == count_max) begin
113
                    if (state == 9) state <= 15; // finished
114
                    else state <= state + 1;     // next state
115
                    delay <= 8'H10;
116
                end
117
            end
118
 
119
        end else if (state < 12) begin
120
 
121
            // set (x,y) position
122
            lcd_rs <= 0;
123
            if (delay > 0) begin
124
                if (counter == count_max) delay <= delay - 1;
125
            end else begin
126
                lcd_data <= ~state[0] ? rowaddress[7:4] : rowaddress[3:0];
127
                if (row < rows_per_display)
128
                     lcd_e[0] <= counter[count_bits-1:count_bits-2] == 2'b01; // generate pulse
129
                else lcd_e[1] <= counter[count_bits-1:count_bits-2] == 2'b01; // generate pulse
130
                if (counter == count_max) begin
131
                    state <= state + 1;
132
                    delay <= 8'H10;
133
                end
134
            end
135
 
136
        end else if (state < 15) begin
137
 
138
            // write characters
139
            lcd_rs <= 1;
140
            if (delay > 0) begin
141
                if (counter == count_max) delay <= delay - 1;
142
            end else begin
143
                if (text_count > 0) begin
144
                    // write character
145
                    lcd_data <= ~state[0] ? text_buffer[0][7:4] : text_buffer[0][3:0];
146
                    if (row < rows_per_display)
147
                         lcd_e[0] <= counter[count_bits-1:count_bits-2] == 2'b01; // generate pulse
148
                    else lcd_e[1] <= counter[count_bits-1:count_bits-2] == 2'b01; // generate pulse
149
                end else if (eol_save) begin
150
                    lcd_data <= ~state[0] ? 2 : 0;                                // write space
151
                    if (row < rows_per_display)
152
                         lcd_e[0] <= counter[count_bits-1:count_bits-2] == 2'b01; // generate pulse
153
                    else lcd_e[1] <= counter[count_bits-1:count_bits-2] == 2'b01; // generate pulse
154
                end
155
 
156
                if (counter == count_max) begin
157
                    if (state[0]) begin
158
                        column <= column + 1;                                     // count up column index
159
                        if (text_count != 0) text_count <= text_count - 1;        // count down number of characters
160
                        for (int i = 0; i < numcolumns-1; i++) begin
161
                            text_buffer[i] <= text_buffer[i+1];                   // shift down to get next character
162
                        end
163
                    end
164
                    if (state[0] && (column == numcolumns-1 || (text_count == 0 && !eol_save))) begin
165
                        state <= 15;                                              // finished
166
                    end else begin
167
                        state[0] <= ~state[0];
168
                    end
169
                    // delay <= 8'H01;
170
                end
171
            end
172
        end else begin
173
            // state = 15. finished
174
            lcd_e <= 0;
175
        end
176
    end
177
    if (state == 15) ready <= 1;
178
    else ready <= 0;
179
 
180
end
181
 
182
 
183
endmodule

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.