Initial commit

Fork of TextLCD by Wim Huiskamp

Committer:
anmar
Date:
Fri Dec 05 10:26:07 2014 +0000
Revision:
21:4984088e349c
Parent:
20:e0da005a777f
Initial commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
simon 1:ac48b187213c 1 /* mbed TextLCD Library, for a 4-bit LCD based on HD44780
simon 6:e4cb7ddee0d3 2 * Copyright (c) 2007-2010, sford, http://mbed.org
wim 14:0c32b66b14b8 3 * 2013, v01: WH, Added LCD types, fixed LCD address issues, added Cursor and UDCs
wim 14:0c32b66b14b8 4 * 2013, v02: WH, Added I2C and SPI bus interfaces
wim 15:b70ebfffb258 5 * 2013, v03: WH, Added support for LCD40x4 which uses 2 controllers
wim 18:bd65dc10f27f 6 * 2013, v04: WH, Added support for Display On/Off, improved 4bit bootprocess
wim 18:bd65dc10f27f 7 * 2013, v05: WH, Added support for 8x2B, added some UDCs
wim 19:c747b9e2e7b8 8 * 2013, v06: WH, Added support for devices that use internal DC/DC converters
wim 20:e0da005a777f 9 * 2013, v07: WH, Added support for backlight and include portdefinitions for LCD2004 Module from DFROBOT
simon 1:ac48b187213c 10 *
simon 1:ac48b187213c 11 * Permission is hereby granted, free of charge, to any person obtaining a copy
simon 1:ac48b187213c 12 * of this software and associated documentation files (the "Software"), to deal
simon 1:ac48b187213c 13 * in the Software without restriction, including without limitation the rights
simon 1:ac48b187213c 14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
simon 1:ac48b187213c 15 * copies of the Software, and to permit persons to whom the Software is
simon 1:ac48b187213c 16 * furnished to do so, subject to the following conditions:
simon 1:ac48b187213c 17 *
simon 1:ac48b187213c 18 * The above copyright notice and this permission notice shall be included in
simon 1:ac48b187213c 19 * all copies or substantial portions of the Software.
simon 1:ac48b187213c 20 *
simon 1:ac48b187213c 21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
simon 1:ac48b187213c 22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
simon 1:ac48b187213c 23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
simon 1:ac48b187213c 24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
simon 1:ac48b187213c 25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
simon 1:ac48b187213c 26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
simon 1:ac48b187213c 27 * THE SOFTWARE.
simon 1:ac48b187213c 28 */
simon 1:ac48b187213c 29
simon 1:ac48b187213c 30 #include "TextLCD.h"
simon 1:ac48b187213c 31 #include "mbed.h"
simon 1:ac48b187213c 32
wim 15:b70ebfffb258 33
wim 13:24506ba22480 34
anmar 21:4984088e349c 35 /* Create a TextLCD interface using SPI
wim 15:b70ebfffb258 36 *
wim 15:b70ebfffb258 37 * @param spi SPI Bus
wim 15:b70ebfffb258 38 * @param cs chip select pin (active low)
wim 15:b70ebfffb258 39 * @param type Sets the panel size/addressing mode (default = LCD16x2)
wim 19:c747b9e2e7b8 40 * @param ctrl LCD controller (default = HD44780)
wim 15:b70ebfffb258 41 */
anmar 21:4984088e349c 42 TextLCD::TextLCD(SPI *spi, PinName cs, PinName rs, LCDType type, LCDCtrl ctrl) :
anmar 21:4984088e349c 43 _e(NC), _bl(NC), _e2(NC),
wim 15:b70ebfffb258 44 _d(NC),
wim 15:b70ebfffb258 45 _spi(spi),
wim 15:b70ebfffb258 46 _cs(cs),
anmar 21:4984088e349c 47 _rs(rs),
wim 19:c747b9e2e7b8 48 _type(type),
wim 19:c747b9e2e7b8 49 _ctrl(ctrl) {
wim 14:0c32b66b14b8 50
wim 14:0c32b66b14b8 51 _busType = _SPIBus;
wim 14:0c32b66b14b8 52
wim 14:0c32b66b14b8 53 // Setup the spi for 8 bit data, low steady state clock,
wim 14:0c32b66b14b8 54 // rising edge capture, with a 500KHz or 1MHz clock rate
wim 14:0c32b66b14b8 55 _spi->format(8,0);
wim 14:0c32b66b14b8 56 _spi->frequency(500000);
wim 14:0c32b66b14b8 57 //_spi.frequency(1000000);
wim 14:0c32b66b14b8 58
wim 14:0c32b66b14b8 59
wim 14:0c32b66b14b8 60 // Init the portexpander bus
wim 15:b70ebfffb258 61 _lcd_bus = D_LCD_BUS_DEF;
wim 14:0c32b66b14b8 62
wim 14:0c32b66b14b8 63 // write the new data to the portexpander
wim 14:0c32b66b14b8 64 _setCS(false);
wim 14:0c32b66b14b8 65 _spi->write(_lcd_bus);
wim 14:0c32b66b14b8 66 _setCS(true);
wim 14:0c32b66b14b8 67
wim 14:0c32b66b14b8 68 _init();
wim 14:0c32b66b14b8 69
wim 14:0c32b66b14b8 70 }
wim 14:0c32b66b14b8 71
wim 14:0c32b66b14b8 72
wim 15:b70ebfffb258 73 /* Init the LCD Controller(s)
wim 13:24506ba22480 74 * Clear display
wim 13:24506ba22480 75 */
wim 13:24506ba22480 76 void TextLCD::_init() {
wim 15:b70ebfffb258 77
wim 15:b70ebfffb258 78 // Select and configure second LCD controller when needed
wim 15:b70ebfffb258 79 if(_type==LCD40x4) {
wim 19:c747b9e2e7b8 80 _ctrl_idx=TextLCD::_LCDCtrl_1; // Select 2nd controller
wim 15:b70ebfffb258 81
wim 19:c747b9e2e7b8 82 _initCtrl(); // Init 2nd controller
wim 15:b70ebfffb258 83
wim 15:b70ebfffb258 84 // Secondary LCD controller Clearscreen
wim 15:b70ebfffb258 85 _writeCommand(0x01); // cls, and set cursor to 0
wim 15:b70ebfffb258 86 wait_ms(10); // The CLS command takes 1.64 ms.
wim 15:b70ebfffb258 87 // Since we are not using the Busy flag, Lets be safe and take 10 ms
wim 15:b70ebfffb258 88
wim 15:b70ebfffb258 89 }
wim 15:b70ebfffb258 90
wim 15:b70ebfffb258 91 // Select and configure primary LCD controller
wim 19:c747b9e2e7b8 92 _ctrl_idx=TextLCD::_LCDCtrl_0; // Select primary controller
wim 13:24506ba22480 93
wim 19:c747b9e2e7b8 94 _initCtrl(); // Init primary controller
wim 15:b70ebfffb258 95
wim 15:b70ebfffb258 96 // Primary LCD controller Clearscreen
wim 15:b70ebfffb258 97 _writeCommand(0x01); // cls, and set cursor to 0
wim 15:b70ebfffb258 98
wim 15:b70ebfffb258 99 wait_ms(10); // The CLS command takes 1.64 ms.
wim 15:b70ebfffb258 100 // Since we are not using the Busy flag, Lets be safe and take 10 ms
wim 15:b70ebfffb258 101
wim 15:b70ebfffb258 102 }
wim 15:b70ebfffb258 103
wim 15:b70ebfffb258 104 /* Init the LCD controller
wim 15:b70ebfffb258 105 * 4-bit mode, number of lines, fonttype, no cursor etc
wim 15:b70ebfffb258 106 *
wim 15:b70ebfffb258 107 */
wim 15:b70ebfffb258 108 void TextLCD::_initCtrl() {
wim 15:b70ebfffb258 109
wim 13:24506ba22480 110 _setRS(false); // command mode
wim 13:24506ba22480 111
wim 15:b70ebfffb258 112 wait_ms(20); // Wait 20ms to ensure powered up
simon 1:ac48b187213c 113
anmar 21:4984088e349c 114 /* // send "Display Settings" 3 times (Only top nibble of 0x30 as we've got 4-bit bus)
wim 17:652ab113bc2e 115 for (int i=0; i<3; i++) {
wim 17:652ab113bc2e 116 _writeNibble(0x3);
wim 20:e0da005a777f 117 wait_ms(15); // This command takes 1.64ms, so wait for it
wim 17:652ab113bc2e 118 }
wim 17:652ab113bc2e 119 _writeNibble(0x2); // 4-bit mode
wim 17:652ab113bc2e 120 wait_us(40); // most instructions take 40us
anmar 21:4984088e349c 121 */
wim 18:bd65dc10f27f 122 // Display is now in 4-bit mode
wim 18:bd65dc10f27f 123
wim 19:c747b9e2e7b8 124
anmar 21:4984088e349c 125 // ST7036 controller: Initialise Voltage booster for VLCD. VDD=3.3V
wim 19:c747b9e2e7b8 126 // Note: supports 1,2 or 3 lines
anmar 21:4984088e349c 127 _writeByte( 0x39 ); // 8-bit Databus, 2 Lines, Select Instruction table 1
wim 20:e0da005a777f 128 wait_ms(30); // > 26,3ms
wim 19:c747b9e2e7b8 129 _writeByte( 0x14 ); // Bias: 1/5, 2-Lines LCD
wim 20:e0da005a777f 130 wait_ms(30); // > 26,3ms
wim 19:c747b9e2e7b8 131 _writeByte( 0x55 ); // Icon off, Booster on, Set Contrast C5, C4
wim 20:e0da005a777f 132 wait_ms(30); // > 26,3ms
wim 19:c747b9e2e7b8 133 _writeByte( 0x6d ); // Voltagefollower On, Ampl ratio Rab2, Rab1, Rab0
wim 19:c747b9e2e7b8 134 wait_ms(200); // > 200ms!
wim 19:c747b9e2e7b8 135 _writeByte( 0x78 ); // Set Contrast C3, C2, C1, C0
wim 20:e0da005a777f 136 wait_ms(30); // > 26,3ms
anmar 21:4984088e349c 137 _writeByte( 0x38 ); // Return to Instruction table 0
anmar 21:4984088e349c 138 wait_ms(50);
anmar 21:4984088e349c 139 _writeByte( 0x0f ); // Return to Instruction table 0
wim 19:c747b9e2e7b8 140 wait_ms(50);
anmar 21:4984088e349c 141 _writeByte( 0x01 ); // Return to Instruction table 0
anmar 21:4984088e349c 142 wait_ms(50);
anmar 21:4984088e349c 143 _writeByte( 0x06 ); // Return to Instruction table 0
anmar 21:4984088e349c 144 wait_ms(50);
anmar 21:4984088e349c 145
wim 19:c747b9e2e7b8 146
wim 14:0c32b66b14b8 147
wim 18:bd65dc10f27f 148 // Initialise Display configuration
wim 10:dd9b3a696acd 149 switch (_type) {
wim 10:dd9b3a696acd 150 case LCD8x1:
wim 18:bd65dc10f27f 151 case LCD8x2B:
wim 18:bd65dc10f27f 152 //8x1 is a regular 1 line display
wim 18:bd65dc10f27f 153 //8x2B is a special case of 16x1
wim 15:b70ebfffb258 154 _writeCommand(0x20); // Function set 001 DL N F - -
wim 15:b70ebfffb258 155 // DL=0 (4 bits bus)
wim 13:24506ba22480 156 // N=0 (1 line)
wim 13:24506ba22480 157 // F=0 (5x7 dots font)
wim 10:dd9b3a696acd 158 break;
wim 10:dd9b3a696acd 159
wim 10:dd9b3a696acd 160 case LCD24x4:
wim 10:dd9b3a696acd 161 // Special mode for KS0078
wim 15:b70ebfffb258 162 _writeCommand(0x2A); // Function set 001 DL N RE DH REV
wim 15:b70ebfffb258 163 // DL=0 (4 bits bus)
wim 13:24506ba22480 164 // N=1 (Dont care for KS0078)
wim 13:24506ba22480 165 // RE=0 (Extended Regs, special mode for KS0078)
wim 13:24506ba22480 166 // DH=1 (Disp shift, special mode for KS0078)
wim 13:24506ba22480 167 // REV=0 (Reverse, special mode for KS0078)
wim 10:dd9b3a696acd 168
wim 15:b70ebfffb258 169 _writeCommand(0x2E); // Function set 001 DL N RE DH REV
wim 15:b70ebfffb258 170 // DL=0 (4 bits bus)
wim 13:24506ba22480 171 // N=1 (Dont care for KS0078)
wim 13:24506ba22480 172 // RE=1 (Ena Extended Regs, special mode for KS0078)
wim 13:24506ba22480 173 // DH=1 (Disp shift, special mode for KS0078)
wim 13:24506ba22480 174 // REV=0 (Reverse, special mode for KS0078)
wim 10:dd9b3a696acd 175
wim 13:24506ba22480 176 _writeCommand(0x09); // Ext Function set 0000 1 FW BW NW
wim 13:24506ba22480 177 // FW=0 (5-dot font, special mode for KS0078)
wim 13:24506ba22480 178 // BW=0 (Cur BW invert disable, special mode for KS0078)
wim 13:24506ba22480 179 // NW=1 (4 Line, special mode for KS0078)
wim 10:dd9b3a696acd 180
wim 15:b70ebfffb258 181 _writeCommand(0x2A); // Function set 001 DL N RE DH REV
wim 15:b70ebfffb258 182 // DL=0 (4 bits bus)
wim 13:24506ba22480 183 // N=1 (Dont care for KS0078)
wim 13:24506ba22480 184 // RE=0 (Dis. Extended Regs, special mode for KS0078)
wim 13:24506ba22480 185 // DH=1 (Disp shift, special mode for KS0078)
wim 13:24506ba22480 186 // REV=0 (Reverse, special mode for KS0078)
wim 10:dd9b3a696acd 187 break;
wim 10:dd9b3a696acd 188
wim 15:b70ebfffb258 189 // All other LCD types are initialised as 2 Line displays (including LCD40x4)
wim 10:dd9b3a696acd 190 default:
anmar 21:4984088e349c 191 _writeCommand(0x39); // Function set 001 DL N F - -
wim 15:b70ebfffb258 192 // DL=0 (4 bits bus)
wim 13:24506ba22480 193 // N=1 (2 lines)
wim 15:b70ebfffb258 194 // F=0 (5x7 dots font, only option for 2 line display)
wim 13:24506ba22480 195 // - (Don't care)
wim 10:dd9b3a696acd 196
wim 10:dd9b3a696acd 197 break;
wim 10:dd9b3a696acd 198 }
wim 10:dd9b3a696acd 199
wim 13:24506ba22480 200 _writeCommand(0x06); // Entry Mode 0000 01 CD S
wim 13:24506ba22480 201 // Cursor Direction and Display Shift
wim 13:24506ba22480 202 // CD=1 (Cur incr)
wim 13:24506ba22480 203 // S=0 (No display shift)
wim 10:dd9b3a696acd 204
wim 13:24506ba22480 205 // _writeCommand(0x0C); // Display Ctrl 0000 1 D C B
wim 17:652ab113bc2e 206 // // Display On, Cursor Off, Blink Off
wim 15:b70ebfffb258 207 setCursor(TextLCD::CurOff_BlkOff);
wim 17:652ab113bc2e 208 setMode(TextLCD::DispOn);
simon 1:ac48b187213c 209 }
simon 1:ac48b187213c 210
wim 8:03116f75b66e 211
wim 16:c276b75e6585 212 // Clear the screen, Cursor home.
wim 15:b70ebfffb258 213 void TextLCD::cls() {
wim 15:b70ebfffb258 214
wim 15:b70ebfffb258 215 // Select and configure second LCD controller when needed
wim 15:b70ebfffb258 216 if(_type==LCD40x4) {
wim 19:c747b9e2e7b8 217 _ctrl_idx=TextLCD::_LCDCtrl_1; // Select 2nd controller
wim 15:b70ebfffb258 218
wim 15:b70ebfffb258 219 // Second LCD controller Cursor always Off
wim 17:652ab113bc2e 220 _setCursorAndDisplayMode(_currentMode, TextLCD::CurOff_BlkOff);
wim 15:b70ebfffb258 221
wim 15:b70ebfffb258 222 // Second LCD controller Clearscreen
wim 15:b70ebfffb258 223 _writeCommand(0x01); // cls, and set cursor to 0
wim 15:b70ebfffb258 224
wim 15:b70ebfffb258 225 wait_ms(10); // The CLS command takes 1.64 ms.
wim 15:b70ebfffb258 226 // Since we are not using the Busy flag, Lets be safe and take 10 ms
wim 15:b70ebfffb258 227
wim 15:b70ebfffb258 228
wim 19:c747b9e2e7b8 229 _ctrl_idx=TextLCD::_LCDCtrl_0; // Select primary controller
wim 15:b70ebfffb258 230 }
wim 15:b70ebfffb258 231
wim 15:b70ebfffb258 232 // Primary LCD controller Clearscreen
wim 15:b70ebfffb258 233 _writeCommand(0x01); // cls, and set cursor to 0
wim 15:b70ebfffb258 234
wim 15:b70ebfffb258 235 wait_ms(10); // The CLS command takes 1.64 ms.
wim 15:b70ebfffb258 236 // Since we are not using the Busy flag, Lets be safe and take 10 ms
wim 15:b70ebfffb258 237
wim 15:b70ebfffb258 238 // Restore cursormode on primary LCD controller when needed
wim 15:b70ebfffb258 239 if(_type==LCD40x4) {
wim 17:652ab113bc2e 240 _setCursorAndDisplayMode(_currentMode,_currentCursor);
wim 15:b70ebfffb258 241 }
wim 15:b70ebfffb258 242
wim 15:b70ebfffb258 243 _row=0; // Reset Cursor location
wim 15:b70ebfffb258 244 _column=0;
simon 1:ac48b187213c 245 }
simon 1:ac48b187213c 246
wim 16:c276b75e6585 247 // Move cursor to selected row and column
simon 1:ac48b187213c 248 void TextLCD::locate(int column, int row) {
wim 15:b70ebfffb258 249
wim 15:b70ebfffb258 250 // setAddress() does all the heavy lifting:
wim 15:b70ebfffb258 251 // check column and row sanity,
wim 15:b70ebfffb258 252 // switch controllers for LCD40x4 if needed
wim 15:b70ebfffb258 253 // switch cursor for LCD40x4 if needed
wim 15:b70ebfffb258 254 // set the new memory address to show cursor at correct location
wim 15:b70ebfffb258 255 setAddress(column, row);
wim 15:b70ebfffb258 256
wim 15:b70ebfffb258 257 }
wim 15:b70ebfffb258 258
wim 15:b70ebfffb258 259
wim 16:c276b75e6585 260 // Write a single character (Stream implementation)
wim 15:b70ebfffb258 261 int TextLCD::_putc(int value) {
wim 15:b70ebfffb258 262 int addr;
wim 15:b70ebfffb258 263
wim 15:b70ebfffb258 264 if (value == '\n') {
wim 15:b70ebfffb258 265 //No character to write
wim 15:b70ebfffb258 266
wim 15:b70ebfffb258 267 //Update Cursor
wim 15:b70ebfffb258 268 _column = 0;
wim 15:b70ebfffb258 269 _row++;
wim 15:b70ebfffb258 270 if (_row >= rows()) {
wim 15:b70ebfffb258 271 _row = 0;
wim 15:b70ebfffb258 272 }
wim 15:b70ebfffb258 273 }
wim 15:b70ebfffb258 274 else {
wim 15:b70ebfffb258 275 //Character to write
wim 15:b70ebfffb258 276 _writeData(value);
wim 15:b70ebfffb258 277
wim 15:b70ebfffb258 278 //Update Cursor
wim 15:b70ebfffb258 279 _column++;
wim 15:b70ebfffb258 280 if (_column >= columns()) {
wim 15:b70ebfffb258 281 _column = 0;
wim 15:b70ebfffb258 282 _row++;
wim 15:b70ebfffb258 283 if (_row >= rows()) {
wim 15:b70ebfffb258 284 _row = 0;
wim 15:b70ebfffb258 285 }
wim 15:b70ebfffb258 286 }
wim 15:b70ebfffb258 287 } //else
wim 15:b70ebfffb258 288
wim 15:b70ebfffb258 289 //Set next memoryaddress, make sure cursor blinks at next location
wim 15:b70ebfffb258 290 addr = getAddress(_column, _row);
wim 15:b70ebfffb258 291 _writeCommand(0x80 | addr);
wim 15:b70ebfffb258 292
wim 15:b70ebfffb258 293 return value;
wim 15:b70ebfffb258 294 }
wim 15:b70ebfffb258 295
wim 15:b70ebfffb258 296
wim 16:c276b75e6585 297 // get a single character (Stream implementation)
simon 1:ac48b187213c 298 int TextLCD::_getc() {
simon 1:ac48b187213c 299 return -1;
simon 1:ac48b187213c 300 }
simon 1:ac48b187213c 301
wim 13:24506ba22480 302
wim 16:c276b75e6585 303 // Set RS pin
wim 16:c276b75e6585 304 // Used for mbed pins, I2C bus expander or SPI shifregister
anmar 21:4984088e349c 305 void TextLCD::_setRS(bool value)
anmar 21:4984088e349c 306 {
anmar 21:4984088e349c 307 if (value)
anmar 21:4984088e349c 308 _rs = 1; // Set RS bit
anmar 21:4984088e349c 309 else
anmar 21:4984088e349c 310 _rs = 0; // Reset RS bit
wim 13:24506ba22480 311 }
wim 13:24506ba22480 312
wim 16:c276b75e6585 313 // Place the 4bit data on the databus
wim 16:c276b75e6585 314 // Used for mbed pins, I2C bus expander or SPI shifregister
anmar 21:4984088e349c 315 void TextLCD::_setData(int value)
anmar 21:4984088e349c 316 {
anmar 21:4984088e349c 317 // write the new data to the SPI portexpander
anmar 21:4984088e349c 318 _setCS(false);
anmar 21:4984088e349c 319 _spi->write(value);
anmar 21:4984088e349c 320 _setCS(true);
wim 13:24506ba22480 321 }
wim 13:24506ba22480 322
wim 13:24506ba22480 323
wim 16:c276b75e6585 324 // Set CS line.
wim 16:c276b75e6585 325 // Only used for SPI bus
anmar 21:4984088e349c 326 void TextLCD::_setCS(bool value)
anmar 21:4984088e349c 327 {
wim 15:b70ebfffb258 328 if (value) {
wim 14:0c32b66b14b8 329 _cs = 1; // Set CS pin
wim 15:b70ebfffb258 330 }
wim 14:0c32b66b14b8 331 else
wim 14:0c32b66b14b8 332 _cs = 0; // Reset CS pin
wim 15:b70ebfffb258 333
wim 14:0c32b66b14b8 334 }
wim 14:0c32b66b14b8 335
wim 14:0c32b66b14b8 336
wim 17:652ab113bc2e 337
wim 16:c276b75e6585 338 // Write a byte using the 4-bit interface
wim 16:c276b75e6585 339 // Used for mbed pins, I2C bus expander or SPI shifregister
wim 13:24506ba22480 340 void TextLCD::_writeByte(int value) {
wim 15:b70ebfffb258 341
anmar 21:4984088e349c 342 _setData(value); // High nibble
wim 15:b70ebfffb258 343 wait_us(1); // Data setup time
simon 1:ac48b187213c 344 }
simon 1:ac48b187213c 345
wim 13:24506ba22480 346 void TextLCD::_writeCommand(int command) {
wim 15:b70ebfffb258 347
wim 13:24506ba22480 348 _setRS(false);
wim 16:c276b75e6585 349 wait_us(1); // Data setup time for RS
wim 15:b70ebfffb258 350
wim 15:b70ebfffb258 351 _writeByte(command);
wim 15:b70ebfffb258 352 wait_us(40); // most instructions take 40us
simon 1:ac48b187213c 353 }
simon 1:ac48b187213c 354
wim 13:24506ba22480 355 void TextLCD::_writeData(int data) {
wim 15:b70ebfffb258 356
wim 13:24506ba22480 357 _setRS(true);
wim 16:c276b75e6585 358 wait_us(1); // Data setup time for RS
wim 15:b70ebfffb258 359
wim 13:24506ba22480 360 _writeByte(data);
wim 15:b70ebfffb258 361 wait_us(40); // data writes take 40us
simon 1:ac48b187213c 362 }
simon 1:ac48b187213c 363
wim 8:03116f75b66e 364
wim 8:03116f75b66e 365
wim 8:03116f75b66e 366
wim 16:c276b75e6585 367 // This replaces the original _address() method.
wim 8:03116f75b66e 368 // Left it in here for compatibility with older code. New applications should use getAddress() instead.
wim 13:24506ba22480 369 int TextLCD::_address(int column, int row) {
wim 8:03116f75b66e 370 return 0x80 | getAddress(column, row);
wim 8:03116f75b66e 371 }
wim 8:03116f75b66e 372
wim 8:03116f75b66e 373 // This is new method to return the memory address based on row, column and displaytype.
wim 8:03116f75b66e 374 //
wim 8:03116f75b66e 375 int TextLCD::getAddress(int column, int row) {
wim 8:03116f75b66e 376
wim 8:03116f75b66e 377 switch (_type) {
wim 8:03116f75b66e 378 case LCD8x1:
wim 8:03116f75b66e 379 return 0x00 + column;
wim 18:bd65dc10f27f 380
wim 18:bd65dc10f27f 381 case LCD8x2B:
wim 18:bd65dc10f27f 382 // LCD8x2B is a special layout of LCD16x1
wim 18:bd65dc10f27f 383 if (row==0)
wim 18:bd65dc10f27f 384 return 0x00 + column;
wim 18:bd65dc10f27f 385 else
wim 18:bd65dc10f27f 386 return 0x08 + column;
wim 18:bd65dc10f27f 387
wim 18:bd65dc10f27f 388
wim 13:24506ba22480 389 case LCD16x1:
wim 13:24506ba22480 390 // LCD16x1 is a special layout of LCD8x2
wim 13:24506ba22480 391 if (column<8)
wim 13:24506ba22480 392 return 0x00 + column;
wim 13:24506ba22480 393 else
wim 13:24506ba22480 394 return 0x40 + (column - 8);
wim 13:24506ba22480 395
wim 15:b70ebfffb258 396 case LCD12x4:
wim 15:b70ebfffb258 397 switch (row) {
wim 15:b70ebfffb258 398 case 0:
wim 15:b70ebfffb258 399 return 0x00 + column;
wim 15:b70ebfffb258 400 case 1:
wim 15:b70ebfffb258 401 return 0x40 + column;
wim 15:b70ebfffb258 402 case 2:
wim 15:b70ebfffb258 403 return 0x0C + column;
wim 15:b70ebfffb258 404 case 3:
wim 15:b70ebfffb258 405 return 0x4C + column;
wim 15:b70ebfffb258 406 }
wim 15:b70ebfffb258 407
wim 8:03116f75b66e 408 case LCD16x4:
wim 8:03116f75b66e 409 switch (row) {
wim 8:03116f75b66e 410 case 0:
wim 8:03116f75b66e 411 return 0x00 + column;
wim 8:03116f75b66e 412 case 1:
wim 8:03116f75b66e 413 return 0x40 + column;
wim 8:03116f75b66e 414 case 2:
wim 8:03116f75b66e 415 return 0x10 + column;
wim 8:03116f75b66e 416 case 3:
wim 8:03116f75b66e 417 return 0x50 + column;
wim 8:03116f75b66e 418 }
wim 8:03116f75b66e 419
wim 8:03116f75b66e 420 case LCD20x4:
wim 8:03116f75b66e 421 switch (row) {
wim 8:03116f75b66e 422 case 0:
wim 8:03116f75b66e 423 return 0x00 + column;
wim 8:03116f75b66e 424 case 1:
wim 8:03116f75b66e 425 return 0x40 + column;
wim 8:03116f75b66e 426 case 2:
wim 8:03116f75b66e 427 return 0x14 + column;
wim 8:03116f75b66e 428 case 3:
wim 8:03116f75b66e 429 return 0x54 + column;
wim 8:03116f75b66e 430 }
wim 8:03116f75b66e 431
wim 10:dd9b3a696acd 432 // Special mode for KS0078
wim 10:dd9b3a696acd 433 case LCD24x4:
wim 10:dd9b3a696acd 434 switch (row) {
wim 10:dd9b3a696acd 435 case 0:
wim 10:dd9b3a696acd 436 return 0x00 + column;
wim 10:dd9b3a696acd 437 case 1:
wim 10:dd9b3a696acd 438 return 0x20 + column;
wim 10:dd9b3a696acd 439 case 2:
wim 10:dd9b3a696acd 440 return 0x40 + column;
wim 10:dd9b3a696acd 441 case 3:
wim 10:dd9b3a696acd 442 return 0x60 + column;
wim 10:dd9b3a696acd 443 }
wim 10:dd9b3a696acd 444
wim 8:03116f75b66e 445 // Not sure about this one, seems wrong.
wim 8:03116f75b66e 446 case LCD16x2B:
wim 8:03116f75b66e 447 return 0x00 + (row * 40) + column;
wim 8:03116f75b66e 448
wim 18:bd65dc10f27f 449 case LCD8x2:
wim 15:b70ebfffb258 450 case LCD12x2:
wim 8:03116f75b66e 451 case LCD16x2:
wim 8:03116f75b66e 452 case LCD20x2:
wim 8:03116f75b66e 453 case LCD24x2:
wim 9:0893d986e717 454 case LCD40x2:
wim 8:03116f75b66e 455 return 0x00 + (row * 0x40) + column;
wim 15:b70ebfffb258 456
wim 15:b70ebfffb258 457 case LCD40x4:
wim 15:b70ebfffb258 458 // LCD40x4 is a special case since it has 2 controllers
wim 15:b70ebfffb258 459 // Each controller is configured as 40x2
wim 15:b70ebfffb258 460 if (row<2) {
wim 15:b70ebfffb258 461 // Test to see if we need to switch between controllers
wim 19:c747b9e2e7b8 462 if (_ctrl_idx != _LCDCtrl_0) {
wim 17:652ab113bc2e 463
wim 15:b70ebfffb258 464 // Second LCD controller Cursor Off
wim 17:652ab113bc2e 465 _setCursorAndDisplayMode(_currentMode, TextLCD::CurOff_BlkOff);
wim 15:b70ebfffb258 466
wim 15:b70ebfffb258 467 // Select primary controller
wim 19:c747b9e2e7b8 468 _ctrl_idx = _LCDCtrl_0;
wim 15:b70ebfffb258 469
wim 15:b70ebfffb258 470 // Restore cursormode on primary LCD controller
wim 17:652ab113bc2e 471 _setCursorAndDisplayMode(_currentMode, _currentCursor);
wim 15:b70ebfffb258 472 }
wim 15:b70ebfffb258 473
wim 15:b70ebfffb258 474 return 0x00 + (row * 0x40) + column;
wim 15:b70ebfffb258 475 }
wim 15:b70ebfffb258 476 else {
wim 15:b70ebfffb258 477
wim 15:b70ebfffb258 478 // Test to see if we need to switch between controllers
wim 19:c747b9e2e7b8 479 if (_ctrl_idx != _LCDCtrl_1) {
wim 15:b70ebfffb258 480 // Primary LCD controller Cursor Off
wim 17:652ab113bc2e 481 _setCursorAndDisplayMode(_currentMode, TextLCD::CurOff_BlkOff);
wim 15:b70ebfffb258 482
wim 15:b70ebfffb258 483 // Select secondary controller
wim 19:c747b9e2e7b8 484 _ctrl_idx = _LCDCtrl_1;
wim 15:b70ebfffb258 485
wim 15:b70ebfffb258 486 // Restore cursormode on secondary LCD controller
wim 17:652ab113bc2e 487 _setCursorAndDisplayMode(_currentMode, _currentCursor);
wim 15:b70ebfffb258 488 }
wim 15:b70ebfffb258 489
wim 15:b70ebfffb258 490 return 0x00 + ((row-2) * 0x40) + column;
wim 15:b70ebfffb258 491 }
wim 8:03116f75b66e 492
wim 8:03116f75b66e 493 // Should never get here.
wim 8:03116f75b66e 494 default:
wim 8:03116f75b66e 495 return 0x00;
wim 8:03116f75b66e 496 }
wim 8:03116f75b66e 497 }
wim 8:03116f75b66e 498
wim 8:03116f75b66e 499
wim 15:b70ebfffb258 500 // Set row, column and update memoryaddress.
wim 8:03116f75b66e 501 //
wim 8:03116f75b66e 502 void TextLCD::setAddress(int column, int row) {
wim 15:b70ebfffb258 503
wim 15:b70ebfffb258 504 // Sanity Check column
wim 15:b70ebfffb258 505 if (column < 0) {
wim 15:b70ebfffb258 506 _column = 0;
wim 15:b70ebfffb258 507 }
wim 15:b70ebfffb258 508 else if (column >= columns()) {
wim 15:b70ebfffb258 509 _column = columns() - 1;
wim 15:b70ebfffb258 510 } else _column = column;
wim 8:03116f75b66e 511
wim 15:b70ebfffb258 512 // Sanity Check row
wim 15:b70ebfffb258 513 if (row < 0) {
wim 15:b70ebfffb258 514 _row = 0;
wim 15:b70ebfffb258 515 }
wim 15:b70ebfffb258 516 else if (row >= rows()) {
wim 15:b70ebfffb258 517 _row = rows() - 1;
wim 15:b70ebfffb258 518 } else _row = row;
wim 15:b70ebfffb258 519
wim 15:b70ebfffb258 520
wim 15:b70ebfffb258 521 // Compute the memory address
wim 15:b70ebfffb258 522 // For LCD40x4: switch controllers if needed
wim 15:b70ebfffb258 523 // switch cursor if needed
wim 15:b70ebfffb258 524 int addr = getAddress(_column, _row);
wim 8:03116f75b66e 525
wim 13:24506ba22480 526 _writeCommand(0x80 | addr);
wim 8:03116f75b66e 527 }
simon 1:ac48b187213c 528
simon 1:ac48b187213c 529 int TextLCD::columns() {
simon 1:ac48b187213c 530 switch (_type) {
wim 8:03116f75b66e 531 case LCD8x1:
wim 8:03116f75b66e 532 case LCD8x2:
wim 18:bd65dc10f27f 533 case LCD8x2B:
wim 8:03116f75b66e 534 return 8;
wim 15:b70ebfffb258 535
wim 15:b70ebfffb258 536 case LCD12x2:
wim 15:b70ebfffb258 537 case LCD12x4:
wim 15:b70ebfffb258 538 return 12;
wim 8:03116f75b66e 539
wim 13:24506ba22480 540 case LCD16x1:
simon 1:ac48b187213c 541 case LCD16x2:
simon 1:ac48b187213c 542 case LCD16x2B:
wim 8:03116f75b66e 543 case LCD16x4:
wim 8:03116f75b66e 544 return 16;
wim 8:03116f75b66e 545
wim 8:03116f75b66e 546 case LCD20x2:
wim 8:03116f75b66e 547 case LCD20x4:
wim 8:03116f75b66e 548 return 20;
wim 8:03116f75b66e 549
wim 8:03116f75b66e 550 case LCD24x2:
wim 10:dd9b3a696acd 551 case LCD24x4:
wim 8:03116f75b66e 552 return 24;
wim 9:0893d986e717 553
wim 9:0893d986e717 554 case LCD40x2:
wim 15:b70ebfffb258 555 case LCD40x4:
wim 9:0893d986e717 556 return 40;
wim 8:03116f75b66e 557
wim 8:03116f75b66e 558 // Should never get here.
simon 1:ac48b187213c 559 default:
wim 8:03116f75b66e 560 return 0;
simon 1:ac48b187213c 561 }
simon 1:ac48b187213c 562 }
simon 1:ac48b187213c 563
simon 1:ac48b187213c 564 int TextLCD::rows() {
simon 1:ac48b187213c 565 switch (_type) {
wim 8:03116f75b66e 566 case LCD8x1:
wim 13:24506ba22480 567 case LCD16x1:
wim 8:03116f75b66e 568 return 1;
wim 8:03116f75b66e 569
wim 15:b70ebfffb258 570 case LCD8x2:
wim 18:bd65dc10f27f 571 case LCD8x2B:
wim 15:b70ebfffb258 572 case LCD12x2:
simon 1:ac48b187213c 573 case LCD16x2:
simon 1:ac48b187213c 574 case LCD16x2B:
simon 1:ac48b187213c 575 case LCD20x2:
wim 8:03116f75b66e 576 case LCD24x2:
wim 9:0893d986e717 577 case LCD40x2:
wim 8:03116f75b66e 578 return 2;
wim 8:03116f75b66e 579
wim 15:b70ebfffb258 580 case LCD12x4:
wim 8:03116f75b66e 581 case LCD16x4:
wim 8:03116f75b66e 582 case LCD20x4:
wim 10:dd9b3a696acd 583 case LCD24x4:
wim 15:b70ebfffb258 584 case LCD40x4:
wim 8:03116f75b66e 585 return 4;
wim 12:6bf9d9957d31 586
wim 12:6bf9d9957d31 587 // Should never get here.
simon 1:ac48b187213c 588 default:
wim 8:03116f75b66e 589 return 0;
simon 1:ac48b187213c 590 }
simon 1:ac48b187213c 591 }
wim 10:dd9b3a696acd 592
wim 10:dd9b3a696acd 593
wim 17:652ab113bc2e 594 // Set the Cursor Mode (Cursor Off & Blink Off, Cursor On & Blink Off, Cursor Off & Blink On, Cursor On & Blink On
wim 17:652ab113bc2e 595 void TextLCD::setCursor(TextLCD::LCDCursor cursorMode) {
wim 15:b70ebfffb258 596
wim 17:652ab113bc2e 597 // Save new cursor mode, needed when 2 controllers are in use or when display is switched off/on
wim 17:652ab113bc2e 598 _currentCursor = cursorMode;
wim 10:dd9b3a696acd 599
wim 17:652ab113bc2e 600 // Configure only current LCD controller
wim 17:652ab113bc2e 601 _setCursorAndDisplayMode(_currentMode, _currentCursor);
wim 15:b70ebfffb258 602
wim 15:b70ebfffb258 603 }
wim 15:b70ebfffb258 604
wim 17:652ab113bc2e 605 // Set the Displaymode (On/Off)
wim 17:652ab113bc2e 606 void TextLCD::setMode(TextLCD::LCDMode displayMode) {
wim 17:652ab113bc2e 607
wim 17:652ab113bc2e 608 // Save new displayMode, needed when 2 controllers are in use or when cursor is changed
wim 17:652ab113bc2e 609 _currentMode = displayMode;
wim 15:b70ebfffb258 610
wim 17:652ab113bc2e 611 // Select and configure second LCD controller when needed
wim 17:652ab113bc2e 612 if(_type==LCD40x4) {
wim 19:c747b9e2e7b8 613 if (_ctrl_idx==TextLCD::_LCDCtrl_0) {
wim 17:652ab113bc2e 614 // Configure primary LCD controller
wim 17:652ab113bc2e 615 _setCursorAndDisplayMode(_currentMode, _currentCursor);
wim 11:9ec02df863a1 616
wim 17:652ab113bc2e 617 // Select 2nd controller
wim 19:c747b9e2e7b8 618 _ctrl_idx=TextLCD::_LCDCtrl_1;
wim 17:652ab113bc2e 619
wim 17:652ab113bc2e 620 // Configure secondary LCD controller
wim 17:652ab113bc2e 621 _setCursorAndDisplayMode(_currentMode, TextLCD::CurOff_BlkOff);
wim 11:9ec02df863a1 622
wim 17:652ab113bc2e 623 // Restore current controller
wim 19:c747b9e2e7b8 624 _ctrl_idx=TextLCD::_LCDCtrl_0;
wim 17:652ab113bc2e 625 }
wim 17:652ab113bc2e 626 else {
wim 17:652ab113bc2e 627 // Select primary controller
wim 19:c747b9e2e7b8 628 _ctrl_idx=TextLCD::_LCDCtrl_0;
wim 17:652ab113bc2e 629
wim 17:652ab113bc2e 630 // Configure primary LCD controller
wim 17:652ab113bc2e 631 _setCursorAndDisplayMode(_currentMode, TextLCD::CurOff_BlkOff);
wim 17:652ab113bc2e 632
wim 17:652ab113bc2e 633 // Restore current controller
wim 19:c747b9e2e7b8 634 _ctrl_idx=TextLCD::_LCDCtrl_1;
wim 11:9ec02df863a1 635
wim 17:652ab113bc2e 636 // Configure secondary LCD controller
wim 17:652ab113bc2e 637 _setCursorAndDisplayMode(_currentMode, _currentCursor);
wim 11:9ec02df863a1 638
wim 10:dd9b3a696acd 639 }
wim 17:652ab113bc2e 640 }
wim 17:652ab113bc2e 641 else {
wim 17:652ab113bc2e 642 // Configure primary LCD controller
wim 17:652ab113bc2e 643 _setCursorAndDisplayMode(_currentMode, _currentCursor);
wim 17:652ab113bc2e 644 }
wim 17:652ab113bc2e 645
wim 17:652ab113bc2e 646 }
wim 17:652ab113bc2e 647
wim 17:652ab113bc2e 648
wim 17:652ab113bc2e 649 // Set the Displaymode (On/Off) and Cursortype for current controller
wim 17:652ab113bc2e 650 void TextLCD::_setCursorAndDisplayMode(TextLCD::LCDMode displayMode, TextLCD::LCDCursor cursorType) {
wim 17:652ab113bc2e 651
wim 17:652ab113bc2e 652 // Configure current LCD controller
wim 17:652ab113bc2e 653 _writeCommand(0x08 | displayMode | cursorType);
wim 10:dd9b3a696acd 654 }
wim 10:dd9b3a696acd 655
wim 20:e0da005a777f 656
wim 10:dd9b3a696acd 657
wim 11:9ec02df863a1 658 void TextLCD::setUDC(unsigned char c, char *udc_data) {
wim 15:b70ebfffb258 659
wim 15:b70ebfffb258 660 // Select and configure second LCD controller when needed
wim 15:b70ebfffb258 661 if(_type==LCD40x4) {
wim 19:c747b9e2e7b8 662 _LCDCtrl_Idx current_ctrl_idx = _ctrl_idx; // Temp save current controller
wim 15:b70ebfffb258 663
wim 15:b70ebfffb258 664 // Select primary controller
wim 19:c747b9e2e7b8 665 _ctrl_idx=TextLCD::_LCDCtrl_0;
wim 15:b70ebfffb258 666
wim 15:b70ebfffb258 667 // Configure primary LCD controller
wim 15:b70ebfffb258 668 _setUDC(c, udc_data);
wim 15:b70ebfffb258 669
wim 15:b70ebfffb258 670 // Select 2nd controller
wim 19:c747b9e2e7b8 671 _ctrl_idx=TextLCD::_LCDCtrl_1;
wim 15:b70ebfffb258 672
wim 15:b70ebfffb258 673 // Configure secondary LCD controller
wim 15:b70ebfffb258 674 _setUDC(c, udc_data);
wim 11:9ec02df863a1 675
wim 15:b70ebfffb258 676 // Restore current controller
wim 19:c747b9e2e7b8 677 _ctrl_idx=current_ctrl_idx;
wim 15:b70ebfffb258 678 }
wim 15:b70ebfffb258 679 else {
wim 15:b70ebfffb258 680 // Configure primary LCD controller
wim 15:b70ebfffb258 681 _setUDC(c, udc_data);
wim 15:b70ebfffb258 682 }
wim 15:b70ebfffb258 683
wim 15:b70ebfffb258 684 }
wim 15:b70ebfffb258 685
wim 15:b70ebfffb258 686 void TextLCD::_setUDC(unsigned char c, char *udc_data) {
wim 15:b70ebfffb258 687
wim 15:b70ebfffb258 688 // Select CG RAM for current LCD controller
wim 15:b70ebfffb258 689 _writeCommand(0x40 + ((c & 0x07) << 3)); //Set CG-RAM address,
wim 15:b70ebfffb258 690 //8 sequential locations needed per UDC
wim 15:b70ebfffb258 691 // Store UDC pattern
wim 11:9ec02df863a1 692 for (int i=0; i<8; i++) {
wim 13:24506ba22480 693 _writeData(*udc_data++);
wim 11:9ec02df863a1 694 }
wim 15:b70ebfffb258 695
wim 15:b70ebfffb258 696 //Select DD RAM again for current LCD controller
wim 15:b70ebfffb258 697 int addr = getAddress(_column, _row);
wim 15:b70ebfffb258 698 _writeCommand(0x80 | addr);
wim 15:b70ebfffb258 699
wim 11:9ec02df863a1 700 }