Reply by Mark January 26, 20122012-01-26
Hi

Ok. Perhaps the other Mark needs to comment on the code in question.

Basically your remarks look to be realistic.
1) I would measure the SPI clock speed to be sure.
2) SSP and SPI are different peripherals - powering the SSP is all that is needed (no need to power SPI)
3) I would check the PLL and bus speed settings to be sure.

Regards

Mark
--- In l..., DeV wrote:
>
> sorry Mark...actually there is another person called Mark who has helped me
> to get the lcd working on olimex 2378-stk kit...im sorry again...anyways my
> questions are still not answered...i have the following queries related to
> LPC2378 processor:
> 1. normally if nothing is mentioned about power control, so the lpc2378
> runs on the internal rc oscillator at 4Mhz right?? so if nothing is
> mentioned about the PLL registers in our program then can we assume a
> frequency of 4mhz being applied to cpu since the cpu divider will also be 1
> if pll is bypassed, am i right??
>
> 2. Second doubt is that the SSP supports SPI format...so if want to use
> the SSP as SPI format then do we have to also power the SPI peripheral for
> it?? if yes then y do v have to power the SPI peripheral for SSP to run as
> SPI??...aren't SSP and SPI 2 individual peripherals??SSP is just using SPI
> format...then y enable SPI peripheral for it??
>
> 3. If anyone can explain to me function of timer...the manual says that
> prescale counter register is the value by which the peripheral clock for
> timer is divided by...so if i dont use pll then my internal rc oscillator
> of 4Mhz is used to generate the CPU clock...so if i set Prescale Counter as
> 4000000 (i.e. 4 x 10^6) and Prescale register as 1 then every 1 second
> Prescale counter will be increamented to 1 and timer counter will be
> also incremented as Prescale counter will be equal to the Prescale
> register..so now prescale register will again be reset to 0....so this is
> wat i inferred from the manual...am i right coz this logic isnt working in
> my program??
> Thanks so much...
>
> On Thu, Jan 26, 2012 at 3:07 AM, Mark wrote:
>
> > **
> >
> >
> > Hi
> >
> > Could you be specific as to which code you are referring to since I don't
> > think that it is from me. I don't recognise any of the mentioned settings
> > and the configuration automatically adapts itself to the clock rate based
> > on the PLL CPU clock speed and other bus dividers in question.
> >
> > Regards
> >
> > Mark
> >

An Engineer's Guide to the LPC2100 Series

Reply by DeV January 26, 20122012-01-26
sorry Mark...actually there is another person called Mark who has helped me
to get the lcd working on olimex 2378-stk kit...im sorry again...anyways my
questions are still not answered...i have the following queries related to
LPC2378 processor:
1. normally if nothing is mentioned about power control, so the lpc2378
runs on the internal rc oscillator at 4Mhz right?? so if nothing is
mentioned about the PLL registers in our program then can we assume a
frequency of 4mhz being applied to cpu since the cpu divider will also be 1
if pll is bypassed, am i right??

2. Second doubt is that the SSP supports SPI format...so if want to use
the SSP as SPI format then do we have to also power the SPI peripheral for
it?? if yes then y do v have to power the SPI peripheral for SSP to run as
SPI??...aren't SSP and SPI 2 individual peripherals??SSP is just using SPI
format...then y enable SPI peripheral for it??

3. If anyone can explain to me function of timer...the manual says that
prescale counter register is the value by which the peripheral clock for
timer is divided by...so if i dont use pll then my internal rc oscillator
of 4Mhz is used to generate the CPU clock...so if i set Prescale Counter as
4000000 (i.e. 4 x 10^6) and Prescale register as 1 then every 1 second
Prescale counter will be increamented to 1 and timer counter will be
also incremented as Prescale counter will be equal to the Prescale
register..so now prescale register will again be reset to 0....so this is
wat i inferred from the manual...am i right coz this logic isnt working in
my program??
Thanks so much...

On Thu, Jan 26, 2012 at 3:07 AM, Mark wrote:

> **
> Hi
>
> Could you be specific as to which code you are referring to since I don't
> think that it is from me. I don't recognise any of the mentioned settings
> and the configuration automatically adapts itself to the clock rate based
> on the PLL CPU clock speed and other bus dividers in question.
>
> Regards
>
> Mark
> --- In l..., DeV wrote:
> >
> > hey Mark...thanks somuch...but guess wat?? i got the lcd working a few
> > hours back...it was all because of yr help....thanks so much
> mark...anyways
> > i have 3 doubts:
> >
> >
> > 1. normally if nothing is mentioned about power control, so the lpc2378
>
> > runs on the internal rc oscillator at 4Mhz right?? so in your file u have
> > set the cpdvsr value of the SSP0 as 18 and yr comment says 72Mhz/18 > > 4Mhz...so how have u got 72Mhz on clock wen u are nowhere using PLL??
> >
> > 2. Seond doubt is that the SSP supports SPI format...so in yr program u
>
> > have used SSP as SPI format and have also powered the SPI peripheral for
> > it...so y do v have to power the SPI peripheral for SSP to run as
> > SPI??...aren't SSP and SPI 2 individual peripherals??SSP is just using
> SPI
> > format...then y enable SPI peripheral for it??
> >
> > 3. If u can explain to me of timer...the manual says that prescale
>
> > counter register is trhe value by which the peripheral clock for timer is
> > divided by...so if i dont use pll then my internal rc oscillator of 4Mhz
> is
> > used to generate the CPU clock...so if i set Prescale Counter as 4000000
> > and Prescale register as 1 then every 1 second Prescale counter will be
> > increamented to 1 and timer counter will be also increamented as Prescale
> > counter will be equal to the Prescale register..so now prescale register
> > will again be reset to 0....so this is wat i inferred from the
> manual...am
> > i right coz this logic isnt working in my program...
> >
> >
> > Thanks so much...
> >
> >
>

--

Dev Sampat****

Cell (Oman): (+968) - 9304 8932****

Email: d...@gmail.com


Reply by Mark January 25, 20122012-01-25
Hi

Could you be specific as to which code you are referring to since I don't think that it is from me. I don't recognise any of the mentioned settings and the configuration automatically adapts itself to the clock rate based on the PLL CPU clock speed and other bus dividers in question.

Regards

Mark
--- In l..., DeV wrote:
>
> hey Mark...thanks somuch...but guess wat?? i got the lcd working a few
> hours back...it was all because of yr help....thanks so much mark...anyways
> i have 3 doubts:
> 1. normally if nothing is mentioned about power control, so the lpc2378
> runs on the internal rc oscillator at 4Mhz right?? so in your file u have
> set the cpdvsr value of the SSP0 as 18 and yr comment says 72Mhz/18 > 4Mhz...so how have u got 72Mhz on clock wen u are nowhere using PLL??
>
> 2. Seond doubt is that the SSP supports SPI format...so in yr program u
> have used SSP as SPI format and have also powered the SPI peripheral for
> it...so y do v have to power the SPI peripheral for SSP to run as
> SPI??...aren't SSP and SPI 2 individual peripherals??SSP is just using SPI
> format...then y enable SPI peripheral for it??
>
> 3. If u can explain to me of timer...the manual says that prescale
> counter register is trhe value by which the peripheral clock for timer is
> divided by...so if i dont use pll then my internal rc oscillator of 4Mhz is
> used to generate the CPU clock...so if i set Prescale Counter as 4000000
> and Prescale register as 1 then every 1 second Prescale counter will be
> increamented to 1 and timer counter will be also increamented as Prescale
> counter will be equal to the Prescale register..so now prescale register
> will again be reset to 0....so this is wat i inferred from the manual...am
> i right coz this logic isnt working in my program...
> Thanks so much...

Reply by DeV January 25, 20122012-01-25
hey Mark...thanks somuch...but guess wat?? i got the lcd working a few
hours back...it was all because of yr help....thanks so much mark...anyways
i have 3 doubts:
1. normally if nothing is mentioned about power control, so the lpc2378
runs on the internal rc oscillator at 4Mhz right?? so in your file u have
set the cpdvsr value of the SSP0 as 18 and yr comment says 72Mhz/18 4Mhz...so how have u got 72Mhz on clock wen u are nowhere using PLL??

2. Seond doubt is that the SSP supports SPI format...so in yr program u
have used SSP as SPI format and have also powered the SPI peripheral for
it...so y do v have to power the SPI peripheral for SSP to run as
SPI??...aren't SSP and SPI 2 individual peripherals??SSP is just using SPI
format...then y enable SPI peripheral for it??

3. If u can explain to me of timer...the manual says that prescale
counter register is trhe value by which the peripheral clock for timer is
divided by...so if i dont use pll then my internal rc oscillator of 4Mhz is
used to generate the CPU clock...so if i set Prescale Counter as 4000000
and Prescale register as 1 then every 1 second Prescale counter will be
increamented to 1 and timer counter will be also increamented as Prescale
counter will be equal to the Prescale register..so now prescale register
will again be reset to 0....so this is wat i inferred from the manual...am
i right coz this logic isnt working in my program...
Thanks so much...

On Wed, Jan 25, 2012 at 5:53 PM, Mark wrote:

> **
> Hi
>
> You can get a complete working project with support for the Olimex
> 2378-stk, with build for most IDEs and simulation of the Nokia LCD (and
> various other) for simple testing and debugging.
>
> See http://www.utasker.com/docs/uTasker/uTaskerLCD.PDF
>
> The LPC2xxx project (with graphic LCD support, TCP/IP stack, USB stack and
> various other features) is available at
> http://www.utasker.com/forum/index.php?topic24.0
> The project is compatible with LPC17xx, available at
> http://www.utasker.com/forum/index.php?topic85.0
>
> sot it is very simpel to move between the two if needed.
>
> Regards
>
> Mark
>
> P.S. Note that using the rather poor quality LCD as output device is not
> the best idea; this is possible but cumbersome. The project allows output
> via UART, TELNET or USB CDC which are much more efficient and practical.
>
> http://www.uTasker.com
> --- In l..., "quesha0811" wrote:
> >
> > Hello all,
> >
> > I have recently purchased an Olimex 2378-stk kit and am using keil and
> flash magic softwares to program it..however,i am new to embedded systems
> and all information that i have now is the lpc2378 manual..unfortunately
> there is no proper documentation for the kit..anyways, i am trying to
> access the lcd on board...a friend has been kind enough to forward me his
> project that uses lcd and most importantly is developed on the same kit...i
> am getting multiple errors which i am unable to understnd..i require any of
> your professional help to extract only the useful lcd information from that
> project and make a kind of a header file for the lcd...this will help
> beginners like me to access the lcd by just calling the required functions
> and passing the data...i really require the lcd to work as it is the only
> possible way to show us any feedback of our programs...pls help me with
> this...i have been trying very hard but unfortunately i am not that strong
> in embedded c programming...so pls help me!! thanks in advance...
> >
> > the file for lcd from my friends project is as follows:
> >
>

--

Dev Sampat****

Cell (Oman): (+968) - 9304 8932****

Email: d...@gmail.com


Reply by Mark January 25, 20122012-01-25
Hi

You can get a complete working project with support for the Olimex 2378-stk, with build for most IDEs and simulation of the Nokia LCD (and various other) for simple testing and debugging.

See http://www.utasker.com/docs/uTasker/uTaskerLCD.PDF

The LPC2xxx project (with graphic LCD support, TCP/IP stack, USB stack and various other features) is available at
http://www.utasker.com/forum/index.php?topic24.0
The project is compatible with LPC17xx, available at http://www.utasker.com/forum/index.php?topic85.0

sot it is very simpel to move between the two if needed.

Regards

Mark

P.S. Note that using the rather poor quality LCD as output device is not the best idea; this is possible but cumbersome. The project allows output via UART, TELNET or USB CDC which are much more efficient and practical.

http://www.uTasker.com
--- In l..., "quesha0811" wrote:
>
> Hello all,
>
> I have recently purchased an Olimex 2378-stk kit and am using keil and flash magic softwares to program it..however,i am new to embedded systems and all information that i have now is the lpc2378 manual..unfortunately there is no proper documentation for the kit..anyways, i am trying to access the lcd on board...a friend has been kind enough to forward me his project that uses lcd and most importantly is developed on the same kit...i am getting multiple errors which i am unable to understnd..i require any of your professional help to extract only the useful lcd information from that project and make a kind of a header file for the lcd...this will help beginners like me to access the lcd by just calling the required functions and passing the data...i really require the lcd to work as it is the only possible way to show us any feedback of our programs...pls help me with this...i have been trying very hard but unfortunately i am not that strong in embedded c programming...so pls help me!! thanks in advance...
>
> the file for lcd from my friends project is as follows:
>

Reply by quesha0811 January 25, 20122012-01-25
Hello all,

I have recently purchased an Olimex 2378-stk kit and am using keil and flash magic softwares to program it..however,i am new to embedded systems and all information that i have now is the lpc2378 manual..unfortunately there is no proper documentation for the kit..anyways, i am trying to access the lcd on board...a friend has been kind enough to forward me his project that uses lcd and most importantly is developed on the same kit...i am getting multiple errors which i am unable to understnd..i require any of your professional help to extract only the useful lcd information from that project and make a kind of a header file for the lcd...this will help beginners like me to access the lcd by just calling the required functions and passing the data...i really require the lcd to work as it is the only possible way to show us any feedback of our programs...pls help me with this...i have been trying very hard but unfortunately i am not that strong in embedded c programming...so pls help me!! thanks in advance...

the file for lcd from my friends project is as follows:

// **************************************************************************************************************
// lcd.c
//
// Nokia 6610 LCD Display Driver (Epson S1D15G00 Controller)
//
// Controller used for LCD Display is a Epson S1D15G00 driver
// Note: For Olimex SAM7-EX256 boards with the G8 decal or the Sparkfun Color LCD 128x128 Nokia Knock-Off
//
//
// We will use a 132 x 132 pixel matrix - each pixel has 12 bits of color information.
//
// _____
// | |
// ___________________|___|___
// | ====================== |
// ^ (131,0) |------------------------- |(131,131)
// | | |
// | | |
// | | |
// | | |
// | | |
// | Rows| Nokia 6610 Display | Note: In general, you can't view column 130 or column 131
// | | |
// X | |
// | | |
// | | |
// | | |
// | | |
// | | |
// | |--------------------------|
// (0,0) Columns (0,131)
//
// ------------Y-------------->
//
//
// 132 x 132 pixel matrix has two methods to specify the color info
//
// 1. 12 bits per pixel
// requires command and 1.5 data bytes to specify a single pixel
// (3 data bytes can specify 2 pixels)
//
// 2. 8 bits per pixel
// requires one command and one data byte to specify the single pixel\//
// note: pixel data byte converted by RGB table to 12-bit format above
//
// THIS IMPLEMENTATION USES THE 12 BITS PER PIXEL METHOD!
// -------------------------
//
//
//
//
// HARDWARE INTERFACE
// ------------------
//
// The Nokia 6610 display uses a SPI serial interface (9 bits)
//
// PA2 = LCD Reset (set to low to reset)
// PA12 = LCD chip select (set to low to select the LCD chip)
// PA16 = SPI0_MISO Master In - Slave Out (not used in Olimex SAM7-EX256 LCD interface)
// PA17 = SPI0_MOSI Master Out - Slave In pin (Serial Data to LCD slave)
// PA18 = SPI0_SPCK Serial Clock (to LCD slave)
//
// SPI baud rate set to MCK/2 = 48054841/3 = 16018280 baud
// (period = 62 nsec, OK since 50 nsec period is min for S1D15G00)
//
// The important thing to note is that you CANNOT read from the LCD!
//
//
// Author: James P Lynch August 30, 2007
// ***************************************************************************************************************
// **************************************
// Include Files
// **************************************
//#include "LPC23xx.h"
#include "lpc-2378-stk.h"

//#include "bmp.h"
// ******************************************************
// Pointers to AT91SAM7X256 peripheral data structures
// ******************************************************
//volatile AT91PS_PIO pPIOA = AT91C_BASE_PIOA;
//volatile AT91PS_PIO pPIOB = AT91C_BASE_PIOB;
//volatile AT91PS_SPI pSPI = AT91C_BASE_SPI0;
//volatile AT91PS_PMC pPMC = AT91C_BASE_PMC;
//volatile AT91PS_PDC pPDC = AT91C_BASE_PDC_SPI0;

// *********************************************************************************************
// InitSpi( )
//
// Sets up SPI channel 0 for communications to Nokia 6610 LCD Display
//
// I/O ports used: PA2 = LCD Reset (set to low to reset)
// PA12 = LCD chip select (set to low to select the LCD chip)
// PA16 = SPI0_MISO Master In - Slave Out (not used in LCD interface)
// PA17 = SPI0_MOSI Master Out - Slave In pin (Serial Data to LCD slave)
// PA18 = SPI0_SPCK Serial Clock (to LCD slave)
// PB20 = backlight control (normally PWM control, 1 = full on)
//
// Author: Olimex, James P Lynch August 30, 2007
// *********************************************************************************************
void InitSpi(void) {

PCONP |=(1<<8);//power to SPI
PCONP |=(1<<21);//power to SSP
SCS |= (1<<1);
SCS |= (1UL<<0); //fast GPIO (probably already set)
PINSEL3 |= 0x0003CF00; // setup SCK0, SSEL0, MISO0, MOSI0
//PINSEL3 |= 3 << 8 | 3 << 10 | 3 << 14;

// backlight
FIO1DIR |= BIT20;
FIO1SET =(1<<26);
// LCD reset
FIO1DIR |= BIT2;
FIO1SET = BIT2;
// Set to HIGH (assert CS_LCD low to enable transmission)
FIO1DIR |= BIT12;
FIO1SET = BIT12;

SSP0CR1 = 0x2; // Enable the SSP

// SSP0CR0 = 0x00C8; // Phase = 1, Polarity = 1, SPI mode, 9 bits
SSP0CR0 = 0x0048; // Phase = 0, Polarity = 1, SPI mode, 9 bits
//SSP0CR0 = 0x0088; // Phase = 1, Polarity = 0, SPI mode, 9 bits
//SSP0CR0 = 0x0008; // Phase = 0, Polarity = 0, SPI mode, 9 bits

//SSP0CR0 = 8 | 7 << 8; // 1000 | 0111 -> 1111 -> 0xF <<8 -> 1111 0000 0000 -> 0x0F00

SSP0CPSR = 18; // 4 MHz clock rate (72/18)
//SSP0CPSR = 0x4; // 3

}
// *****************************************************************************
// WriteSpiCommand.c
//
// Writes 9-bit command to LCD display via SPI interface
//
// Inputs: data - Epson S1D15G00 controller/driver command
//
//
// Note: clears bit 8 to indicate command transfer
//
// Author: Olimex, James P Lynch August 30, 2007
// *****************************************************************************
void WriteSpiCommand(volatile unsigned int command) {
// wait for the previous transfer to complete
while((SSP0SR & (1<<0)) == 0);
// clear bit 8 - indicates a "command"
command = (command & ~0x0100);
// send the command
SSP0DR = command;
}
// *****************************************************************************
// WriteSpiData.c
//
// Writes 9-bit command to LCD display via SPI interface
//
// Inputs: data - Epson S1D15G00 controller/driver command
//
//
// Note: Sets bit 8 to indicate data transfer
//
// Author: Olimex, James P Lynch August 30, 2007
// *****************************************************************************
void WriteSpiData(volatile unsigned int data) {
// wait for the transfer to complete
while((SSP0SR & (1<<0)) == 0);
// set bit 8, indicates "data"
data = (data | 0x0100);
// send the data
SSP0DR = data;
}
// *****************************************************************************
// Backlight.c
//
// Turns the backlight on and off
//
// Inputs: state - 1 = backlight on
// 2 = backlight off
//
//
// Author: Olimex, James P Lynch August 30, 2007
// *****************************************************************************
void Backlight(unsigned char state) {
if(state == 1)
FIO1CLR = BIT20; // Set PB20 to HIGH
else
FIO1SET = BIT20; // Set PB20 to LOW
}
// *****************************************************************************
// InitLcd.c
//
// Initializes the Epson S1D15G00 LCD Controller
//
// Inputs: none
//
// Author: James P Lynch August 30, 2007
// *****************************************************************************
void InitLcd(void) {

// PCONP |=(1<<8);
// PCONP |=(1<<21);
// SCS |= (1<<1);
// SCS |= (1UL<<0);
// PINSEL3 |= 0x0003CF00; // setup SCK0, SSEL0, MISO0, MOSI0
//PINSEL3 |= 3 << 8 | 3 << 10 | 3 << 14;
// SSP0CR1 = 0x2; // Enable the SSP

// SSP0CR0 = 0x00C8; // Phase = 1, Polarity = 1, SPI mode, 9 bits
//SSP0CR0 = 0x0048; // Phase = 0, Polarity = 1, SPI mode, 9 bits
//SSP0CR0 = 0x0088; // Phase = 1, Polarity = 0, SPI mode, 9 bits
//SSP0CR0 = 0x0008; // Phase = 0, Polarity = 0, SPI mode, 9 bits
// SSP0CR0 = 8 | 7 << 8;
//SSP0CPSR = 18; // 4 MHz clock rate (72/18)
// SSP0CPSR = 0x2;
// Hardware reset
//LCD_RESET_LOW;
//Delay(10000);
//LCD_RESET_HIGH;
//Delay(10000);
SCS |= (1UL<<0);
FIO3DIR |= (1<<25); // make output pin
FIO3CLR = (1<<25); // pull low to reset LCD
FIO3SET = (1<<25); // end reset

// Display control
WriteSpiCommand(DISCTL);
WriteSpiData(0x00); // P1: 0x00 = 2 divisions, switching period=8 (default)
WriteSpiData(0x20); // P2: 0x20 = nlines/4 - 1 = 132/4 - 1 = 32)
WriteSpiData(0x00); // P3: 0x00 = no inversely highlighted lines

// COM scan
WriteSpiCommand(COMSCN);
WriteSpiData(1); // P1: 0x01 = Scan 1->80, 160<-81

// Internal oscilator ON
WriteSpiCommand(OSCON);
// Sleep out
WriteSpiCommand(SLPOUT);
// Power control
WriteSpiCommand(PWRCTR);
WriteSpiData(0x0f); // reference voltage regulator on, circuit voltage follower on, BOOST ON
// Inverse display
WriteSpiCommand(DISINV);
//WriteSpiCommand(DISNOR);

// WriteSpiCommand(RGBSET8);

// Data control
WriteSpiCommand(DATCTL);
WriteSpiData(0x00); //changed to 0x00 by mcm on 12/12/09 - page address normal
// P1: 0x01 = page address inverted, column address normal, address scan in column direction

WriteSpiData(0x00); // P2: 0x00 = RGB sequence (default value)
WriteSpiData(0x02); // P3: 0x02 = Grayscale -> 16 (selects 12-bit color, type A)

// Voltage control (contrast setting)
WriteSpiCommand(VOLCTR);
WriteSpiData(43); // P1 = 32 volume value (experiment with this value to get the best contrast)
WriteSpiData(3); // P2 = 3 resistance ratio (only value that works)

// allow power supply to stabilize
Delay(100000);
// turn on the display
WriteSpiCommand(DISON);
}

// *****************************************************************************
// LCDClearScreen.c
//
// Clears the LCD screen to single color (BLACK)
//
// Inputs: none
//
// Author: James P Lynch August 30, 2007
// *****************************************************************************
void LCDClearScreen(void) {
long i; // loop counter
// Row address set (command 0x2B)
WriteSpiCommand(PASET);
WriteSpiData(0);
WriteSpiData(131);
// Column address set (command 0x2A)
WriteSpiCommand(CASET);
WriteSpiData(0);
WriteSpiData(131);
// set the display memory to BLACK
WriteSpiCommand(RAMWR);
for(i = 0; i < ((131 * 131) / 2); i++) {
WriteSpiData((BACKGRND >> 4) & 0xFF);
WriteSpiData(((BACKGRND & 0xF) << 4) | ((BACKGRND >> 8) & 0xF));
WriteSpiData(BACKGRND & 0xFF);
}
}
// *****************************************************************************
// LCDPutChar.c
//
// Draws an ASCII character at the specified (x,y) address and color
//
// Inputs: c = character to be displayed
// x = row address (0 .. 131)
// y = column address (0 .. 131)
// size = font pitch (SMALL, MEDIUM, LARGE)
// fcolor = 12-bit foreground color value rrrrggggbbbb
// bcolor = 12-bit background color value rrrrggggbbbb
//
// Returns: nothing
//
// Notes: Here's an example to display "E" at address (20,20)
//
// LCDPutChar('E', 20, 20, MEDIUM, WHITE, BLACK);
//
// (27,20) (27,27)
// | |
// | |
// ^ V V
// : _ # # # # # # # 0x7F
// : _ _ # # _ _ _ # 0x31
// : _ _ # # _ # _ _ 0x34
// x _ _ # # # # _ _ 0x3C
// : _ _ # # _ # _ _ 0x34
// : _ _ # # _ _ _ # 0x31
// : _ # # # # # # # 0x7F
// : _ _ _ _ _ _ _ _ 0x00
// ^ ^
// | |
// | |
// (20,20) (20,27)
//
// ------y----------->
//
//
// The most efficient way to display a character is to make use of the "wrap-around" feature
// of the Epson S1D16G00 LCD controller chip.
//
// Assume that we position the character at (20, 20) that's a (row, col) specification.
// With the row and column address set commands, you can specify an 8x8 box for the SMALL and MEDIUM
// characters or a 16x8 box for the LARGE characters.
//
// WriteSpiCommand(PASET); // set the row drawing limits
// WriteSpiData(20); //
// WriteSpiData(27); // limit rows to (20, 27)
//
// WriteSpiCommand(CASET); // set the column drawing limits
// WriteSpiData(20); //
// WriteSpiData(27); // limit columns to (20,27)
//
// When the algorithm completes col 27, the column address wraps back to 20
// At the same time, the row address increases by one (this is done by the controller)
//
// We walk through each row, two pixels at a time. The purpose is to create three
// data bytes representing these two pixels in the following format
//
// Data for pixel 0: RRRRGGGGBBBB
// Data for Pixel 1: RRRRGGGGBBBB
//
// WriteSpiCommand(RAMWR); // start a memory write (96 data bytes to follow)
//
// WriteSpiData(RRRRGGGG); // first pixel, red and green data
// WriteSpiData(BBBBRRRR); // first pixel, blue data; second pixel, red data
// WriteSpiData(GGGGBBBB); // second pixel, green and blue data
// :
// and so on until all pixels displayed!
// :
// WriteSpiCommand(NOP); // this will terminate the RAMWR command
//
//
// Author: James P Lynch August 30, 2007
// *****************************************************************************
void LCDPutChar(char c, int x, int y, int size, int fColor, int bColor)
{
// extern const unsigned char FONT6x8[97][8];
// extern const unsigned char FONT8x8[97][8];
// extern const unsigned char FONT8x16[97][16];
extern const unsigned char *FontTable[];

int i;
unsigned int j;
unsigned int nCols;
unsigned int nRows;
unsigned int nBytes;
unsigned char PixelRow;
unsigned char Mask;
unsigned int Word0;
unsigned int Word1;
unsigned char *pFont;
unsigned char *pChar;
// unsigned char *FontTable[] = { (unsigned char *)FONT6x8,
// (unsigned char *)FONT8x8,
// (unsigned char *)FONT8x16};

// get pointer to the beginning of the selected font table
pFont = (unsigned char *)FontTable[size];
// get the nColumns, nRows and nBytes
nCols = *pFont;
nRows = *(pFont + 1);
nBytes = *(pFont + 2);
// get pointer to the last byte of the desired character
// pChar = pFont + (nBytes * (c - 0x1F)) + nBytes - 1;

// get pointer to the first byte of the desired character
pChar = pFont + (nBytes * (c - 0x1F)) ;

// Row address set (command 0x2B)
WriteSpiCommand(PASET);
WriteSpiData(x);
WriteSpiData(x + nRows - 1 );
// Column address set (command 0x2A)
WriteSpiCommand(CASET);
WriteSpiData(y);
WriteSpiData(y + nCols - 1);
// WRITE MEMORY
WriteSpiCommand(RAMWR);

// loop on each row, working from the top to the bottom
for (i = nRows - 1; i >= 0; i--)
{
// copy pixel row from font table and then decrement row
PixelRow = *pChar++;
// loop on each pixel in the row (left to right)
// Note: we do two pixels each loop
Mask = 0x80;
for (j = 0; j < nCols; j += 2)
{
// if pixel bit set, use foreground color; else use the background color
// now get the pixel color for two successive pixels
if ((PixelRow & Mask) == 0)
Word0 = bColor;
else
Word0 = fColor;

Mask = Mask >> 1;

if ((PixelRow & Mask) == 0)
Word1 = bColor;
else
Word1 = fColor;

Mask = Mask >> 1;
// use this information to output three data bytes
WriteSpiData((Word0 >> 4) & 0xFF);
WriteSpiData(((Word0 & 0xF) << 4) | ((Word1 >> 8) & 0xF));
WriteSpiData(Word1 & 0xFF);
}
}

// terminate the Write Memory command
WriteSpiCommand(NOP);
}
// *************************************************************************************************
// LCDPutStr.c
//
// Draws a null-terminates character string at the specified (x,y) address, size and color
//
// Inputs: pString = pointer to character string to be displayed
// x = row address (0 .. 131)
// y = column address (0 .. 131)
// Size = font pitch (SMALL, MEDIUM, LARGE)
// fColor = 12-bit foreground color value rrrrggggbbbb
// bColor = 12-bit background color value rrrrggggbbbb
//
//
// Returns: nothing
//
// Notes: Here's an example to display "Hello World!" at address (20,20)
//
// LCDPutChar("Hello World!", 20, 20, LARGE, WHITE, BLACK);
//
//
// Author: James P Lynch August 30, 2007
// *************************************************************************************************
void LCDPutStr(char *pString, int x, int y, int Size, int fColor, int bColor)
{
// loop until null-terminator is seen
while (*pString != 0x00)
{
// draw the character
LCDPutChar(*pString++, x, y, Size, fColor, bColor);

// advance the y position
if (Size == SMALL)
y = y + 6;
else if (Size == MEDIUM)
y = y + 8;
else
y = y + 8;

// bail out if y exceeds 131
if (y > 131) break;
}
}
// *****************************************************************************
// Delay.c
//
// Simple for loop delay
//
// Inputs: a - loop count
//
// Author: James P Lynch August 30, 2007
// *****************************************************************************
void Delay (unsigned long a) {
while (--a!=0);
}
// *********************************************************************************
//
// Font tables for Nokia 6610 LCD Display Driver (S1D15G00 Controller)
//
// FONT6x8 - SMALL font (mostly 5x7)
// FONT8x8 - MEDIUM font (8x8 characters, a bit thicker)
// FONT8x16 - LARGE font (8x16 characters, thicker)
//
// Note: ASCII characters 0x00 through 0x1F are not included in these fonts.
//
// Author: Jim Parise, James P Lynch August 30, 2007
// *********************************************************************************
const unsigned char FONT6x8[97][8] = {
{0x06,0x08,0x08,0x00,0x00,0x00,0x00,0x00,}, // columns, rows, num_bytes_per_char
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,}, // space 0x20
{0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00,}, // !
{0x50,0x50,0x50,0x00,0x00,0x00,0x00,0x00,}, // "
{0x50,0x50,0xF8,0x50,0xF8,0x50,0x50,0x00,}, // #
{0x20,0x78,0xA0,0x70,0x28,0xF0,0x20,0x00,}, // $
{0xC0,0xC8,0x10,0x20,0x40,0x98,0x18,0x00,}, // %
{0x40,0xA0,0xA0,0x40,0xA8,0x90,0x68,0x00,}, // &
{0x30,0x30,0x20,0x40,0x00,0x00,0x00,0x00,}, // '
{0x10,0x20,0x40,0x40,0x40,0x20,0x10,0x00,}, // (
{0x40,0x20,0x10,0x10,0x10,0x20,0x40,0x00,}, // )
{0x00,0x20,0xA8,0x70,0x70,0xA8,0x20,0x00,}, // *
{0x00,0x20,0x20,0xF8,0x20,0x20,0x00,0x00,}, // +
{0x00,0x00,0x00,0x00,0x30,0x30,0x20,0x40,}, // ,
{0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,}, // -
{0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,}, // .
{0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,}, // / (forward slash)
{0x70,0x88,0x88,0xA8,0x88,0x88,0x70,0x00,}, // 0 0x30
{0x20,0x60,0x20,0x20,0x20,0x20,0x70,0x00,}, // 1
{0x70,0x88,0x08,0x70,0x80,0x80,0xF8,0x00,}, // 2
{0xF8,0x08,0x10,0x30,0x08,0x88,0x70,0x00,}, // 3
{0x10,0x30,0x50,0x90,0xF8,0x10,0x10,0x00,}, // 4
{0xF8,0x80,0xF0,0x08,0x08,0x88,0x70,0x00,}, // 5
{0x38,0x40,0x80,0xF0,0x88,0x88,0x70,0x00,}, // 6
{0xF8,0x08,0x08,0x10,0x20,0x40,0x80,0x00,}, // 7
{0x70,0x88,0x88,0x70,0x88,0x88,0x70,0x00,}, // 8
{0x70,0x88,0x88,0x78,0x08,0x10,0xE0,0x00,}, // 9
{0x00,0x00,0x20,0x00,0x20,0x00,0x00,0x00,}, // :
{0x00,0x00,0x20,0x00,0x20,0x20,0x40,0x00,}, // ;
{0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x00,}, // <
{0x00,0x00,0xF8,0x00,0xF8,0x00,0x00,0x00,}, // {0x40,0x20,0x10,0x08,0x10,0x20,0x40,0x00,}, // >
{0x70,0x88,0x08,0x30,0x20,0x00,0x20,0x00,}, // ?
{0x70,0x88,0xA8,0xB8,0xB0,0x80,0x78,0x00,}, // @ 0x40
{0x20,0x50,0x88,0x88,0xF8,0x88,0x88,0x00,}, // A
{0xF0,0x88,0x88,0xF0,0x88,0x88,0xF0,0x00,}, // B
{0x70,0x88,0x80,0x80,0x80,0x88,0x70,0x00,}, // C
{0xF0,0x88,0x88,0x88,0x88,0x88,0xF0,0x00,}, // D
{0xF8,0x80,0x80,0xF0,0x80,0x80,0xF8,0x00,}, // E
{0xF8,0x80,0x80,0xF0,0x80,0x80,0x80,0x00,}, // F
{0x78,0x88,0x80,0x80,0x98,0x88,0x78,0x00,}, // G
{0x88,0x88,0x88,0xF8,0x88,0x88,0x88,0x00,}, // H
{0x70,0x20,0x20,0x20,0x20,0x20,0x70,0x00,}, // I
{0x38,0x10,0x10,0x10,0x10,0x90,0x60,0x00,}, // J
{0x88,0x90,0xA0,0xC0,0xA0,0x90,0x88,0x00,}, // K
{0x80,0x80,0x80,0x80,0x80,0x80,0xF8,0x00,}, // L
{0x88,0xD8,0xA8,0xA8,0xA8,0x88,0x88,0x00,}, // M
{0x88,0x88,0xC8,0xA8,0x98,0x88,0x88,0x00,}, // N
{0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00,}, // O
{0xF0,0x88,0x88,0xF0,0x80,0x80,0x80,0x00,}, // P 0x50
{0x70,0x88,0x88,0x88,0xA8,0x90,0x68,0x00,}, // Q
{0xF0,0x88,0x88,0xF0,0xA0,0x90,0x88,0x00,}, // R
{0x70,0x88,0x80,0x70,0x08,0x88,0x70,0x00,}, // S
{0xF8,0xA8,0x20,0x20,0x20,0x20,0x20,0x00,}, // T
{0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,}, // U
{0x88,0x88,0x88,0x88,0x88,0x50,0x20,0x00,}, // V
{0x88,0x88,0x88,0xA8,0xA8,0xA8,0x50,0x00,}, // W
{0x88,0x88,0x50,0x20,0x50,0x88,0x88,0x00,}, // X
{0x88,0x88,0x50,0x20,0x20,0x20,0x20,0x00,}, // Y
{0xF8,0x08,0x10,0x70,0x40,0x80,0xF8,0x00,}, // Z
{0x78,0x40,0x40,0x40,0x40,0x40,0x78,0x00,}, // [
{0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00,}, // \ (back slash)
{0x78,0x08,0x08,0x08,0x08,0x08,0x78,0x00,}, // ]
{0x20,0x50,0x88,0x00,0x00,0x00,0x00,0x00,}, // ^
{0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x00,}, // _
{0x60,0x60,0x20,0x10,0x00,0x00,0x00,0x00,}, // ` 0x60
{0x00,0x00,0x60,0x10,0x70,0x90,0x78,0x00,}, // a
{0x80,0x80,0xB0,0xC8,0x88,0xC8,0xB0,0x00,}, // b
{0x00,0x00,0x70,0x88,0x80,0x88,0x70,0x00,}, // c
{0x08,0x08,0x68,0x98,0x88,0x98,0x68,0x00,}, // d
{0x00,0x00,0x70,0x88,0xF8,0x80,0x70,0x00,}, // e
{0x10,0x28,0x20,0x70,0x20,0x20,0x20,0x00,}, // f
{0x00,0x00,0x70,0x98,0x98,0x68,0x08,0x70,}, // g
{0x80,0x80,0xB0,0xC8,0x88,0x88,0x88,0x00,}, // h
{0x20,0x00,0x60,0x20,0x20,0x20,0x70,0x00,}, // i
{0x10,0x00,0x10,0x10,0x10,0x90,0x60,0x00,}, // j
{0x80,0x80,0x90,0xA0,0xC0,0xA0,0x90,0x00,}, // k
{0x60,0x20,0x20,0x20,0x20,0x20,0x70,0x00,}, // l
{0x00,0x00,0xD0,0xA8,0xA8,0xA8,0xA8,0x00,}, // m
{0x00,0x00,0xB0,0xC8,0x88,0x88,0x88,0x00,}, // n
{0x00,0x00,0x70,0x88,0x88,0x88,0x70,0x00,}, // o
{0x00,0x00,0xB0,0xC8,0xC8,0xB0,0x80,0x80,}, // p 0x70
{0x00,0x00,0x68,0x98,0x98,0x68,0x08,0x08,}, // q
{0x00,0x00,0xB0,0xC8,0x80,0x80,0x80,0x00,}, // r
{0x00,0x00,0x78,0x80,0x70,0x08,0xF0,0x00,}, // s
{0x20,0x20,0xF8,0x20,0x20,0x28,0x10,0x00,}, // t
{0x00,0x00,0x88,0x88,0x88,0x98,0x68,0x00,}, // u
{0x00,0x00,0x88,0x88,0x88,0x50,0x20,0x00,}, // v
{0x00,0x00,0x88,0x88,0xA8,0xA8,0x50,0x00,}, // w
{0x00,0x00,0x88,0x50,0x20,0x50,0x88,0x00,}, // x
{0x00,0x00,0x88,0x88,0x78,0x08,0x88,0x70,}, // y
{0x00,0x00,0xF8,0x10,0x20,0x40,0xF8,0x00,}, // z
{0x10,0x20,0x20,0x40,0x20,0x20,0x10,0x00,}, // {
{0x20,0x20,0x20,0x00,0x20,0x20,0x20,0x00,}, // |
{0x40,0x20,0x20,0x10,0x20,0x20,0x40,0x00,}, // }
{0x40,0xA8,0x10,0x00,0x00,0x00,0x00,0x00,}, // ~
{0x70,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00}}; // DEL

/*

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