Commit 25e4bc569caf14a7a76e14adb5ef72fcfb138849
receivedSat, 14. Sep 2024, 15:00:20 (by user sx)
Sat, 14 Sep 2024 13:00:20 +0000 (15:00 +0200)
authorManfred Steiner <sx@htl-kaindorf.at>
Sat, 14 Sep 2024 13:00:13 +0000 (15:00 +0200)
committerManfred Steiner <sx@htl-kaindorf.at>
Sat, 14 Sep 2024 13:00:13 +0000 (15:00 +0200)
2 files changed:
software/nano-644/test_2024-07-23/src/units/lcd.cpp
software/nano-644/test_2024-07-23/src/units/lcd.hpp

index 02df19dea7e01d681b830f9fab6b6b27b630e2cb..e779c16e53582a9c18f58d229442f6008fa80aeb 100644 (file)
    
    // 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));
    }
 
    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();
       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));
    }
 
       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
 #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
index 0ea1c28cc4fb520fac5184fc86575006cbd7e9a2..47a30ccc8da2fe98d930829ec06890bbfeabd77a 100644 (file)
@@ -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 ();
 
 };