/*
*************************************************************************************************
*	  								  SSD1289 driver for PIC24
*										All Rights Reserved
* File name		: SSD1289.c
* Programmer 	: John Leung, TechToys Co. Hong Kong
* Web presence  : www.TechToys.com.hk
* Note			: 
* Language		: C30 complier version 3.01, MPLAB v7.60
* Hardware		: PIC24_Eval1 connected to a prototype board for FG020214 by strip wires
* Date			: 3 Nov 2007		Version 1.0a
*************************************************************************************************
*										DESCRIPTION
*
* This module provides an interface to FG020214 262k color graphical LCD module of 240*320dots
* Display controller chip is SSD1289
* Module requires 3.3V DC supply to Vdd, LED backlight requires 15mA typical
* Backlight driven by LT1932 for 15mA constant current driver
* <PS3:PS1:PS0> in <1:0:0> for 8-bit data bus mode 8080
* PMP module used for interface. 
*
* LCD pinout function on PCB (FG020214_BO) summarized as below 
* --------- LCD		MCU -----------------
* pin 2		SHDN_BL - PWM for brightness control
* pin 4 	GND 	- GND
* pin 6		VCC  	- 3.3V supply
* pin 8		n.c.	- n.c.
* pin 10	WR		- PMWR(RD4)
* pin 12	RD		- PMRD(RD5)
* pin 14	CS		- PMCS1(RD11)
* pin 16	CD		- PMA0(RB15)
* pin 18	RST		- To system reset
* pin 20:34	D0:D7	- LCD_DATA connected to PMD0:7 (RE0:7)
* pin 36	SHUT	- n.c.
* pin 38	n.c.
* pin 40	n.c.
*
* Remarks: Pins at the odd number side is not used for 8-bit mode. 
*
***********************************************************************************************
*/


#include <p24fj128ga010.h>	
#define USE_AND_OR					//use & | mask for configuration bits for Timer1
#include <timer.h>					//use peripheral library provided by C30							
#include "SSD1289.h"
#include "sysfont.h"	

/*
*********************************************************************************************************
*											LOCAL DEFINITIONS
*********************************************************************************************************
*/

//PMA0 has been wired to DC pin of the LCD module.  This allows us to control command/data write 
//by a single instruction as PMADDR = 1 for data, or PMADDR = 0 for command read/write.
//Since we are using PMCS1 as the chip select CS line of LCD, we also need to activiate
//PMCS1 via an instruction PMADDR = 0x4000. Putting them together we just need to define a constant
//value for LCDDATA (0x4001) for data read/write, and LCDCMD (0x4000) for command read/write
//For details please consult REGISTER PMADDR for reference
#define LCDDATA			0x4001	//CD = 1 for data read/write with bitwise OR 0x4000 for PMCS1 enable
#define LCDCMD			0x4000	//CD = 0 for command read/write with bitwise OR 0x4000 for PMCS1 enable


/*
*********************************************************************************************************
*                         				DISPLAY INITIALIZATION
*
* Description : This function initializes the LCD module		
* Arguments   : none
*			
* Returns     : none
* Note		  : This function should be called once before any of the other functions
*********************************************************************************************************
*/
void cDispInit(void)
{
	cDispInitPort();

	cDispWrCmd(0x00);	//Start Oscillation
	cDispWrDat(0x0001);

	cDispWrCmd(0x01);	//Driver Output Control
	cDispWrDat(0x233F);

	cDispWrCmd(0x02);	//LCD Drive AC Control
	cDispWrDat(0x0600);

	cDispWrCmd(0x03);	//Power Control (1)
	cDispWrDat(0xA8A6);

	cDispWrCmd(0x07);	//Display Control
	cDispWrDat(0x0033);

	cDispWrCmd(0x11);	//Entry Mode (R11h): Set Display color mode for 65k/262k color
	cDispWrDat(0x6830);	//DFM1:DFM0=1:1 for 65k color (POR)
	
	cDispWrCmd(0x0C);	//Power Control (2)
	cDispWrDat(0x0005);

	cDispWrCmd(0x0D);	//Power Control (3)
	cDispWrDat(0x300B);

	cDispWrCmd(0x0E);	//Power Control (4)
	cDispWrDat(0x2000);

	cDispWrCmd(0x10);	//Exit Sleep Mode
	cDispWrDat(0x0000);

	TMR1 = 0;
	while(TMR1<2000);	//2000*16us tick = 32ms (16us tick configured in cDispInitPort())
	//DelayMs(30);		//delay 30ms

	cDispWrCmd(0x1E);	//Power Control (5)
	cDispWrDat(0x00A8);

	cDispWrCmd(0x44);	//Horizontal RAM address position start/end setup
	cDispWrDat(0xEF00);	//dec 239
						//dec 0, i.e. horizontal ranges from 0 -> 239
						//POR value is 0xEF00 anyway. This address must be set before RAM write
	
	cDispWrCmd(0x45);	//Vertical RAM address start position setting
	cDispWrDat(0x0000);	//0x0000 = dec 0

	cDispWrCmd(0x46);	//Vertical RAM address end position setting
	cDispWrDat(0x013F);	//0x013F = dec 319

	cDispWrCmd(0x22);	//RAM write command

						//clear display in white color here
	cDispClr(RGB16(31,63,31));

}

	
/*
*********************************************************************************************************
*                         	CLEAR DISPLAY BY WRITING PURE COLOR TO THE WHOLE SCREEN
*
* Description : This function writes a 16 bit integer to all pixels making use of the automatic
*				address increment feature for X and Y address counters
*
* Arguments   : 'color' is in 16-bit in form of RGB16(r,g,b) for 65k color display mode
* 				16-bit color in [R4R3R2R1R0G5G4G3][G2G1G0B4B3B2B1B0]
*				Therefore (r,g,b) from (0,0,0) to (31,63,31)
*						color=0x0000 eq. black
*						color=0xF800 eq. red
*						color=0x07E0 eq. green
*						color=0x001F eq. blue		
*						color=0xFFFF in white		
* Returns     : none
* Remarks	  :
*
*********************************************************************************************************
*/
void cDispClr(INT16U color)
{
	INT16U i,j;

	for(j=0;j<320;j++)
	{
		for(i=0;i<240;i++)
		{
			cDispWrDat(color);
		}
	}
	
}


/*
*********************************************************************************************************
*                         				SET PIXEL AT x, y POSITION
*
* Description : This function sets a pixel with (INT16U)color at a position defined by (x,y) following 
*				Cartesian coordinate system. Coordinates (0,0) at the top left corner, 
*				coordinates (239,319) at the lower right corner of the LCD screen, w/ module viewed from
*				frontal up direction on FG020214_BO
*
* Arguments   : 'x'    		0....239 is the matrix position in x-axis (left ->right)
*				'y'    		0....319 is the matrix position in y-axis (up -> down)
*				'color'  	sets 16-bit color
* Returns     : none
* Notes		  :
*********************************************************************************************************
*/
void cDispSetPixel(INT8U x, INT16U y, INT16U color)
{
	cDispWrCmd(0x4E);		//set address in the 240 pixel direction
	cDispWrDat(x);			//0<x<239

	cDispWrCmd(0x4F);		//set address in the 320 pixel direction
	cDispWrDat(y);

	cDispWrCmd(0x22);		//RAM write command
	cDispWrDat(color);		//write color content here	
}


/*
*********************************************************************************************************
*               		CONVERT A STRING FROM ROM TO PIXEL DATA AND DISPLAY AT x,y
*
* Description : This function outputs a string in graphic mode (pixel-by-pixel) at a position defined 
*				by (x,y) following Cartesian coordinate system with variable font spacing defined by 
*				fontSpace. Character wrapping is allowed. String from ROM so const rom keyword used
*				*** REQUIRE AT LEAST ONE FONT SET (sysfont.h) included under this file ****
*				Cartesian coordinates as (0,0) at the top left hand corner, (239,319) at the 
*				lower right hand corner, as seen from frontal up view of FG020214_BO
*
* Arguments   : 'x'    		0....239 is matrix position in horizontal direction (x-axis).
*							
*				'y'    		0....319 is matrix position in vertical direction (y-axis).
*
*				'*pStr'		pointer to an ASCII string in ROM (flash), null terminated
*				'fontSpace' font spacing from 1 to 127
*				'color'		16-bit color possible
* Returns     : none
* Notes		  : 
* Example 	  : ....
*				....
*				main()
*				{ 
*					cDispPixStrAt(0,20,"Hello!",1,RGB(31,0,0)); 	//Display the ASCII string "Hello!"
*																	//at (x,y)=(0,20), font space = 1
*																	//color in red
*				}
*********************************************************************************************************
*/
void cDisprStrAt(INT8U x, INT16U y, const char *pStr, INT8U fontSpace, INT16U color)
{
	INT8U pixelByte,bit_idx, i;				//loop counters 
	INT8U c,fwidth, fheight;				//character, font width & height store

	while (*pStr)
	{
		c = *pStr++ - 32;
				
		fwidth = SYS_FNT[c].fontWidth;
		fheight = 8;

		if((x+fwidth)>240) 		//character wrapping here				
		{
			x=0;
			y+=fheight;
		}

		if((y+fheight)>320)		//check for y boundary				
		{
			y=0;
		}

		for(i=0;i<fheight;i++)
		{
			pixelByte = SYS_FNT[c].fontBody[i];
			for(bit_idx=0; bit_idx<fwidth; bit_idx++)
				{
						if((pixelByte)&(0x80>>bit_idx))
							cDispSetPixel(x+bit_idx, y+i, color);
				}
		}
		
		x = x+fwidth+fontSpace;
	}	
}

/*
*********************************************************************************************************
*                         				WRITE A PATTERN AT X, Y COORDINATES
*
* Description : This function writes a particular pattern of size patWidth and patHeight at a position 
*				defined by (x,y) following Cartesian coordinate system. 
*				Pattern defined in ROM (flash)
*				Cartesian coordinates as (0,0) at the top left hand corner, (239,319) at the 
*				lower right hand corner, as seen from frontal up view of FG020214_BO
* Arguments   : 'x'    		0....239 is matrix position in horizontal direction (x-axis)
*				'y'    		0....319 is matrix position in vertical direction (y-axis)
*				'*pPat'		pointer to pattern structure in const rom (FLASH)
*				'color'  	color in 16-bit mode
* Returns     :	none
* Notes		  : 
*********************************************************************************************************
*/
void cDisprPatAt(INT8U x, INT16U y, const INT16U *pPat)
{
 	INT16U   col, row, pWidth, pHeight, pixel;

	pWidth  = pPat[0];
	pHeight = pPat[1];

	for(row=0;row<pHeight;row++)
		{	
			for(col=0;col<pWidth;col++)
			{
				pixel = pPat[col+row*pWidth+2];
				cDispSetPixel(col+x,row+y,pixel);
			}
		}
}

/*
*********************************************************************************************************
*                         			LOW LEVEL PORT INITIALIZATION
*
* Description : This function performs low level port initialization
* Arguments   : none
* Returns     : none
* Notes		  : Hardware specific (PMP module)
*********************************************************************************************************
*/
void cDispInitPort(void)
{	
	PMCON  = 0x8380;	//enable the PMP, CS at PMCS1 (active low), active low for PMWR and PMRD
	PMMODE = 0x0200;	//Master mode 2, with the shortest waits for SSD1289
	PMAEN  = 0x4001;	//PMCS1 & PMA0 enabled
					
	//Fosc/2 = 16MHz, prescaled 1:256, it is 16us/tick
	//a PR value of 2000 implies a timeout value of 32ms for LCD startup in cDispInit(void)
	OpenTimer1((T1_ON|T1_PS_1_256),0xFFFF);
}

/*
*********************************************************************************************************
*                         				LOW LEVEL COMMAND WRITE TO LCD
*
* Description : This function performs low level command write to LCD
* Arguments   : (INT8U) 'cmd' 	is the command written to the LCD module
* Returns     : none
* Notes		  : Hardware specific (PMP module)
*********************************************************************************************************
*/
void cDispWrCmd(INT8U cmd)
{
	cDISP_CD 		= LCDCMD;	
	cDISP_DATA		= cmd;		//strobe here
}
/*
*********************************************************************************************************
*                         				LOW LEVEL DATA WRITE TO LCD
*
* Description : This function performs low level display data write to LCD
* Arguments   : (INT16U) 'dat' 	is the data written to the LCD module
* Returns     : none
* Notes		  : Hardware specific (PMP module)
*********************************************************************************************************
*/
void cDispWrDat(INT16U dat)
{
	INT8U hibyte, lowbyte;
	hibyte  = dat>>8;
	lowbyte = (INT8U)dat;

	cDISP_CD 		= LCDDATA;
	cDISP_DATA		= hibyte;		//strobe here
	cDISP_DATA		= lowbyte;		//strobe again for low 8-bits


}



