#include "STM32_AddressDefs.h"
#include "TFT018.h"

#define USARTx_SR USART1_SR
#define USARTx_DR USART1_DR

#define LED             ( 1 << 5 )                // PB5: LED D2

/*----------------------------------------------------------*\
 | SOFTWARE DATA                                            |
\*----------------------------------------------------------*/
unsigned short  analog [3];            /* voltage on analog Pins PA1 .. PA3 */
/*----------------------------------------------------------*\
 | ADC Initialisation                                       |
\*----------------------------------------------------------*/
void adc_Init (void) {

//  GPIOA->CRL &= ~0x0000000F;                   /* set PIN1 analog input (see stm32_Init.c) */

  RCC_AHBENR |= (1<<0);                       /* enable periperal clock for DMA       */

  DMA1_CMAR  = (unsigned long)&analog; /* set chn1 memory address     */
  DMA1_CPAR  = (unsigned long)&(ADC1_DR);     /* set chn1 peripheral address */
  DMA1_CNDTR = 3;                     /* transmit 3 words                     */
//  DMA1_CCR   = 0x00002520;            /* configure DMA channel 1              */
  DMA1_CCR   = 0x000025A0;            /* configure DMA channel 1              */
                                               /* circular mode, memory increment mode */
                                               /* memory & peripheral size 16bit       */
                                               /* channel priotity high                */
  DMA1_CCR  |= (1 << 0);              /* enable DMA Channe1                   */

  RCC_APB2ENR |= (1<<9);                      /* enable periperal clock for ADC1      */

  ADC1_SQR1  = 0x00200000;                    /* three conversions                    */
  ADC1_SQR3  = (3<<10) | (2<<5) | (1<<0);     /* set order to chn1 - chn2 - chn3      */
  ADC1_SMPR2 = (5<< 9) | (5<<6) | (5<<3);     /* set sample time (55,5 cycles)        */ 

  ADC1_CR1   =  0x00000100;                   /* use independant mode, SCAN mode      */
  ADC1_CR2   =  0x000E0103;                   /* data align right, cont. conversion   */
                                               /* EXTSEL = SWSTART                     */ 
                                               /* enable ADC, DMA mode                 */
  ADC1_CR2  |=  0x00500000;                   /* start SW conversion                  */
  }

char RecvData(){
  volatile int c;

  while (!(USARTx_SR & 0x0020));
  c = ((int)(USARTx_DR & 0x1FF));

  return (char )c;
}

void SendData(char data){
  while (!(USARTx_SR & 0x0080));
  USARTx_DR = ((unsigned int)data & 0x1FF);
}

void USART_handler(){
  char c;
  c= RecvData();

  if(c == '0'){
    SendData('O');
    SendData('F');
    SendData('F');
    SendData('\n');
    SendData('\r');
    GPIOB_ODR &= ~LED;
    return;
  }
  if(c == '1'){
    SendData('O');
    SendData('N');
    GPIOB_ODR |= LED;
    SendData('\n');
    SendData('\r');
    return;
  }
  
  SendData('E');
  SendData('R');
  SendData('R');
  SendData('\n');
  SendData('\r');

}

#define __EFI_ACR_Val 0x00000012
#define __RCC_CR_VAL  0x01010082
#define __RCC_CFGR_VAL 0x00118402
#define __NVIC_VTOR_VAL 0x00000000
#define __SYSTICK_CTRL_VAL 0x00000002
#define __SYSTICK_PERIOD 0x0000000A
#define CFGR_HPRE_MASK 0x000000F0 // Mask for AHB prescaler
#define __HCLKPRESC  0x00000000
#define __SYSTICKCLK (__HCLK>>3)
#define __HSE 12000000UL
#define CFGR_PLLMULL_MASK 0x003C0000 // Mask for PLL multiplier
#define __PLLMULL (((__RCC_CFGR_VAL & CFGR_PLLMULL_MASK) >> 18) + 2)
#define __SYSCLK  (__HSE * __PLLMULL)  // SYSCLK = HSE * pllmul
#define __HCLK        (__SYSCLK)
#define CFGR_PRE2_MASK 0x00003800 // Mask for APB2 prescaler 
#define __PCLK2       (__HCLK)

#define CFGR_PRE1_MASK      0x00000700             // Mask for APB1 prescaler     
#define __PCLK1PRESC  ((__RCC_CFGR_VAL & CFGR_PRE1_MASK) >> 8)
#if (__PCLK1PRESC & 0x04)
  #define __PCLK1       (__HCLK >> ((__PCLK1PRESC & 0x03)+1))
#else
  #define __PCLK1       (__HCLK)
#endif

/*----------------------------------------------------------------------------
 Define  TIMXCLK
 *----------------------------------------------------------------------------*/
#if (__PCLK1PRESC & 0x04)
  #define __TIMXCLK    (2*__PCLK1)
#else
  #define __TIMXCLK    (__PCLK1)
#endif

#define __USART1_BAUDRATE         115200 //  4
#define __USART1_DATABITS         0x00000000
#define __USART1_STOPBITS         0x00000000
#define __USART1_PARITY           0x00000000
#define __USART1_FLOWCTRL         0x00000000

#define __DIV(__PCLK, __BAUD)       ((__PCLK*25)/(4*__BAUD))
#define __DIVMANT(__PCLK, __BAUD)   (__DIV(__PCLK, __BAUD)/100)
#define __DIVFRAQ(__PCLK, __BAUD)   (((__DIV(__PCLK, __BAUD) - (__DIVMANT(__PCLK, __BAUD) * 100)) * 16 + 50) / 100)
#define __USART_BRR(__PCLK, __BAUD) ((__DIVMANT(__PCLK, __BAUD) << 4)|(__DIVFRAQ(__PCLK, __BAUD) & 0x0F))

/*----------------------------------------------------------------------------
 Define Timer PSC and ARR settings
 *----------------------------------------------------------------------------*/
#define __VAL(__TIMCLK, __PERIOD) ((__TIMCLK/1000000UL)*__PERIOD)
//#define __PSC(__TIMCLK, __PERIOD) ((__VAL(__TIMCLK, __PERIOD)-1)>>15)
#define __PSC(__TIMCLK, __PERIOD)  (((__VAL(__TIMCLK, __PERIOD)+49999UL)/50000UL) - 1)
#define __ARR(__TIMCLK, __PERIOD) ((__VAL(__TIMCLK, __PERIOD)/(__PSC(__TIMCLK, __PERIOD)+1)) - 1)

#define __TIMER_DETAILS           0x000A                  //  2

#define __TIM2_PERIOD             0x00064                 // 20
#define __TIM2_PSC                0x0000                  // 21
#define __TIM2_ARR                0x0048                  // 22
#define __TIM2_CCR1               0x001E                  // 29
#define __TIM2_CCR2               0x1388                  // 30
#define __TIM2_CCR3               0x0005                  // 31
#define __TIM2_CCR4               0x0000                  // 32
#define __TIM2_CCMR1              0x6000                  // 26
#define __TIM2_CCMR2              0x0060                  // 27
#define __TIM2_CCER               0x0100                  // 28
#define __TIM2_CCR1               0x001E                  // 29
#define __TIM2_CCR2               0x1388                  // 30
#define __TIM2_CR1                0x0004                  // 23
#define __TIM2_CR2                0x0000                  // 24

#define TIMX_CR1_CEN         ((unsigned short)0x0001)
#define RCC_APB1ENR_TIM2EN    ((unsigned long)0x00000001)
void initTIM2() {                                // TIM2 used
    RCC_APB1ENR |= RCC_APB1ENR_TIM2EN;                     // enable clock for TIM2

    TIM2_PSC = __PSC(__TIMXCLK, __TIM2_PERIOD);            // set prescaler
    TIM2_ARR = __ARR(__TIMXCLK, __TIM2_PERIOD);            // set auto-reload

    TIM2_CR1 = 0;                                          // reset command register 1
    TIM2_CR2 = 0;                                          // reset command register 2

    if (__TIMER_DETAILS & 0x02) {                           // detailed settings used
      TIM2_PSC = __TIM2_PSC;                               // set prescaler
      TIM2_ARR = __TIM2_ARR;                               // set auto-reload

      TIM2_CCR1  = __TIM2_CCR1;                            //
      TIM2_CCR2  = __TIM2_CCR2;                            //
      TIM2_CCR3  = __TIM2_CCR3;                            //
      TIM2_CCR4  = __TIM2_CCR4;                            //
      TIM2_CCMR1 = __TIM2_CCMR1;                           //
      TIM2_CCMR2 = __TIM2_CCMR2;                           //
      TIM2_CCER  = __TIM2_CCER;                            // set capture/compare enable register

      TIM2_CR1 = __TIM2_CR1;                               // set command register 1
      TIM2_CR2 = __TIM2_CR2;                               // set command register 2
    }

    TIM2_CR1 |= TIMX_CR1_CEN;                              // enable timer
}

unsigned  char Clock1s;
unsigned int ticks;

void SysTick_Handler (void) {
  if (ticks++ >= 99) { // Set Clock1s to 1 every 1 second
    ticks   = 0;
    Clock1s = 1;
  }
}

void short2hexstr(int val, char *s){
  int i;
  char c;

  for(i=0;i<4;i++){
    switch((val>>((3-i)<<2))&0xF){
    case 0 : c = '0'; break;
    case 1 : c = '1'; break;
    case 2 : c = '2'; break;
    case 3 : c = '3'; break;
    case 4 : c = '4'; break;
    case 5 : c = '5'; break;
    case 6 : c = '6'; break;
    case 7 : c = '7'; break;
    case 8 : c = '8'; break;
    case 9 : c = '9'; break;
    case 10 : c = 'A'; break;
    case 11 : c = 'B'; break;
    case 12 : c = 'C'; break;
    case 13 : c = 'D'; break;
    case 14 : c = 'E'; break;
    case 15 : c = 'F'; break;
    default: c = 'X';
    }
    *s ++ = c;
  }
}

void SendIntHex(int val){
  int i;
  char s[4];

  short2hexstr(val, s);
  for(i=0;i<4;i++){
    SendData(s[i]);
  }
  SendData('\r');
  SendData('\n');
}


void BreakPoint_Handler(){
  SendData('B');
  SendData('K');
  SendData('P');
  SendData('T');
  SendData('\r');
  SendData('\n');

  while(1);
}
 
int main(){

  char s[20];
  int i;

  // EFI Configuration
  FLASH_ACR = __EFI_ACR_Val; // set access control register 
  
  // Clock Configuration
  RCC_CFGR = __RCC_CFGR_VAL; // set clock configuration register
  RCC_CR   = __RCC_CR_VAL; // set clock control register
  
  while ((RCC_CR & 0x00020000) == 0){} // Wait for HSERDY = 1 (HSE is ready)
  while ((RCC_CR & 0x02000000) == 0){} // Wait for PLLRDY = 1 (PLL is ready)
  
  /* Wait till SYSCLK is stabilized (depending on selected clock) */
  while ((RCC_CFGR & 0xC) != ((__RCC_CFGR_VAL<<2) & 0xC));

  // NVIC Configuration
  SCB_ExceptionTableOffset = (__NVIC_VTOR_VAL & 0x1FFFFF80); // set register

  // SysTick Configuration
#if ((__SYSTICK_PERIOD*(__SYSTICKCLK/1000)-1) > 0xFFFFFF) // reload value to large
   #error "Reload Value to large! Please use 'HCLK/8' as System Timer clock source or smaller period"
#else
  SysTick_LOAD  = __SYSTICK_PERIOD*(__SYSTICKCLK/1000)-1; // set reload register
  SysTick_CTRL  = __SYSTICK_CTRL_VAL; // set clock source and Interrupt enable

  SysTick_VAL   =  0; // clear  the counter

  SysTick_CTRL |= 0x1; // enable the counter
#endif

  // GPIO Configuration
  // GPIO Port A
  RCC_APB2ENR |= 0x00000004; // enable clock for GPIOA
  GPIOA_CRL = 0x00000B04; // set Port configuration register low
  GPIOA_CRH = 0x00000000; // set Port configuration register high

  // GPIO Port B
  RCC_APB2ENR |= 0x00000008; // enable clock for GPIOB
  GPIOB_CRL = 0x00300000; // set Port configuration register low
  GPIOB_CRH = 0x00000000; // set Port configuration register high
  

  // USART Configuration
  // USART1 used
  AFIO_MAPR   &= ~(1 << 2); // clear USART1 remap
  // USART1 no remap
  RCC_APB2ENR |= 0x00000004; // enable clock for GPIOA
  GPIOA_CRH &= ~(0xFFUL  << 4); // Clear PA9, PA10
  GPIOA_CRH |=  (0x0BUL  << 4); // USART1 Tx (PA9)  alternate output push-pull
  GPIOA_CRH |=  (0x04UL  << 8); // USART1 Rx (PA10) input floating

  RCC_APB2ENR |= 0x00004000; // enable clock for USART1
  
  USART1_BRR = __USART_BRR(__PCLK2, __USART1_BAUDRATE); // set baudrate
  USART1_CR1 = __USART1_DATABITS; // set Data bits
  USART1_CR2 = __USART1_STOPBITS; // set Stop bits
  USART1_CR1 |= __USART1_PARITY; // set Parity
  USART1_CR3 = __USART1_FLOWCTRL; // Set Flow Control
  
  USART1_CR1 |= (0x00000004 | 0x00000008); // RX, TX enable

  GPIOB_ODR |= LED;

  // USART interrupts used
  USART1_CR1 |= (0x1<<5);
  USART1_CR2 |= 0x0;
  USART1_CR3 |= 0x0;
  //  NVIC_Enable[1] |= (1 << (0x25 & 0x1F)); // enable interrupt
  *((volatile unsigned int *)0xE000E104) |= (1 << 5); // enable interrupt
  USART1_CR1 |= 0x00002000; // USART enable

  adc_Init();
  initTIM2();     //for back light
  LCD_Init();
  LCD_Clear_Screen(Blue);
  adc_Init();

  for(;;) {
    Font = 0;
    LCD_PutString(12,0,"STM32F 開発キット",Cyan,Blue);
    LCD_PutString(30,16,"ADC  入力デモ",Red,Yellow);
    Font = 1;
    LCD_PutString(38,32,"Version 1.0",Green,Blue);
    Font = 0;
    LCD_PutString(16,94,"日昇テクノロジー",Yellow,Blue);
    LCD_PutString(24,111,"www.csun.co.jp",Magenta,Blue);

	for(i=0;i<3;i++) {
		s[0] = 'P';	s[1] = 'A';
		s[2] = '0' + i;
		s[3] = 0;
      LCD_PutString(4+52*i,42,s,Red,Yellow);

	short2hexstr(analog[i], s);
		s[4] = 0;
      LCD_PutString(4+52*i,60,s,Red,Yellow);
	  }
	i = analog[1] * 150 / 0xFFF;
	LCD_Rectangle( 5,80,5+i,86, Magenta );
	LCD_Rectangle( 6+i,80,155,86, Green );

    if (Clock1s) {
      Clock1s = 0;
      SendIntHex(analog[1]);
    }
  }

  return 1;
}
