/*------------------------------------------------------------------
* Name: LCD.c
* Purpose: 2x16 Character LCD functions
*-----------------------------------------------------------------*/
#include "LCD.h"

GPIO_InitTypeDef GPIO_InitStructure;
/*------------------------------------------------------------------
LCD initialization
*-----------------------------------------------------------------*/
void LCD_Init(){
  /* Lcd Data Port Periph clock enable */
  RCC_AHB1PeriphClockCmd(LCD_DATA_PORT_CLK, ENABLE);
  GPIO_InitStructure.GPIO_Pin = LCD_D4_PIN | LCD_D5_PIN | LCD_D6_PIN | LCD_D7_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
  GPIO_Init(LCD_DATA_PORT, &GPIO_InitStructure);
  
  /* Lcd Command Port Periph clock enable */
  RCC_AHB1PeriphClockCmd(LCD_CMD_PORT_CLK, ENABLE);
  GPIO_InitStructure.GPIO_Pin = LCD_RS_PIN | LCD_E_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
  GPIO_Init(LCD_CMD_PORT, &GPIO_InitStructure);
  
  GPIO_ResetBits(LCD_CMD_PORT, LCD_E_PIN | LCD_RS_PIN);
  
  msDelay(50);        // wait for lcd to power up
  LCD_NIBBLE(0x30,0); // general initialization
  msDelay(5);         // wait 5ms
  LCD_NIBBLE(0x30,0); // general initialization
  msDelay(1);         // wait 1ms
  LCD_DATA(0x02,0);   // general initialization
  LCD_DATA(0x0c,0);   // general initialization 
  LCD_DATA(0x01,0);   // clear display
  LCD_DATA(0x06,0);   // move cursor right after write
}

/*------------------------------------------------------------------
LCD_DATA function
*-----------------------------------------------------------------*/
void LCD_DATA(unsigned char data,unsigned char type){
  msDelay(2);
  if(type == 0)                // 1 for Data Write, 0 for Command Write
  GPIO_ResetBits(LCD_CMD_PORT, LCD_RS_PIN);
  else 
  GPIO_SetBits(LCD_CMD_PORT, LCD_RS_PIN);
  
  LCD_NIBBLE(data>>4,type);    //WRITE THE UPPER NIBBLE
  LCD_NIBBLE(data,type);       //WRITE THE LOWER NIBBLE
}

/*------------------------------------------------------------------
LCD_NIBBLE function
*-----------------------------------------------------------------*/
void LCD_NIBBLE(unsigned char nibble,unsigned char type){
  LCD_DATA_PORT->ODR &= DATA_CLR;    // clear
  LCD_DATA_PORT->ODR |= (nibble << DATA); 
  
  if(type == 0)                      // 1 for Data Write, 0 for Command Write
    GPIO_ResetBits(LCD_CMD_PORT, LCD_RS_PIN);
  else 
    GPIO_SetBits(LCD_CMD_PORT, LCD_RS_PIN);
  
  GPIO_SetBits(LCD_CMD_PORT, LCD_E_PIN);
  msDelay(1); 
  GPIO_ResetBits(LCD_CMD_PORT, LCD_E_PIN);
}

/*------------------------------------------------------------------
LCD_STR function
*-----------------------------------------------------------------*/
void LCD_STR(const char *text){
  while(*text){
    LCD_DATA(*text++,1);
  }
}

/*------------------------------------------------------------------
LCD_MOVE_LINE function
*-----------------------------------------------------------------*/
void LCD_MOVE_LINE(char line){
  switch(line){
    case 0:
    case 1:
      LCD_DATA(LINE1,0);
      break;
    case 2:
      LCD_DATA(LINE2,0);
      break;
  }
}