This is the code used on my video series "Hybrid Supercapacitor Car Battery" for my own hardware monitoring system. THe videos can be found on madelectronengineering.com

Dependencies:   BurstSPI Fonts INA219 mbed LPC1114_WakeInterruptIn

Fork of SharpMemoryLCD by Paul Staron

SharpLCD.cpp

Committer:
star297
Date:
2015-08-23
Revision:
0:0a76610c48a1
Child:
2:0c49a8f32f6e

File content as of revision 0:0a76610c48a1:


#include "mbed.h"
#include "SharpLCD.h"

const unsigned char FONT8x8[97][8] = {
{0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00}, // columns, rows, num_bytes_per_char
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // space 0x20
{0x30,0x78,0x78,0x30,0x30,0x00,0x30,0x00}, // !
{0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00}, // "
{0x6C,0x6C,0xFE,0x6C,0xFE,0x6C,0x6C,0x00}, // #
{0x18,0x3E,0x60,0x3C,0x06,0x7C,0x18,0x00}, // $
{0x00,0x63,0x66,0x0C,0x18,0x33,0x63,0x00}, // %
{0x1C,0x36,0x1C,0x3B,0x6E,0x66,0x3B,0x00}, // &
{0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00}, // '
{0x0C,0x18,0x30,0x30,0x30,0x18,0x0C,0x00}, // (
{0x30,0x18,0x0C,0x0C,0x0C,0x18,0x30,0x00}, // )
{0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00}, // *
{0x00,0x30,0x30,0xFC,0x30,0x30,0x00,0x00}, // +
{0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x30}, // ,
{0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00}, // -
{0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00}, // .
{0x03,0x06,0x0C,0x18,0x30,0x60,0x40,0x00}, // / (forward slash)
{0x3E,0x63,0x63,0x6B,0x63,0x63,0x3E,0x00}, // 0 0x30
{0x18,0x38,0x58,0x18,0x18,0x18,0x7E,0x00}, // 1
{0x3C,0x66,0x06,0x1C,0x30,0x66,0x7E,0x00}, // 2
{0x3C,0x66,0x06,0x1C,0x06,0x66,0x3C,0x00}, // 3
{0x0E,0x1E,0x36,0x66,0x7F,0x06,0x0F,0x00}, // 4
{0x7E,0x60,0x7C,0x06,0x06,0x66,0x3C,0x00}, // 5
{0x1C,0x30,0x60,0x7C,0x66,0x66,0x3C,0x00}, // 6
{0x7E,0x66,0x06,0x0C,0x18,0x18,0x18,0x00}, // 7
{0x3C,0x66,0x66,0x3C,0x66,0x66,0x3C,0x00}, // 8
{0x3C,0x66,0x66,0x3E,0x06,0x0C,0x38,0x00}, // 9
{0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x00}, // :
{0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x30}, // ;
{0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x00}, // <
{0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00}, // =
{0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x00}, // >
{0x3C,0x66,0x06,0x0C,0x18,0x00,0x18,0x00}, // ?
{0x3E,0x63,0x6F,0x69,0x6F,0x60,0x3E,0x00}, // @ 0x40
{0x18,0x3C,0x66,0x66,0x7E,0x66,0x66,0x00}, // A
{0x7E,0x33,0x33,0x3E,0x33,0x33,0x7E,0x00}, // B
{0x1E,0x33,0x60,0x60,0x60,0x33,0x1E,0x00}, // C
{0x7C,0x36,0x33,0x33,0x33,0x36,0x7C,0x00}, // D
{0x7F,0x31,0x34,0x3C,0x34,0x31,0x7F,0x00}, // E
{0x7F,0x31,0x34,0x3C,0x34,0x30,0x78,0x00}, // F
{0x1E,0x33,0x60,0x60,0x67,0x33,0x1F,0x00}, // G
{0x66,0x66,0x66,0x7E,0x66,0x66,0x66,0x00}, // H
{0x3C,0x18,0x18,0x18,0x18,0x18,0x3C,0x00}, // I
{0x0F,0x06,0x06,0x06,0x66,0x66,0x3C,0x00}, // J
{0x73,0x33,0x36,0x3C,0x36,0x33,0x73,0x00}, // K
{0x78,0x30,0x30,0x30,0x31,0x33,0x7F,0x00}, // L
{0x63,0x77,0x7F,0x7F,0x6B,0x63,0x63,0x00}, // M
{0x63,0x73,0x7B,0x6F,0x67,0x63,0x63,0x00}, // N
{0x3E,0x63,0x63,0x63,0x63,0x63,0x3E,0x00}, // O
{0x7E,0x33,0x33,0x3E,0x30,0x30,0x78,0x00}, // P 0x50
{0x3C,0x66,0x66,0x66,0x6E,0x3C,0x0E,0x00}, // Q
{0x7E,0x33,0x33,0x3E,0x36,0x33,0x73,0x00}, // R
{0x3C,0x66,0x30,0x18,0x0C,0x66,0x3C,0x00}, // S
{0x7E,0x5A,0x18,0x18,0x18,0x18,0x3C,0x00}, // T
{0x66,0x66,0x66,0x66,0x66,0x66,0x7E,0x00}, // U
{0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00}, // V
{0x63,0x63,0x63,0x6B,0x7F,0x77,0x63,0x00}, // W
{0x63,0x63,0x36,0x1C,0x1C,0x36,0x63,0x00}, // X
{0x66,0x66,0x66,0x3C,0x18,0x18,0x3C,0x00}, // Y
{0x7F,0x63,0x46,0x0C,0x19,0x33,0x7F,0x00}, // Z
{0x3C,0x30,0x30,0x30,0x30,0x30,0x3C,0x00}, // [
{0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x00}, // \ (back slash)
{0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00}, // ]
{0x08,0x1C,0x36,0x63,0x00,0x00,0x00,0x00}, // ^
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF}, // _
{0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00}, // ` 0x60
{0x00,0x00,0x3C,0x06,0x3E,0x66,0x3B,0x00}, // a
{0x70,0x30,0x3E,0x33,0x33,0x33,0x6E,0x00}, // b
{0x00,0x00,0x3C,0x66,0x60,0x66,0x3C,0x00}, // c
{0x0E,0x06,0x3E,0x66,0x66,0x66,0x3B,0x00}, // d
{0x00,0x00,0x3C,0x66,0x7E,0x60,0x3C,0x00}, // e
{0x1C,0x36,0x30,0x78,0x30,0x30,0x78,0x00}, // f
{0x00,0x00,0x3B,0x66,0x66,0x3E,0x06,0x7C}, // g
{0x70,0x30,0x36,0x3B,0x33,0x33,0x73,0x00}, // h
{0x18,0x00,0x38,0x18,0x18,0x18,0x3C,0x00}, // i
{0x06,0x00,0x06,0x06,0x06,0x66,0x66,0x3C}, // j
{0x70,0x30,0x33,0x36,0x3C,0x36,0x73,0x00}, // k
{0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00}, // l
{0x00,0x00,0x66,0x7F,0x7F,0x6B,0x63,0x00}, // m
{0x00,0x00,0x7C,0x66,0x66,0x66,0x66,0x00}, // n
{0x00,0x00,0x3C,0x66,0x66,0x66,0x3C,0x00}, // o
{0x00,0x00,0x6E,0x33,0x33,0x3E,0x30,0x78}, // p
{0x00,0x00,0x3B,0x66,0x66,0x3E,0x06,0x0F}, // q
{0x00,0x00,0x6E,0x3B,0x33,0x30,0x78,0x00}, // r
{0x00,0x00,0x3E,0x60,0x3C,0x06,0x7C,0x00}, // s
{0x08,0x18,0x3E,0x18,0x18,0x1A,0x0C,0x00}, // t
{0x00,0x00,0x66,0x66,0x66,0x66,0x3B,0x00}, // u
{0x00,0x00,0x66,0x66,0x66,0x3C,0x18,0x00}, // v
{0x00,0x00,0x63,0x6B,0x7F,0x7F,0x36,0x00}, // w
{0x00,0x00,0x63,0x36,0x1C,0x36,0x63,0x00}, // x
{0x00,0x00,0x66,0x66,0x66,0x3E,0x06,0x7C}, // y
{0x00,0x00,0x7E,0x4C,0x18,0x32,0x7E,0x00}, // z
{0x0E,0x18,0x18,0x70,0x18,0x18,0x0E,0x00}, // {
{0x0C,0x0C,0x0C,0x00,0x0C,0x0C,0x0C,0x00}, // |
{0x70,0x18,0x18,0x0E,0x18,0x18,0x70,0x00}, // }
{0x3B,0x6E,0x00,0x00,0x00,0x00,0x00,0x00}, // ~
{0x1C,0x36,0x36,0x1C,0x00,0x00,0x00,0x00}}; // DEL

// SharpLCD commands
#define SharpLCD_CMD_UPDATE     (0x01)
#define SharpLCD_CMD_ALL_CLEAR  (0x04)

// Macro to switch endianness on char value
#define SWAP8(a) ((((a) & 0x80) >> 7) | (((a) & 0x40) >> 5) | (((a) & 0x20) >> 3) | (((a) & 0x10) >> 1) | (((a) & 0x08) << 1) | (((a) & 0x04) << 3) | (((a) & 0x02) << 5) | (((a) & 0x01) << 7))

SharpLCD::SharpLCD(PinName mosi, PinName miso, PinName sclk, PinName chipSelect, PinName enable, PinName extcom)
         :  spi(mosi, miso, sclk), chipSelect(chipSelect), Enable(enable), ExtCom(extcom)
{
	//Initialize
	spi.frequency(3500000);// Nominal speed is 1MHz, tested working at 3MHz
	lcdPolarity = 0;	
	rowCount = 0;
	memset((uint8_t*)pixelBuffer, White, sizeof(pixelBuffer));	// init full pixel buffer to White
	memset((void*)RowState, 0, sizeof(RowState));	// init row status
    // current pixel location
	_x = 0;
	_y = 0;
	// window settings
	_x1 = 0;
	_x2 = 0;
	_y1 = 0;
	_y2 = 0;
	 _row = 0;
    _column = 0;
}
// Call this function at 55 ~ 65 Hz to keep the display up-to-date.
void SharpLCD::toggle() {
	ExtCom=!ExtCom;
}

void SharpLCD::enableDisplay(void) {
    Enable = 1;
}

void SharpLCD::disableDisplay(void) {
    Enable = 0;
}

void SharpLCD::clearImmediate() {
	// Clear out the pixel buffer
	memset((void*)pixelBuffer, foreground, sizeof(pixelBuffer));
	memset((void*)RowState, 0, sizeof(RowState));
	chipSelect = 1;
	// send clear command to display
	cmd[0] = (uint8_t)(SWAP8(SharpLCD_CMD_ALL_CLEAR | lcdPolarity));
	cmd[1] = 0;	
	spi.fastWrite(cmd[0]);
	spi.fastWrite(cmd[1]);
	spi.clearRX();	
	chipSelect = 0;
}

void SharpLCD::update() {
	//Initialize the command vector
	cmd[0] = (uint8_t)SWAP8(SharpLCD_CMD_UPDATE);
	cmd[1] = SWAP8(1);
	chipSelect=1;
	rowCount = 0;
	display_write();
}

void SharpLCD::display_write() {	
	while(rowCount < DISPLAY_HEIGHT) {		
		// Determine the next line to send
		if((RowState[rowCount / DISPLAY_BUFFER_TYPE_SIZE] & (1 << (rowCount % DISPLAY_BUFFER_TYPE_SIZE))) != 0) {
			// Row has pixel changes, send this row to the display
			cmd[1] = (uint8_t)SWAP8(rowCount+1);
			
			memcpy(&(cmd[2]), (const void*)&(pixelBuffer[rowCount*(DISPLAY_WIDTH/DISPLAY_BUFFER_TYPE_SIZE)]), DISPLAY_WIDTH / DISPLAY_BUFFER_TYPE_SIZE * sizeof(DISPLAY_BUFFER_TYPE));
						
			int len=sizeof(cmd);			
			for(int i=0; i<len; i++) {		
				spi.fastWrite(cmd[i]);		
				}
			// update pixel change status of this line as sent
			RowState[rowCount / DISPLAY_BUFFER_TYPE_SIZE] &= ~(1 << (rowCount % DISPLAY_BUFFER_TYPE_SIZE));				
		}				
		rowCount++;
	}
	// send end of transfer bytes 
	spi.fastWrite(cmd[0]);
	spi.fastWrite(0xFF);
	// clear SPI RX buffer
	spi.clearRX();					
	chipSelect = 0;		
}

void SharpLCD::pixel(int x, int y, int colour) {
    uint8_t swapx = 7 - ((unsigned int)x & 0x07);
	    x = ((unsigned int)x & 0xFFFFFFF8) | swapx;
	    // determine if row has pixel changes
	    bool change = ((pixelBuffer[((y * DISPLAY_WIDTH) + x) / DISPLAY_BUFFER_TYPE_SIZE] & (1 << (x % DISPLAY_BUFFER_TYPE_SIZE))) != ((colour & 0x01) << (x % DISPLAY_BUFFER_TYPE_SIZE)));
		if(change) {
            // xor operation
            pixelBuffer[((y * DISPLAY_WIDTH) + x) / DISPLAY_BUFFER_TYPE_SIZE] ^= (1 << (x % DISPLAY_BUFFER_TYPE_SIZE));
            // update pixel change status of this line
            RowState[y / DISPLAY_BUFFER_TYPE_SIZE] |= (1 << (y % DISPLAY_BUFFER_TYPE_SIZE));
		}
	}
    
int SharpLCD::_putc(int value) {
    if(value == '\n') {
        _column = 0;
        _row++;
        if(_row >= rows()) {
            _row = 0;
        }
    } else {
        character(_column, _row, value);
        _column++;
        if(_column >= columns()) {
            _column = 0;
            _row++;
            if(_row >= rows()) {
                _row = 0;
            }
        }
    }
    return value;
}

void SharpLCD::set_font(const unsigned char * f) {
    font = f;
    if (font==NULL){externalfont=0;}	// set display.font
    	else{externalfont=1;}
}

void SharpLCD::locate(int column, int row) {
    _column = column;
    _row = row;
    char_x = column;
    char_y = row;
}

int SharpLCD::_getc() {
    return -1;
}

void SharpLCD::printf(const char* format, ...) {
	char buffer[MAX_PRINTF_CHARS + 1] = { 0 };
	uint32_t iterator = 0;
	va_list args;
	va_start(args, format);
	vsprintf(buffer, format, args);
	va_end(args);

	while((buffer[iterator] != 0) && (iterator < MAX_PRINTF_CHARS)) {
		_putc(buffer[iterator++]);
	}
}
   
void SharpLCD::character(int column, int row, int value) {    
    if(externalfont){ // send external font
    	unsigned int hor,vert,offset,bpl,j,i,b;
    	const unsigned char* sign;
    	unsigned char z,w;
    	if ((value < 31) || (value > 127)) return;   // test char range
    	// read font parameter from start of array
    	offset = font[0];                    // bytes / char
    	hor = font[1];                       // get hor size of font
    	vert = font[2];                      // get vert size of font
    	bpl = font[3];                       // bytes per line
    	if (char_x + hor > width()) {
        	char_x = 0;
        	char_y = char_y + vert;
       		if (char_y >= height() - font[2]) {
            	char_y = 0;
        	}
    	}     
    	window(char_x, char_y,hor,vert); 
    	sign = &font[((value -32) * offset) + 4]; 
    	w = sign[0];                         
    	for (j=0; j<vert; j++) {  
        	for (i=0; i<hor; i++) {  
            	z =  sign[bpl * i + ((j & 0xF8) >> 3)+1];
            	b = 1 << (j & 0x07);
            	if (( z & b ) == 0x00) {               
                	putp(foreground);              
            	} 
            	else {                     
               		putp(background);                                
            	}
        	}
    	}
    	if ((w + 2) < hor) {                   // x offset to next char
        	char_x += w + 2;
    		}
    		else char_x += hor;
	}	
	// send default font using blitbit function 			
	else{
		blitbit(column * 8, row * 8, 8, 8, (char*)&(FONT8x8[value - 0x1F][0]));
		}
}

void SharpLCD::window(int x, int y, int w, int h) {
    // current pixel location
    _x = x;
    _y = y;
    // window settings
    _x1 = x;
    _x2 = x + w - 1;
    _y1 = y;
    _y2 = y + h - 1;
}
    
void SharpLCD::putp(int colour) {
    pixel(_x, _y, colour);
    _x++;
    if(_x > _x2) {
        _x = _x1;
        _y++;
        if(_y > _y2) {
            _y = _y1;
        }
    }
}

void SharpLCD::rect(int x0, int y0, int x1, int y1, int color) {
    if (x1 > x0) hline(x0,x1,y0,color);
    else  hline(x1,x0,y0,color);
    if (y1 > y0) vline(x0,y0,y1,color);
    else vline(x0,y1,y0,color);
    if (x1 > x0) hline(x0,x1,y1,color);
    else  hline(x1,x0,y1,color);
    if (y1 > y0) vline(x1,y0,y1,color);
    else vline(x1,y1,y0,color);
    return;
}

void SharpLCD::fillrect(int x0, int y0, int w, int h, int colour) {
    unsigned long int index=0;
    if (w < 0) {
        x0 = x0 + w;
        w = -w;
    }
    if (h < 0) {
        y0 = y0 + h;
        h = -h;
    }
    window(x0,y0,w,h);
    int num = h*w;
    for( index = 0; index<num; index++ ) {
       putp(colour); 
    }
    return;
}

void SharpLCD::circle(int x, int y, int r,int colour){
	int ce = -r;
	int cx = r;
	int cy = 0;
	while(cx >= cy){
		pixel(x+cx,y+cy,colour);
		pixel(x-cx,y-cy,colour);
		pixel(x-cx,y+cy,colour);
		pixel(x+cx,y-cy,colour);
		pixel(x+cy,y+cx,colour);
		pixel(x-cy,y+cx,colour);
		pixel(x-cy,y-cx,colour);
		pixel(x+cy,y-cx,colour);
		ce += 2*cy++ + 1;
		if(ce >= 0){
			ce -= 2*cx---1;	
		}		
	}
}

void SharpLCD::ellipse(int xc, int yc, int a, int b, unsigned int colour)
{
    int x = 0, y = b;
    long a2 = (long)a*a, b2 = (long)b*b;
    long crit1 = -(a2/4 + a%2 + b2);
    long crit2 = -(b2/4 + b%2 + a2);
    long crit3 = -(b2/4 + b%2);
    long t = -a2*y;
    long dxt = 2*b2*x, dyt = -2*a2*y;
    long d2xt = 2*b2, d2yt = 2*a2;
    while (y>=0 && x<=a) {
        pixel(xc+x, yc+y, colour);
        if (x!=0 || y!=0)
            pixel(xc-x, yc-y, colour);
        if (x!=0 && y!=0) {
            pixel(xc+x, yc-y, colour);
            pixel(xc-x, yc+y, colour);
        }
        if (t + b2*x <= crit1 ||            
                t + a2*y <= crit3)          
            incx();
        else if (t - a2*y > crit2)          
            incy();
        else {
            incx();
            incy();
        }
    }
}

void SharpLCD::fillellipse(int xc, int yc, int a, int b, unsigned int colour)
{
   	int x = 0, y = b;
    int rx = x, ry = y;
    unsigned int width = 1;
    unsigned int height = 1;
    long a2 = (long)a*a, b2 = (long)b*b;
    long crit1 = -(a2/4 + a%2 + b2);
    long crit2 = -(b2/4 + b%2 + a2);
    long crit3 = -(b2/4 + b%2);
    long t = -a2*y;                         
    long dxt = 2*b2*x, dyt = -2*a2*y;
    long d2xt = 2*b2, d2yt = 2*a2;
    if (b == 0) {
        fillrect(xc-a, yc, 2*a+1, 1, colour);
        return;
    }
    while (y>=0 && x<=a) {
        if (t + b2*x <= crit1 ||            
                t + a2*y <= crit3) {        
            if (height == 1)
                ;                           
            else if (ry*2+1 > (height-1)*2) {
                fillrect(xc-rx, yc-ry, width, height-1, colour);
                fillrect(xc-rx, yc+ry+1, width, 1-height, colour);
                ry -= height-1;
                height = 1;
            } else {
                fillrect(xc-rx, yc-ry, width, ry*2+1, colour);
                ry -= ry;
                height = 1;
            }
            incx();
            rx++;
            width += 2;
        } else if (t - a2*y > crit2) {      
            incy();
            height++;
        } else {
            if (ry*2+1 > height*2) {
                fillrect(xc-rx, yc-ry, width, height, colour);
                fillrect(xc-rx, yc+ry+1, width, -height, colour);
            } else {
                fillrect(xc-rx, yc-ry, width, ry*2+1, colour);
            }
            incx();
            incy();
            rx++;
            width += 2;
            ry -= height;
            height = 1;
        }
    }
    if (ry > height) {
        fillrect(xc-rx, yc-ry, width, height, colour);
        fillrect(xc-rx, yc+ry+1, width, -height, colour);
    } else {
        fillrect(xc-rx, yc-ry, width, ry*2+1, colour);
    }
}

void SharpLCD::line(int x0, int y0, int x1, int y1, int colour) {
    int   dx = 0, dy = 0;
    int   dx_sym = 0, dy_sym = 0;
    int   dx_x2 = 0, dy_x2 = 0;
    int   di = 0;
    dx = x1-x0;
    dy = y1-y0;

    if (dx == 0) {        
        if (y1 > y0) vline(x0,y0,y1,colour);
        else vline(x0,y1,y0,colour);
        return;
    }
    if (dx > 0) {
        dx_sym = 1;
    } else {
        dx_sym = -1;
    }
    if (dy == 0) {        
        if (x1 > x0) hline(x0,x1,y0,colour);
        else  hline(x1,x0,y0,colour);
        return;
    }
    if (dy > 0) {
        dy_sym = 1;
    } else {
        dy_sym = -1;
    }
    dx = dx_sym*dx;
    dy = dy_sym*dy;
    dx_x2 = dx*2;
    dy_x2 = dy*2;
    if (dx >= dy) {
        di = dy_x2 - dx;
        while (x0 != x1) {

            pixel(x0, y0, colour);
            x0 += dx_sym;
            if (di<0) {
                di += dy_x2;
            } else {
                di += dy_x2 - dx_x2;
                y0 += dy_sym;
            }
        }
        pixel(x0, y0, colour);
    } else {
        di = dx_x2 - dy;
        while (y0 != y1) {
            pixel(x0, y0, colour);
            y0 += dy_sym;
            if (di < 0) {
                di += dx_x2;
            } else {
                di += dx_x2 - dy_x2;
                x0 += dx_sym;
            }
        }
        pixel(x0, y0, colour);
    }
    return;
}

void SharpLCD::hline(int x0, int x1, int y, int colour) {
    int w;
    w = x1 - x0 + 1;
    window(x0,y,w,1);
    for (int x=0; x<w; x++) {
        putp(colour);
    }
    return;
}

void SharpLCD::vline(int x, int y0, int y1, int colour) {
    int h;
    h = y1 - y0 + 1;
    window(x,y0,1,h);
    for (int y=0; y<h; y++) {
        putp(colour);
    }
    return;
}
    
void SharpLCD::blit(int x, int y, int w, int h, const int *colour) { 
    window(x, y, w, h);
    for(int i=0; i<w*h; i++) {
        putp(colour[i]);
    }
}
    
void SharpLCD::blitbit(int x, int y, int w, int h, const char* colour) {
    window(x, y, w, h);
    for(int i = 0; i < w*h; i++) {
        char byte = colour[i >> 3];
        int offset = i & 0x7;
        int c = ((byte << (offset)) & 0x80) ? background : foreground;
        putp(c);
    }
}
    
int SharpLCD::columns() { 
    return width() / 8; 
}

int SharpLCD::rows() { 
    return height() / 8; 
}

int SharpLCD::width() {
	return DISPLAY_WIDTH;
}

int SharpLCD::height() {
	return DISPLAY_HEIGHT;
}

void SharpLCD::showBMP(const uint8_t* bitmap, const uint32_t bmpWidth, const uint32_t bmpHeight, const uint32_t startX, const uint32_t startY) {
	uint32_t bitmapLine = 0, y = startY, bytesPerLine = ((bmpWidth >= (DISPLAY_WIDTH - startX)) ? (DISPLAY_WIDTH - startX) : bmpWidth) / 8;

	// Apply constraints
	if((bmpWidth & 0x07) != 0) return;
	if(startX >= DISPLAY_WIDTH) return;
	
	// Copy over bytes to pixel buffer
	for(; y < startY + bmpHeight; y++) {
		memcpy( (void*) &(((uint8_t*)pixelBuffer)[((y * DISPLAY_WIDTH) + startX) / 8]),
				(const void*) &(bitmap[bitmapLine * (bmpWidth / 8)]),
				bytesPerLine);
		RowState[y / DISPLAY_BUFFER_TYPE_SIZE] |= (1 << (y % DISPLAY_BUFFER_TYPE_SIZE));
		bitmapLine++;
	}
	return;
}