Class Module for EA DOGS102 Graphic LCD display SPI Interface

Dependents:   mDotEVBM2X MTDOT-EVB-LinkCheck-AL MTDOT-EVBDemo-DRH MTDOT_BOX_EVB_LCD_Helloworld ... more

Revision:
0:f40dbeaefe69
Child:
1:3b02b7fb79c9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DOGS102.cpp	Mon Jul 06 19:37:13 2015 +0000
@@ -0,0 +1,346 @@
+/**
+ * @file    DOGS102.cpp
+ * @brief   Device driver - DOGS102 102x64 pixel Graphic LCD display W/RTOS Support
+ * @author  Tim Barr
+ * @version 1.0
+ * @see     http://www.lcd-module.com/eng/pdf/grafik/dogs102-6e.pdf
+ * @see     http://www.lcd-module.com/eng/pdf/zubehoer/uc1701.pdf
+ *
+ * Copyright (c) 2015
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+#include "DOGS102.h"
+#include "mbed_debug.h"
+#include "rtos.h"
+
+// macro to make sure x falls into range from low to high (inclusive)
+#define CLIP(x, low, high) { if ( (x) < (low) ) x = (low); if ( (x) > (high) ) x = (high); } while (0);
+ 
+DOGS102::DOGS102(SPI &spi, DigitalOut &lcd_cs, DigitalOut &cmnd_data)
+{
+    _spi =  &spi;
+    _lcd_cs = &lcd_cs;
+    _cmnd_data = &cmnd_data;
+
+    DOGS102::init();
+    
+    return;
+}
+uint8_t DOGS102::setCursor(uint8_t xcur, uint8_t ycur)
+{
+    uint8_t ypage;
+    uint8_t y_shift;
+
+	CLIP(xcur, 0, LCDWIDTH-1);
+	ypage = ycur/8;
+    CLIP(ypage, 0, LCDPAGES-1);
+    y_shift = ycur % 8;
+    DOGS102::writeCommand(SETPGADDR,ypage);
+    DOGS102::writeCommand(SETCOLADDRMSB,xcur>>4);
+    DOGS102::writeCommand(SETCOLADDRLSB,xcur);
+    return y_shift;
+ }
+
+void DOGS102::clearBuffer(void)
+{
+    memset(_lcdbuffer, 0, sizeof(_lcdbuffer));
+
+    if (!_update_flag)
+    {
+    	DOGS102::sendBuffer(_lcdbuffer);
+    }
+
+}
+
+void DOGS102::writeText(uint8_t column, uint8_t page, const uint8_t *font_address, const char *text, const uint8_t size)
+{
+	// Position of character data in memory array
+	uint16_t pos_array;
+	// temporary column, page address, and column_cnt are used
+	// to stay inside display area
+	uint8_t i,y, column_cnt = 0;
+
+	// font information, needed for calculation
+	uint8_t start_code, last_code, width, page_height, bytes_p_char;
+
+	uint8_t *txtbuffer;
+
+	start_code 	 = font_address[2];  // get first defined character
+	last_code	 = font_address[3];  // get last defined character
+	width		 = font_address[4];  // width in pixel of one char
+	page_height  = font_address[6];  // page count per char
+	bytes_p_char = font_address[7];  // bytes per char
+
+	if(page_height + page > LCDPAGES) //stay inside display area
+		page_height = LCDPAGES - page;
+
+	// The string is displayed character after character. If the font has more then one page,
+	// the top page is printed first, then the next page and so on
+	for(y = 0; y < page_height; y++)
+	{
+		txtbuffer = &_lcdbuffer[page*LCDWIDTH + column];
+		column_cnt = 0;					// clear column_cnt start point
+		i = 0;
+		while(( i < size) && ((column_cnt + column) < LCDWIDTH))
+		{
+			if(text[i] < start_code || (uint8_t)text[i] > last_code) //make sure data is valid
+				i++;
+			else
+			{
+				// calculate position of ASCII character in font array
+				// bytes for header + (ASCII - startcode) * bytes per char)
+				pos_array = 8 + (uint8_t)(text[i++] - start_code) * bytes_p_char;
+
+				// get the dot pattern for the part of the char to print
+				pos_array += y*width;
+
+				// stay inside display area
+				if((column_cnt + width + column) > LCDWIDTH)
+					column_cnt = LCDWIDTH-width;
+
+				// copy character data to buffer
+				memcpy (txtbuffer+column_cnt,font_address+pos_array,width);
+			}
+
+			column_cnt += width;
+		}
+		if (!_update_flag)
+		{
+			setCursor(column,(page+y)*8);	// set start position x and y
+			DOGS102::writeData(txtbuffer,column_cnt);
+		}
+	}
+}
+
+void DOGS102::writeBitmap(uint8_t column, uint8_t page, const uint8_t *bm_address)
+{
+	uint8_t width, page_cnt, bm_pntr;
+
+    width = bm_address[0];
+	page_cnt = (bm_address[1] + 7) / 8; //height in pages, add 7 and divide by 8 for getting the used pages (byte boundaries)
+
+	if(width + column > LCDWIDTH) //stay inside display area
+		width = LCDWIDTH - column;
+	if(page_cnt + page > LCDPAGES)
+		page_cnt = LCDPAGES - page;
+
+	for (uint8_t i=0;i < page_cnt;i++ )
+	{
+		bm_pntr = 2+i*width;
+		memcpy(_lcdbuffer+column+((i+page)*LCDWIDTH),bm_address+bm_pntr, width);
+	}
+
+	if (_update_flag == 0)
+	{
+		DOGS102::sendBuffer(_lcdbuffer);
+	}
+}
+
+void DOGS102::startUpdate(void)
+{
+	_update_flag++;
+}
+
+void DOGS102::endUpdate(void)
+{
+	_update_flag--;
+	
+	// fix boundary issue
+	if (_update_flag < 0)
+	    _update_flag = 0;
+	
+	if (_update_flag == 0)
+	{
+		DOGS102::sendBuffer(_lcdbuffer);
+	}
+}
+
+uint8_t DOGS102::getUpdateState(void)
+{
+	return _update_flag;
+}
+
+uint8_t DOGS102::init(void)
+{
+    uint8_t result = 0;
+    
+    _spi->frequency(4000000);
+    _spi->format(8,3);		// 8bit transfers, SPI mode 3
+    _lcd_cs->write(1);		// initialize chip select pin
+    _cmnd_data->write(1);	// initialize command/data pin
+    _update_flag = 0;		// initialize update semaphore
+    
+    // Reset all registers to POR values
+//    result = DOGS102::writeCommand(SOFTRESET);
+    osDelay(50);
+
+    // send initial setup commands to power up the display
+    result |= DOGS102::writeCommand(SETSCROLLLINE,0x00);	// set scroll line to 0
+    result |= DOGS102::writeCommand(SETSEGDIR,0x01);		// set reverse seg direction
+    result |= DOGS102::writeCommand(SETCOMDIR,0x00);		// set normal com direction
+    result |= DOGS102::writeCommand(SETALLPIXELON,0x00);	// disable all pixel on mode
+    result |= DOGS102::writeCommand(SETINVDISP,0x00);		// Turn display inverse off
+    result |= DOGS102::writeCommand(SETLCDBIAS,0x00);		// set bias ratio to 1/9
+    result |= DOGS102::writeCommand(SETPWRCTRL,0x07);		// turn on booster,regulator and follower
+    result |= DOGS102::writeCommand(SETVLCDRESRATIO,0x07);	// Set resistor ratio tomax
+    result |= DOGS102::writeCommand(SETELECVOL,0x10);		// set contrast to 32 out of 63
+    result |= DOGS102::writeCommand(SETAPROGCTRL,0x83);		// enable wrap around bits
+    result |= DOGS102::writeCommand(SETDISPEN,0x01);		// set display enable bit
+
+    DOGS102::clearBuffer();
+
+    if(result != 0)
+    {
+        debug("%s %d: ILS29011:init failed\n\r", __FILE__, __LINE__);
+    }
+    
+     return result;
+}
+
+uint8_t DOGS102::writeCommand(uint8_t const reg, uint8_t const data) const
+{
+    uint8_t buf;
+    uint8_t result = 0;
+
+    switch (reg)		// setup data byte for specific command register write
+    {
+    case SETCOLADDRLSB :
+    	// use COLMASK for data
+   		buf = SETCOLADDRLSB | (data & COLMASK);
+   		break;
+    case SETCOLADDRMSB :
+    	// use COLMASK for data
+   		buf = SETCOLADDRMSB | (data & COLMASK);
+    	break;
+    case SETPWRCTRL :
+    	// use PCMASK for data
+    	buf = SETPWRCTRL | (data & PCMASK);
+    	break;
+    case SETSCROLLLINE :
+    	// use SLMASK for data
+    	buf = SETSCROLLLINE | (data & SLMASK);
+    	break;
+    case SETPGADDR :
+    	// use COLMASK for data
+   		buf = SETPGADDR | (data & COLMASK);
+    	break;
+    case SETVLCDRESRATIO :
+    	// use PCMASK for data
+   		buf = SETVLCDRESRATIO | (data & PCMASK);
+    	break;
+    case SETELECVOL :
+    	// double byte command use SLMASK for data
+   		buf = data & SLMASK;
+    	break;
+    case SETALLPIXELON :
+		// use LSBMASK for data
+   		buf = SETALLPIXELON | (data & LSBMASK);
+		break;
+    case SETINVDISP :
+		// use LSBMASK for data
+   		buf = SETINVDISP | (data & LSBMASK);
+		break;
+    case SETDISPEN :
+		// use LSBMASK for data
+   		buf = SETDISPEN | (data & LSBMASK);
+		break;
+    case SETSEGDIR :
+		// use LSBMASK for data
+   		buf = SETSEGDIR | (data & LSBMASK);
+		break;
+    case SETLCDBIAS :
+		// use LSBMASK for data
+   		buf = SETLCDBIAS | (data & LSBMASK);
+		break;
+    case SETCOMDIR :
+    	// use LC1MASK for data
+   		buf = SETCOMDIR | ((data << 3) & COLMASK);
+    	break;
+    case SOFTRESET :
+    	// no data mask needed
+   		buf = SOFTRESET;
+    	break;
+    case SETAPROGCTRL :
+    	// Double byte command use WAMASK and TCMASK for data
+   		buf = data & (COLMASK | TCMASK);
+    	break;
+    default :
+    	debug("Command Register not valid\n\r");
+    	result = 1;
+    }
+
+    if (result == 0)
+    {
+        _spi->frequency(4000000);
+        _spi->format(8,3);		// 8bit transfers, SPI mode 3
+
+        _lcd_cs->write (0);			// enable LCD SPI interface
+    	_cmnd_data->write(0);		// set to command mode
+
+    	switch (reg)				// send first byte of double byte command for these register
+    	{
+    	case SETELECVOL :
+    	case SETAPROGCTRL :
+        	_spi->write(reg);
+        	break;
+        }
+
+    	_spi->write(buf);			// send command register
+
+    	_cmnd_data->write(1);		// set back to data mode
+    	_lcd_cs->write(1);			// disable LCD SPI Interface
+
+    }
+    
+    if(result != 0)
+    {
+        debug("DOGS102:writeCommand failed\n\r");
+    }
+    
+    return result;
+}
+
+void DOGS102::writeData(const uint8_t* data, uint8_t count) const
+{
+    uint8_t result = 0;
+    uint8_t i;
+    
+    _spi->frequency(4000000);
+    _spi->format(8,3);		// 8bit transfers, SPI mode 3
+
+    _lcd_cs->write(0);			// enable LCD SPI interface
+	i = 0;						// initialize transfer counter
+
+    do
+    {
+        _spi->write(data[i]);
+        i++;
+    } while ((result == 0) && (i <= count)) ;
+
+	_lcd_cs->write(1);			// disable LCD SPI interface
+    
+    return;
+}
+
+void DOGS102::sendBuffer(const uint8_t* buffer)
+{
+    //debug("Sending LCD Buffer\n");
+    for (int i=0; i<LCDPAGES; i++)
+    {
+    	DOGS102::setCursor(0,i*8);
+    	DOGS102::writeData(buffer + i*LCDWIDTH, LCDWIDTH);
+    }
+}
+