URL
https://opencores.org/ocsvn/forwardcom/forwardcom/trunk
Subversion Repositories forwardcom
[/] [forwardcom/] [trunk/] [lcd.sv] - Rev 138
Go to most recent revision | Compare with Previous | Blame | View Log
//////////////////////////////////////////////////////////////////////////////////// Engineer: Agner Fog//// Create Date: 2020-06-22// Last modified: 2020-06-29// Module Name: decoder// Project Name: ForwardCom soft core// Target Devices: Artix 7// Tool Versions: Vivado v. 2020.1// License: CERN-OHL-W v. 2 or later// Description: Driver for LCD displays// Two LCD displays with each 4 lines x 20 characters//////////////////////////////////////////////////////////////////////////////////`include "defines.vh"module lcd#(parameter numrows = 8, // number of lines of combined displays (2 - 8)parameter numcolumns = 20, // number of characters per lineparameter rows_per_display = 4) // number of rows per display unit(input clock, // system clock 100 MHzinput reset, // reset and clearinput [4:0] x, // column number (0 = left)input [2:0] y, // row number (0 = top)input [7:0] text[0:numcolumns-1], // text for one lineinput [4:0] text_length, // length of textinput start, // start writinginput eol, // pad with spaces until end of lineoutput reg lcd_rs, // LCD RS pinoutput reg [1:0] lcd_e, // enable pins for two LCD displaysoutput reg [3:0] lcd_data, // LCD data, 4 bit busoutput reg ready // finished writing. ready for next line);localparam count_bits = 14; // number of bits in clock divider counterlocalparam count_max = (2**count_bits)-1;// maximum countlogic [7:0] rowaddress; // command for setting row addressreg [count_bits-1:0] counter = 0; // clock dividerreg [7:0] delay; // delay counterreg [3:0] state = 0; // state machine for initialization// 0 - 9: initialization sequence// 10 - 11: set x,y position// 12 - 13: write characters// 15: finishedreg [7:0] text_buffer [0:numcolumns-1]; // copy of input textreg [4:0] column; // text columnreg [2:0] row; // text rowreg [4:0] text_count; // count down characters in textreg eol_save; // copy of eol/* initialization sequence:The display can receive data in 4-bit or 8-bit mode. We are using 4-bit mode,sending 4 bits at a time, with only the upper four bits connected.First, we send 8'H3x three times to get into 8-bit mode. Then 8'H2x to getinto 4-bit mode. The remaining numbers are 8-bit pairs:8'H28: multi-line mode (the first needs a long delay)8'H01: reset (needs long delay)8'H0C: display on, no cursor, no blink//8'H06 forward direction*/reg [3:0] initialization_sequence [10] = {3, 3, 3, 2, 2, 8, 0, 1, 0, 12 };always_comb begin// command to set row addressif (rows_per_display == 4) begincase (row[1:0]) // 4 lines per display0: rowaddress = 8'H80 + column;1: rowaddress = 8'HC0 + column;2: rowaddress = 8'H80 + numcolumns + column;3: rowaddress = 8'HC0 + numcolumns + column;endcaseend else begincase (row[0]) // 2 lines per display0: rowaddress = 8'H80 + column;1: rowaddress = 8'HC0 + column;endcaseendendalways_ff @(posedge clock) beginlcd_e <= 0;if (reset) begin// resetcounter <= 0;delay <= 8'H80;state <= 0;end else if (start && state == 15) begin// write command receivedtext_buffer <= text;column <= x;row <= y;text_count <= text_length;eol_save <= eol;counter <= 0;state <= 10;end else beginif (state < 10) begin// initialization sequencelcd_rs <= 0;if (delay > 0) beginif (counter == count_max) delay <= delay - 1;end else beginlcd_data <= initialization_sequence[state];lcd_e[0] <= counter[count_bits-1:count_bits-2] == 2'b01; // generate pulse for display unit 0lcd_e[1] <= counter[count_bits-1:count_bits-2] == 2'b01; // generate pulse for display unit 1if (counter == count_max) beginif (state == 9) state <= 15; // finishedelse state <= state + 1; // next statedelay <= 8'H10;endendend else if (state < 12) begin// set (x,y) positionlcd_rs <= 0;if (delay > 0) beginif (counter == count_max) delay <= delay - 1;end else beginlcd_data <= ~state[0] ? rowaddress[7:4] : rowaddress[3:0];if (row < rows_per_display)lcd_e[0] <= counter[count_bits-1:count_bits-2] == 2'b01; // generate pulseelse lcd_e[1] <= counter[count_bits-1:count_bits-2] == 2'b01; // generate pulseif (counter == count_max) beginstate <= state + 1;delay <= 8'H10;endendend else if (state < 15) begin// write characterslcd_rs <= 1;if (delay > 0) beginif (counter == count_max) delay <= delay - 1;end else beginif (text_count > 0) begin// write characterlcd_data <= ~state[0] ? text_buffer[0][7:4] : text_buffer[0][3:0];if (row < rows_per_display)lcd_e[0] <= counter[count_bits-1:count_bits-2] == 2'b01; // generate pulseelse lcd_e[1] <= counter[count_bits-1:count_bits-2] == 2'b01; // generate pulseend else if (eol_save) beginlcd_data <= ~state[0] ? 2 : 0; // write spaceif (row < rows_per_display)lcd_e[0] <= counter[count_bits-1:count_bits-2] == 2'b01; // generate pulseelse lcd_e[1] <= counter[count_bits-1:count_bits-2] == 2'b01; // generate pulseendif (counter == count_max) beginif (state[0]) begincolumn <= column + 1; // count up column indexif (text_count != 0) text_count <= text_count - 1; // count down number of charactersfor (int i = 0; i < numcolumns-1; i++) begintext_buffer[i] <= text_buffer[i+1]; // shift down to get next characterendendif (state[0] && (column == numcolumns-1 || (text_count == 0 && !eol_save))) beginstate <= 15; // finishedend else beginstate[0] <= ~state[0];end// delay <= 8'H01;endendend else begin// state = 15. finishedlcd_e <= 0;endendif (state == 15) ready <= 1;else ready <= 0;endendmodule
Go to most recent revision | Compare with Previous | Blame | View Log
