/*
 * hal_LCD.c
 *
 *  Created on: Nov 4, 2011
 *      Author: RomanM
 */

#include "stm32f10x.h"
#include "hal_LCD.h"

/*
 * Initialization of LCD ports
 */
void hal_LCD_Init(void) {
	GPIO_InitTypeDef GPIO_InitStructure;				// GPIO Init structure

	RCC_APB2PeriphClockCmd(LCD_GPIO_CLOCK, ENABLE);		// Enable GPIO clock

#ifdef LCD_4bit
	GPIO_InitStructure.GPIO_Pin = LCD_E_PIN | LCD_RS_PIN | LCD_RW_PIN |
								  LCD_D4_PIN | LCD_D5_PIN | LCD_D6_PIN| LCD_D7_PIN;	// Select pins
#else
	GPIO_InitStructure.GPIO_Pin = LCD_E_PIN | LCD_RS_PIN | LCD_RW_PIN |
								  LCD_D0_PIN | LCD_D1_PIN | LCD_D2_PIN| LCD_D3_PIN
								  LCD_D4_PIN | LCD_D5_PIN | LCD_D6_PIN| LCD_D7_PIN;	// Select pins
#endif

	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	// Push-pull mode
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

	GPIO_Init(LCD_PORT, &GPIO_InitStructure);			// Initialize port

	hal_LCD_RS(0);
	hal_LCD_RW(0);
	hal_LCD_E(0);
}

/*
 * Set LCD port as output
 */
void hal_LCD_Port_Out(void) {
	GPIO_InitTypeDef GPIO_InitStructure;

#ifdef LCD_4bit
	GPIO_InitStructure.GPIO_Pin = LCD_D4_PIN | LCD_D5_PIN | LCD_D6_PIN| LCD_D7_PIN;	// Select pins
#else
	GPIO_InitStructure.GPIO_Pin = LCD_D0_PIN | LCD_D1_PIN | LCD_D2_PIN| LCD_D3_PIN
								  LCD_D4_PIN | LCD_D5_PIN | LCD_D6_PIN| LCD_D7_PIN;	// Select pins
#endif

	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	// Push-pull mode
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

	GPIO_Init(LCD_PORT, &GPIO_InitStructure);
}

/*
 * Set LCD port as input
 */
void hal_LCD_Port_In(void) {
	GPIO_InitTypeDef GPIO_InitStructure;

#ifdef LCD_4bit
	GPIO_InitStructure.GPIO_Pin = LCD_D4_PIN | LCD_D5_PIN | LCD_D6_PIN| LCD_D7_PIN;	// Select pins
#else
	GPIO_InitStructure.GPIO_Pin = LCD_D0_PIN | LCD_D1_PIN | LCD_D2_PIN| LCD_D3_PIN
								  LCD_D4_PIN | LCD_D5_PIN | LCD_D6_PIN| LCD_D7_PIN;	// Select pins
#endif

	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;	// Input
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

	GPIO_Init(LCD_PORT, &GPIO_InitStructure);
}

/*
 * Initialization of backlight
 */
void hal_LCD_BL_Init(void) {
	// PB9 TIM4 CH4
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef	TIM_TimeBaseStructure;
	TIM_OCInitTypeDef TIM_OCInitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);

	/* Port initialization */
	GPIO_InitStructure.GPIO_Pin	= GPIO_Pin_9;			// Setting for pin 9
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;		// Alternative function push-pull
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);				// Initialize GPIO

	/* Timer initialization */
	TIM_TimeBaseStructure.TIM_Period = 65535;
	TIM_TimeBaseStructure.TIM_Prescaler = 0;
	TIM_TimeBaseStructure.TIM_ClockDivision = 0;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);

	/* Timer output initialization */
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCInitStructure.TIM_Pulse = 0;
	TIM_OC4Init(TIM4, &TIM_OCInitStructure);

	TIM_Cmd(TIM4, ENABLE);				// Counter enable
}

/*
 * Send 4-bit data to port
 */
void hal_LCD_DataOut_4bit(uint8_t data) {
	GPIO_ResetBits(LCD_PORT, LCD_D4_PIN | LCD_D5_PIN | LCD_D6_PIN | LCD_D7_PIN);	// Clear port
	GPIO_SetBits(LCD_PORT, (data & 0x0f) << LCD_DATA_ROT);							// Set high nibble
}

/*
 * Send 8-bit data to port
 */
void hal_LCD_DataOut_8bit(uint8_t data) {
	GPIO_ResetBits(LCD_PORT, LCD_D0_PIN | LCD_D1_PIN | LCD_D2_PIN | LCD_D3_PIN |
							 LCD_D4_PIN | LCD_D5_PIN | LCD_D6_PIN | LCD_D7_PIN);	// Clear port
	GPIO_SetBits(LCD_PORT, data << LCD_DATA_ROT);									// Set high nibble
}

/*
 * Read 4-bit data from port
 */
uint8_t hal_LCD_DataIn_4bit(void) {
	return (uint8_t)((GPIO_ReadInputData(LCD_PORT) >> LCD_DATA_ROT) & 0x0f);
}

/*
 * Read 8-bit data from port
 */
uint8_t hal_LCD_DataIn_8bit(void) {
	return (uint8_t)((GPIO_ReadInputData(LCD_PORT) >> LCD_DATA_ROT) & 0xff);
}

/*
 * Set backlight brightness
 */
void hal_LCD_BL_Set(uint16_t value) {
	if (value > LCD_BL_MAX) value = LCD_BL_MAX;		// Backlight protection
	TIM4->CCR4 = value;
}

/*
 * Driving Enable pin
 */
void hal_LCD_E(uint8_t state) {
	if (state) {
		GPIO_SetBits(LCD_PORT, LCD_E_PIN);
	}
	else {
		GPIO_ResetBits(LCD_PORT, LCD_E_PIN);
	}
}

/*
 * Driving Read/Write pin
 */
void hal_LCD_RW(uint8_t state) {
	if (state) {
		GPIO_SetBits(LCD_PORT, LCD_RW_PIN);
	}
	else {
		GPIO_ResetBits(LCD_PORT, LCD_RW_PIN);
	}
}

/*
 * Driving Instruction/Data pin
 */
void hal_LCD_RS(uint8_t state) {
	if (state) {
		GPIO_SetBits(LCD_PORT, LCD_RS_PIN);
	}
	else {
		GPIO_ResetBits(LCD_PORT, LCD_RS_PIN);
	}
}

/*
 * Delay function
 */
void hal_LCD_Delay(__IO uint32_t nTick) {
	for(; nTick != 0; nTick--);
}
