Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
screen/EALCD.cpp
- Committer:
- richardparker
- Date:
- 2010-02-11
- Revision:
- 0:839ecbf5cb2a
- Child:
- 1:f04bcaea1d60
File content as of revision 0:839ecbf5cb2a:
// Copyright 2010 Richard Parker #include "mbed.h" #include "EALCD.h" // Register addresses. #define EALCD_DEVICE_CODE_ADDRESS 0x00 #define EALCD_TOUCH_FREQ 10000 #define EALCD_LCD_FREQ 20000000 EALCD::EALCD( PinName LED_PWM, PinName LCD_RS, PinName LCD_SO, PinName LCD_SI, PinName LCD_SCL, PinName LCD_CS, PinName TCH_CS) : _backlight(LED_PWM), _comm(LCD_SI, LCD_SO, LCD_SCL), _rs(LCD_RS), _cs(LCD_CS), _tch_cs(TCH_CS) { // Make sure not selecting either chip. _cs = 1; _tch_cs = 1; // Set the frequency of the PWM backlight to have a period ~400us. _backlight.period_us(400); // By default 40% on. setBrightness(0.4); // Set up comms, 8 bit interface. _comm.format(8); _comm.frequency(EALCD_LCD_FREQ); // Now actual initialise the connection. _initialise(); } EALCD::~EALCD() { } void EALCD::setBrightness(float percentage) { // Check the value is within the correct range. if (percentage < 0) { percentage = 0; } else if (percentage > 1) { percentage = 1; } _backlight = 1-percentage; } void EALCD::_writeToDisplay(unsigned short data) { // Set RS which is connected to DC and so when high is to data. _rs = 1; // Activate the chip (active low). _cs = 0; // Write the msb data. _comm.write(data >> 8); // Write the lsb data. _comm.write(data & 0xff); // Deactivate the chip (active low). _cs = 1; } void EALCD::_writeToRegister(unsigned short addr, unsigned short data) { // Command phase. // Set RS which is connected to DC and so when low is to command. _rs = 0; // Activate the chip (active low). _cs = 0; // Write the msb address. _comm.write(addr >> 8); // Write the lsb address. _comm.write(addr & 0xff); // Deactivate the chip (active low). _cs = 1; // Data phase. // Set RS which is connected to DC and so when high is data. _rs = 1; // Activate the chip (active low). _cs = 0; // Write the msb data. _comm.write(data >> 8); // Write the lsb data. _comm.write(data & 0xff); // Deactivate the chip (active low). _cs = 1; // Restore index to GRAM by accessing GRAM register. // Set RS which is connected to DC and so when low is to command. _rs = 0; // Activate the chip (active low). _cs = 0; // Write the msb address. _comm.write(0x00); // Write the lsb address. _comm.write(0x22); // Deactivate the chip (active low). _cs = 1; } void EALCD::_initialise() { // Start up sequence. See page 72 of SSD1289 V1.3 datasheet for reasons. _writeToRegister(0x07, 0x0021); // Oscillator on. _writeToRegister(0x00, 0x0001); _writeToRegister(0x07, 0x0723); // Exit sleep mode _writeToRegister(0x10, 0x0000); // Pause 200ms (need at least 30ms). wait(0.2); _writeToRegister(0x07, 0x0033); // Setup screen orientation and colour mode etc. _writeToRegister(0x11, 0x6828); // LCD driving waveform. _writeToRegister(0x02, 0x0600); _writeToRegister(0x0f, 0x0000); // Driver output control. _writeToRegister(0x01, 0x2b3f); _writeToRegister(0x0b, 0x5308); // Set refresh rate to 70Hz. _writeToRegister(0x25, 0xa000); } void EALCD::_moveTo(short x, short y) { // Limit movement. if (x < 0) { x = 0; } if (y < 0) { y = 0; } if (x >= width()) { x = width()-1; } if (y >= height()) { y = height()-1; } // Masking values to prevent too large. x = x & 0x1ff; _writeToRegister(0x4f, x); // Mask to get down to a sensible number. y = y & 0xff; // -1 because pixel at top of screen is 239 (as 0 indexed therefore 240 high). y = height() - 1 - y; _writeToRegister(0x4e, y); } void EALCD::_window(short x, short y, unsigned short w, unsigned short h) { // If start off screen then no need to even try drawing. if ((x >= width()) || (y >= height())) { return; } // Limit to not go off screen. if ((x + w) > width()) { w = width()-x; } if ((y + h) > height()) { h = height()-y; } // Move x and y to correct location. if (x < 0) { x = 0; } if (y < 0) { y = 0; } y = height() - 1 - y; // Vertical. unsigned short hsa = y - h + 1; unsigned short hea = y; hea = hea << 8; _writeToRegister(0x44, hsa | hea); // Horizontal unsigned short vsa = x; unsigned short vea = x + w - 1; _writeToRegister(0x45, vsa); _writeToRegister(0x46, vea); } void EALCD::_getTouch(unsigned short& x, unsigned short& y, unsigned short& z1, unsigned short& z2) { // As about to change clock freq and so data is not valid for screen disable. _cs = 1; x = 0; y = 0; z1 = 0; z2 = 0; // Set comm frequency to access touch screen. _comm.frequency(EALCD_TOUCH_FREQ); // Read the x value. // Activate the chip (active low). _tch_cs = 0; // 0x83 = Set start bit high, power mode is 2'b11 (always on). // 0x50 = Set address to 3'b101 _comm.write(0x83 | 0x50 | 0x00); // Read two bytes in, the last 3 bits are uninteresting (12 bit reading). x = _comm.write(0x00) << 8; x = x | _comm.write(0x00); x = x << 1; x = x >> 4; // Deactivate the chip (active low). _tch_cs = 1; // Read the y value. // Activate the chip (active low). _tch_cs = 0; // 0x83 = Set start bit high, power mode is 2'b11 (always on). // 0x50 = Set address to 3'b001 _comm.write(0x83 | 0x10 | 0x00); // Read two bytes in, the last 3 bits are uninteresting (12 bit reading). y = _comm.write(0x00) << 8; y = y | _comm.write(0x00); y = y << 1; y = y >> 4; // Deactivate the chip (active low). _tch_cs = 1; // Read the z1 value. // Activate the chip (active low). _tch_cs = 0; // 0x83 = Set start bit high, power mode is 2'b11 (always on). // 0x50 = Set address to 3'b011 _comm.write(0x83 | 0x30 | 0x00); // Read two bytes in, the last 3 bits are uninteresting (12 bit reading). z1 = _comm.write(0x00) << 8; z1 = z1 | _comm.write(0x00); z1 = z1 << 1; z1 = z1 >> 4; // Deactivate the chip (active low). _tch_cs = 1; // Read the z2 value. // Activate the chip (active low). _tch_cs = 0; // 0x83 = Set start bit high, power mode is 2'b11 (always on). // 0x50 = Set address to 3'b100 _comm.write(0x83 | 0x40 | 0x00); // Read two bytes in, the last 3 bits are uninteresting (12 bit reading). z2 = _comm.write(0x00) << 8; z2 = z2 | _comm.write(0x00); z2 = z2 << 1; z2 = z2 >> 4; // Deactivate the chip (active low). _tch_cs = 1; // Set comm frequency to access lcd. _comm.frequency(EALCD_LCD_FREQ); } void EALCD::_drawPoint(short x, short y, unsigned short c) { // No need to draw if off screen. if ((x >= width()) || (y >= height()) || (x < 0) || (y < 0)) { return; } // Move to the position on the screen to place the pixel. _moveTo(x, y); // Draw the pixel with the current pen value. _writeToDisplay(c); } void EALCD::_swap(short& i, short& j) { short temp = i; i = j; j = temp; } void EALCD::_draw4EllipsePoints(short cX, short cY, short x, short y, bool filled) { if (filled == true) { // line in quadrant 2 to 1. _drawLine(cX-x, cY+y, cX+x, cY+y, _brush.color().rawValue()); // Point in quadrant 3 to 4. _drawLine(cX-x, cY-y, cX+x, cY-y, _brush.color().rawValue()); } else { // Point in quadrant 1. _drawPoint(cX+x, cY+y, _pen.color().rawValue()); // Point in quadrant 2. _drawPoint(cX-x, cY+y, _pen.color().rawValue()); // Point in quadrant 3. _drawPoint(cX-x, cY-y, _pen.color().rawValue()); // Point in quadrant 4. _drawPoint(cX+x, cY-y, _pen.color().rawValue()); } } void EALCD::_drawEllipse(short x, short y, unsigned short w, unsigned short h, bool filled) { // Algorithm taken from http://homepage.smc.edu/kennedy_john/belipse.pdf short xRadius = w/2; short yRadius = h/2; short cX = x + xRadius; short cY = y + yRadius; int xChange = yRadius*yRadius*(1 - 2*xRadius); int yChange = xRadius*xRadius; int ellipseError = 0; int twoASquare = 2*xRadius*xRadius; int twoBSquare = 2*yRadius*yRadius; int stoppingX = twoBSquare*xRadius; int stoppingY = 0; x = xRadius; y = 0; while (stoppingX >= stoppingY) { // 1st set of points, y' > -1. _draw4EllipsePoints(cX, cY, x, y, filled); y += 1; stoppingY += twoASquare; ellipseError += yChange; yChange += twoASquare; if ((2*ellipseError + yChange) > 0) { x -= 1; stoppingX -= twoBSquare; ellipseError += xChange; xChange += twoBSquare; } } // 1st point set is done; start the 2nd set of points. x = 0; y = yRadius-1; xChange = yRadius*yRadius; yChange = xRadius*xRadius*(1 - 2*yRadius); ellipseError = 0; stoppingX = 0; stoppingY = twoASquare*yRadius; while (stoppingX <= stoppingY) { // 2nd set of points, y' < -1. _draw4EllipsePoints(cX, cY, x, y, filled); x += 1; stoppingX += twoBSquare; ellipseError += xChange; xChange += twoBSquare; if ((2*ellipseError + yChange) > 0) { y -= 1; stoppingY -= twoASquare; ellipseError += yChange; yChange += twoASquare; } } } void EALCD::_drawLine(short x0, short y0, short x1, short y1, unsigned short c) { // Check if can be done faster. if (y0 == y1) { // Not on screen so don't draw. if ((y0 >= height()) || (y0 < 0)) { return; } // Horizontal line. unsigned short sx = (x0 < x1) ? x0 : x1; unsigned short length = abs(x1 - x0); // Make sure not going off edge of screen. if (sx+length > width()) { length = width()-sx; } // Move to start of line and just draw. _moveTo(sx, y0); for (int i = 0; i < length; i++) { _writeToDisplay(c); } return; } // This code is from http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm - the fast section i.e. // relies on only integer maths. bool steep = (abs(y1 - y0) > abs(x1 - x0)); if (steep == true) { _swap(x0, y0); _swap(x1, y1); } if (x0 > x1) { _swap(x0, x1); _swap(y0, y1); } int deltaX = x1 - x0; int deltaY = abs(y1 - y0); int error = deltaX / 2; int yStep; int y = y0; int x = 0; if (y0 < y1) { yStep = 1; } else { yStep = -1; } // Now actually loop and draw the line. for (x = x0; x < x1; x++) { // Channge drawing if drawing horizontal or vertical. if (steep == true) { _drawPoint(y, x, c); } else { _drawPoint(x, y, c); } // Calculate the error to decide to step or not. error = error - deltaY; if (error < 0) { y = y + yStep; error = error + deltaX; } } } void EALCD::clearScreen() { // First move to the top left. _window(0, 0, width(), height()); _moveTo(0, 0); // Now fill in relying on the addresses to be automatically updated. for(int i = 0; i < (width()*height()); i++) { _writeToDisplay(_brush.color().rawValue()); } } void EALCD::drawPoint(short x, short y) { // Draw the pixel with the current pen value. _drawPoint(x, y, _pen.color().rawValue()); } void EALCD::drawLine(short x0, short y0, short x1, short y1) { _drawLine(x0, y0, x1, y1, _pen.color().rawValue()); } void EALCD::drawRect(short x, short y, unsigned short w, unsigned short h) { // Draw the top horizontal line. drawLine(x, y, x + w - 1, y); // Draw the bottom horizontal line. drawLine(x, y + h - 1, x + w - 1, y + h - 1); // Draw the left vertical line. drawLine(x, y, x, y + h - 1); // Draw the right vertical line. drawLine(x + w - 1, y, x + w - 1, y + h); } void EALCD::drawFilledRect(short x, short y, unsigned short w, unsigned short h) { if (x < 0) { x = 0; } if (y < 0) { y = 0; } // Set the window so that automatically wrap and go inside the box. _window(x, y, w, h); _moveTo(x, y); for (int i = 0; i < (w*h); i++) { _writeToDisplay(_brush.color().rawValue()); } drawRect(x, y, w, h); } void EALCD::drawEllipse(short x, short y, unsigned short w, unsigned short h) { _drawEllipse(x, y, w, h, false); } void EALCD::drawFilledEllipse(short x, short y, unsigned short w, unsigned short h) { _drawEllipse(x, y, w, h, true); _drawEllipse(x, y, w, h, false); } void EALCD::drawImage(unsigned short x, unsigned short y, EAImage& img) { // Don't try painting an invalid image. if (img.isValid() == false) { return; } // Set the position to draw. img.setX(x); img.setY(y); // Draw the image. img.paint(*this); } void EALCD::drawText(unsigned short x, unsigned short y, char* text) { // Don't try painting with an invalid font or no text if ((_font.isValid() == false) || (text == NULL)) { return; } EAImage img; EAFont::EACharacter detail; img.load(_font.path()); for (int i = 0; i < strlen(text); i++) { if (_font.getCharacter(text[i], detail) == true) { img.setX(x+detail.xOffset); img.setY(y+detail.yOffset); img.paint(*this, detail.x, detail.y, detail.width, detail.height); x += detail.xAdvance; } else { // Character is unrecognised. } } }