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