graphlcd-base/glcddrivers/sed1520.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
 * sed1520.c  -  SED1520 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) 2003 Andreas 'randy' Weinberger <vdr AT smue.org>
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 "port.h"
root@4
    18
#include "sed1520.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
const unsigned char kSEAD = 0x00; // Set (X) Column Address
root@4
    26
const unsigned char kSEPA = 0xb8; // Set (Y) Page Address
root@4
    27
const unsigned char kSEDS = 0xc0;  // Set Display Start Line
root@4
    28
const unsigned char kDION = 0xaf; // Display on
root@4
    29
const unsigned char kDIOF = 0xae; // Display off
root@4
    30
root@4
    31
// control bits for DirectIO
root@4
    32
#define CE1     0x01
root@4
    33
#define CE1HI   0x01  // Chip Enable 1 on
root@4
    34
#define CE1LO   0x00  // Chip Enable 1 off
root@4
    35
root@4
    36
const unsigned char kCS1HI = 0x00; // Chip Select 1
root@4
    37
const unsigned char kCS1LO = 0x01;
root@4
    38
const unsigned char kCS2HI = 0x04; // Chip Select 2
root@4
    39
const unsigned char kCS2LO = 0x00;
root@4
    40
const unsigned char kCDHI  = 0x08; // Command/Data Register Select
root@4
    41
const unsigned char kCDLO  = 0x00;
root@4
    42
const unsigned char kLEDHI = 0x02; // LED Backlight (not supported currently)
root@4
    43
const unsigned char kLEDLO = 0x00;
root@4
    44
root@4
    45
root@4
    46
cDriverSED1520::cDriverSED1520(cDriverConfig * config)
root@4
    47
:   config(config)
root@4
    48
{
root@4
    49
    oldConfig = new cDriverConfig(*config);
root@4
    50
root@4
    51
    port = new cParallelPort();
root@4
    52
root@4
    53
    refreshCounter = 0;
root@4
    54
}
root@4
    55
root@4
    56
cDriverSED1520::~cDriverSED1520()
root@4
    57
{
root@4
    58
    delete port;
root@4
    59
    delete oldConfig;
root@4
    60
}
root@4
    61
root@4
    62
int cDriverSED1520::Init()
root@4
    63
{
root@4
    64
    int x;
root@4
    65
    int i;
root@4
    66
    struct timeval tv1, tv2;
root@4
    67
root@4
    68
    if (!(config->width % 8) == 0) {
root@4
    69
        width = config->width + (8 - (config->width % 8));
root@4
    70
    } else {
root@4
    71
        width = config->width;
root@4
    72
    }
root@4
    73
root@4
    74
    if (!(config->height % 8) == 0) {
root@4
    75
        height = config->height + (8 - (config->height % 8));
root@4
    76
    } else {
root@4
    77
        height = config->height;
root@4
    78
    }
root@4
    79
root@4
    80
    if (width <= 0)
root@4
    81
        width = 120;
root@4
    82
    if (height <= 0)
root@4
    83
        height = 32;
root@4
    84
root@4
    85
    SEAD = kSEAD;
root@4
    86
    SEPA = kSEPA;
root@4
    87
    SEDS = kSEDS;
root@4
    88
    DION = kDION;
root@4
    89
    DIOF = kDIOF;
root@4
    90
    LED  = kLEDHI;
root@4
    91
    CDHI = kCDHI;
root@4
    92
    CDLO = kCDLO;
root@4
    93
    CS1HI = kCS1HI;
root@4
    94
    CS1LO = kCS1LO;
root@4
    95
    CS2HI = kCS2HI;
root@4
    96
    CS2LO = kCS2LO;
root@4
    97
root@4
    98
    for (unsigned int i = 0; i < config->options.size(); i++)
root@4
    99
    {
root@4
   100
        if (config->options[i].name == "")
root@4
   101
        {
root@4
   102
        }
root@4
   103
    }
root@4
   104
root@4
   105
    // setup linear lcd array
root@4
   106
    LCD = new unsigned char *[(width + 7) / 8];
root@4
   107
    if (LCD)
root@4
   108
    {
root@4
   109
        for (x = 0; x < (width + 7) / 8; x++)
root@4
   110
        {
root@4
   111
            LCD[x] = new unsigned char[height];
root@4
   112
            memset(LCD[x], 0, height);
root@4
   113
        }
root@4
   114
    }
root@4
   115
    // setup the lcd array for the paged sed1520
root@4
   116
    LCD_page = new unsigned char *[width];
root@4
   117
    if (LCD_page)
root@4
   118
    {
root@4
   119
        for (x = 0; x < width; x++)
root@4
   120
        {
root@4
   121
            LCD_page[x] = new unsigned char[(height + 7) / 8];
root@4
   122
            memset(LCD_page[x], 0, (height + 7) / 8);
root@4
   123
        }
root@4
   124
    }
root@4
   125
root@4
   126
    if (config->device == "")
root@4
   127
    {
root@4
   128
        // use DirectIO
root@4
   129
        if (port->Open(config->port) != 0)
root@4
   130
            return -1;
root@4
   131
        uSleep(10);
root@4
   132
    }
root@4
   133
    else
root@4
   134
    {
root@4
   135
        // use ppdev
root@4
   136
        if (port->Open(config->device.c_str()) != 0)
root@4
   137
            return -1;
root@4
   138
    }
root@4
   139
root@4
   140
    if (nSleepInit() != 0)
root@4
   141
    {
root@4
   142
        syslog(LOG_DEBUG, "%s: INFO: cannot change wait parameters (cDriver::Init)\n", config->name.c_str());
root@4
   143
        useSleepInit = false;
root@4
   144
    }
root@4
   145
    else
root@4
   146
    {
root@4
   147
        useSleepInit = true;
root@4
   148
    }
root@4
   149
root@4
   150
    syslog(LOG_DEBUG, "%s: benchmark started.\n", config->name.c_str());
root@4
   151
    gettimeofday(&tv1, 0);
root@4
   152
    for (i = 0; i < 1000; i++)
root@4
   153
    {
root@4
   154
        port->WriteData(i % 0x100);
root@4
   155
    }
root@4
   156
    gettimeofday(&tv2, 0);
root@4
   157
    if (useSleepInit)
root@4
   158
        nSleepDeInit();
root@4
   159
    timeForPortCmdInNs = (tv2.tv_sec - tv1.tv_sec) * 1000000 + (tv2.tv_usec - tv1.tv_usec);
root@4
   160
    syslog(LOG_DEBUG, "%s: benchmark stopped. Time for Command: %ldns\n", config->name.c_str(), timeForPortCmdInNs);
root@4
   161
root@4
   162
    // initialize graphic mode
root@4
   163
    InitGraphic();
root@4
   164
root@4
   165
    port->Release();
root@4
   166
root@4
   167
    *oldConfig = *config;
root@4
   168
root@4
   169
    // clear display
root@4
   170
    Clear();
root@4
   171
root@4
   172
    syslog(LOG_INFO, "%s: SED1520 initialized.\n", config->name.c_str());
root@4
   173
    return 0;
root@4
   174
}
root@4
   175
root@4
   176
int cDriverSED1520::DeInit()
root@4
   177
{
root@4
   178
    int x;
root@4
   179
root@4
   180
    // free linear lcd array
root@4
   181
    if (LCD)
root@4
   182
    {
root@4
   183
        for (x = 0; x < (width + 7) / 8; x++)
root@4
   184
        {
root@4
   185
            delete[] LCD[x];
root@4
   186
        }
root@4
   187
        delete[] LCD;
root@4
   188
    }
root@4
   189
    // free the lcd array for the paged sed1520
root@4
   190
    if (LCD_page)
root@4
   191
    {
root@4
   192
        for (x = 0; x < width; x++)
root@4
   193
        {
root@4
   194
            delete[] LCD_page[x];
root@4
   195
        }
root@4
   196
        delete[] LCD_page;
root@4
   197
    }
root@4
   198
root@4
   199
    if (port->Close() != 0)
root@4
   200
        return -1;
root@4
   201
    return 0;
root@4
   202
}
root@4
   203
root@4
   204
int cDriverSED1520::CheckSetup()
root@4
   205
{
root@4
   206
    if (config->device != oldConfig->device ||
root@4
   207
        config->port != oldConfig->port ||
root@4
   208
        config->width != oldConfig->width ||
root@4
   209
        config->height != oldConfig->height)
root@4
   210
    {
root@4
   211
        DeInit();
root@4
   212
        Init();
root@4
   213
        return 0;
root@4
   214
    }
root@4
   215
root@4
   216
    if (config->upsideDown != oldConfig->upsideDown ||
root@4
   217
        config->invert != oldConfig->invert)
root@4
   218
    {
root@4
   219
        oldConfig->upsideDown = config->upsideDown;
root@4
   220
        oldConfig->invert = config->invert;
root@4
   221
        return 1;
root@4
   222
    }
root@4
   223
    return 0;
root@4
   224
}
root@4
   225
root@4
   226
int cDriverSED1520::InitGraphic()
root@4
   227
{
root@4
   228
    // initialize controller1, set display start 0, set page 0, set y address 0, display on
root@4
   229
    SED1520Cmd(SEDS, 1);
root@4
   230
    SED1520Cmd(SEPA, 1);
root@4
   231
    SED1520Cmd(SEAD, 1);
root@4
   232
    SED1520Cmd(DION, 1);
root@4
   233
root@4
   234
    // initialize controller2, set display start 0, set page 0, set y address 0, display on
root@4
   235
    SED1520Cmd(SEDS, 2);
root@4
   236
    SED1520Cmd(SEPA, 2);
root@4
   237
    SED1520Cmd(SEAD, 2);
root@4
   238
    SED1520Cmd(DION, 2);
root@4
   239
root@4
   240
    return 0;
root@4
   241
}
root@4
   242
root@4
   243
void cDriverSED1520::SED1520Cmd(unsigned char data, int cmdcs)
root@4
   244
{
root@4
   245
    if (useSleepInit)
root@4
   246
        nSleepInit();
root@4
   247
root@4
   248
    switch (cmdcs)
root@4
   249
    {
root@4
   250
        case 1:
root@4
   251
            port->WriteControl(CDHI | CS1LO | CS2LO | LEDHI);
root@4
   252
            nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
root@4
   253
            port->WriteData(data);
root@4
   254
            nSleep(650 - timeForPortCmdInNs + 100 * config->adjustTiming);
root@4
   255
            port->WriteControl(CDHI | CS1HI | CS2LO | LEDHI);
root@4
   256
            nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
root@4
   257
            break;
root@4
   258
        case 2:
root@4
   259
            port->WriteControl(CDHI | CS1LO | CS2LO | LED);
root@4
   260
            nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
root@4
   261
            port->WriteData(data);
root@4
   262
            nSleep(650 - timeForPortCmdInNs + 100 * config->adjustTiming);
root@4
   263
            port->WriteControl(CDHI | CS1LO | CS2HI | LED);
root@4
   264
            nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
root@4
   265
            break;
root@4
   266
    }
root@4
   267
    if (useSleepInit)
root@4
   268
        nSleepDeInit();
root@4
   269
}
root@4
   270
root@4
   271
void cDriverSED1520::SED1520Data(unsigned char data, int datacs)
root@4
   272
{
root@4
   273
    if (useSleepInit)
root@4
   274
        nSleepInit();
root@4
   275
root@4
   276
    switch (datacs)
root@4
   277
    {
root@4
   278
        case 1:
root@4
   279
            port->WriteControl(CDLO | CS1LO | CS2LO | LEDHI);
root@4
   280
            nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
root@4
   281
            port->WriteData(data);
root@4
   282
            nSleep(650 - timeForPortCmdInNs + 100 * config->adjustTiming);
root@4
   283
            port->WriteControl(CDLO | CS1HI | CS2LO | LEDHI);
root@4
   284
            nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
root@4
   285
            break;
root@4
   286
        case 2:
root@4
   287
            port->WriteControl(CDLO | CS1LO | CS2LO | LED);
root@4
   288
            nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
root@4
   289
            port->WriteData(data);
root@4
   290
            nSleep(650 - timeForPortCmdInNs + 100 * config->adjustTiming);
root@4
   291
            port->WriteControl(CDLO | CS1LO | CS2HI | LED);
root@4
   292
            nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming);
root@4
   293
            break;
root@4
   294
    }
root@4
   295
    if (useSleepInit)
root@4
   296
        nSleepDeInit();
root@4
   297
}
root@4
   298
root@4
   299
void cDriverSED1520::Clear()
root@4
   300
{
root@4
   301
    for (int x = 0; x < (width + 7) / 8; x++)
root@4
   302
        memset(LCD[x], 0, height);
root@4
   303
}
root@4
   304
root@4
   305
void cDriverSED1520::Set8Pixels (int x, int y, unsigned char data)
root@4
   306
{
root@4
   307
    if (x >= width || y >= height)
root@4
   308
        return;
root@4
   309
root@4
   310
    if (!config->upsideDown)
root@4
   311
    {
root@4
   312
        // normal orientation
root@4
   313
        LCD[x / 8][y] = LCD[x / 8][y] | data;
root@4
   314
    }
root@4
   315
    else
root@4
   316
    {
root@4
   317
        // upside down orientation
root@4
   318
        x = width - 1 - x;
root@4
   319
        y = height - 1 - y;
root@4
   320
        LCD[x / 8][y] = LCD[x / 8][y] | ReverseBits(data);
root@4
   321
    }
root@4
   322
}
root@4
   323
root@4
   324
void cDriverSED1520::Refresh(bool refreshAll)
root@4
   325
{
root@4
   326
    int x,y,xx,yy;
root@4
   327
    unsigned char dByte, oneBlock[8];
root@4
   328
root@4
   329
    if (CheckSetup() > 0)
root@4
   330
        refreshAll = true;
root@4
   331
root@4
   332
    if (config->refreshDisplay > 0)
root@4
   333
    {
root@4
   334
        refreshCounter = (refreshCounter + 1) % config->refreshDisplay;
root@4
   335
        if (!refreshAll && !refreshCounter)
root@4
   336
            refreshAll = true;
root@4
   337
    }
root@4
   338
root@4
   339
    refreshAll = true; // differential update is not yet supported
root@4
   340
root@4
   341
    if (refreshAll)
root@4
   342
    {
root@4
   343
        // draw all
root@4
   344
root@4
   345
        // convert the linear lcd array to the paged array for the display
root@4
   346
        for (y = 0; y < (height + 7) / 8; y++)
root@4
   347
        {
root@4
   348
            for (x = 0; x < (width + 7) / 8; x++)
root@4
   349
            {
root@4
   350
                for (yy = 0; yy < 8; yy++)
root@4
   351
                {
root@4
   352
                    oneBlock[yy] = LCD[x][yy + (y * 8)] ^ (config->invert ? 0xff : 0x00);
root@4
   353
                }
root@4
   354
                for (xx = 0; xx < 8; xx++)
root@4
   355
                {
root@4
   356
                    dByte = 0;
root@4
   357
                    for (yy = 0; yy < 8; yy++)
root@4
   358
                    {
root@4
   359
                        if (oneBlock[yy] & bitmask[xx])
root@4
   360
                        {
root@4
   361
                            dByte += (1 << yy);
root@4
   362
                        }
root@4
   363
                    }
root@4
   364
                    LCD_page[x * 8 + xx][y] = dByte;
root@4
   365
                }
root@4
   366
            }
root@4
   367
        }
root@4
   368
root@4
   369
        port->Claim();
root@4
   370
root@4
   371
        // send lcd_soll data to display, controller 1
root@4
   372
        // set page and start address
root@4
   373
        for (y = 0; y < (height + 7) / 8; y++)
root@4
   374
        {
root@4
   375
            SED1520Cmd(SEAD, 1);
root@4
   376
            SED1520Cmd(SEPA + y, 1);
root@4
   377
            SED1520Data(0x00 ^ (config->invert ? 0xff : 0x00), 1); // fill first row with zero
root@4
   378
root@4
   379
            for (x = 0; x < width / 2 + 1; x++)
root@4
   380
            {
root@4
   381
                SED1520Data(LCD_page[x][y], 1);
root@4
   382
            }
root@4
   383
root@4
   384
            SED1520Cmd(SEAD, 2);
root@4
   385
            SED1520Cmd(SEPA + y, 2);
root@4
   386
root@4
   387
            for (x = width / 2; x < width; x++)
root@4
   388
            {
root@4
   389
                SED1520Data(LCD_page[x][y], 2);
root@4
   390
            }
root@4
   391
root@4
   392
            SED1520Data(0x00 ^ (config->invert ? 0xff : 0x00), 2); // fill last row with zero
root@4
   393
        }
root@4
   394
        port->Release();
root@4
   395
    }
root@4
   396
    else
root@4
   397
    {
root@4
   398
        // draw only the changed bytes
root@4
   399
    }
root@4
   400
}
root@4
   401
root@4
   402
} // end of namespace