//*****************************************************************************
// Last Rev: 10/2/2006
// Lab 2 LCD Code
// Purpose:  This code demonstrates communication to the LCD screen on the
//           MCUSLK project board.  

#include <hidef.h>      /* common defines and macros */
#include <mc9s12c32.h>     /* derivative information */
#pragma LINK_INFO DERIVATIVE "mc9s12c32"


#define ENABLE_BIT 0x80
#define RS_BIT 0x40

void LCDInit(void);
void LCDdelay(unsigned long ms);
void spiWR(unsigned char data);
void LCDWR(unsigned char data);
void LCDChar(unsigned char letter);
void LCDString(char *pt);
void LCDClear(void);

void LCDCursorOn(void);
void LCDCursorOff(void);

void main(void) {

  EnableInterrupts;

  LCDInit();
  LCDClear();
  LCDString("ECE5780\nLab2");
  LCDCursorOff();

  for(;;) {} /* loop forever */
  /* please make sure that you never leave this function */
}




//****************************************************************************
// See document AN1774.pdf pg 11
// Purpose:  These set of instructions initialize the LCD screen
// after power ON.  The necessary 4bit data mode is set
// and requires two writes for each write.
//****************************************************************************
void LCDInit() {
  //set up SPI to write to LCD
  SPICR1 = 0x5E;
  //Data Sheet - PG419
  //bit7 - SPI Interrupt Enable Bit
  //bit6 - SPI System Enable Bit
  //bit5 - SPI Transmit Interrupt Enable
  //bit4 - SPI Master/Slave Mode Select Bit
  //bit3 - SPI Clock Polarity Bit
  //bit2 - SPI Clock Phase Bit
  //bit1 - Slave Select Output Enable
  //bit0 - LSB-First Enable 
  
  
  
  SPICR2 = 0x10;
  //bit 4 - Mode Fault Enable Bit
  //bit 3 - Output Enable in the Bidirectional Mode of Operation
  //bit 1 - SPI Stop in LCDdelay Mode Bit
  //bit 0 - Serial Pin Control Bit 0
  
  
  //MISO - Master In, Serial Out
  //MOSI - Master Out, Serial In
  
  
  
  
  //baud rate = 8 MHz / 640 = 12.5 KHz
  //0100 0110
  //baud rate = 8 MHz / 8 = 1 MHz
  //0111 0000
  SPIBR = 0x70;
  
  LCDdelay(10);
  
  
  LCDWR(0x03);  // Set interface is 8bits
  LCDdelay(10);
  LCDWR(0x03);  // Set interface is 8 bits
  LCDdelay(10);
  LCDWR(0x03);  // Set interface is 8 bits
  LCDdelay(1);
  LCDWR(0x02);  // Set interface is 4 bits
  
  LCDWR(0x02);  // Set interface is 4 bits
  LCDWR(0x08);  // Specify Display Lines and Fonts
  LCDdelay(10);            // 1 = # of lines, 0 Font
  
  //Display OFF
  LCDWR(0x00);  
  LCDWR(0x08);
  LCDdelay(10);
  
  //Clear display
  LCDWR(0x00);
  LCDWR(0x01);
  LCDdelay(16);
  
  //Entry mode Set
  LCDWR(0x00);
  LCDWR(0x06);
  LCDdelay(10);
  
  
  //Turn display on with blinking cursor
  LCDWR(0x00);
  LCDWR(0x0F);

}

//******************************************************************************
//Purpose:  This function clears the data from the LCD screen and returns
//          the cursor back to home.
//******************************************************************************
void LCDClear() {
 //Clear
  LCDWR(0x00);
  LCDWR(0x01);
  LCDdelay(10);

  //Return the cursor home
  LCDWR(0x00);
  LCDWR(0x02);
  LCDdelay(10);

}




//******************************************************************************
//Purpose:  LCDCursorOff turns off the cursor indicator of the LCD display
//          proceeds to send the new data.
//******************************************************************************
void LCDCursorOff(){
  LCDWR(0x00);
  LCDWR(0x0C);
}


//******************************************************************************
//Purpose:  LCDCursorOn turns on the cursor indicator of the LCD display
//          
//******************************************************************************
void LCDCursorOn(){
  LCDWR(0x00);
  LCDWR(0x0F); 
}



//******************************************************************************
//Purpose:  spiWR waits for the SPI to report it's ready to accept new data and then
//          proceeds to send the new data.
//******************************************************************************
void spiWR(unsigned char data) {

  while (!(SPISR & 0x20));                              //Loop until SPTEF = 1
  SPIDR = data;                                         //Send data out to 74HC595 Chip
}





//******************************************************************************
//Purpose:  LCDString accepts a string and sends each character
//          to the LCDChar function to output the character onto the LCD screen.
//******************************************************************************
void LCDString(char *pt){
  int temp = 0;
  int j = 0;
  while(*pt) {
    if(*pt == '\n') {
      for(j = 0; j < (40-temp); j++) {
        LCDChar(' ');
      }
    pt++;
    temp=0;  
    } 
    else {
    LCDChar(*pt);
    pt++;
    temp++;
    }
  }
}

//******************************************************************************
//Purpose:  LCDChar sends the proper communication over the SPI to the 
//          74HC95 chip.  The chip in turn communicates with the LCD module as 
//          specified in the AN1774 document.
//******************************************************************************                                                                            
void LCDChar(unsigned char outchar){

  // Output the higher four bits.
  spiWR((0x0F&(outchar>>4)) & ~ENABLE_BIT | RS_BIT);    // Place data onto bus
  LCDdelay(1);
  spiWR((0x0F&(outchar>>4)) | ENABLE_BIT | RS_BIT);     // Set EN
  LCDdelay(1);                                          // LCDdelay for 1 ms.
  spiWR((0x0F&(outchar>>4)) & ~ENABLE_BIT | RS_BIT);    // Clear EN.
  LCDdelay(1);  
  
  // Output the lower four bits.
  spiWR((0x0F&(outchar)) & ~ENABLE_BIT | RS_BIT);       // Place lower four bits onto bus.
  LCDdelay(1);
  spiWR((0x0F&(outchar)) | ENABLE_BIT | RS_BIT);        // Set EN
  LCDdelay(1);                                          // LCDdelay for 1ms.
  spiWR((0x0F&(outchar)) & ~ENABLE_BIT | RS_BIT);       // Clear EN
  LCDdelay(1);  
    
}


//******************************************************************************
//Purpose:  LCDWR sends a 4-bit messages to the LCD module.  Used to send
//          setup instructions to the LCD module.
//******************************************************************************

void LCDWR(unsigned char data) {
  spiWR(data & ~ENABLE_BIT);
  LCDdelay(1);
  spiWR(data | ENABLE_BIT);     // Set EN
  LCDdelay(1);
  spiWR(data & ~ENABLE_BIT);    // Clear EN
  LCDdelay(1);  
}

//******************************************************************************
//Purpose:  LCDdelay is a custom delay function that loops for a number of cycles
//          based on the number of miliseconds specified in its parameter. 
//******************************************************************************
void LCDdelay(unsigned long ms) {
char i;

for (i=0;i < ms; i++) {
  
asm {
PSHX
LDX #$640
Loop:
NOP
NOP
DBNE X, Loop
PULX
}

}
}