Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

executable file 936 lines (771 sloc) 25.807 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935
/*
glcd_Device.cpp - Arduino library support for graphic LCDs
Copyright (c) 2009, 2010 Michael Margolis and Bill Perry
vi:ts=4

This file is part of the Arduino GLCD library.

GLCD is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.

GLCD is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with GLCD. If not, see <http://www.gnu.org/licenses/>.
The glcd_Device class impliments the protocol for sending and receiving data and commands to a GLCD device.
It uses glcd_io.h to for the io primitives and glcd_Config.h for user specific configuration.

*/

#include "include/glcd_Device.h"
#include "include/glcd_io.h"

#define WriteCmd(cmd) (this->WriteCommand(cmd, 0))

// From SSD1305.h by "Andrea" with a few additions
#define SSD1305_SETLOWCOLUMN 0x00
#define SSD1305_SETHIGHCOLUMN 0x10
#define SSD1305_SETSTARTCOLUMN 0x21
#define SSD1305_SETSTARTPAGE 0x22
#define SSD1305_MEMORYMODE 0x20
#define SSD1305_SETSTARTLINE 0x40
#define SSD1305_SETCONTRAST 0x81
#define SSD1305_SEGREMAP 0xA0
#define SSD1305_SEGREMAP1 0xA1
#define SSD1305_DISPLAYALLON_RESUME 0xA4
#define SSD1305_DISPLAYALLON 0xA5
#define SSD1305_NORMALDISPLAY 0xA6
#define SSD1305_INVERTDISPLAY 0xA7
#define SSD1305_SETMULTIPLEX 0xA8
#define SSD1305_DCVOLTCONVERT 0xAD
#define SSD1305_DISPLAYOFF 0xAE
#define SSD1305_DISPLAYON 0xAF
#define SSD1305_SET_PAGE 0xB0
#define SSD1305_COMSCANDEC 0xC8
#define SSD1305_SETDISPLAYOFFSET 0xD3
#define SSD1305_SETDISPLAYCLOCKDIV 0xD5
#define SSD1305_SETPRECHARGE 0xD9
#define SSD1305_SETCOMPINS 0xDA
#define SSD1305_SETVCOMDETECT 0xDB
#define SSD1305_SET_MODIFY 0xE0
#define SSD1305_CLR_MODIFY 0xEE
#define SSD1305_NOP 0xE3

#define SSD1305_SETHORISCROLL 0x26 // Horizontal scroll setup
#define SSD1305_SETVERTSCROLL 0xA3 // Set vertical scroll area
#define SSD1305_SETCONTSCROLL 0x29 // Continuous vertical & horizontal scroll setup
#define SSD1305_CLRSCROLL 0x2E // Deactivate scroll
#define SSD1305_SETSCROLL 0x2F // Activate scroll

/*
* define the static variables declared in glcd_Device
*/

uint8_t glcd_Device::Inverted;
lcdCoord glcd_Device::Coord;

/*
* Experimental defines
*/

//#define TRUE_WRITE // does writes to glcd memory on page crossings vs ORs
// This option only affects writes that span LCD pages.
// None of the graphic rouintes nor the NEW_FONTDRAW rendering option do this.
// Only the old font rendering and bitmap rendering do unaligned PAGE writes.
// While this fixes a few issus for the old routines,
// it also creates new ones.
// The issue is routines like the bitmap rendering
// routine attempt to use a drawing method that does not work.
// when this is on, pixels are no longer ORd in but are written in.
// so all the good/desired pixels get set, but then so do some
// undesired pixels.
//
// current RECOMMENDED setting: OFF

#define GLCD_TEENSY_PCB_RESET_WAIT // turns on code to deal with slow rising reset on Teensy PCB ADAPTER
// this code is only turned on when library is compiled for teensy boards.
// The reason for this was to support a ks0108 GLCD adapter PCB for the Teensy.
// The reset signal created on that board is 250ms long
// but rises very slow so reset polling
// does not work properly. So for now the code simply does a wait of 250ms
// to give the Teensy PCB reset circuit time to clear.
//

//#define GLCD_POLL_RESET // turns on code to poll glcd module RESET signal
// While this would be optimal, it turns out that on slow
// rising reset signals to the GLCD the reset bit will clear
// in the status *before* reset to the actual glcd chips.
// this creates a situation where the code starts sending commands
// to the display prior to it being ready. And unfortunately, the first
// commands sent are to turn on the display. Since the glcd command protocol
// only has a busy bit, commands appear to work as busy will not be
// asserted during this reset "grey area".
//
// If you turn this on, additional code will be created to poll reset.
// and to work with the Teensy GLCD adapter, the blind delay for teensy is disabled
// and after reset goes away an additional 50ms will be added to work with the
// Teensy PCB.
//
// When enabled the code is 50+ bytes larger than a dumb/blind wait and it isn't
// clear if reset polling works the same across all glcds as the datasheets don't
// fully document how it works.
//
// So for now, this is disabled, and the teensy code will get a blind delay
// if the RESET_WAIT define above is turned on.

//#define GLCD_XCOL_SUPPORT //turns on code to track the hardware X/column to minimize set column commands.
// Believe it or not, the code on the ks0108s runs slower with this
// enabled.


#ifdef GLCD_READ_CACHE
/*
* Declare a static buffer for the Frame buffer for the Read Cache
*/
uint8_t glcd_rdcache[DISPLAY_HEIGHT/8][DISPLAY_WIDTH];
#endif


glcd_Device::glcd_Device(){
  
}

// ssd1305-specific initialization
void glcd_Device::glcd_DeviceInit(int chip) {

// Custom init sequence
WriteCmd(SSD1305_DISPLAYOFF); // Display = off
WriteCmd(SSD1305_DCVOLTCONVERT); // DC-DC voltage regulator =
WriteCmd(0x8A); // Disabled (8A = off, 8B = on)

WriteCmd(SSD1305_SETMULTIPLEX); // Multiplex ratio =
WriteCmd(0x3F); // 1/64

WriteCmd(SSD1305_SETDISPLAYOFFSET); // Display offset =
WriteCmd(0x00); // 0

WriteCmd(SSD1305_SETSTARTLINE); // Display start line =
WriteCmd(0x0); // 0

WriteCmd(SSD1305_COMSCANDEC); // Set common output scan direction
// to remapped mode.

// WriteCmd(0xC0); // Common output scan direction = WRONG
// WriteCmd(0xA6); // A6 = normal, A7 = reversed WRONG

// WriteCmd(SSD1305_DISPLAYALLON); // -Entire- display OFF (A4 = off, A5 = on)

// SetContrast(0xFF); // Contrast = 00 to FF

WriteCmd(SSD1305_SETDISPLAYCLOCKDIV); // Clock divider & OSC frequency =
WriteCmd(0xF0); // "max"

//WriteCmd(0x70); // Set lower column address(low nybble = 0)
WriteCmd(SSD1305_SETPRECHARGE); // Pre/Discharge period =
WriteCmd(0x00); // ?

WriteCmd(SSD1305_MEMORYMODE); // Addressing mode =
WriteCmd(0x02); // 0=Hori, 1=Vert, 2=Page

WriteCmd(SSD1305_SEGREMAP1);

//WriteCmd(SSD1305_DISPLAYON); // Display = on

// SetPixels(0, 0, DISPLAY_WIDTH-1, DISPLAY_HEIGHT-1, BLACK);
// TODO [delay 5000L NOPs]
}

/**
* set pixel at x,y to the given color
*
* @param x X coordinate, a value from 0 to GLCD.Width-1
* @param y Y coordinate, a value from 0 to GLCD.Heigh-1
* @param color WHITE or BLACK
*
* Sets the pixel at location x,y to the specified color.
* x and y are relative to the 0,0 origin of the display which
* is the upper left corner.
* Requests to set pixels outside the range of the display will be ignored.
*
* @note If the display has been set to INVERTED mode then the colors
* will be automically reversed.
*
*/

void glcd_Device::SetDot(uint8_t x, uint8_t y, uint8_t color)
{
uint8_t data;

if((x >= DISPLAY_WIDTH) || (y >= DISPLAY_HEIGHT))
return;

this->GotoXY(x, y-y%8); // read data from display memory
  
data = this->ReadData();
if(color == BLACK){
data |= 0x01 << (y%8); // set dot
} else {
data &= ~(0x01 << (y%8)); // clear dot
}
this->WriteData(data); // write data back to display
}

/**
* set an area of pixels
*
* @param x X coordinate of upper left corner
* @param y Y coordinate of upper left corner
* @param x2 X coordinate of lower right corner
* @param y2 Y coordinate of lower right corner
* @param color
*
* sets the pixels an area bounded by x,y to x2,y2 inclusive
* to the specified color.
*
* The width of the area is x2-x + 1.
* The height of the area is y2-y+1
*
*
*/

// set pixels from upper left edge x,y to lower right edge x1,y1 to the given color
// the width of the region is x1-x + 1, height is y1-y+1

void glcd_Device::SetPixels(uint8_t x, uint8_t y,uint8_t x2, uint8_t y2, uint8_t color)
{

#if 0
if(x > x2) {
uint8_t t = x2;
x2 = x;
x = t;
}

if(y > y2) {
uint8_t t = y2;
y2 = y;
y = t;
}
#endif

uint8_t mask, pageOffset, h, i, data;
uint8_t height = y2-y+1;
uint8_t width = x2-x+1;

pageOffset = y%8;
y -= pageOffset;
mask = 0xFF;
if(height < 8-pageOffset) {
mask >>= (8-height);
h = height;
} else {
h = 8-pageOffset;
}
mask <<= pageOffset;

this->GotoXY(x, y);
for(i=0; i < width; i++) {
data = this->ReadData();

if(color == BLACK) {
data |= mask;
} else {
data &= ~mask;
}

this->WriteData(data);
}

while(h+8 <= height) {
h += 8;
y += 8;
this->GotoXY(x, y);

for(i=0; i <width; i++) {
this->WriteData(color);
}
}

if(h < height) {
mask = ~(0xFF << (height-h));
this->GotoXY(x, y+8);

for(i=0; i < width; i++) {
data = this->ReadData();

if(color == BLACK) {
data |= mask;
} else {
data &= ~mask;
}

this->WriteData(data);
}
}
}

/**
* set current x,y coordinate on display device
*
* @param x X coordinate
* @param y Y coordinate
*
* Sets the current pixel location to x,y.
* x and y are relative to the 0,0 origin of the display which
* is the upper left most pixel on the display.
*/

#if 0
void glcd_Device::GotoXY(uint8_t x, uint8_t y)
{
  uint8_t chip, cmd;

  if((x == this->Coord.x) && (y == this->Coord.y))
return;

  if( (x > DISPLAY_WIDTH-1) || (y > DISPLAY_HEIGHT-1) ) // exit if coordinates are not legal
  {
    return;
  }

  this->Coord.x = x; // save new coordinates
  this->Coord.y = y;

  chip = glcd_DevXYval2Chip(x, y);

if(y/8 != this->Coord.chip[chip].page)
{
   this->Coord.chip[chip].page = y/8;
cmd = LCD_SET_PAGE | this->Coord.chip[chip].page;
this->WriteCommand(cmd, chip);
}

/*
* NOTE: For now, the "if" below is intentionally commented out.
* In order for this to work, the code must properly track
* the x coordinate of the chips and not allow it go beyond proper
* boundaries. It isnn't complicated to do, it jsut isn't done that
* way right now.
*/

x = glcd_DevXval2ChipCol(x);

#ifdef GLCD_XCOL_SUPPORT
if(x != this->Coord.chip[chip].col)
#endif
{

#ifdef GLCD_XCOL_SUPPORT
this->Coord.chip[chip].col = x;
#endif

#ifdef LCD_SET_ADDLO
cmd = LCD_SET_ADDLO | glcd_DevCol2addrlo(x);
this->WriteCommand(cmd, chip);

cmd = LCD_SET_ADDHI | glcd_DevCol2addrhi(x);
this->WriteCommand(cmd, chip);
#else
cmd = LCD_SET_ADD | x;
this->WriteCommand(cmd, chip);
#endif
}
}
#endif


#if 1
void glcd_Device::GotoXY(uint8_t x, uint8_t y)
{
  uint8_t chip, cmd;

  if((x == this->Coord.x) && (y == this->Coord.y))
return;

  if( (x > DISPLAY_WIDTH-1) || (y > DISPLAY_HEIGHT-1) ) // exit if coordinates are not legal
  {
    return;
  }

  this->Coord.x = x; // save new coordinates
  this->Coord.y = y;

  WriteCmd(SSD1305_SETSTARTCOLUMN);
  WriteCmd(x);
  WriteCmd(DISPLAY_WIDTH - 1);
  WriteCmd(SSD1305_SET_PAGE + (y / 8));
}
#endif

/**
* Low level h/w initialization of display and AVR pins
*
* @param invert specifices whether display is in normal mode or inverted mode.
*
* This should only be called by other library code.
*
* It does all the low level hardware initalization of the display device.
*
* The optional invert parameter specifies if the display should be run in a normal
* mode, dark pixels on light background or inverted, light pixels on a dark background.
*
* To specify dark pixels use the define @b NON-INVERTED and to use light pixels use
* the define @b INVERTED
*
* Upon completion of the initialization, the entire display will be cleared
* and the x,y postion will be set to 0,0
*
*/

/*
* Note: This Initilization code can be called more than once as the user
* is free to re-initliaze the hardware.
*/

void glcd_Device::Init(uint8_t invert)
{

/*
* Now setup the pinmode for all of our control pins.
* The data lines will be configured as necessary when needed.
*/

lcdPinMode(glcdDI,OUTPUT);
lcdPinMode(glcdRW,OUTPUT);

#ifdef glcdE1
lcdPinMode(glcdE1,OUTPUT);
lcdfastWrite(glcdE1,LOW);
#endif
#ifdef glcdE2
lcdPinMode(glcdE2,OUTPUT);
lcdfastWrite(glcdE2,LOW);
#endif

#ifdef glcdEN
lcdPinMode(glcdEN,OUTPUT);
lcdfastWrite(glcdEN, LOW);
#endif

#ifdef glcdCSEL1
lcdPinMode(glcdCSEL1,OUTPUT);
lcdfastWrite(glcdCSEL1, LOW);
#endif

#ifdef glcdCSEL2
lcdPinMode(glcdCSEL2,OUTPUT);
lcdfastWrite(glcdCSEL2, LOW);
#endif

#ifdef glcdCSEL3
lcdPinMode(glcdCSEL3,OUTPUT);
lcdfastWrite(glcdCSEL3, LOW);
#endif

#ifdef glcdCSEL4
lcdPinMode(glcdCSEL4,OUTPUT);
lcdfastWrite(glcdCSEL4, LOW);
#endif

/*
* If reset control
*/
#ifdef glcdRES
lcdPinMode(glcdRES,OUTPUT);
#endif


lcdfastWrite(glcdDI, LOW);
lcdfastWrite(glcdRW, LOW);

this->Coord.x = -1; // invalidate the s/w coordinates so the first GotoXY() works
this->Coord.y = -1; // invalidate the s/w coordinates so the first GotoXY() works

this->Inverted = invert;

/*
* Reset the glcd module if there is a reset pin defined
*/
#ifdef glcdRES
lcdReset();
lcdDelayMilliseconds(2);
lcdUnReset();
lcdDelayMilliseconds(10);
#endif

#if defined(GLCD_TEENSY_PCB_RESET_WAIT) && defined(CORE_TEENSY) && !defined(GLCD_POLL_RESET)
/*
* Delay for Teensy ks0108 PCB adapter reset signal
* Reset polling is not realiable by itself so this is easier and much less code
* - see long comment above where GLCD_POLL_RESET is defined
*/
lcdDelayMilliseconds(250);
#endif

for(uint8_t chip=0; chip < glcd_CHIP_COUNT; chip++)
{
/*
* flush out internal state to force first GotoXY() to talk to GLCD hardware
*/
this->Coord.chip[chip].page = -1;
#ifdef GLCD_XCOL_SUPPORT
this->Coord.chip[chip].col = -1;
#endif

#ifdef GLCD_POLL_RESET
/*
* Wait to make sure reset is really complete
*/
this->WaitReset(chip);
lcdDelayMilliseconds(50); // extra delay for *very* slow rising reset signals
#endif

//#ifdef glcd_DeviceInit // this provides override for chip specific init - mem 8 Dec 09
        glcd_DeviceInit(chip); // call device specific initialization if defined
//#else
// #error this is not supposed to be executed
// this->WriteCommand(LCD_ON, chip); // display on
// this->WriteCommand(LCD_DISP_START, chip); // display start line = 0
//#endif

}

/*
* All hardware initialization is complete.
*
* Now, clear the screen and home the cursor to ensure that the display always starts
* in an identical state after being initialized.
*
* Note: the reason that SetPixels() below always uses WHITE, is that once the
* the invert flag is in place, the lower level read/write code will invert data
* as needed.
* So clearing an areas to WHITE when the mode is INVERTED will set the area to BLACK
* as is required.
*/

this->SetPixels(0,0, DISPLAY_WIDTH-1,DISPLAY_HEIGHT-1, WHITE);
this->GotoXY(0,0);
}

void glcd_Device::SetMUX(uint8_t num){
//WriteCmd(SSD1305_SETMULTIPLEX);
//WriteCmd(64);
//WriteCmd(SSD1305_SETSTARTLINE); // Display start line =
WriteCmd(SSD1305_SETMULTIPLEX);
WriteCmd(num);
}

void glcd_Device::SetupHScroll(){}
void glcd_Device::SetupVScroll(){}
void glcd_Device::SetupScroll(uint8_t page_beg, uint8_t page_end, int8_t vstep, int8_t hstep, uint8_t delay){
//Scroll(false);
WriteCmd(SSD1305_SETCONTSCROLL);
WriteCmd(hstep); // Horizontal scroll
WriteCmd(page_beg); // Beg page address
WriteCmd(delay); // Time interval per 6 frames
WriteCmd(page_end); // End page address
WriteCmd(vstep); // Vertical scroll
}

void glcd_Device::Scroll(bool on){
WriteCmd(on ? SSD1305_SETSCROLL : SSD1305_CLRSCROLL);
}

void glcd_Device::DisplayOn()
{
WriteCmd(SSD1305_DISPLAYON);
}

void glcd_Device::DisplayOff()
{
WriteCmd(SSD1305_DISPLAYOFF);
}

void glcd_Device::SetContrast(uint8_t value)
{
WriteCmd(SSD1305_SETCONTRAST);
WriteCmd(value);
}

#ifdef glcd_CHIP0 // if at least one chip select string
__inline__ void glcd_Device::SelectChip(uint8_t chip)
{

#ifdef glcd_CHIP3
if(chip == 3) lcdChipSelect(glcd_CHIP3); else
#endif
#ifdef glcd_CHIP2
if(chip == 2) lcdChipSelect(glcd_CHIP2); else
#endif
#ifdef glcd_CHIP1
if(chip == 1) lcdChipSelect(glcd_CHIP1); else
#endif
lcdChipSelect(glcd_CHIP0);
}
#endif

void glcd_Device::WaitReady( uint8_t chip)
{

// wait until LCD busy bit goes to zero
glcd_DevSelectChip(chip);
lcdDataDir(0x00);
lcdfastWrite(glcdDI, LOW);
lcdfastWrite(glcdRW, HIGH);
// lcdDelayNanoseconds(GLCD_tAS);
glcd_DevENstrobeHi(chip);
lcdDelayNanoseconds(GLCD_tDDR);

//while(lcdIsBusy());

glcd_DevENstrobeLo(chip);
}

#ifdef GLCD_POLL_RESET
void glcd_Device::WaitReset( uint8_t chip)
{
// wait until LCD busy bit goes to zero
glcd_DevSelectChip(chip);
lcdDataDir(0x00);
lcdfastWrite(glcdDI, LOW);
lcdfastWrite(glcdRW, HIGH);
// lcdDelayNanoseconds(GLCD_tAS);
glcd_DevENstrobeHi(chip);
lcdDelayNanoseconds(GLCD_tDDR);

while(lcdIsReset())
{
       ;
}
glcd_DevENstrobeLo(chip);
}
#endif


/*
* read a single data byte from chip
*/
uint8_t glcd_Device::DoReadData()
{
uint8_t data, chip;

chip = glcd_DevXYval2Chip(this->Coord.x, this->Coord.y);

this->WaitReady(chip);
lcdfastWrite(glcdDI, HIGH); // D/I = 1
lcdfastWrite(glcdRW, HIGH); // R/W = 1

lcdDelayNanoseconds(GLCD_tAS);
glcd_DevENstrobeHi(chip);
lcdDelayNanoseconds(GLCD_tDDR);

data = lcdDataIn(); // Read the data bits from the LCD

glcd_DevENstrobeLo(chip);
#ifdef GLCD_XCOL_SUPPORT
#error huh what
this->Coord.chip[chip].col++;
#endif
return data;
}
/**
* read a data byte from display device memory
*
* @return the data byte at the current x,y position
*
* @note the current x,y location is not modified by the routine.
* This allows a read/modify/write operation.
* Code can call ReadData() modify the data then
* call WriteData() and update the same location.
*
* @see WriteData()
*/

#ifdef GLCD_READ_CACHE
uint8_t glcd_Device::ReadData()
{
uint8_t x, data;
x = this->Coord.x;
if(x >= DISPLAY_WIDTH)
{
return(0);
}
data = glcd_rdcache[this->Coord.y/8][x];

if(this->Inverted)
{
data = ~data;
}
return(data);
}
#else

inline uint8_t glcd_Device::ReadData()
{
uint8_t x, data;


x = this->Coord.x;
if(x >= DISPLAY_WIDTH)
{
return(0);
}

this->DoReadData(); // dummy read

data = this->DoReadData(); // "real" read

if(this->Inverted)
{
data = ~data;
}

this->Coord.x = -1; // force a set column on GotoXY

this->GotoXY(x, this->Coord.y);
return(data);
}
#endif

void glcd_Device::WriteCommand(uint8_t cmd, uint8_t chip)
{
this->WaitReady(chip);
lcdfastWrite(glcdDI, LOW); // D/I = 0
lcdfastWrite(glcdRW, LOW); // R/W = 0
lcdDataDir(0xFF);

lcdDataOut(cmd); /* This could be done before or after raising E */
lcdDelayNanoseconds(GLCD_tAS);
glcd_DevENstrobeHi(chip);
lcdDelayNanoseconds(GLCD_tWH);
glcd_DevENstrobeLo(chip);
}

/**
* Write a byte to display device memory
*
* @param data date byte to write to memory
*
* The data specified is written to glcd memory at the current
* x,y position. If the y location is not on a byte boundary, the write
* is fragemented up into multiple writes.
*
* @note the full behavior of this during split byte writes
* currently varies depending on a compile time define.
* The code can be configured to either OR in 1 data bits or set all
* the data bits.
* @b TRUE_WRITE controls this behavior.
*
* @note the x,y address will not be the same as it was prior to this call.
* The y address will remain the aame but the x address will advance by one.
* This allows back to writes to write sequentially through memory without having
* to do additional x,y positioning.
*
* @see ReadData()
*
*/

void glcd_Device::WriteData(uint8_t data) {
uint8_t displayData, yOffset, chip;
//showHex("wrData",data);
    //showXY("wr", this->Coord.x,this->Coord.y);

#ifdef GLCD_DEBUG
volatile uint16_t i;
for(i=0; i<5000; i++);
#endif

if(this->Coord.x >= DISPLAY_WIDTH){
return;
}

    chip = glcd_DevXYval2Chip(this->Coord.x, this->Coord.y);

yOffset = this->Coord.y%8;

if(yOffset != 0) {
// first page
displayData = this->ReadData();
this->WaitReady(chip);
    lcdfastWrite(glcdDI, HIGH); // D/I = 1
lcdfastWrite(glcdRW, LOW); // R/W = 0
lcdDataDir(0xFF); // data port is output
lcdDelayNanoseconds(GLCD_tAS);
glcd_DevENstrobeHi(chip);
#ifdef TRUE_WRITE
/*
* Strip out bits we need to update.
*/
displayData &= (_BV(yOffset)-1);
#endif

displayData |= data << yOffset;

if(this->Inverted){
displayData = ~displayData;
}
lcdDataOut( displayData); // write data
lcdDelayNanoseconds(GLCD_tWH);
glcd_DevENstrobeLo(chip);
#ifdef GLCD_READ_CACHE
glcd_rdcache[this->Coord.y/8][this->Coord.x] = displayData; // save to read cache
#endif

// second page

/*
* Make sure to goto y address of start of next page
* and ensure that we don't fall off the bottom of the display.
*/
uint8_t ysave = this->Coord.y;
if(((ysave+8) & ~7) >= DISPLAY_HEIGHT)
{
this->GotoXY(this->Coord.x+1, ysave);
return;
}

this->GotoXY(this->Coord.x, ((ysave+8) & ~7));

displayData = this->ReadData();
this->WaitReady(chip);

    lcdfastWrite(glcdDI, HIGH); // D/I = 1
lcdfastWrite(glcdRW, LOW); // R/W = 0
lcdDataDir(0xFF); // data port is output
lcdDelayNanoseconds(GLCD_tAS);
glcd_DevENstrobeHi(chip);

#ifdef TRUE_WRITE
/*
* Strip out bits we need to update.
*/
displayData &= ~(_BV(yOffset)-1);

#endif
displayData |= data >> (8-yOffset);
if(this->Inverted){
displayData = ~displayData;
}
lcdDataOut(displayData); // write data
lcdDelayNanoseconds(GLCD_tWH);
glcd_DevENstrobeLo(chip);
#ifdef GLCD_READ_CACHE
glcd_rdcache[this->Coord.y/8][this->Coord.x] = displayData; // save to read cache
#endif
this->GotoXY(this->Coord.x+1, ysave);
}else
{
     this->WaitReady(chip);

lcdfastWrite(glcdDI, HIGH); // D/I = 1
lcdfastWrite(glcdRW, LOW); // R/W = 0
lcdDataDir(0xFF); // data port is output

// just this code gets executed if the write is on a single page
if(this->Inverted)
data = ~data;

lcdDelayNanoseconds(GLCD_tAS);
glcd_DevENstrobeHi(chip);

lcdDataOut(data); // write data

lcdDelayNanoseconds(GLCD_tWH);

glcd_DevENstrobeLo(chip);
#ifdef GLCD_READ_CACHE
glcd_rdcache[this->Coord.y/8][this->Coord.x] = data; // save to read cache
#endif

/*
* NOTE/WARNING:
* This bump can cause the s/w X coordinate to bump beyond a legal value
* for the display. This is allowed because after writing to the display
* display, the column (x coordinate) is always bumped. However,
* when writing to the the very last column, the resulting column location
* inside the hardware is somewhat undefined.
* Some chips roll it back to 0, some stop the maximu of the LCD, and others
* advance further as the chip supports more pixels than the LCD shows.
*
* So to ensure that the s/w is never indicating a column (x value) that is
* incorrect, we allow it bump beyond the end.
*
* Future read/writes will not attempt to talk to the chip until this
* condition is remedied (by a GotoXY()) and by having this somewhat
* "invalid" value, it also ensures that the next GotoXY() will always send
* both a set column and set page address to reposition the glcd hardware.
*/

this->Coord.x++;
#ifdef GLCD_XCOL_SUPPORT
this->Coord.chip[chip].col++;
#endif


/*
* Check for crossing into the next chip.
*/
if( glcd_DevXYval2Chip(this->Coord.x, this->Coord.y) != chip)
{
if(this->Coord.x < DISPLAY_WIDTH)
{
uint8_t x = this->Coord.x;
this->Coord.x = -1;
this->GotoXY(x, this->Coord.y);
}
  }
//showXY("WrData",this->Coord.x, this->Coord.y);
}
}

/*
* needed to resolve virtual print functions
*/
size_t glcd_Device::write(uint8_t) // for Print base class
{

}
Something went wrong with that request. Please try again.