
#include <stdio.h>

#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "inc/hw_gpio.h"

#include "driverlib/gpio.h"
#include "driverlib/rom.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"

#define ENB     0x80     // Enable
#define CMD     0x00     // Command
#define DAT     0x40     // Data
#define LCD_PIN 0xFC     // used pins

void lcd_port_init( void );
void write_4bit( unsigned char, unsigned char );
void write_8bit( unsigned char, unsigned char );
void lcd_init( void );
void lcd_clear_display( void );
void lcd_set_cursor( unsigned char, unsigned char );


// ポート初期化関数
void lcd_port_init( void )
{
    // ポートAをイネーブル
    ROM_SysCtlPeripheralEnable( SYSCTL_PERIPH_GPIOA );
    // LCDに接続しているポートを出力に設定
    ROM_GPIOPinTypeGPIOOutput( GPIO_PORTA_BASE, LCD_PIN );
    // LCDに接続しているポートにLを出力
    ROM_GPIOPinWrite( GPIO_PORTA_BASE, LCD_PIN, 0x00 );
}

// 4bitアクセス関数
void write_4bit( unsigned char rs, unsigned char data )
{
    unsigned char       data_h = ( data >> 2 ) & 0x3C;
    unsigned char       data_l = ( data << 2 ) & 0x3C;
  
    // RS信号、データバスに信号を出力
    ROM_GPIOPinWrite( GPIO_PORTA_BASE, LCD_PIN, rs | data_h );
    // 100ns以上ウェイト
    ROM_SysCtlDelay( 3 );
    // E信号にハイレベルを出力
    ROM_GPIOPinWrite( GPIO_PORTA_BASE, LCD_PIN, ENB | rs | data_h );
    // 300ns以上ウェイト
    ROM_SysCtlDelay( 8 );
    // E信号にローレベルを出力
    ROM_GPIOPinWrite( GPIO_PORTA_BASE, LCD_PIN, rs | data_h );
    // 10ns以上ウェイト
    ROM_SysCtlDelay( 1 );
    // すべての信号にローレベルを出力
    ROM_GPIOPinWrite( GPIO_PORTA_BASE, LCD_PIN, 0x00 );
    // 100ns以上ウェイト
    ROM_SysCtlDelay( 3 );
    // RS信号、データバスに信号を出力
    ROM_GPIOPinWrite( GPIO_PORTA_BASE, LCD_PIN, rs | data_l );
    // 100ns以上ウェイト
    ROM_SysCtlDelay( 3 );
    // E信号にハイレベルを出力
    ROM_GPIOPinWrite( GPIO_PORTA_BASE, LCD_PIN, ENB | rs | data_l );
    // 300ns以上ウェイト
    ROM_SysCtlDelay( 8 );
    // E信号にローレベルを出力
    ROM_GPIOPinWrite( GPIO_PORTA_BASE, LCD_PIN, rs | data_l );
    // 10ns以上ウェイト
    ROM_SysCtlDelay( 1 );
    // すべての信号にローレベルを出力
    ROM_GPIOPinWrite( GPIO_PORTA_BASE, LCD_PIN, 0x00 );
    // 100ns以上ウェイト
    ROM_SysCtlDelay( 3 );
}

// 8bitアクセス関数
void write_8bit( unsigned char rs, unsigned char data )
{
    unsigned char       data_h = ( data >> 2 ) & 0x3C;

    // RS信号、データバスに信号を出力
    ROM_GPIOPinWrite( GPIO_PORTA_BASE, LCD_PIN, rs | data_h );
    // 100ns以上ウェイト
    ROM_SysCtlDelay( 3 );
    // E信号にハイレベルを出力
    ROM_GPIOPinWrite( GPIO_PORTA_BASE, LCD_PIN, ENB | rs | data_h );
    // 300ns以上ウェイト
    ROM_SysCtlDelay( 8 );
    // E信号にローレベルを出力
    ROM_GPIOPinWrite( GPIO_PORTA_BASE, LCD_PIN, rs | data_h );
    // 10ns以上ウェイト
    ROM_SysCtlDelay( 1 );
    // すべての信号にローレベルを出力
    ROM_GPIOPinWrite( GPIO_PORTA_BASE, LCD_PIN, 0x00 );
    // 100ns以上以上ウェイト
    ROM_SysCtlDelay( 3 );						
}

// LCDモジュール初期化関数
void lcd_init( void )
{
    // ポートを初期化
    lcd_port_init();

    // 15ms以上以上ウェイト
    ROM_SysCtlDelay( 400000 );
    // Function Set(8bit)
    write_8bit( CMD, 0x30 );
    // 4.1ms以上ウェイト
    ROM_SysCtlDelay( 109334 );
    // Function Set(8bit)
    write_8bit( CMD, 0x30 );
    // 100us以上ウェイト
    ROM_SysCtlDelay( 2667 );
    // Function Set(8bit)
    write_8bit( CMD, 0x30 );
    // 39us以上ウェイト
    ROM_SysCtlDelay( 1040 );	
    // Function Set(4bit)
    write_8bit( CMD, 0x20 );
    // 39us以上ウェイト
    ROM_SysCtlDelay( 1040 );
    // Function set(4bit, N=1, F=0)
    write_4bit( CMD, 0x28 );
    // 39us以上ウェイト
    ROM_SysCtlDelay( 1040 );
    // Display Off (D=0, C=0, B=0)
    write_4bit( CMD, 0x08 );
    // 39us以上ウェイト
    ROM_SysCtlDelay( 1040 );
    // Display clear
    write_4bit( CMD, 0x01 );
    // 1.53ms以上ウェイト
    ROM_SysCtlDelay( 40800 );
    // Entry mode (I/D=1, S=0)
    write_4bit( CMD, 0x06 );
    // 39us以上ウェイト
    ROM_SysCtlDelay( 1040 );
    // Display On(D=1, C=0, B=0)
    write_4bit( CMD, 0x0c );
    // 39us以上ウェイト
    ROM_SysCtlDelay( 1040 );	
}

// ディスプレイクリア関数
void lcd_clear_display( void )
{
    // Display clear
    write_4bit( CMD, 0x01 );
    // 1.53ms以上ウェイト
    ROM_SysCtlDelay( 40800 );
}

// セットカーソル関数
void lcd_set_cursor( unsigned char line, unsigned char column )
{
    // カーソル位置設定
    write_4bit( CMD, 0x80 | (((line - 1) << 6) & 0x40) | ((column - 1) & 0x0f) );
    // 39us以上ウェイト
    ROM_SysCtlDelay( 1040 );
}

// 1文字出力関数
int putchar(int data )
{
    // 1文字出力
    write_4bit( DAT, (unsigned char)data );
    // 43us以上ウェイト
    ROM_SysCtlDelay( 1147 );
    return data;
}
