#include "src/stm32f10x.h"
#include "src/stm32f10x_rcc.h"

// RESET - PB13, CS-PB14, WR-PB11, RD-PB12, RS-PB10
#define RST_H (GPIOB->BSRR = GPIO_BSRR_BS13)
#define RST_L (GPIOB->BSRR = GPIO_BSRR_BR13)

#define CS_H (GPIOB->BSRR = GPIO_BSRR_BS14)
#define CS_L (GPIOB->BSRR = GPIO_BSRR_BR14)

#define WR_H (GPIOB->BSRR = GPIO_BSRR_BS11)
#define WR_L (GPIOB->BSRR = GPIO_BSRR_BR11)

#define RD_H (GPIOB->BSRR = GPIO_BSRR_BS12)
#define RD_L (GPIOB->BSRR = GPIO_BSRR_BR12)

#define RS_H (GPIOB->BSRR = GPIO_BSRR_BS10)
#define RS_L (GPIOB->BSRR = GPIO_BSRR_BR10)

volatile unsigned int SysTickDelay;

void delay_ms(uint32_t Val)
{
   SysTickDelay = Val;
   while (SysTickDelay != 0) {};
}

//------------------------------------------------------------------------
void SysTick_Handler(void)
{
   if (SysTickDelay != 0)
   {
      SysTickDelay--;
   }
}

/******************************************************************************/
void lcd_cmd (uint16_t RegIndex){
   CS_L;
   RS_L;
   GPIOA->ODR = RegIndex;
   WR_L;
   WR_H;

  return;
}
/******************************************************************************/
void lcd_dat (uint16_t RegValue){
   CS_L;
   RS_H;
   GPIOA->ODR = RegValue;
   WR_L;
   WR_H;

  return;
}
/******************************************************************************/

void LCD_WriteReg(uint8_t addr, uint16_t cmd){
	lcd_cmd(addr);
	lcd_dat(cmd);

	return;
}

void LCD_SetCursor(uint16_t Xpos, uint16_t Ypos)
{
  LCD_WriteReg(0x004E, Xpos);
  LCD_WriteReg(0x004F, Ypos);

  return;
}

void LCD_WriteRAM_Prepare(void)
{
  lcd_cmd (0x0022);
}

void LCD_Clear(uint16_t Color)
{
  uint32_t index = 0;
  LCD_SetCursor(0x00, 0x00);
  LCD_WriteRAM_Prepare(); /* Prepare to write GRAM */
  for(index = 0; index < 76800; index++)
  {
    lcd_dat (Color);
  }
}

void lcd_init(void)
{
	RST_H;
	delay_ms(10);
	RST_L;
	delay_ms(30);
	RST_H;
	delay_ms(50);

	RS_H;
	WR_H;
	RD_H;
	CS_L;
	    // power supply setting
	    // set R07h at 0021h (GON=1,DTE=0,D[1:0]=01)
	    LCD_WriteReg(0x0007,0x0021);
	    // set R00h at 0001h (OSCEN=1)
	    LCD_WriteReg(0x0000,0x0001);
	    // set R07h at 0023h (GON=1,DTE=0,D[1:0]=11)
	    LCD_WriteReg(0x0007,0x0023);
	    // set R10h at 0000h (Exit sleep mode)
	    LCD_WriteReg(0x0010,0x0000);
	    // Wait 30ms
	    delay_ms(30);
	    // set R07h at 0033h (GON=1,DTE=1,D[1:0]=11)
	    LCD_WriteReg(0x0007,0x0033);
	    // Entry mode setting (R11h)
	    // R11H Entry mode
	    // vsmode DFM1 DFM0 TRANS OEDef WMode DMode1 DMode0 TY1 TY0 ID1 ID0 AM LG2 LG2 LG0
	    //   0     1    1     0     0     0     0      0     0   1   1   1  *   0   0   0
	    LCD_WriteReg(0x0011,0x6078);
	    // LCD driver AC setting (R02h)
	    LCD_WriteReg(0x0002,0x0600);
	    // power control 1
	    // DCT3 DCT2 DCT1 DCT0 BT2 BT1 BT0 0 DC3 DC2 DC1 DC0 AP2 AP1 AP0 0
	    // 1     0    1    0    1   0   0  0  1   0   1   0   0   1   0  0
	    // DCT[3:0] fosc/4 BT[2:0]  DC{3:0] fosc/4
	    LCD_WriteReg(0x0003,0x0804);//0xA8A4
	    LCD_WriteReg(0x000C,0x0000);//
	    LCD_WriteReg(0x000D,0x0808);// 0x080C --> 0x0808
	    // power control 4
	    // 0 0 VCOMG VDV4 VDV3 VDV2 VDV1 VDV0 0 0 0 0 0 0 0 0
	    // 0 0   1    0    1    0    1    1   0 0 0 0 0 0 0 0
	    LCD_WriteReg(0x000E,0x2900);
	    LCD_WriteReg(0x001E,0x00B8);
	    LCD_WriteReg(0x0001,0x293F);//vertical inversion; start->left bottom corner
	    LCD_WriteReg(0x0010,0x0000);
	    LCD_WriteReg(0x0005,0x0000);
	    LCD_WriteReg(0x0006,0x0000);
	    LCD_WriteReg(0x0016,0xEF1C);
	    LCD_WriteReg(0x0017,0x0003);
	    LCD_WriteReg(0x0007,0x0233);
	    LCD_WriteReg(0x000B,0x0000|(3<<6));
	    LCD_WriteReg(0x000F,0x0000);
	    LCD_WriteReg(0x0041,0x0000);
	    LCD_WriteReg(0x0042,0x0000);
	    LCD_WriteReg(0x0048,0x0000);
	    LCD_WriteReg(0x0049,0x013F);
	    LCD_WriteReg(0x004A,0x0000);
	    LCD_WriteReg(0x004B,0x0000);
	    LCD_WriteReg(0x0030,0x0707);
	    LCD_WriteReg(0x0031,0x0204);
	    LCD_WriteReg(0x0032,0x0204);
	    LCD_WriteReg(0x0033,0x0502);
	    LCD_WriteReg(0x0034,0x0507);
	    LCD_WriteReg(0x0035,0x0204);
	    LCD_WriteReg(0x0036,0x0204);
	    LCD_WriteReg(0x0037,0x0502);
	    LCD_WriteReg(0x003A,0x0302);
	    LCD_WriteReg(0x003B,0x0302);
	    LCD_WriteReg(0x0023,0x0000);
	    LCD_WriteReg(0x0024,0x0000);
	    LCD_WriteReg(0x0025,0x8000);
	    LCD_WriteReg(0x004f,0);
	    LCD_WriteReg(0x004e,0);

	    delay_ms(50);

	    LCD_Clear(0x07E0);

	 return;
}

void init(){

	RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN; // Разрешить тактирование PORTC.

    GPIOA->CRL &= ~(GPIO_CRL_CNF0 | GPIO_CRL_CNF1 | GPIO_CRL_CNF2 | GPIO_CRL_CNF3 | GPIO_CRL_CNF4 | GPIO_CRL_CNF5 | GPIO_CRL_CNF6 | GPIO_CRL_CNF7);
    GPIOA->CRL |=  (GPIO_CRL_MODE0_1 | GPIO_CRL_MODE1_1 | GPIO_CRL_MODE2_1 | GPIO_CRL_MODE3_1 | GPIO_CRL_MODE4_1 | GPIO_CRL_MODE5_1);
    GPIOA->CRL |=  (GPIO_CRL_MODE6_1 | GPIO_CRL_MODE7_1);

    GPIOA->CRH &= ~(GPIO_CRH_CNF8 | GPIO_CRH_CNF9 | GPIO_CRH_CNF10 | GPIO_CRH_CNF11 | GPIO_CRH_CNF12 | GPIO_CRH_CNF13 | GPIO_CRH_CNF14 | GPIO_CRH_CNF15);
    GPIOA->CRH |=  (GPIO_CRH_MODE8_1 | GPIO_CRH_MODE9_1 | GPIO_CRH_MODE10_1 | GPIO_CRH_MODE11_1 | GPIO_CRH_MODE12_1 | GPIO_CRH_MODE13_1);
    GPIOA->CRH |=  (GPIO_CRH_MODE14_1 | GPIO_CRH_MODE15_1);

    GPIOB->CRH &= ~(GPIO_CRH_CNF10 | GPIO_CRH_CNF11 | GPIO_CRH_CNF12 | GPIO_CRH_CNF13 | GPIO_CRH_CNF14);
    GPIOB->CRH |=  (GPIO_CRH_MODE10_1 | GPIO_CRH_MODE11_1 | GPIO_CRH_MODE12_1 | GPIO_CRH_MODE13_1 | GPIO_CRH_MODE14_1);

    SysTick_Config(24000000/1000);//1ms
}

int main(){

	init();

	lcd_init();

	while(1)
	{

	}

	return 0;
}
