From 25e4bc569caf14a7a76e14adb5ef72fcfb138849 Mon Sep 17 00:00:00 2001 From: Manfred Steiner Date: Sat, 14 Sep 2024 15:00:13 +0200 Subject: [PATCH] software/.../test_2024-07-23: unit lcd fertig (V1a/V2a) --- .../test_2024-07-23/src/units/lcd.cpp | 379 ++++++++---------- .../test_2024-07-23/src/units/lcd.hpp | 17 +- 2 files changed, 172 insertions(+), 224 deletions(-) diff --git a/software/nano-644/test_2024-07-23/src/units/lcd.cpp b/software/nano-644/test_2024-07-23/src/units/lcd.cpp index 02df19d..e779c16 100644 --- a/software/nano-644/test_2024-07-23/src/units/lcd.cpp +++ b/software/nano-644/test_2024-07-23/src/units/lcd.cpp @@ -12,32 +12,33 @@ // Nano-X-Base V1a V2a Beschreibung // --------------------------------- ------- + // BL ........... PC0 PC0 Backlight ON(=1) / OFF(=0) // E ........... PA3 PA3 LCD Enable (Verbindung via J25 erforderlich) // R/W .......... PD6 PD6 Read/Write: Read=1, Write=0 // RS ........... PD7 PD7 Register Select: Command=0, Data=1 // Data ......... PB7:0 PB7:0 Achtung von 5V LCD nicht lesen! - - // #define LCD_3V3 - #ifdef LCD_3V3 - #define DATA_PIN PINB - #endif - void Lcd::init () { - DDRA |= (1 << PA3); + DDRA |= (1 << PA3) | (1 << PA0); DDRB = 0xff; DDRD |= (1 << PD7) | (1 << PD6); initLcd(); - #ifdef LCD_3V3 - printf_P(PSTR("init 3.3V LCD (%d)"), status); - #else - printf_P(PSTR("init 5V LCD (%d)"), status); - #endif + printf_P(PSTR("init LCD (")); + if (status == 1) { + printf_P(PSTR("OK)")); + } else { + printf_P(PSTR("ERROR %d)"), status); + } + setBacklightOn(); } void Lcd::cleanup () { - DDRA &= ~(1 << PA3); + clear(); + PORTA &= ~((1 << PA3) | (1 << PA0)); + DDRA &= ~((1 << PA3) | (1 << PA0)); + PORTB = 0; DDRB = 0; + PORTD &= ~((1 << PD7) | (1 << PD6)); DDRD &= ~((1 << PD7) | (1 << PD6)); } @@ -47,33 +48,65 @@ void Lcd::clrRW () { PORTD &= ~(1 << PD6); } void Lcd::setE () { PORTA |= (1 << PA3); } void Lcd::clrE () { PORTA &= ~(1 << PA3); } - void Lcd::dataDirectionIn () { DDRB = 0x00; } void Lcd::dataDirectionOut () { DDRB = 0xff; } + void Lcd::dataDirectionIn () { + if (hardwareVersion == 1) { + // read back not allowed (missing level shifter 5V -> 3.3V) + DDRB = 0xff; + } else { + DDRB = 0x00; + } + } + uint8_t Lcd::getData () { - return PINB; + if (hardwareVersion == 1) { + // read back not allowed (missing level shifter 5V -> 3.3V) + _delay_ms(1); + return 0x00; // bit 8 (busy) = 0 + } else { + return PINB; + } } void Lcd::setData (uint8_t data) { PORTB = data; } + + void Lcd::setBacklightOn () { + PORTA |= (1 << PA0); + } + + void Lcd::setBacklightOff () { + PORTA &= ~(1 << PA0); + } + #endif #ifdef __AVR_ATmega328P__ // Arduino Nano (5V) // --------------------------------------------------------------- + + // Nano-X-Base V1a V2a Beschreibung + // --------------------------------- ------- + // BL ........... PC0 PC0 Backlight ON(=1) / OFF(=0) + // E ........... PC3 PC3 LCD Enable (Verbindung via J25 erforderlich) + // R/W .......... PD3 PD3 Read/Write: Read=1, Write=0 + // RS ........... PD2 PD2 Register Select: Command=0, Data=1 + // Data0 ........ PD4 PD4 + // Data1 .........PB0 PB0 + // Data2 .........PD7 PD7 + // Data3 .........PD6 PD6 + // Data4 .........PB2 PB2 + // Data5 .........PB3 PB3 + // Data6 .........PB4 PB4 + // Data7 .........PB5 PB5 + // PC3 ..... E --> LCD Enable (Verbindung via J25 erforderlich) // PD3 ..... R/W --> Read/Write: Read=1, Write=0 // PD2 ..... RS --> Register Select: Command=0, Data=1 - // PD4 ..... Data0 - // PB0 ..... Data1 - // PD7 ..... Data2 - // PD6 ..... Data3 - // PB2 ..... Data4 - // PB3 ..... Data5 - // PB4 ..... Data6 - // PB5 ..... Data7 + void Lcd::init () { clrRW(); @@ -81,23 +114,25 @@ clrE(); setData(0); DDRB |= (1 << PB5) | (1 << PB4) | (1 << PB3) | (1 << PB2) | (1 << PB0); - DDRC |= (1 << PC3); + DDRC |= (1 << PC3) | (1 << PC0); DDRD |= (1 << PD7) | (1 << PD6) | (1 << PD4) | (1 << PD3) | (1 << PD2); initLcd(); - #ifdef LCD_3V3 - printf_P(PSTR("init 3.3V LCD")); - #else - printf_P(PSTR("init 5V LCD")); - #endif + printf_P(PSTR("init LCD (")); + if (status == 1) { + printf_P(PSTR("OK)")); + } else { + printf_P(PSTR("ERROR %d)"), status); + } + setBacklightOn(); } void Lcd::cleanup () { - clrRW(); - clrRS(); - clrE(); - setData(0); + clear(); + PORTB &= ~((1 << PB5) | (1 << PB4) | (1 << PB3) | (1 << PB2) | (1 << PB0)); + PORTC &= ~((1 << PC3) | (1 << PC0)); + PORTD &= ~((1 << PD7) | (1 << PD6) | (1 << PD4) | (1 << PD3) | (1 << PD2)); DDRB &= ~((1 << PB5) | (1 << PB4) | (1 << PB3) | (1 << PB2) | (1 << PB0)); - DDRC &= ~(1 << PC3); + DDRC &= ~((1 << PC3) | (1 << PC0)); DDRD &= ~((1 << PD7) | (1 << PD6) | (1 << PD4) | (1 << PD3) | (1 << PD2)); } @@ -118,6 +153,55 @@ if (data & 0x40) PORTB |= (1 << PB4); else PORTB &= ~((1 << PB4)); if (data & 0x80) PORTB |= (1 << PB5); else PORTB &= ~((1 << PB5)); } + + void Lcd::dataDirectionOut () { + if (!mode4Bit) { + DDRB |= (1 << PB0); + DDRD |= ((1 << PD7) | (1 << PD6) | (1 << PD4)); + } + DDRB |= ((1 << PB5) | (1 << PB4) | (1 << PB3) | (1 << PB2)); + } + + void Lcd::dataDirectionIn () { + if (hardwareVersion == 1) { + // read back not allowed (missing level shifter 5V -> 3.3V) + dataDirectionOut(); + } else { + if (!mode4Bit) { + DDRB &= ~(1 << PB0); + DDRD &= ~((1 << PD7) | (1 << PD6) | (1 << PD4)); + } + DDRB &= ~((1 << PB5) | (1 << PB4) | (1 << PB3) | (1 << PB2)); + } + } + + uint8_t Lcd::getData () { + if (hardwareVersion == 1) { + // read back not allowed (missing level shifter 5V -> 3.3V) + _delay_ms(1); + return 0x00; // bit 8 (busy) = 0 + } else { + uint8_t b = 0; + b |= ((PIND & (1 << PD4)) != 0) << 0; + b |= ((PINB & (1 << PB0)) != 0) << 1; + b |= ((PIND & (1 << PD7)) != 0) << 2; + b |= ((PIND & (1 << PD6)) != 0) << 3; + b |= ((PINB & (1 << PB2)) != 0) << 4; + b |= ((PINB & (1 << PB3)) != 0) << 5; + b |= ((PINB & (1 << PB4)) != 0) << 6; + b |= ((PINB & (1 << PB5)) != 0) << 7; + return b; + } + } + + void Lcd::setBacklightOn () { + PORTC |= (1 << PC0); + } + + void Lcd::setBacklightOff () { + PORTC &= ~(1 << PC0); + } + #endif // Befehle für das Display @@ -136,7 +220,7 @@ #define LCD_CMD_SET_ENTRY_MODE 0x04 // Entry Mode Set #define LCD_CMD_DISPLAY_ON_OFF 0x08 // Display on/off #define LCD_CMD_SHIFT 0x10 // Display shift -#define LCD_CMD_SET_FUNCTION 0x20 // 4/8 Bits... +#define LCD_CMD_SET_MODE4BIT 0x20 // 4/8 Bits... #define LCD_CMD_SET_CGRAM_ADDR 0x40 // Character Generator ROM #define LCD_CMD_SET_DDRAM_ADDR 0x80 // Display Data RAM #define LCD_BUSY_FLAG 0x80 @@ -170,151 +254,20 @@ int8_t Lcd::run (uint8_t subtest) { return 0; } -// void Lcd::initLcd () { -// _delay_ms(16); // min 15ms warten für Reset des Displays - -// if (mode8Bit) { -// setData( 0b00111011 ); // 8bit Modus, 5x7 Zeichen, Mehrzeilen Display -// clrRW(); // write -// clrRS(); // command -// setE(); // E = 1 (transfer start) -// _delay_us(10); // min. 10us -// clrE(); // E = 0 (transfer end) -// _delay_ms(5); // min. 4.1ms - -// setData( 0b00111011 ); // 8bit Modus, 5x7 Zeichen, Mehrzeilen Display -// clrRW(); // write -// clrRS(); // command -// setE(); // E = 1 (transfer start) -// _delay_us(10); // min. 10us -// clrE(); // E = 0 (transfer end) -// _delay_us(100); // min. 100us - -// setData( 0b00111011 ); // 8bit Modus, 5x7 Zeichen, Mehrzeilen Display -// clrRW(); // write -// clrRS(); // command -// setE(); // E = 1 (transfer start) -// _delay_us(10); // min. 10us -// clrE(); // E = 0 (transfer end) -// _delay_us(100); // min. 100us - -// } else { -// setData( 0b0010 << 4 ); // 4bit Modus, 5x7 Zeichen, Mehrzeilen Display -// } - -// writeCommand(DISP_OFF); // Display aus -// while(isBusy()) {}; -// writeCommand(DISP_ON); // Display ein -// while(isBusy()) {}; -// writeCommand( BLINK_OFF & CURSOR_OFF); // Blink aus und Cursor aus -// while(isBusy()) {}; -// writeCommand(DISP_CLEAR);// Clear display -// while(isBusy()) {}; -// } - -// uint8_t Lcd::isBusy () { -// #ifdef LCD_3V3 -// // DIR_DATA_PORT = 0; -// // SET_RW_PIN; // read -// // CLR_RS_PIN; // command -// // SET_E_PIN; // E = 1 (transfer start) -// // _delay_us(10); -// // uint8_t busy = DATA_PIN & 0x80; // read bit 7 (busy bit) -// // CLR_E_PIN; // E = 0 (transfer end) -// // CLR_RW_PIN; -// // DIR_DATA_PORT = 0xff; -// // return busy != 0; -// _delay_us(200); -// #else -// _delay_us(200); -// #endif -// return 0; -// } - -// void Lcd::writeCommand (uint8_t cmd) { -// setData(cmd); -// clrRW(); // write -// clrRS(); // command -// setE(); // E = 1 (transfer start) -// _delay_us(10); // min. 10us -// clrE(); // E = 0 (transfer end) -// setData(0); -// } - -// void Lcd::setDDRamAddr (uint8_t address) { -// setData(address | 0x80); -// clrRW(); // write -// clrRS(); // command -// setE(); // E = 1 (transfer start) -// _delay_us(10); // min. 10us -// clrE(); // E = 0 (transfer end) -// _delay_us(10); // min. 10us -// setData(0); -// } - -// void Lcd::writeString (const char *s) { -// while (*s) { -// writeData(*s++); -// while (isBusy()) {}; -// } -// } - -// void Lcd::writeData (uint8_t data) { -// setData(data); -// setRS(); // data -// clrRW(); // write -// setE(); // E = 1 (transfer start) -// _delay_us(10); // min. 10us -// clrE(); // E = 0 (transfer end) -// _delay_us(10); // min. 10us -// clrRS(); -// setData(0); -// } - -// void Lcd::setCursor (uint8_t row, uint8_t column) { -// uint8_t b; -// if (column > 20) { -// return; -// } -// switch (row) { -// case 1: b = 0x00 + column - 1; break; -// case 2: b = 0x40 + column - 1; break; -// case 3: b = 0x14 + column - 1; break; -// case 4: b = 0x54 + column - 1; break; -// default: return; -// } -// setDDRamAddr(b); -// while (isBusy()) {}; -// } - - void Lcd::initLcd () { setData(0x00); dataDirectionOut(); - // setE(); - // _delay_us(200); - // clrE(); - // for (uint8_t i = 0; i < 16; i++) { - // setData(i << 4); - // _delay_us(200); - // } - - // for (uint8_t i = 0; i < 10; i++) { - // clrRS(); - // setRW(); - // _delay_us(200); - // setRS(); - // clrRW(); - // _delay_us(200); - // } - _delay_ms(16); // min 15ms warten für Reset des Displays status = 0; for (uint8_t i = 0; i < 4; i++) { - setRegister(LCD_CMD_SET_FUNCTION | 0x08); // 4 Bit, 2 Zeilen, 5x7 + if (mode4Bit) { + setRegister(LCD_CMD_SET_MODE4BIT | 0x08); // 4 Bit, 2/4 Zeilen, 5x7 + } else { + setRegister(0x08); // 8 Bit, 2 Zeilen, 5x7 + } if (i == 0) { _delay_ms(5); } else { @@ -343,23 +296,25 @@ void Lcd::initLcd () { status = 1; } - void Lcd::setRegister (uint8_t cmd) { - - setData(0x00); - dataDirectionOut(); - - clrE(); clrRW(); clrRS(); - - setData(cmd & 0xf0); // send High-Nibble - setE(); - _delay_us(LCD_PULSE_LENGTH); - clrE(); - _delay_us(1); + writeData(cmd); +} - setData(cmd << 4); // send Low-Nibble +void Lcd::writeData (uint8_t data) { + clrE(); + dataDirectionOut(); + if (mode4Bit) { + setData(data & 0xf0); // send High-Nibble + setE(); + _delay_us(LCD_PULSE_LENGTH); + clrE(); + _delay_us(1); + setData(data << 4); // send Low-Nibble + } else { + setData(data); // send data byte + } setE(); _delay_us(LCD_PULSE_LENGTH); clrE(); @@ -378,11 +333,15 @@ void Lcd::waitOnReady () { } } - bool Lcd::isReady (uint16_t us) { if (status < 0) { return false; } + if (hardwareVersion == 1) { + // read back not allowed (missing level shifter) + _delay_ms(1); + return true; + } uint8_t busy; dataDirectionIn(); @@ -424,67 +383,61 @@ bool Lcd::isReady (uint16_t us) { void Lcd::setDisplayOn () { + if (status != 1) { + return; + } waitOnReady(); setRegister(LCD_CMD_DISPLAY_ON_OFF | 0x04); // display on waitOnReady(); } void Lcd::setDisplayOff () { + if (status != 1) { + return; + } waitOnReady(); setRegister(LCD_CMD_DISPLAY_ON_OFF); // display off waitOnReady(); } void Lcd::clear () { + if (status != 1) { + return; + } waitOnReady(); setRegister(LCD_CMD_DISPLAY_CLEAR); - while (!isReady(1200)) { - } + waitOnReady(); } void Lcd::setCursor (uint8_t rowIndex, uint8_t columnIndex) { - if (status != 1 || rowIndex > 1) { + if (status != 1 || columnIndex >= 20) { return; } - if (rowIndex) { - setDRAddr(0x40 + columnIndex); - } else { - setDRAddr(columnIndex); + uint8_t b; + switch (rowIndex) { + case 0: b = 0x00 + columnIndex; break; + case 1: b = 0x40 + columnIndex; break; + case 2: b = 0x14 + columnIndex; break; + case 3: b = 0x54 + columnIndex; break; + default: return; } + setDRAddr(b); + waitOnReady(); } void Lcd::putChar (char c) { if (status != 1) { return; } - - waitOnReady(); - - setData(0x00); - dataDirectionOut(); - clrE(); clrRW(); setRS(); - - PORTB &= 0x0f; - setData(c & 0xf0); // send High-Nibble - setE(); - _delay_us(LCD_PULSE_LENGTH); - clrE(); - _delay_us(1); - - setData(c << 4); // send Low-Nibble - setE(); - _delay_us(LCD_PULSE_LENGTH); - clrE(); - _delay_us(1); + writeData(c); clrRS(); - _delay_us(1); + waitOnReady(); } void Lcd::puts (const char * str) { while (*str && status == 1) { putChar(*str++); } - waitOnReady(); } \ No newline at end of file diff --git a/software/nano-644/test_2024-07-23/src/units/lcd.hpp b/software/nano-644/test_2024-07-23/src/units/lcd.hpp index 0ea1c28..47a30cc 100644 --- a/software/nano-644/test_2024-07-23/src/units/lcd.hpp +++ b/software/nano-644/test_2024-07-23/src/units/lcd.hpp @@ -7,26 +7,20 @@ class Lcd : public TestUnit { public: - Lcd () { mode8Bit = 0; status = 0; }; + Lcd () { mode4Bit = hardwareVersion == 1 ? false : true; status = 0; }; virtual void init (); virtual void cleanup (); virtual int8_t run (uint8_t subtest); virtual PGM_P getName () { return PSTR("Lcd"); } private: - - bool mode8Bit; + bool mode4Bit; int8_t status; - void initLcd (); - // uint8_t isBusy (); - // void writeCommand (uint8_t); - // void setDDRamAddr (uint8_t); - // void writeString (const char *s); - // void writeData (uint8_t); - // void setCursor (uint8_t row, uint8_t column); + void initLcd (); void setRegister (uint8_t cmd); void setDRAddr (uint8_t address); + void writeData (uint8_t data); void waitOnReady (); bool isReady (uint16_t us); void setDisplayOn (); @@ -36,7 +30,6 @@ class Lcd : public TestUnit { void putChar (char c); void puts (const char * str); - void setRS (); void clrRS (); void setRW (); @@ -47,6 +40,8 @@ class Lcd : public TestUnit { void setData (uint8_t data); void dataDirectionIn (); void dataDirectionOut (); + void setBacklightOn (); + void setBacklightOff (); }; -- 2.39.5