Commit 0fcf3e4396b47ea364324bca13ae3fdf033765bb
receivedFri, 13. Sep 2024, 19:03:39 (by user sx)
Fri, 13 Sep 2024 17:03:39 +0000 (19:03 +0200)
authorManfred Steiner <sx@htl-kaindorf.at>
Fri, 13 Sep 2024 17:03:33 +0000 (19:03 +0200)
committerManfred Steiner <sx@htl-kaindorf.at>
Fri, 13 Sep 2024 17:03:33 +0000 (19:03 +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 86406900388c8de7c33a9b88c2869ca7d4ad566c..02df19dea7e01d681b830f9fab6b6b27b630e2cb 100644 (file)
@@ -7,12 +7,15 @@
 
 #if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)
 
-   // Nano-644
+   // Nano-644 / Nano-1284
    // ---------------------------------------------------------------
-   // PA3 ..... E    --> LCD Enable (Verbindung via J25 erforderlich)
-   // PD6 ..... R/W  --> Read/Write: Read=1, Write=0
-   // PD7 ..... RS   --> Register Select: Command=0, Data=1
-   // PB7:0 ... Data --> Achtung von 5V LCD nicht lesen!
+   
+   // Nano-X-Base    V1a   V2a     Beschreibung
+   // --------------------------------- -------
+   // 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
@@ -26,9 +29,9 @@
       DDRD |= (1 << PD7) | (1 << PD6);
       initLcd();
       #ifdef LCD_3V3
-         printf_P(PSTR("init 3.3V LCD"));
+         printf_P(PSTR("init 3.3V LCD (%d)"), status);
       #else
-         printf_P(PSTR("init 5V LCD"));
+         printf_P(PSTR("init 5V LCD (%d)"), status);
       #endif
    }
 
    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; }
+
+   uint8_t Lcd::getData () {
+      return PINB;
+   }
 
    void Lcd::setData (uint8_t data) {
       PORTB = data;
 #define BLINK_ON    0b00001111   // Cursor Blink    
 #define BLINK_OFF   0b00001110   // Cursor No Blink 
 
+#define LCD_PULSE_LENGTH 15
+#define LCD_CMD_DISPLAY_CLEAR  0x01  // Display clear
+#define LCD_CMD_CURSOR_HOME    0x02  // Move cursor digit 1
+#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_CGRAM_ADDR 0x40  // Character Generator ROM
+#define LCD_CMD_SET_DDRAM_ADDR 0x80  // Display Data RAM
+#define LCD_BUSY_FLAG          0x80
+
+
+
 int8_t Lcd::run (uint8_t subtest) {
    if (subtest == 0) {
       for (uint8_t i = 0; i < 20 * 4; i++) {
          char c = (char)(i + 32);
          if (i % 20 == 0) {
-            setCursor(i / 20 + 1, 1);
+            setCursor(i / 20, 0);
          }
-         writeData(c);
-         while (isBusy()) {};
+         putChar(c);
+         waitOnReady();
+      }
+      printf_P(PSTR("LCD "));
+      if (status == 1) {
+         printf_P(PSTR("OK"));
+      } else {
+         printf_P(PSTR("ERROR(%d)"), status);
       }
-      // setCursor(1, 1);
-      // writeString(" 1234567890<>,;.:-_#+");
-      // setCursor(2, 1);
-      // writeString("abcdefghijklmnopqrst");
-      // setCursor(3, 1);
-      // writeString("uvwxyzABCDEFGHIJKLMN");
-      // setCursor(4, 1);
-      // writeString("OPQRSTUVWXYZ ");
-      printf_P(PSTR("LCD beschrieben"));
       while (wait(1) == EOF) {
       }
 
@@ -151,114 +170,321 @@ 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 (i == 0) {
+         _delay_ms(5);
+      } else {
+         _delay_us(100);
+      }
+   }
 
-   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
-
-   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()) {};
+   setRegister(LCD_CMD_DISPLAY_ON_OFF | 0x04); // display on, cursor off
+   if (!isReady(50)) {
+      status = -1;
+      return;
+   }
+
+   setRegister(LCD_CMD_DISPLAY_ON_OFF | 0x04); // display on, cursor off
+   if (!isReady(50)) {
+      status = -3;
+      return;
+   }
+
+   setRegister(LCD_CMD_DISPLAY_CLEAR);
+   if (!isReady(1200)) {
+      status = -4;
+      return;
+   }
+
+   status = 1;
 }
 
-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::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);
+
+   setData(cmd << 4); // send Low-Nibble
+   setE();
+   _delay_us(LCD_PULSE_LENGTH);
+   clrE();
+   _delay_us(1);
 }
 
-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::setDRAddr (uint8_t address) {
+   waitOnReady();
+   setRegister(LCD_CMD_SET_DDRAM_ADDR | address);
+   waitOnReady();
 }
 
-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::waitOnReady () {
+   if (isReady(50) == 0) {
+      status = -6;
+   }
 }
 
-void Lcd::writeString (const char *s) {
-   while (*s) {
-      writeData(*s++);
-      while (isBusy()) {};
+
+bool Lcd::isReady (uint16_t us) {
+   if (status < 0) {
+      return false;
+   }
+
+   uint8_t busy;
+   dataDirectionIn();
+   setData(0xff); // enable internal pull up 
+
+   do {
+      uint8_t data = 0;
+      setRW();
+      clrRS();
+
+      _delay_us(1);
+      setE();
+      _delay_us(LCD_PULSE_LENGTH);
+      data = getData() & 0xf0; // High Nibble
+      clrE();
+
+      _delay_us(1);
+      setE();
+      _delay_us(LCD_PULSE_LENGTH);
+      data |= getData() >> 4; // Low Nibble
+      
+      clrE();
+      _delay_us(1);
+      clrRW();
+
+      busy = data & LCD_BUSY_FLAG;
+      us = (us >= 11) ? us - 11 : 0;
+   } while (us > 0 && busy);
+
+   if (status == 1 && busy) {
+      status = -5;
    }
+
+   setData(0x00);
+   dataDirectionOut();
+
+   return busy == 0;   
 }
 
-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::setDisplayOn () {
+   waitOnReady();
+   setRegister(LCD_CMD_DISPLAY_ON_OFF | 0x04); // display on
+   waitOnReady();
+}
+
+void Lcd::setDisplayOff () {
+   waitOnReady();
+   setRegister(LCD_CMD_DISPLAY_ON_OFF); // display off
+   waitOnReady();
+}
+
+void Lcd::clear () {
+   waitOnReady();
+   setRegister(LCD_CMD_DISPLAY_CLEAR);
+   while (!isReady(1200)) {
+   }
 }
 
-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::setCursor (uint8_t rowIndex, uint8_t columnIndex) {
+   if (status != 1 || rowIndex > 1) {
+      return;
+   }
+   if (rowIndex) {
+      setDRAddr(0x40 + columnIndex);
+   } else {
+      setDRAddr(columnIndex);
+   }
 }
+
+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);
+   clrRS();
+   _delay_us(1);
+}
+
+void Lcd::puts (const char * str) {
+   while (*str && status == 1) {
+      putChar(*str++);
+   }
+   waitOnReady();
+}
\ No newline at end of file
index 3eb445694a5a55f21e0fb8b42ec3e2bd425927cd..0ea1c28cc4fb520fac5184fc86575006cbd7e9a2 100644 (file)
@@ -7,27 +7,46 @@
 
 class Lcd : public TestUnit {
    public:
-      Lcd () {};
+      Lcd () { mode8Bit = 0; 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;
+      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);
+      // 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 setRegister (uint8_t cmd);
+      void setDRAddr (uint8_t address);
+      void waitOnReady ();
+      bool isReady (uint16_t us);
+      void setDisplayOn ();
+      void setDisplayOff ();
+      void clear ();
+      void setCursor (uint8_t rowIndex, uint8_t columnIndex);
+      void putChar (char c);
+      void puts (const char * str);
+
+
       void setRS ();
       void clrRS ();
       void setRW ();
       void clrRW ();
       void setE ();
       void clrE ();
+      uint8_t getData ();
       void setData (uint8_t data);
+      void dataDirectionIn ();
+      void dataDirectionOut ();
 
 };