132 x 176 STN LCD Controller

HD66766.cpp

Committer:
og
Date:
2016-09-24
Revision:
0:56ce29613827

File content as of revision 0:56ce29613827:

#include "HD66766.h"
#include "glcdfont.h"

HD66766::HD66766(
    PinName rd, PinName wr, PinName rs, PinName cs, PinName rst,
    PinName d0, PinName d1, PinName d2, PinName d3,
    PinName d4, PinName d5, PinName d6, PinName d7,
    PinName d8, PinName d9, PinName d10, PinName d11,
    PinName d12, PinName d13, PinName d14, PinName d15
    ):
    _rd(rd), _wr(wr), _rs(rs), _cs(cs), _rst(rst),
    _d(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15)
{
    _width = LCDWIDTH;
    _height = LCDHEIGHT;
    
    _rd=1; 
    _wr=1;
    _rs=1;
    _cs=1;
    _rst = 1;

    cursor_y = cursor_x = 0;
    textsize = 1;
    textcolor = 0xFFFF;
 }

void HD66766::goHome(void) {
  goTo(0,0);
}

uint16_t HD66766::width(void) {
  return _width;
}
uint16_t HD66766::height(void) {
  return _height;
}
uint16_t HD66766::rb_swap(uint16_t c) {
    uint16_t rc;
    if (_rb_swap == 0) {
        rc = c;
    }
    else {
        rc =  c  & 0x07E0;
        rc |= (c >> 11) & 0x001F;
        rc |= (c & 0x001F) << 11;
    }
    return rc;
}

void HD66766::fillScreen(uint16_t color) {
    setWriteDir();
    writeRegister(0x0021, _gramstart);
    writeCommand(0x0022);
    _cs = 0;
    _rs = 1;
    _rd = 1;
    _wr = 1;
    for (int i = 0x0000; i < 0x5000; i++) {
        writeData_unsafe(rb_swap(color));
        //wait_ms(10);
    }
    _cs = 1;
}


void HD66766::drawPixel(uint16_t x, uint16_t y, uint16_t color)
{
    uint16_t AC;
    AC = (y<<8)+x + _gramstart;
    writeRegister(0x0021,AC);
    writeRegister(0x0022, rb_swap(color)); 
}

void HD66766::initDisplay(void) {
    //uint16_t a, d;
    reset();
    writeRegister(0x0000, 0x0001);
    mirror(1);
    //writeRegister(0x0001, 0x0215);  // Driver Output Control
    //writeRegister(0x0001, 0x0013);  // Driver Output Control
    writeRegister(0x0002, 0x0000); // LCD-Driving-Waveform Control
    //writeRegister(0x0003, 0x7e6c); // Power Control 1
    //writeRegister(0x0003, 0x6e78); // Power Control 1
    writeRegister(0x0003, 0x9e78); // Power Control 1
    writeRegister(0x0004, 0x0000); // Contrast Control
    //writeRegister(0x0005, 0x0030); // Entry Mode
    writeRegister(0x0005, 0x0030); // Entry Mode
    writeRegister(0x0007, 0x0003); // Display on
    writeRegister(0x000c, 0x0006); // Power Control 2
    writeRegister(0x0011, 0x0000); // Vertical Scroll Control
    writeRegister(0x0016, 0x7F00); // Set window horizontal position to top to bottom of ram address 127 to 0 (128)
    writeRegister(0x0017, 0xAF00); // Set window vertical position to top to bottom of ram address 159 to 0 (160)
    writeRegister(0x0020, 0x0000); // RAM Write Data Mask
    writeRegister(0x0021, _gramstart); // GRAM Address Set
}

void HD66766::setWriteDir(void) {
        _d.output();
}

void HD66766::setReadDir(void) {
        _d.input();
}

void HD66766::_write(uint16_t rs, uint16_t d) {
    _cs=0;
    _rd=1;
    _rs=rs;   

    _d.output();
    _d=d;
    _wr=0;
    _delay(1);
    _wr=1;

    _cs=1; 
}

void HD66766::writeData_unsafe(uint16_t d)
{
    //_d.output();
    _d = d;
    _wr = 0;
    _delay(1);
    _wr = 1;
}

void HD66766::reset(void)
{
    _rst=0;
    _delay(1000);
    _rst=1;
    _delay(1000);
 }
 
uint16_t HD66766::readData(){
    uint16_t d = 0;
    _d.input();
    _cs = 0;
    _rs = 1;
    _wr = 1;
    _rd = 1;


    _delay(1);
    _rd = 0;
    _delay(10);
    d = _d;
    _rd = 1;
    _cs = 1;
    return d;
}

uint16_t HD66766::readRegister(uint16_t addr) {
   writeCommand(addr);
   return readData();
}
void HD66766::writeRegister(uint16_t addr, uint16_t data) {
   writeCommand(addr);
   writeData(data);
}
void HD66766::goTo(uint16_t x, uint16_t y) {
    uint16_t AC;
    AC = (y<<8)+x + _gramstart;
    writeRegister(0x0021,AC);
}

void HD66766::drawVerticalLine(uint16_t x, uint16_t y, uint16_t length, uint16_t color)
{
  if (x >= _width) return;

  drawLine(x, y, x, y+length, color);
}

void HD66766::drawHorizontalLine(uint16_t x, uint16_t y, uint16_t length, uint16_t color)
{
  if (y >= _height) return;
  drawLine(x, y, x+length, y, color);
}

void HD66766::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, 
              uint16_t color) {
  // if you're in rotation 1 or 3, we need to swap the X and Y's

  int16_t steep = abs(y1 - y0) > abs(x1 - x0);
  if (steep) {
    swap(x0, y0);
    swap(x1, y1);
  }

  if (x0 > x1) {
    swap(x0, x1);
    swap(y0, y1);
  }

  int16_t dx, dy;
  dx = x1 - x0;
  //dy = abs(y1 - y0);
  dy = abs(y1 - y0);

  int16_t err = dx / 2;
  int16_t ystep;

  if (y0 < y1) {
    ystep = 1;
  } else {
    ystep = -1;}

  for (; x0<=x1; x0++) {
    if (steep) {
      drawPixel(y0, x0, color);
    } else {
      drawPixel(x0, y0, color);
    }
    err -= dy;
    if (err < 0) {
      y0 += ystep;
      err += dx;
    }
  }
}


void HD66766::drawTriangle(uint16_t x0, uint16_t y0,
              uint16_t x1, uint16_t y1,
              uint16_t x2, uint16_t y2, uint16_t color)
{
  drawLine(x0, y0, x1, y1, color);
  drawLine(x1, y1, x2, y2, color);
  drawLine(x2, y2, x0, y0, color); 
}

void HD66766::fillTriangle ( int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint16_t color)
{
  if (y0 > y1) {
    swap(y0, y1); swap(x0, x1);
  }
  if (y1 > y2) {
    swap(y2, y1); swap(x2, x1);
  }
  if (y0 > y1) {
    swap(y0, y1); swap(x0, x1);
  }

  int32_t dx1, dx2, dx3; // Interpolation deltas
  int32_t sx1, sx2, sy; // Scanline co-ordinates

  sx2=(int32_t)x0 * (int32_t)1000; // Use fixed point math for x axis values
  sx1 = sx2;
  sy=y0;

  // Calculate interpolation deltas
  if (y1-y0 > 0) dx1=((x1-x0)*1000)/(y1-y0);
    else dx1=0;
  if (y2-y0 > 0) dx2=((x2-x0)*1000)/(y2-y0);
    else dx2=0;
  if (y2-y1 > 0) dx3=((x2-x1)*1000)/(y2-y1);
    else dx3=0;

  // Render scanlines (horizontal lines are the fastest rendering method)
  if (dx1 > dx2)
  {
    for(; sy<=y1; sy++, sx1+=dx2, sx2+=dx1)
    {
      drawHorizontalLine(sx1/1000, sy, (sx2-sx1)/1000, color);
    }
    sx2 = x1*1000;
    sy = y1;
    for(; sy<=y2; sy++, sx1+=dx2, sx2+=dx3)
    {
      drawHorizontalLine(sx1/1000, sy, (sx2-sx1)/1000, color);
    }
  }
  else
  {
    for(; sy<=y1; sy++, sx1+=dx1, sx2+=dx2)
    {
      drawHorizontalLine(sx1/1000, sy, (sx2-sx1)/1000, color);
    }
    sx1 = x1*1000;
    sy = y1;
    for(; sy<=y2; sy++, sx1+=dx3, sx2+=dx2)
    {
      drawHorizontalLine(sx1/1000, sy, (sx2-sx1)/1000, color);
    }
  }
}

uint16_t HD66766::Color565(uint8_t r, uint8_t g, uint8_t b) {
    uint16_t c;
    c = r >> 3;
    c <<= 6;
    c |= g >> 2;
    c <<= 5;
    c |= b >> 3;

    //printf("%x\r\n", c);
    return c;
}

// draw a rectangle
void HD66766::drawRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, 
              uint16_t color) {
  // smarter version
  drawHorizontalLine(x, y, w, color);
  drawHorizontalLine(x, y+h-1, w, color);
  drawVerticalLine(x, y, h, color);
  drawVerticalLine(x+w-1, y, h, color);
}

// draw a rounded rectangle
void HD66766::drawRoundRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t r,
               uint16_t color) {
  // smarter version
  drawHorizontalLine(x+r, y, w-2*r, color);
  drawHorizontalLine(x+r, y+h-1, w-2*r, color);
  drawVerticalLine(x, y+r, h-2*r, color);
  drawVerticalLine(x+w-1, y+r, h-2*r, color);
  // draw four corners
  drawCircleHelper(x+r, y+r, r, 1, color);
  drawCircleHelper(x+w-r-1, y+r, r, 2, color);
  drawCircleHelper(x+w-r-1, y+h-r-1, r, 4, color);
  drawCircleHelper(x+r, y+h-r-1, r, 8, color);
}


// fill a rounded rectangle
void HD66766::fillRoundRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t r,
               uint16_t color) {
  // smarter version
  fillRect(x+r, y, w-2*r, h, color);

  // draw four corners
  fillCircleHelper(x+w-r-1, y+r, r, 1, h-2*r-1, color);
  fillCircleHelper(x+r, y+r, r, 2, h-2*r-1, color);
}

// fill a circle
void HD66766::fillCircle(uint16_t x0, uint16_t y0, uint16_t r, uint16_t color) {
  //writeRegister(TFTLCD_ENTRY_MOD, 0x1030);
  drawVerticalLine(x0, y0-r, 2*r+1, color);
  fillCircleHelper(x0, y0, r, 3, 0, color);
}


// used to do circles and roundrects!
void HD66766::fillCircleHelper(uint16_t x0, uint16_t y0, uint16_t r, uint8_t cornername, uint16_t delta,
            uint16_t color) {

  int16_t f = 1 - r;
  int16_t ddF_x = 1;
  int16_t ddF_y = -2 * r;
  int16_t x = 0;
  int16_t y = r;

  while (x<y) {
    if (f >= 0) {
      y--;
      ddF_y += 2;
      f += ddF_y;
    }
    x++;
    ddF_x += 2;
    f += ddF_x;
  
    if (cornername & 0x1) {
      drawVerticalLine(x0+x, y0-y, 2*y+1+delta, color);
      drawVerticalLine(x0+y, y0-x, 2*x+1+delta, color);
    }
    if (cornername & 0x2) {
      drawVerticalLine(x0-x, y0-y, 2*y+1+delta, color);
      drawVerticalLine(x0-y, y0-x, 2*x+1+delta, color);
    }
  }
}


// draw a circle outline

void HD66766::drawCircle(uint16_t x0, uint16_t y0, uint16_t r, 
            uint16_t color) {
  drawPixel(x0, y0+r, color);
  drawPixel(x0, y0-r, color);
  drawPixel(x0+r, y0, color);
  drawPixel(x0-r, y0, color);

  drawCircleHelper(x0, y0, r, 0xF, color);
}

void HD66766::drawCircleHelper(uint16_t x0, uint16_t y0, uint16_t r, uint8_t cornername,
            uint16_t color) {
  int16_t f = 1 - r;
  int16_t ddF_x = 1;
  int16_t ddF_y = -2 * r;
  int16_t x = 0;
  int16_t y = r;


  while (x<y) {
    if (f >= 0) {
      y--;
      ddF_y += 2;
      f += ddF_y;
    }
    x++;
    ddF_x += 2;
    f += ddF_x;
    if (cornername & 0x4) {
      drawPixel(x0 + x, y0 + y, color);
      drawPixel(x0 + y, y0 + x, color);
    } 
    if (cornername & 0x2) {
      drawPixel(x0 + x, y0 - y, color);
      drawPixel(x0 + y, y0 - x, color);
    }
    if (cornername & 0x8) {
      drawPixel(x0 - y, y0 + x, color);
      drawPixel(x0 - x, y0 + y, color);
    }
    if (cornername & 0x1) {
      drawPixel(x0 - y, y0 - x, color);
      drawPixel(x0 - x, y0 - y, color);
    }
  }
}

// fill a rectangle
void HD66766::fillRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, 
              uint16_t fillcolor) {
  // smarter version
  while (h--)
    drawHorizontalLine(x, y++, w, fillcolor);
}


void HD66766::setCursor(uint16_t x, uint16_t y) {
  cursor_x = x;
  cursor_y = y;
}

void HD66766::setTextSize(uint8_t s) {
  textsize = s;
}

void HD66766::setTextColor(uint16_t c) {
  textcolor = c;
}

size_t HD66766::println(char *c){
  while (c[0] != 0) {
    write(c[0]);
    c++;
  }
    //drawString(cursor_x, cursor_y, c, textcolor);
    return sizeof(c);
}

size_t HD66766::write(uint8_t c) {
  if (c == '\n') {
    cursor_y += textsize*8;
    cursor_x = 0;
  } else if (c == '\r') {
    // skip em
  } else {
    drawChar(cursor_x, cursor_y, c, textcolor, textsize);
    cursor_x += textsize*6;
  }
  return 0;
}

// draw a character
void HD66766::drawChar(uint16_t x, uint16_t y, char c, 
              uint16_t color, uint8_t size) {
  for (uint8_t i =0; i<5; i++ ) {
    uint8_t line = font[(c*5)+i];
    for (uint8_t j = 0; j<8; j++) {
      if (line & 0x1) {
    if (size == 1) // default size
      drawPixel(x+i, y+j, color);
    else {  // big size
      fillRect(x+i*size, y+j*size, size, size, color);
    } 
      }
      line >>= 1;
    }
  }
}

void HD66766::mirror(uint16_t d) {
    switch(d) {
        case 0: {
            _gramstart = 0x0000;
            _rb_swap = 0;
            writeRegister(0x0001, 0x0013);  // Driver Output Control
            writeRegister(0x0016, 0x7F00); // Set window horizontal position to top to bottom of ram address 127 to 0 (128)
            writeRegister(0x0017, 0xAF00); // Set window vertical position to top to bottom of ram address 159 to 0 (160)
            break;
            }
        case 1: {
            _rb_swap = 0;
            _gramstart = 0x1000;
            writeRegister(0x0001, 0x0215);  // Driver Output Control
            writeRegister(0x0016, 0x7F00); // Set window horizontal position to top to bottom of ram address 127 to 0 (128)
            writeRegister(0x0017, 0xAF00); // Set window vertical position to top to bottom of ram address 159 to 0 (160)
            break;
            }
        case 2: {
            _rb_swap = 1;
            _gramstart = 0x0004;
            writeRegister(0x0001, 0x0113);  // Driver Output Control
            writeRegister(0x0016, 0x8304); // Set window horizontal position to top to bottom of ram address 127 to 0 (128)
            writeRegister(0x0017, 0xAF00); // Set window vertical position to top to bottom of ram address 159 to 0 (160)
            break;
            }
        case 3: {
            _gramstart = 0x1004;
            _rb_swap = 1;
            writeRegister(0x0001, 0x0315);  // Driver Output Control
            writeRegister(0x0016, 0x8304); // Set window horizontal position to top to bottom of ram address 127 to 0 (128)
            writeRegister(0x0017, 0xAF00); // Set window vertical position to top to bottom of ram address 159 to 0 (160)
            break;
            }
    }
}

void HD66766::_delay(uint16_t t)
{
    //wait_us(1);
}