A TextDisplay driver that supports graphical displays using on of the SED133x conrtrolers. Allows stdout and stderr output to be redirected to the display.
TextLCD.cpp@9:68ad299df12b, 2011-01-29 (annotated)
- Committer:
- llagendijk
- Date:
- Sat Jan 29 21:28:42 2011 +0000
- Revision:
- 9:68ad299df12b
- Parent:
- 1:18c56f038905
First release of my version of TextDisPlay
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
llagendijk | 0:9e72c57b16fd | 1 | /* mbed TextLCD Library |
llagendijk | 0:9e72c57b16fd | 2 | * Copyright (c) 2007-2009 sford |
llagendijk | 0:9e72c57b16fd | 3 | * Released under the MIT License: http://mbed.org/license/mit |
llagendijk | 0:9e72c57b16fd | 4 | * |
llagendijk | 0:9e72c57b16fd | 5 | * Modified by Ned Konz to provide better support for 4-line LCDs and ones with other controller chips. |
llagendijk | 0:9e72c57b16fd | 6 | */ |
llagendijk | 0:9e72c57b16fd | 7 | |
llagendijk | 0:9e72c57b16fd | 8 | #include "TextLCD.h" |
llagendijk | 0:9e72c57b16fd | 9 | #include "mbed.h" |
llagendijk | 0:9e72c57b16fd | 10 | |
llagendijk | 0:9e72c57b16fd | 11 | /* |
llagendijk | 0:9e72c57b16fd | 12 | * useful info found at http://www.a-netz.de/lcd.en.php |
llagendijk | 0:9e72c57b16fd | 13 | * |
llagendijk | 0:9e72c57b16fd | 14 | * Initialisation |
llagendijk | 0:9e72c57b16fd | 15 | * ============== |
llagendijk | 0:9e72c57b16fd | 16 | * |
llagendijk | 0:9e72c57b16fd | 17 | * After attaching the supply voltage/after a reset, the display needs to be brought in to a defined state |
llagendijk | 0:9e72c57b16fd | 18 | * |
llagendijk | 0:9e72c57b16fd | 19 | * - wait approximately 15 ms so the display is ready to execute commands |
llagendijk | 0:9e72c57b16fd | 20 | * - Execute the command 0x30 ("Display Settings") three times (wait 1,64ms after each command, the busy flag cannot be queried now). |
llagendijk | 0:9e72c57b16fd | 21 | * - The display is in 8 bit mode, so if you have only connected 4 data pins you should only transmit the higher nibble of each command. |
llagendijk | 0:9e72c57b16fd | 22 | * - If you want to use the 4 bit mode, now you can execute the command to switch over to this mode now. |
llagendijk | 0:9e72c57b16fd | 23 | * - Execute the "clear display" command |
llagendijk | 0:9e72c57b16fd | 24 | * |
llagendijk | 0:9e72c57b16fd | 25 | * Timing |
llagendijk | 0:9e72c57b16fd | 26 | * ====== |
llagendijk | 0:9e72c57b16fd | 27 | * |
llagendijk | 0:9e72c57b16fd | 28 | * Nearly all commands transmitted to the display need 40us for execution. |
llagendijk | 0:9e72c57b16fd | 29 | * Exceptions are the commands "Clear Display and Reset" and "Set Cursor to Start Position" |
llagendijk | 0:9e72c57b16fd | 30 | * These commands need 1.64ms for execution. These timings are valid for all displays working with an |
llagendijk | 0:9e72c57b16fd | 31 | * internal clock of 250kHz. But I do not know any displays that use other frequencies. Any time you |
llagendijk | 0:9e72c57b16fd | 32 | * can use the busy flag to test if the display is ready to accept the next command. |
llagendijk | 0:9e72c57b16fd | 33 | * |
llagendijk | 0:9e72c57b16fd | 34 | * _e is kept low except when being used. |
llagendijk | 0:9e72c57b16fd | 35 | * _rw is kept 0 (write) apart from actions that use it differently |
llagendijk | 0:9e72c57b16fd | 36 | * _rs is set by the data/command writes |
llagendijk | 0:9e72c57b16fd | 37 | */ |
llagendijk | 0:9e72c57b16fd | 38 | |
llagendijk | 0:9e72c57b16fd | 39 | TextLCD::TextLCD(PinName rs, PinName rw, PinName e, PinName d0, PinName d1, |
llagendijk | 1:18c56f038905 | 40 | PinName d2, PinName d3, uint16_t rows, uint16_t cols, const char *name) : |
llagendijk | 1:18c56f038905 | 41 | TextDisplay(name), _rw(rw), _rs(rs), |
llagendijk | 0:9e72c57b16fd | 42 | _e(e), _d(d0, d1, d2, d3), _rows(rows), _columns(cols) { |
llagendijk | 0:9e72c57b16fd | 43 | |
llagendijk | 0:9e72c57b16fd | 44 | _rw = 0; |
llagendijk | 0:9e72c57b16fd | 45 | wait_us(1); // min. 100nsec delay |
llagendijk | 0:9e72c57b16fd | 46 | _e = 0; |
llagendijk | 0:9e72c57b16fd | 47 | _rs = 0; // command mode |
llagendijk | 0:9e72c57b16fd | 48 | _d.output(); |
llagendijk | 0:9e72c57b16fd | 49 | |
llagendijk | 0:9e72c57b16fd | 50 | reset(); |
llagendijk | 0:9e72c57b16fd | 51 | cls(); |
llagendijk | 0:9e72c57b16fd | 52 | } |
llagendijk | 0:9e72c57b16fd | 53 | |
llagendijk | 0:9e72c57b16fd | 54 | void TextLCD::reset() { |
llagendijk | 0:9e72c57b16fd | 55 | wait_ms(15); |
llagendijk | 0:9e72c57b16fd | 56 | // e is low at this point, as is rw. |
llagendijk | 0:9e72c57b16fd | 57 | // 2. Send 0x3 and wait 150 ms (will stay in 8-bit mode if already there) |
llagendijk | 0:9e72c57b16fd | 58 | writeHalfByte(0x3); |
llagendijk | 0:9e72c57b16fd | 59 | wait_ms(5); |
llagendijk | 0:9e72c57b16fd | 60 | // 3. Send 0x3 and wait 150 ms (will go to 8-bit mode if was in 4-bit without any garbage nibble) |
llagendijk | 0:9e72c57b16fd | 61 | writeHalfByte(0x3); |
llagendijk | 0:9e72c57b16fd | 62 | wait_ms(5); |
llagendijk | 0:9e72c57b16fd | 63 | // 4. Send 0x3 and wait 250 ms (will go to 8-bit mode even if garbage nibble was previously received) |
llagendijk | 0:9e72c57b16fd | 64 | writeHalfByte(0x3); |
llagendijk | 0:9e72c57b16fd | 65 | wait_ms(5); |
llagendijk | 0:9e72c57b16fd | 66 | // 5. Send 0x2 and wait 200 ms (should go to 4-bit mode now) |
llagendijk | 0:9e72c57b16fd | 67 | writeHalfByte(0x2); |
llagendijk | 0:9e72c57b16fd | 68 | wait_ms(5); |
llagendijk | 0:9e72c57b16fd | 69 | // 7. Send LCD setup sequence (eg 0x2, 0x8 (=0x28), 0x0, 0x8 (=0x08), etc.) |
llagendijk | 0:9e72c57b16fd | 70 | writeCommand(0x28); // Function set 001 BW N F - - |
llagendijk | 0:9e72c57b16fd | 71 | wait_ms(15); |
llagendijk | 0:9e72c57b16fd | 72 | |
llagendijk | 0:9e72c57b16fd | 73 | writeCommand(0x08); // display off, cursor invisible |
llagendijk | 0:9e72c57b16fd | 74 | wait_ms(15); |
llagendijk | 0:9e72c57b16fd | 75 | |
llagendijk | 0:9e72c57b16fd | 76 | writeCommand(0x01); |
llagendijk | 0:9e72c57b16fd | 77 | wait_ms(15); // 1.64ms command |
llagendijk | 0:9e72c57b16fd | 78 | |
llagendijk | 0:9e72c57b16fd | 79 | writeCommand(0x0C); // display enabled, cursor invisible |
llagendijk | 0:9e72c57b16fd | 80 | wait_ms(15); |
llagendijk | 0:9e72c57b16fd | 81 | |
llagendijk | 0:9e72c57b16fd | 82 | writeCommand(0x6); // Cursor Direction and Display Shift : 0000 01 CD S (CD 0-left, 1-right S(hift) 0-no, 1-yes |
llagendijk | 0:9e72c57b16fd | 83 | wait_ms(15); |
llagendijk | 0:9e72c57b16fd | 84 | |
llagendijk | 0:9e72c57b16fd | 85 | locate(0,0); |
llagendijk | 0:9e72c57b16fd | 86 | } |
llagendijk | 0:9e72c57b16fd | 87 | |
llagendijk | 0:9e72c57b16fd | 88 | // memory starts at 0x80, and is 0x40 chars long per row |
llagendijk | 0:9e72c57b16fd | 89 | // However, rows 2 and 3 of 4-line displays are actually adjacent to rows 0 and 1. |
llagendijk | 0:9e72c57b16fd | 90 | // 16x4 displays are addressed the same way as 20x4 ones. |
llagendijk | 0:9e72c57b16fd | 91 | |
llagendijk | 0:9e72c57b16fd | 92 | void TextLCD::character(uint16_t column, uint16_t row, int c) { |
llagendijk | 0:9e72c57b16fd | 93 | int address; |
llagendijk | 0:9e72c57b16fd | 94 | address = 0x80 + ((row & ~2) * 0x40) + column; |
llagendijk | 0:9e72c57b16fd | 95 | if (row > 1) |
llagendijk | 0:9e72c57b16fd | 96 | address += 20; |
llagendijk | 0:9e72c57b16fd | 97 | writeCommand(address); |
llagendijk | 0:9e72c57b16fd | 98 | writeData(c); |
llagendijk | 0:9e72c57b16fd | 99 | } |
llagendijk | 0:9e72c57b16fd | 100 | |
llagendijk | 0:9e72c57b16fd | 101 | void TextLCD::writeHalfByte(uint16_t value) { |
llagendijk | 0:9e72c57b16fd | 102 | _e = 1; |
llagendijk | 0:9e72c57b16fd | 103 | wait_us(1); |
llagendijk | 0:9e72c57b16fd | 104 | _d = value & 0x0F; // send data on bus |
llagendijk | 0:9e72c57b16fd | 105 | wait_us(1); // setup time |
llagendijk | 0:9e72c57b16fd | 106 | _e = 0; // strobe |
llagendijk | 0:9e72c57b16fd | 107 | wait_us(1); // hold time |
llagendijk | 0:9e72c57b16fd | 108 | } |
llagendijk | 0:9e72c57b16fd | 109 | |
llagendijk | 0:9e72c57b16fd | 110 | void TextLCD::writeByte(uint16_t value) { |
llagendijk | 0:9e72c57b16fd | 111 | writeHalfByte(value>>4); |
llagendijk | 0:9e72c57b16fd | 112 | writeHalfByte(value); |
llagendijk | 0:9e72c57b16fd | 113 | } |
llagendijk | 0:9e72c57b16fd | 114 | |
llagendijk | 0:9e72c57b16fd | 115 | void TextLCD::writeCommand(uint16_t command) { |
llagendijk | 0:9e72c57b16fd | 116 | _rs = 0; |
llagendijk | 0:9e72c57b16fd | 117 | writeByte(command); |
llagendijk | 0:9e72c57b16fd | 118 | waitUntilDone(); |
llagendijk | 0:9e72c57b16fd | 119 | } |
llagendijk | 0:9e72c57b16fd | 120 | |
llagendijk | 0:9e72c57b16fd | 121 | void TextLCD::writeData(uint16_t data) { |
llagendijk | 0:9e72c57b16fd | 122 | _rs = 1; |
llagendijk | 0:9e72c57b16fd | 123 | writeByte(data); |
llagendijk | 0:9e72c57b16fd | 124 | waitUntilDone(); |
llagendijk | 0:9e72c57b16fd | 125 | } |
llagendijk | 0:9e72c57b16fd | 126 | |
llagendijk | 0:9e72c57b16fd | 127 | void TextLCD::cls() { |
llagendijk | 0:9e72c57b16fd | 128 | writeCommand(0x01); |
llagendijk | 0:9e72c57b16fd | 129 | wait_us(2000); // 1.64ms command |
llagendijk | 0:9e72c57b16fd | 130 | locate(0,0); |
llagendijk | 0:9e72c57b16fd | 131 | } |
llagendijk | 0:9e72c57b16fd | 132 | |
llagendijk | 0:9e72c57b16fd | 133 | // This should be changed to use readAddressAndBusy() when that works. |
llagendijk | 0:9e72c57b16fd | 134 | void TextLCD::waitUntilDone() { |
llagendijk | 0:9e72c57b16fd | 135 | wait_us(60); |
llagendijk | 0:9e72c57b16fd | 136 | } |
llagendijk | 0:9e72c57b16fd | 137 | |
llagendijk | 0:9e72c57b16fd | 138 | // Return the busy/address byte. |
llagendijk | 0:9e72c57b16fd | 139 | // The busy flag is the high bit. |
llagendijk | 0:9e72c57b16fd | 140 | // Not yet working reliably. |
llagendijk | 0:9e72c57b16fd | 141 | uint16_t TextLCD::readAddressAndBusy() { |
llagendijk | 0:9e72c57b16fd | 142 | _d.input(); |
llagendijk | 0:9e72c57b16fd | 143 | _rw = 1; |
llagendijk | 0:9e72c57b16fd | 144 | wait_us(1); |
llagendijk | 0:9e72c57b16fd | 145 | _e = 1; |
llagendijk | 0:9e72c57b16fd | 146 | wait_us(1); |
llagendijk | 0:9e72c57b16fd | 147 | _e = 0; |
llagendijk | 0:9e72c57b16fd | 148 | |
llagendijk | 0:9e72c57b16fd | 149 | uint16_t retval = _d.read() << 4; |
llagendijk | 0:9e72c57b16fd | 150 | |
llagendijk | 0:9e72c57b16fd | 151 | wait_us(1); |
llagendijk | 0:9e72c57b16fd | 152 | _e = 1; |
llagendijk | 0:9e72c57b16fd | 153 | wait_us(1); |
llagendijk | 0:9e72c57b16fd | 154 | _e = 0; |
llagendijk | 0:9e72c57b16fd | 155 | |
llagendijk | 0:9e72c57b16fd | 156 | retval |= _d.read(); |
llagendijk | 0:9e72c57b16fd | 157 | _rw = 0; |
llagendijk | 0:9e72c57b16fd | 158 | |
llagendijk | 0:9e72c57b16fd | 159 | _d.output(); |
llagendijk | 0:9e72c57b16fd | 160 | return retval; |
llagendijk | 0:9e72c57b16fd | 161 | } |
llagendijk | 0:9e72c57b16fd | 162 |