graphlcd-base/glcddrivers/hd61830.c
changeset 4 df6a40031aa5
equal deleted inserted replaced
3:d0e62fc47285 4:df6a40031aa5
       
     1 /*
       
     2  * GraphLCD driver library
       
     3  *
       
     4  * hd61830.c  -  HD61830 driver class
       
     5  *
       
     6  * This file is released under the GNU General Public License. Refer
       
     7  * to the COPYING file distributed with this package.
       
     8  *
       
     9  * (c) 2001-2004 Carsten Siebholz <c.siebholz AT t-online.de>
       
    10  */
       
    11 
       
    12 #include <syslog.h>
       
    13 #include <sys/time.h>
       
    14 
       
    15 #include "common.h"
       
    16 #include "config.h"
       
    17 #include "hd61830.h"
       
    18 #include "port.h"
       
    19 
       
    20 
       
    21 namespace GLCD
       
    22 {
       
    23 
       
    24 // commands
       
    25 #define MCNT    0x00
       
    26 #define CPIT    0x01
       
    27 #define NOCH    0x02
       
    28 #define NOTD    0x03
       
    29 #define CPOS    0x04
       
    30 
       
    31 #define DSAL    0x08
       
    32 #define DSAH    0x09
       
    33 #define CACL    0x0A
       
    34 #define CACH    0x0B
       
    35 
       
    36 #define WDDI    0x0C
       
    37 #define RDDI    0x0D
       
    38 
       
    39 #define CBIT    0x0E
       
    40 #define SBIT    0x0F
       
    41 
       
    42 // control bits for DirectIO
       
    43 #define EN      0x01
       
    44 #define ENHI    0x00
       
    45 #define ENLO    0x01
       
    46 
       
    47 #define RW      0x02
       
    48 #define RWHI    0x00
       
    49 #define RWLO    0x02
       
    50 
       
    51 #define RS      0x04
       
    52 #define RSHI    0x04
       
    53 #define RSLO    0x00
       
    54 
       
    55 
       
    56 cDriverHD61830::cDriverHD61830(cDriverConfig * config)
       
    57 :   config(config)
       
    58 {
       
    59     oldConfig = new cDriverConfig(*config);
       
    60 
       
    61     port = new cParallelPort();
       
    62 
       
    63     useSleepInit = false;
       
    64 
       
    65     refreshCounter = 0;
       
    66     timeForPortCmdInNs = 0;
       
    67 }
       
    68 
       
    69 cDriverHD61830::~cDriverHD61830()
       
    70 {
       
    71     delete port;
       
    72     delete oldConfig;
       
    73 }
       
    74 
       
    75 int cDriverHD61830::Init()
       
    76 {
       
    77     int i;
       
    78     int x;
       
    79     struct timeval tv1, tv2;
       
    80 
       
    81     width = config->width;
       
    82     if (width <= 0)
       
    83         width = 240;
       
    84     height = config->height;
       
    85     if (height <= 0)
       
    86         height = 128;
       
    87 
       
    88     for (unsigned int i = 0; i < config->options.size(); i++)
       
    89     {
       
    90         if (config->options[i].name == "")
       
    91         {
       
    92         }
       
    93     }
       
    94 
       
    95     // setup lcd array (wanted state)
       
    96     newLCD = new unsigned char *[(width + 7) / 8];
       
    97     if (newLCD)
       
    98     {
       
    99         for (x = 0; x < (width + 7) / 8; x++)
       
   100         {
       
   101             newLCD[x] = new unsigned char[height];
       
   102             memset(newLCD[x], 0, height);
       
   103         }
       
   104     }
       
   105     // setup lcd array (current state)
       
   106     oldLCD = new unsigned char*[(width + 7) / 8];
       
   107     if (oldLCD)
       
   108     {
       
   109         for (x = 0; x < (width + 7) / 8; x++)
       
   110         {
       
   111             oldLCD[x] = new unsigned char[height];
       
   112             memset(oldLCD[x], 0, height);
       
   113         }
       
   114     }
       
   115 
       
   116     if (config->device == "")
       
   117     {
       
   118         // use DirectIO
       
   119         if (port->Open(config->port) != 0)
       
   120             return -1;
       
   121         uSleep(10);
       
   122     }
       
   123     else
       
   124     {
       
   125         // use ppdev
       
   126         if (port->Open(config->device.c_str()) != 0)
       
   127             return -1;
       
   128     }
       
   129 
       
   130     if (nSleepInit() != 0)
       
   131     {
       
   132         syslog(LOG_DEBUG, "%s: INFO: cannot change wait parameters (cDriver::Init)\n", config->name.c_str());
       
   133         useSleepInit = false;
       
   134     }
       
   135     else
       
   136     {
       
   137         useSleepInit = true;
       
   138     }
       
   139 
       
   140     syslog(LOG_DEBUG, "%s: benchmark started.\n", config->name.c_str());
       
   141     gettimeofday(&tv1, 0);
       
   142     for (i = 0; i < 1000; i++)
       
   143     {
       
   144         port->WriteData(1 % 0x100);
       
   145     }
       
   146     gettimeofday(&tv2, 0);
       
   147     if (useSleepInit)
       
   148         nSleepDeInit();
       
   149     timeForPortCmdInNs = (tv2.tv_sec-tv1.tv_sec) * 1000000 + (tv2.tv_usec-tv1.tv_usec);
       
   150     syslog(LOG_DEBUG, "%s: benchmark stopped. Time for Port Command: %ldns\n", config->name.c_str(), timeForPortCmdInNs);
       
   151 
       
   152     // initialize graphic mode
       
   153     InitGraphic();
       
   154 
       
   155     port->Release();
       
   156 
       
   157     *oldConfig = *config;
       
   158 
       
   159     // clear display
       
   160     Clear();
       
   161 
       
   162     syslog(LOG_INFO, "%s: HD61830 initialized.\n", config->name.c_str());
       
   163     return 0;
       
   164 }
       
   165 
       
   166 int cDriverHD61830::DeInit()
       
   167 {
       
   168     int x;
       
   169 
       
   170     // free lcd array (wanted state)
       
   171     if (newLCD)
       
   172     {
       
   173         for (x = 0; x < (width + 7) / 8; x++)
       
   174         {
       
   175             delete[] newLCD[x];
       
   176         }
       
   177         delete[] newLCD;
       
   178     }
       
   179     // free lcd array (current state)
       
   180     if (oldLCD)
       
   181     {
       
   182         for (x = 0; x < (width + 7) / 8; x++)
       
   183         {
       
   184             delete[] oldLCD[x];
       
   185         }
       
   186         delete[] oldLCD;
       
   187     }
       
   188     if (port->Close() != 0)
       
   189         return -1;
       
   190     return 0;
       
   191 }
       
   192 
       
   193 int cDriverHD61830::CheckSetup()
       
   194 {
       
   195     if (config->device != oldConfig->device ||
       
   196         config->port != oldConfig->port ||
       
   197         config->width != oldConfig->width ||
       
   198         config->height != oldConfig->height)
       
   199     {
       
   200         DeInit();
       
   201         Init();
       
   202         return 0;
       
   203     }
       
   204 
       
   205     if (config->upsideDown != oldConfig->upsideDown ||
       
   206         config->invert != oldConfig->invert)
       
   207     {
       
   208         oldConfig->upsideDown = config->upsideDown;
       
   209         oldConfig->invert = config->invert;
       
   210         return 1;
       
   211     }
       
   212     return 0;
       
   213 }
       
   214 
       
   215 int cDriverHD61830::InitGraphic()
       
   216 {
       
   217     Write(MCNT, 0x32); // set Mode Control Register
       
   218     // DISP ON, MASTER ON, BLINK OFF, CURSOR OFF, GRAPHIC-Mode, int.Clock
       
   219     Write(CPIT, 0x07); // set Character Pitch Register
       
   220     // 8 pixels per byte
       
   221     Write(NOCH, std::max(1, (width + 7) / 8 - 1)); // set Number-Of-Characters Register
       
   222     // (width - 1) / 8 bytes per line horizontally
       
   223     Write(NOTD, std::max(1, height - 1)); // set Number-Of-Time-Divisions Register
       
   224     // height - 1
       
   225     Write(CPOS, 0x00); // set Cursor Position Register
       
   226     // optional, because we havn't enabled a cursor
       
   227     Write(DSAL, 0x00); // set Display Start Address Register (Low Order Byte)
       
   228     Write(DSAH, 0x00); // set Display Start Address Register (High Order Byte)
       
   229     Write(CACL, 0x00); // set Cursor Address Counter Register (Low Order Byte)
       
   230     Write(CACH, 0x00); // set Cursor Address Counter Register (High Order Byte)
       
   231 
       
   232     return 0;
       
   233 }
       
   234 
       
   235 void cDriverHD61830::Write(unsigned char cmd, unsigned char data)
       
   236 {
       
   237     if (useSleepInit)
       
   238         nSleepInit();
       
   239 
       
   240     // set RS high (instruction), RW low (write) and E low
       
   241     port->WriteControl(RSHI | RWLO | ENLO);
       
   242     nSleep(140 - timeForPortCmdInNs + 100 * config->adjustTiming);
       
   243 
       
   244     // Output the actual command
       
   245     port->WriteData(cmd);
       
   246 
       
   247     // set E high
       
   248     port->WriteControl(RSHI | RWLO | ENHI);
       
   249     nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
       
   250 
       
   251     // set E low
       
   252     port->WriteControl(RSHI | RWLO | ENLO);
       
   253     nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
       
   254 
       
   255 
       
   256     // set RS low (data), RW low (write) and E low
       
   257     port->WriteControl(RSLO | RWLO | ENLO);
       
   258     nSleep(140 - timeForPortCmdInNs + 100 * config->adjustTiming);
       
   259 
       
   260     // Output the actual data
       
   261     port->WriteData(data);
       
   262 
       
   263     // set E high
       
   264     port->WriteControl(RSLO | RWLO | ENHI);
       
   265     nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
       
   266 
       
   267     // set E low
       
   268     port->WriteControl(RSLO | RWLO | ENLO);
       
   269     nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
       
   270 
       
   271     switch (cmd)
       
   272     {
       
   273         case MCNT:
       
   274         case CPIT:
       
   275         case NOCH:
       
   276         case NOTD:
       
   277         case CPOS:
       
   278         case DSAL:
       
   279         case DSAH:
       
   280         case CACL:
       
   281         case CACH:
       
   282             nSleep(4000 - std::max(450l, timeForPortCmdInNs) + 100 * config->adjustTiming);
       
   283             break;
       
   284         case WDDI:
       
   285         case RDDI:
       
   286             nSleep(6000 - std::max(450l, timeForPortCmdInNs) + 100 * config->adjustTiming);
       
   287             break;
       
   288         case CBIT:
       
   289         case SBIT:
       
   290             nSleep(36000 - std::max(450l, timeForPortCmdInNs) + 100 * config->adjustTiming);
       
   291             break;
       
   292     }
       
   293     if (useSleepInit)
       
   294         nSleepDeInit();
       
   295 }
       
   296 
       
   297 void cDriverHD61830::Clear()
       
   298 {
       
   299     for (int x = 0; x < (width + 7) / 8; x++)
       
   300         memset(newLCD[x], 0, height);
       
   301 }
       
   302 
       
   303 void cDriverHD61830::Set8Pixels(int x, int y, unsigned char data)
       
   304 {
       
   305     if (x >= width || y >= height)
       
   306         return;
       
   307 
       
   308     if (!config->upsideDown)
       
   309     {
       
   310         // normal orientation
       
   311         newLCD[x / 8][y] = newLCD[x / 8][y] | ReverseBits(data);
       
   312     }
       
   313     else
       
   314     {
       
   315         // upside down orientation
       
   316         x = width - 1 - x;
       
   317         y = height - 1 - y;
       
   318         newLCD[x / 8][y] = newLCD[x / 8][y] | data;
       
   319     }
       
   320 }
       
   321 
       
   322 void cDriverHD61830::Refresh(bool refreshAll)
       
   323 {
       
   324     int x;
       
   325     int y;
       
   326     int pos = 0;
       
   327 
       
   328     if (CheckSetup() > 0)
       
   329         refreshAll = true;
       
   330 
       
   331     if (config->refreshDisplay > 0)
       
   332     {
       
   333         refreshCounter = (refreshCounter + 1) % config->refreshDisplay;
       
   334         if (!refreshAll && !refreshCounter)
       
   335             refreshAll = true;
       
   336     }
       
   337 
       
   338     port->Claim();
       
   339 
       
   340     if (refreshAll)
       
   341     {
       
   342         // draw all
       
   343 
       
   344         for (y = 0; y < height; y++)
       
   345         {
       
   346             for (x = 0; x < (width + 7) / 8; x++)
       
   347             {
       
   348                 // (re-setting the cursor position
       
   349                 //  might be removed, when the graphic glitches are solved)
       
   350                 Write(CACL, (pos % 0x100));
       
   351                 Write(CACH, (pos / 0x100));
       
   352                 Write(WDDI, (newLCD[x][y]) ^ (config->invert ? 0xff : 0x00));
       
   353                 oldLCD[x][y] = newLCD[x][y];
       
   354                 pos++;
       
   355             }
       
   356         }
       
   357         // and reset RefreshCounter
       
   358         refreshCounter = 0;
       
   359     }
       
   360     else
       
   361     {
       
   362         // draw only the changed bytes
       
   363 
       
   364         bool cs = false;
       
   365         for (y = 0; y < height; y++)
       
   366         {
       
   367             for (x = 0; x < (width + 7) / 8; x++)
       
   368             {
       
   369                 if (newLCD[x][y] != oldLCD[x][y])
       
   370                 {
       
   371                     if (!cs)
       
   372                     {
       
   373                         Write(CACL, (pos % 0x100));
       
   374                         Write(CACH, (pos / 0x100));
       
   375                         cs = true;
       
   376                     }
       
   377                     Write(WDDI, (newLCD[x][y]) ^ (config->invert ? 0xff : 0x00));
       
   378                     oldLCD[x][y] = newLCD[x][y];
       
   379                 }
       
   380                 else
       
   381                 {
       
   382                     cs = false;
       
   383                 }
       
   384                 pos++;
       
   385             }
       
   386         }
       
   387     }
       
   388     port->Release();
       
   389 }
       
   390 
       
   391 } // end of namespace