diff options
Diffstat (limited to 'glcddrivers/sed1330.c')
-rw-r--r-- | glcddrivers/sed1330.c | 630 |
1 files changed, 630 insertions, 0 deletions
diff --git a/glcddrivers/sed1330.c b/glcddrivers/sed1330.c new file mode 100644 index 0000000..34b1c74 --- /dev/null +++ b/glcddrivers/sed1330.c @@ -0,0 +1,630 @@ +/* + * GraphLCD driver library + * + * sed1330.c - SED1330 driver class + * + * based on: hd61830.c + * (c) 2001-2004 Carsten Siebholz <c.siebholz AT t-online.de> + * + * changes for Seiko-Epson displays: Mar 2004 + * (c) 2004 Heinz Gressenberger <heinz.gressenberger AT stmk.gv.at> + * + * init sequence taken from Thomas Baumann's LCD-Test program + * + * This file is released under the GNU General Public License. Refer + * to the COPYING file distributed with this package. + * + * (c) 2003 Roland Praml <praml.roland AT t-online.de> + */ + +#include <syslog.h> +#include <sys/time.h> + +#include "common.h" +#include "config.h" +#include "port.h" +#include "sed1330.h" + + +namespace GLCD +{ + +// SED1330 Commands + +// Command Codes, Bytes for Param + +#define C_SYSTEMSET 0x40 +#define C_SLEEPIN 0x53 +#define C_DISPON 0x59 +#define C_DISPOFF 0x58 +#define C_SCROLL 0x44 +#define C_CSRFORM 0x5D +#define C_CGRAMADR 0x5C +#define C_CSRDIR_R 0x4C +#define C_CSRDIR_L 0x4D +#define C_CSRDIR_U 0x4E +#define C_CSRDIR_D 0x4F +#define C_HDOTSCR 0x5A +#define C_OVLAY 0x5B +#define C_CSRW 0x46 +#define C_CSRR 0x47 +#define C_MWRITE 0x42 +#define C_MREAD 0x43 + +#define M0 0 +// 0-internal CG ROM, 1-external CG-ROM/RAM + +#define M1 0 +// 0 - 32 char CG-RAM, 1 - 64 char + +#define M2 0 +// 0 - 8x8, 1 - 8x16 matrix in CG-RAM/ROM + +#define FX 8 +// character-with +#define FY 8 +// character-height +#define BPC 1 +// byte per character, 1 - FX<=8, 2 - FX=9..16 + +#define SAD1 0x0000 +// startadress first screen + + +const int kInterface6800 = 0; +const int kInterface8080 = 1; + +const std::string kWiringOriginal = "Original"; +const std::string kWiringPowerLCD = "PowerLCD"; +const std::string kWiringLCDProc = "LCDProc"; +const std::string kWiringTweakers = "Tweakers"; +const std::string kWiringYASEDW = "YASEDW"; + +const unsigned char kOriginalA0HI = kInitHigh; +const unsigned char kOriginalA0LO = kInitLow; +const unsigned char kOriginalRDHI = kStrobeHigh; +const unsigned char kOriginalRDLO = kStrobeLow; +const unsigned char kOriginalWRHI = kAutoHigh; +const unsigned char kOriginalWRLO = kAutoLow; +const unsigned char kOriginalCSHI = kSelectHigh; +const unsigned char kOriginalCSLO = kSelectLow; + +const unsigned char kPowerLCDA0HI = kInitHigh; +const unsigned char kPowerLCDA0LO = kInitLow; +const unsigned char kPowerLCDRDHI = kSelectHigh; +const unsigned char kPowerLCDRDLO = kSelectLow; +const unsigned char kPowerLCDWRHI = kStrobeHigh; +const unsigned char kPowerLCDWRLO = kStrobeLow; +const unsigned char kPowerLCDCSHI = kAutoHigh; +const unsigned char kPowerLCDCSLO = kAutoLow; + +const unsigned char kLCDProcA0HI = kSelectHigh; +const unsigned char kLCDProcA0LO = kSelectLow; +const unsigned char kLCDProcRDHI = kInitHigh; +const unsigned char kLCDProcRDLO = kInitLow; +const unsigned char kLCDProcWRHI = kAutoHigh; +const unsigned char kLCDProcWRLO = kAutoLow; +const unsigned char kLCDProcCSHI = kStrobeHigh; +const unsigned char kLCDProcCSLO = kStrobeLow; + +const unsigned char kTweakersA0HI = kSelectHigh; +const unsigned char kTweakersA0LO = kSelectLow; +const unsigned char kTweakersRDHI = kAutoHigh; +const unsigned char kTweakersRDLO = kAutoLow; +const unsigned char kTweakersWRHI = kInitHigh; +const unsigned char kTweakersWRLO = kInitLow; +const unsigned char kTweakersCSHI = kStrobeHigh; +const unsigned char kTweakersCSLO = kStrobeLow; + +const unsigned char kYASEDWA0HI = kAutoHigh; +const unsigned char kYASEDWA0LO = kAutoLow; +const unsigned char kYASEDWRDHI = kInitHigh; +const unsigned char kYASEDWRDLO = kInitLow; +const unsigned char kYASEDWWRHI = kStrobeHigh; +const unsigned char kYASEDWWRLO = kStrobeLow; +const unsigned char kYASEDWCSHI = kSelectHigh; +const unsigned char kYASEDWCSLO = kSelectLow; + + +cDriverSED1330::cDriverSED1330(cDriverConfig * config) +: config(config) +{ + oldConfig = new cDriverConfig(*config); + + port = new cParallelPort(); + + refreshCounter = 0; +} + +cDriverSED1330::~cDriverSED1330() +{ + delete port; + delete oldConfig; +} + +int cDriverSED1330::Init() +{ + int x; + struct timeval tv1, tv2; + + width = config->width; + if (width <= 0) + width = 320; + height = config->height; + if (height <= 0) + height = 240; + + // default values + oscillatorFrequency = 9600; + interface = kInterface6800; + A0HI = kOriginalA0HI; + A0LO = kOriginalA0LO; + RDHI = kOriginalRDHI; + RDLO = kOriginalRDLO; + WRHI = kOriginalWRHI; + WRLO = kOriginalWRLO; + CSHI = kOriginalCSHI; + CSLO = kOriginalCSLO; + ENHI = RDHI; + ENLO = RDLO; + RWHI = WRHI; + RWLO = WRLO; + + for (unsigned int i = 0; i < config->options.size(); i++) + { + if (config->options[i].name == "Wiring") + { + if (config->options[i].value == kWiringOriginal) + { + A0HI = kOriginalA0HI; + A0LO = kOriginalA0LO; + RDHI = kOriginalRDHI; + RDLO = kOriginalRDLO; + WRHI = kOriginalWRHI; + WRLO = kOriginalWRLO; + CSHI = kOriginalCSHI; + CSLO = kOriginalCSLO; + } + else if (config->options[i].value == kWiringPowerLCD) + { + A0HI = kPowerLCDA0HI; + A0LO = kPowerLCDA0LO; + RDHI = kPowerLCDRDHI; + RDLO = kPowerLCDRDLO; + WRHI = kPowerLCDWRHI; + WRLO = kPowerLCDWRLO; + CSHI = kPowerLCDCSHI; + CSLO = kPowerLCDCSLO; + } + else if (config->options[i].value == kWiringLCDProc) + { + A0HI = kLCDProcA0HI; + A0LO = kLCDProcA0LO; + RDHI = kLCDProcRDHI; + RDLO = kLCDProcRDLO; + WRHI = kLCDProcWRHI; + WRLO = kLCDProcWRLO; + CSHI = kLCDProcCSHI; + CSLO = kLCDProcCSLO; + } + else if (config->options[i].value == kWiringTweakers) + { + A0HI = kTweakersA0HI; + A0LO = kTweakersA0LO; + RDHI = kTweakersRDHI; + RDLO = kTweakersRDLO; + WRHI = kTweakersWRHI; + WRLO = kTweakersWRLO; + CSHI = kTweakersCSHI; + CSLO = kTweakersCSLO; + } + else if (config->options[i].value == kWiringYASEDW) + { + A0HI = kYASEDWA0HI; + A0LO = kYASEDWA0LO; + RDHI = kYASEDWRDHI; + RDLO = kYASEDWRDLO; + WRHI = kYASEDWWRHI; + WRLO = kYASEDWWRLO; + CSHI = kYASEDWCSHI; + CSLO = kYASEDWCSLO; + } + else + { + syslog(LOG_ERR, "%s error: wiring %s not supported, using default (Original)!\n", + config->name.c_str(), config->options[i].value.c_str()); + } + ENHI = RDHI; + ENLO = RDLO; + RWHI = WRHI; + RWLO = WRLO; + } + else if (config->options[i].name == "OscillatorFrequency") + { + int freq = atoi(config->options[i].value.c_str()); + if (freq > 1000 && freq < 15000) + oscillatorFrequency = freq; + else + syslog(LOG_ERR, "%s error: oscillator frequency %d out of range, using default (%d)!\n", + config->name.c_str(), freq, oscillatorFrequency); + } + if (config->options[i].name == "Interface") + { + if (config->options[i].value == "6800") + interface = kInterface6800; + else if (config->options[i].value == "8080") + interface = kInterface8080; + else + syslog(LOG_ERR, "%s error: interface %s not supported, using default (6800)!\n", + config->name.c_str(), config->options[i].value.c_str()); + } + } + + // setup lcd array (wanted state) + newLCD = new unsigned char *[(width + 7) / 8]; + if (newLCD) + { + for (x = 0; x < (width + 7) / 8; x++) + { + newLCD[x] = new unsigned char[height]; + memset(newLCD[x], 0, height); + } + } + // setup lcd array (current state) + oldLCD = new unsigned char *[(width + 7) / 8]; + if (oldLCD) + { + for (x = 0; x < (width + 7) / 8; x++) + { + oldLCD[x] = new unsigned char[height]; + memset(oldLCD[x], 0, height); + } + } + + if (config->device == "") + { + // use DirectIO + if (port->Open(config->port) != 0) + return -1; + uSleep(10); + } + else + { + // use ppdev + if (port->Open(config->device.c_str()) != 0) + return -1; + } + + if (nSleepInit() != 0) + { + syslog(LOG_DEBUG, "%s: INFO: cannot change wait parameters (cDriver::Init)\n", config->name.c_str()); + useSleepInit = false; + } + else + { + useSleepInit = true; + } + + syslog(LOG_DEBUG, "%s: benchmark started.\n", config->name.c_str()); + gettimeofday(&tv1, 0); + for (x = 0; x < 1000; x++) + { + port->WriteData(x % 0x100); + } + gettimeofday(&tv2, 0); + if (useSleepInit) + nSleepDeInit(); + timeForPortCmdInNs = (tv2.tv_sec - tv1.tv_sec) * 1000000 + (tv2.tv_usec - tv1.tv_usec); + syslog(LOG_DEBUG, "%s: benchmark stopped. Time for Command: %ldns\n", config->name.c_str(), timeForPortCmdInNs); + + // initialize graphic mode + InitGraphic(); + + *oldConfig = *config; + + // clear display + Clear(); + // The SED1330 can have up to 64k memory. If there is less memory + // it will be overwritten twice or more times. + WriteCmd(C_MWRITE); + for (x = 0; x < 65536; x++) + WriteData(0x00); + + WriteCmd(C_CSRW); + WriteData(0x00); // initializing cursor adress, low byte + WriteData(0x00); // high byte + + port->Release(); + + syslog(LOG_INFO, "%s: SED1330 initialized.\n", config->name.c_str()); + return 0; +} + +int cDriverSED1330::DeInit() +{ + int x; + + // free lcd array (wanted state) + if (newLCD) + { + for (x = 0; x < (width + 7) / 8; x++) + { + delete[] newLCD[x]; + } + delete[] newLCD; + } + // free lcd array (current state) + if (oldLCD) + { + for (x = 0; x < (width + 7) / 8; x++) + { + delete[] oldLCD[x]; + } + delete[] oldLCD; + } + + if (port->Close() != 0) + return -1; + return 0; +} + +int cDriverSED1330::CheckSetup() +{ + if (config->device != oldConfig->device || + config->port != oldConfig->port || + config->width != oldConfig->width || + config->height != oldConfig->height) + { + DeInit(); + Init(); + return 0; + } + + if (config->upsideDown != oldConfig->upsideDown || + config->invert != oldConfig->invert) + { + oldConfig->upsideDown = config->upsideDown; + oldConfig->invert = config->invert; + return 1; + } + return 0; +} + +int cDriverSED1330::InitGraphic() +{ + // initialize setup with two graphic screens + // most parts taken from Thomas Baumann's LCD-Test program + int cr; + int memGraph; + int sad1l, sad1h, sad2l, sad2h; + + cr = (width / FX - 1) * BPC; + memGraph = ((cr + 1) * height); // required memory for a graphic layer + sad1l = SAD1 & 0xFF; + sad1h = SAD1 >> 8 & 0xFF; + sad2l = ((SAD1 + memGraph) & 0xFF); + sad2h = ((SAD1 + memGraph) >> 8 & 0xFF); + + WriteCmd(C_SYSTEMSET); + WriteData(0x30 + M0 + (M1 << 1) + (M2 << 2)); + WriteData(0x80 + (FX - 1)); + WriteData(0x00 + (FY - 1)); + WriteData(cr); // C/R .. display adresses per line + WriteData((oscillatorFrequency * 1000 / (70 * height) - 1) / 9); // TC/R .. , fFR=70Hz + WriteData(height - 1); // L/F .. display lines per screen + WriteData(cr + 1); // adresses per virtual display line, low byte + WriteData(0x00); // adresses per virtual display line, high byte + // currently we don't use virtual screens greater then the display, + // therefore the high byte should always be zero + + WriteCmd(C_SCROLL); + WriteData(sad1l); // low-byte startadress first layer + WriteData(sad1h); // high-byte startadress first layer + WriteData(height); // lines per screen + WriteData(sad2l); // low-byte startadress second layer + WriteData(sad2h); // high-byte startadress second layer + WriteData(height); // lines per screen + WriteData(0x00); // low-byte startadress third layer, not used + WriteData(0x00); // high-byte startadress third layer, not used + WriteData(0x00); // low-byte startadress fourth layer, not used + WriteData(0x00); // high-byte startadress fourth layer, not used + + WriteCmd(C_CSRFORM); + WriteData(0x00); // cursor with: 1 pixel + WriteData(0x86); // cursor height: 7 lines, block mode + + WriteCmd(C_CSRDIR_R); // automatic cursor increment to the right + + WriteCmd(C_OVLAY); + WriteData(0x0C); // two layer composition with Priority-OR + + WriteCmd(C_HDOTSCR); + WriteData(0x00); + + WriteCmd(C_DISPON); // display ON with + WriteData(0x04); // cursor OFF and first layer ON without flashing + + WriteCmd(C_CSRW); + WriteData(0x00); // initializing cursor adress, low byte + WriteData(0x00); // high byte + + return 0; +} + +void cDriverSED1330::WriteCmd(unsigned char cmd) +{ + //if (useSleepInit) + // nSleepInit(); + + if (interface == kInterface6800) + { + // set A0 high (instruction), RW low (write) and E low + port->WriteControl(A0HI | CSLO | RWLO | ENLO); + //nSleep(140 - timeForPortCmdInNs + 100 * config->adjustTiming); + // Output the actual command + port->WriteData(cmd); + //nSleep(140 - timeForPortCmdInNs + 100 * config->adjustTiming); + // set E high + port->WriteControl(A0HI | CSLO | RWLO | ENHI); + //nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming); + // set E low + port->WriteControl(A0HI | CSLO | RWLO | ENLO); + //nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming); + } + else + { + // set A0 high (instruction), CS low, RD and WR high + port->WriteControl(A0HI | CSLO | RDHI | WRHI); + //nSleep(140 - timeForPortCmdInNs + 100 * config->adjustTiming); + // Output the actual command + port->WriteData(cmd); + //nSleep(140 - timeForPortCmdInNs + 100 * config->adjustTiming); + // set WR low + port->WriteControl(A0HI | CSLO | RDHI | WRLO); + //nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming); + // set WR high + port->WriteControl(A0HI | CSLO | RDHI | WRHI); + //nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming); + } + + //if (useSleepInit) + // nSleepDeInit(); +} + +void cDriverSED1330::WriteData(unsigned char data) +{ + //if (useSleepInit) + // nSleepInit(); + + if (interface == kInterface6800) + { + // set A0 low (data), RW low (write) and E low + port->WriteControl(A0LO | CSLO | RWLO | ENLO); + //nSleep(140 - timeForPortCmdInNs + 100 * config->adjustTiming); + // Output the actual data + port->WriteData(data); + //nSleep(140 - timeForPortCmdInNs + 100 * config->adjustTiming); + // set E high + port->WriteControl(A0LO | CSLO | RWLO | ENHI); + //nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming); + // set E low + port->WriteControl(A0LO | CSLO | RWLO | ENLO); + //nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming); + } + else + { + // set A0 low (data), CS low, RD and WR high + port->WriteControl(A0LO | CSLO | RDHI | WRHI); + //nSleep(140 - timeForPortCmdInNs + 100 * config->adjustTiming); + // Output the actual data + port->WriteData(data); + //nSleep(140 - timeForPortCmdInNs + 100 * config->adjustTiming); + // set WR low + port->WriteControl(A0LO | CSLO | RDHI | WRLO); + //nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming); + // set WR high + port->WriteControl(A0LO | CSLO | RDHI | WRHI); + //nSleep(450 - timeForPortCmdInNs + 100 * config->adjustTiming); + } + + //if (useSleepInit) + // nSleepDeInit(); +} + +void cDriverSED1330::Clear() +{ + for (int x = 0; x < (width + 7) / 8; x++) + memset(newLCD[x], 0, height); +} + +void cDriverSED1330::Set8Pixels(int x, int y, unsigned char data) +{ + if (x >= width || y >= height) + return; + + if (!config->upsideDown) + { + // normal orientation + newLCD[x / 8][y] = newLCD[x / 8][y] | data; + } + else + { + // upside down orientation + x = width - 1 - x; + y = height - 1 - y; + newLCD[x / 8][y] = newLCD[x / 8][y] | ReverseBits(data); + } +} + +void cDriverSED1330::Refresh(bool refreshAll) +{ + int x; + int y; + int pos = SAD1; + + if (CheckSetup() > 0) + refreshAll = true; + + if (config->refreshDisplay > 0) + { + refreshCounter = (refreshCounter + 1) % config->refreshDisplay; + if (!refreshAll && !refreshCounter) + refreshAll = true; + } + + port->Claim(); + + if (refreshAll) + { + // draw all + // set cursor to startadress + WriteCmd(C_CSRW); + WriteData(pos & 0xFF); + WriteData(pos >> 8); + + for (y = 0; y < height; y++) + { + for (x = 0; x < (width + 7) / 8; x++) + { + WriteCmd(C_MWRITE); // cursor increments automatically + WriteData(newLCD[x][y] ^ (config->invert ? 0xff : 0x00)); + oldLCD[x][y] = newLCD[x][y]; + pos++; + } + } + // and reset RefreshCounter + refreshCounter = 0; + } + else + { + // draw only the changed bytes + bool cs = false; + for (y = 0; y < height; y++) + { + for (x = 0; x < (width + 7) / 8; x++) + { + if (newLCD[x][y] != oldLCD[x][y]) + { + if (!cs) + { + WriteCmd(C_CSRW); + WriteData(pos & 0xFF); + WriteData(pos >> 8); + WriteCmd(C_MWRITE); + cs = true; + } + WriteData(newLCD[x][y] ^ (config->invert ? 0xff : 0x00)); + oldLCD[x][y] = newLCD[x][y]; + } + else + { + cs = false; + } + pos++; + } + } + } + port->Release(); +} + +} // end of namespace |