/*******************************************************************************
* Project:      Amped'RF Bluetooth
* File name:    SU_TCMain.c
* Author:       Bill Colias
* Created:      05/27/2008
* Description:  Startup module
*
* Copyright (c) 2008 Amped'RF Inc. All rights reserved.
*******************************************************************************/
#include "Common.h"
#ifdef STM32F4xx
#include "GKI_lib.h"
#include "string.h"
#include "stdlib.h"
#include "SU_PowerUpCheckVar.h"
#include "TM_FlashManager.h"
#include "TM_PioDef.h"
#include "UT_DES.h"
#include "TM_TimerControl.h"
#ifdef CUSTOM_AUDIO_WM8904
#include "WM8904.h"
#endif

#include "stm32f4xx_flash.h"
#include "Utilities.h"


#define DEBUG_STARTUP
#ifdef  DEBUG_STARTUP
char dbgmsg[128];
#define TRACE_PRINT(a)				sprintf(dbgmsg,a);              GKI_putstring(dbgmsg)
#define TRACE_PRINT1(a,p1)			sprintf(dbgmsg,a,p1);           GKI_putstring(dbgmsg)
#define TRACE_PRINT2(a,p1,p2)		sprintf(dbgmsg,a,p1,p2);        GKI_putstring(dbgmsg)
#define TRACE_PRINT3(a,p1,p2,p3)	sprintf(dbgmsg,a,p1,p2,p3);     GKI_putstring(dbgmsg)
#else
#define TRACE_PRINT(a)
#define TRACE_PRINT1(a,p1)
#define TRACE_PRINT2(a,p1,p2)
#define TRACE_PRINT3(a,p1,p3)
#endif





//----------------------------------
// External prototypes / globals
//----------------------------------
//void InitDebugUart(u32);
void __SETPRIMASK(void);
extern USART_TypeDef * UART[];


//----------------------------------
// Mask for APB1 Prescaler
//----------------------------------
#define CFGR_PPRE1_Set_Mask       ((u32)0x00000700)


//----------------------------------
//  Globals
//----------------------------------
uint8 HSE_Status;


/* Create section in compiler */
#pragma section = "IRAM"
uint32 IRamArea @ "IRAM";

//------------------------------------------------------------------------------
#pragma section = "CSTACK"
#pragma section = "SVC_STACK"
#pragma section = "IRQ_STACK"
#pragma section = "FIQ_STACK"
#pragma section = "UND_STACK"
#pragma section = "ABT_STACK"
#pragma section = "HEAP"
void * CStackTop        = __section_end  ("CSTACK");
void * CStackBottom     = __section_begin("CSTACK");
void * SVCstackTop      = __section_end  ("SVC_STACK");
void * SVCstackBottom   = __section_begin("SVC_STACK");
void * FIQstackTop      = __section_end  ("FIQ_STACK");
void * FIQstackBottom   = __section_begin("FIQ_STACK");
void * ABTstackTop      = __section_end  ("ABT_STACK");
void * ABTstackBottom   = __section_begin("ABT_STACK");
void * UNDstackTop      = __section_end  ("UND_STACK");
void * UNDstackBottom   = __section_begin("UND_STACK");
void * IRQstackTop      = __section_end  ("IRQ_STACK");
void * IRQstackBottom   = __section_begin("IRQ_STACK");
void * HeapTop          = __section_end  ("HEAP");
void * HeapBottom       = __section_begin("HEAP");
//------------------------------------------------------------------------------
void * IRamTop          = (void *)BOOT_RAMSTART_BASE;
void * IRamBottom       = __section_begin("IRAM");



//------------------------------------------------------------------------------
// Forward declarations
//------------------------------------------------------------------------------
#ifndef CUSTOM_LITE
void SU_Determine_HSE_Speed(void);
#endif // CUSTOM_LITE
void main_startup(void);



//-------------------------------------------------------------------
// TM_BT_ClockConfig -- setup BT clock (LPO) using PWM to 32 KHz
// Assuming 32MHz, Pin is PB0
//-------------------------------------------------------------------
/*
void TM_BT_ClockConfig(uint32 Hz)
{
#ifdef DISABLE_LPO
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_StructInit(&GPIO_InitStruct);          // Default is an input
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
    GPIO_Init(GPIOB, &GPIO_InitStruct);
#else

    //InitUart();
    //TRACE_PRINT("\r\n");
    //TRACE_PRINT("TM_BT_ClockConfig()\r\n");
//    GKI_show_clocks();


    RCC_ClocksTypeDef RCC_Clocks;
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_OCInitTypeDef  TIM_OCInitStructure;
    uint32 Period;
    uint32 freq;

    // TIM3 clock enable
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

    // PB0 Configuration: TIM3 as alternate function push-pull
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_StructInit(&GPIO_InitStruct);
    GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_0;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_AF;
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStruct.GPIO_PuPd  = GPIO_PuPd_UP ;
    GPIO_Init(GPIOB, &GPIO_InitStruct);
    //GKI_io_Config(IO_HCI_LPCLK, GKI_IO_AF_PP | GKI_IO_Speed_50MHz);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource0, GPIO_AF_TIM3);


    // Get Clock frequency and determine period divisor for 32K
    RCC_GetClocksFreq(&RCC_Clocks);
    freq = RCC_Clocks.PCLK1_Frequency;

    // If APB1 prescaler is not 1 nor 2 then multiply freq by 2
    u32 APB1_PreScaler = (RCC->CFGR & RCC_CFGR_PPRE1) >> 10;
    if (APB1_PreScaler==1) {
        freq *= 2;
    }

    // Calculate Period
    Period = freq / Hz;


// Old F1 setup
#if 0

    // Time base configuration
    memset(&TIM_TimeBaseStructure, 0, sizeof(TIM_TimeBaseStructure));
    TIM_TimeBaseStructure.TIM_Period        = Period; // -1;
    TIM_TimeBaseStructure.TIM_Prescaler     = 0;
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode   = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);


    // Setup PWM
    memset(&TIM_OCInitStructure, 0, sizeof(TIM_OCInitStructure));
    TIM_OCInitStructure.TIM_OCMode          = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState     = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse           = Period/2;
    TIM_OCInitStructure.TIM_OCPolarity      = TIM_OCPolarity_Low;
    TIM_OC3Init(TIM3, &TIM_OCInitStructure);
    TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);
    TIM_Cmd(TIM3, ENABLE);

#endif

    // Time base configuration
    memset(&TIM_TimeBaseStructure, 0, sizeof(TIM_TimeBaseStructure));
    TIM_TimeBaseStructure.TIM_Period        = Period; // -1;
    TIM_TimeBaseStructure.TIM_Prescaler     = 0;
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode   = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);


    // Setup PWM
    memset(&TIM_OCInitStructure, 0, sizeof(TIM_OCInitStructure));
    TIM_OCInitStructure.TIM_OCMode          = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState     = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse           = Period/2;
    TIM_OCInitStructure.TIM_OCPolarity      = TIM_OCPolarity_High;
    TIM_OC3Init(TIM3, &TIM_OCInitStructure);
    TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);

    TIM_ARRPreloadConfig(TIM3, ENABLE);

    TIM_Cmd(TIM3, ENABLE);
#endif
}
*/




// TM_BT_PIN_ClockConfig -- setup BT clock (LPO) PIN AS GPIO_Mode_IPD

extern void RCC_GetClocksFreq(RCC_ClocksTypeDef* RCC_Clocks);
void TM_BT_ClockConfigDelete(void)//kelong 2012.3.11  //LKL 2012.6.6
{
        TRACE_PRINT("TM_BT_ClockConfigDelete()\r\n");
#if !defined(BT24)
        //Set output 100% duty ratio, before closed TIM3 PWM output
        TIM_OCInitTypeDef  TIM_OCInitStructure;
        uint16 Period;
        uint32 freq;
        RCC_ClocksTypeDef RCC_Clocks;

        // Get Clock frequency and determine period divisor for 32K
        RCC_GetClocksFreq(&RCC_Clocks);
        freq = RCC_Clocks.PCLK1_Frequency;

        // If APB1 prescaler is not 1 then multiply freq by 2
        if (RCC->CFGR & CFGR_PPRE1_Set_Mask) {
            freq *= 2;
        }

        // Calculate Period
        Period = freq / TM_BT_CLOCK_SPEED;

        // Setup PWM
        memset(&TIM_OCInitStructure, 0, sizeof(TIM_OCInitStructure));
        TIM_OCInitStructure.TIM_OCMode          = TIM_OCMode_PWM1;
        TIM_OCInitStructure.TIM_OutputState     = TIM_OutputState_Enable;
        TIM_OCInitStructure.TIM_Pulse           = Period;
        TIM_OCInitStructure.TIM_OCPolarity      = TIM_OCPolarity_Low;
        TIM_OC3Init(TIM3, &TIM_OCInitStructure);
        TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);
        TIM_Cmd(TIM3, ENABLE);
        //Delay
        for(int i=0;i<100;i++);
        //PWM TIM3 closed
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, DISABLE);
        // in_floating
        GKI_io_Config(IO_HCI_LPCLK, GKI_IO_IN_FLOATING | GKI_IO_Speed_10MHz); //GPIO_Mode_IN_FLOATING;//GPIO_Mode_IPD;
#endif
}


//------------------------------------------------------------------------------
// Init main uart for debugging (USART1)
//------------------------------------------------------------------------------
void InitUart(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;

    // Turn on GPIOA and USART1 clocks
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

    // Setup USART1 Alternate Function Pins
    GPIO_PinAFConfig(_BASE(IO_MAIN_TX), _PIN(IO_MAIN_TX),  GPIO_AF_USART1);
    GPIO_PinAFConfig(_BASE(IO_MAIN_RX), _PIN(IO_MAIN_RX),  GPIO_AF_USART1);

    // Configure USART1 Tx
    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_OType   = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd    = GPIO_PuPd_UP;
    GPIO_InitStructure.GPIO_Mode    = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Pin     = _MASK(IO_MAIN_TX);
    GPIO_InitStructure.GPIO_Speed   = GPIO_Speed_50MHz;
    GPIO_Init(_BASE(IO_MAIN_TX), &GPIO_InitStructure);

    // Configure USART1 Rx
    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_PuPd    = GPIO_PuPd_UP;
    GPIO_InitStructure.GPIO_Mode    = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Pin     = _MASK(IO_MAIN_RX);
    GPIO_InitStructure.GPIO_Speed   = GPIO_Speed_50MHz;
    GPIO_Init(_BASE(IO_MAIN_RX), &GPIO_InitStructure);

    // Setup USART1
    USART_InitStructure.USART_BaudRate = 115200;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(USART1, &USART_InitStructure);
    USART_Cmd(USART1, ENABLE);

    // Remove Spurious data
    u16 data = USART1->DR;
    u16 status = USART1->SR;
}


#ifndef CUSTOM_LITE
//------------------------------------------------------------------------------
#define CMD_STRING_SIZE 80
//------------------------------------------------------------------------------
u32 SerialKeyPressed(u8 *key)
{
  if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) != RESET)
  {
    *key = (u8)USART1->DR;
    return 1;
  }
  else
  {
    return 0;
  }
}
//------------------------------------------------------------------------------
u8 GetKey(void)
{
  u8 key = 0;

  /* Waiting for user input */
  while (1)
  {
    if (SerialKeyPressed((u8*)&key)) break;
  }
  return key;
}
#endif // CUSTOM_LITE

#if defined(BT24)||defined(TI2564)
void SerialPutHciUART(char c)
{
  USART_SendData(USART2, c);
  while (USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET); // was USART_FLAG_TXE
}

#endif
//------------------------------------------------------------------------------
void SerialPutChar(char c)
{
  USART_SendData(USART1, c);
  while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); // was USART_FLAG_TXE
}
//------------------------------------------------------------------------------
void SerialPutString(char *s)
{
  while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
      ; // Wait until previous characters are out of the queue

  while (*s != '\0')
  {
    SerialPutChar(*s);
    s ++;
  }
}
#ifndef CUSTOM_LITE
void SerialWriteString(void *str, uint16 length)
{
  char *s=str;
  while (length--) {
    SerialPutChar(*s++);
  }
}
//------------------------------------------------------------------------------
void GetInputString(char * buffP)
{
  u32 bytes_read = 0;
  u8 c = 0;
  do
  {
    c = GetKey();
    if (c == '\r')
      break;
    if (c == '\b') /* Backspace */
    {
      if (bytes_read > 0)
      {
        SerialPutString("\b \b");
        bytes_read --;
      }
      continue;
    }
    if (bytes_read >= CMD_STRING_SIZE)
    {
      SerialPutString("Command string size overflow\r\n");
      bytes_read = 0;
      continue;
    }
    if (c >= 0x20 && c <= 0x7E)
    {
      buffP[bytes_read++] = c;
            //     SerialPutChar(c);
    }
  }
  while (1);

  buffP[bytes_read] = '\0';
}
#endif //CUSTOM_LITE



//------------------------------------------------------------------------------
//  Platform Setup
//------------------------------------------------------------------------------
//#define USE_32K_EXTERNAL
//#define SysClk_72MHz
//#define SysClk_64MHz
#ifdef BT43
#define SysClk_16MHz
#else
#define SysClk_32MHz
#endif //BT43
//------------------------------------------------------------------------------


/*******************************************************************************
* Function Name  : RCC_Config
* Platform       : Cortex M3
* Description    : Configure the system clocks
*******************************************************************************/
void RCC_Config(void)
{

    // Enable Prefetch Buffer and  2 wait state
    FLASH_PrefetchBufferCmd(ENABLE);
    FLASH_SetLatency(FLASH_Latency_2);
    //RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
    PWR_BackupAccessCmd(ENABLE);            // Allow access to BKP Domain
    //RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);


/***
    // Start HSE
    RCC_HSEConfig(RCC_HSE_ON);
    RCC_WaitForHSEStartUp();

    // Default Sysclk
    RCC_HCLKConfig(RCC_SYSCLK_Div1);
    RCC_PCLK1Config(RCC_HCLK_Div1);
    RCC_PCLK2Config(RCC_HCLK_Div1);
#ifdef USE_HSE_CLOCK
    RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE);
    while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET)
    {}  // Wait till HSE is ready
#else
    // RCC system reset(for debug purpose)
    RCC_DeInit();
    //RTC_SetPrescaler(0x21);

    // Enable Prefetch Buffer and  2 wait state
    FLASH_PrefetchBufferCmd(ENABLE);
    FLASH_SetLatency(FLASH_Latency_2);


    //-------------------------------------
    //  Turn on Crystal for BT and System
    //-------------------------------------
#if defined(BT43)
    RCC_HSEConfig(RCC_HSE_ON); //KS BT43
    HSE_Status = RCC_WaitForHSEStartUp();
#endif

    RCC_HSICmd(ENABLE);                 // Should already be enabled
    RCC_HCLKConfig(RCC_SYSCLK_Div1);    // HCLK = SYSCLK
    RCC_PCLK2Config(RCC_HCLK_Div1);
    RCC_PCLK1Config(RCC_HCLK_Div1);

    // Assume PLLCLK = 8MHz
#if defined(BT43)
    // using 13MHz HSE for MCO pin - output 26Mhz
    RCC_PLLConfig(RCC_PLLSource_HSE_Div2, RCC_PLLMul_8);
#else //Not BT43
#if defined(SysClk_72MHz)
    RCC_PLLConfig(RCC_PLLSource_HSI_Div1, RCC_PLLMul_9);
#elif defined(SysClk_64MHz)
    RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_16);
#elif defined(SysClk_32MHz)
    if(TM_CpuMHz == 32 )
    {
        RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_8);
    }
    else
    {
        RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_16);
    }
#elif defined(SysClk_24MHz)
    RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_6);
#elif defined(SysClk_16MHz)
    RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_4);
#endif
#endif //BT43

    RCC_PLLCmd(ENABLE);                 // Enable PLL
    while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
    {}  // Wait till PLL is ready

#if defined(USE_HSE_CLOCK)
    // Select HSE as system clock source
    RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE);
    while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET)
    {}  // Wait till HSE is ready
#else
    // Select PLL as system clock source
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    while (RCC_GetSYSCLKSource() != RCC_PLL_RDY)
    {}  // Wait till PLL is used as system clock source
#endif // USE_HSE_CLOCK

    //----------------------------------------------------------------------------
    // Enable the PWR and BKP Clocks
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
    PWR_BackupAccessCmd(ENABLE);            // Allow access to BKP Domain
    BKP_DeInit();                           // Reset Backup Domain
//    if (TM_USE_EXT_LPO) {
#ifdef USE_32K_EXTERNAL // bcolias 100204
        RCC_LSEConfig(RCC_LSE_Bypass);          // Enable External LSE
        while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
        {}                                      // Wait till LSE is ready
        RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); // Select LSE as RTC Clock Source
//    }
#else
//    else {
        RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI); // Select LSI as RTC Clock Source
        RCC_LSICmd(ENABLE);                     // Enable Low Speed Internal clock source
//    }
#endif


    //----------------------------------------------------------------------------
    RCC_ClearFlag();
    //----------------------------------------------------------------------------
    // DMA clock enable
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

#endif
**/
}


/*******************************************************************************
* Function Name  : Reset_NVIC
* Platform       : Cortex M3
* Description    : Reset NVIC, Vectors, Priority group
*******************************************************************************/
void Reset_NVIC(void)
{
    __set_PRIMASK(0);
    //__SETPRIMASK();
    //NVIC_DeInit();                                    // Deinitialize NVIC
    NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0);         // Vector = 0x08000000
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);     // Grp Priorities = 4
}


/*******************************************************************************
* Function Name  : Reset_ABP_Peripherals
* Platform       : Cortex M3
* Description    : Reset all APB1 & APB2 Peripherals
*******************************************************************************/
void Reset_ABP_Peripherals(void)
{
    u32 APB1_ENB = {
        RCC_APB1Periph_TIM2     |
        RCC_APB1Periph_TIM3     |
        //RCC_APB1Periph_TIM4     |
        //RCC_APB1Periph_TIM5     |
        //RCC_APB1Periph_TIM6     |
        //RCC_APB1Periph_TIM7     |
        //RCC_APB1Periph_TIM12    |
        //RCC_APB1Periph_TIM13    |
        //RCC_APB1Periph_TIM14    |
        RCC_APB1Periph_WWDG     |
        //RCC_APB1Periph_SPI2     |
        //RCC_APB1Periph_SPI3     |
        RCC_APB1Periph_USART2   |
        //RCC_APB1Periph_USART3   |
        //RCC_APB1Periph_UART4    |
        //RCC_APB1Periph_UART5    |
        //RCC_APB1Periph_I2C1     |
        //RCC_APB1Periph_I2C2     |
        //RCC_APB1Periph_I2C3     |
        //RCC_APB1Periph_CAN1     |
        //RCC_APB1Periph_CAN2     |
        RCC_APB1Periph_PWR      |
        //RCC_APB1Periph_DAC      |
        0
    };
    u32 APB2_ENB = {
        RCC_APB2Periph_TIM1     |
        //RCC_APB2Periph_TIM8     |
        RCC_APB2Periph_USART1   |
        //RCC_APB2Periph_USART6   |
        //RCC_APB2Periph_ADC      |
        //RCC_APB2Periph_ADC1     |
        //RCC_APB2Periph_ADC2     |
        //RCC_APB2Periph_ADC3     |
        //RCC_APB2Periph_SDIO     |
        RCC_APB2Periph_SPI1     |
        RCC_APB2Periph_SYSCFG   |
        //RCC_APB2Periph_TIM9     |
        RCC_APB2Periph_TIM10    |
        //RCC_APB2Periph_TIM11    |
        0
    };

    // Reset all APB1 peripherals
    RCC_APB1PeriphClockCmd(APB1_ENB, DISABLE);
    RCC_APB1PeriphClockCmd(APB1_ENB, ENABLE);
    RCC_APB1PeriphResetCmd(APB1_ENB, DISABLE);
    RCC_APB1PeriphClockCmd(APB1_ENB, ENABLE);

    // Reset all APB2 peripherals
    RCC_APB2PeriphClockCmd(APB2_ENB, DISABLE);
    RCC_APB2PeriphClockCmd(APB2_ENB, ENABLE);
    RCC_APB2PeriphResetCmd(APB2_ENB, DISABLE);
    RCC_APB2PeriphClockCmd(APB2_ENB, ENABLE);
}



/*******************************************************************************
* Function Name  : Set_AHB_Peripherals
*******************************************************************************/
void Set_AHB_Peripherals(void)
{
    u32 AHB1_ENB = {
        RCC_AHB1Periph_GPIOA    |
        RCC_AHB1Periph_GPIOB    |
        RCC_AHB1Periph_GPIOC    |
        RCC_AHB1Periph_CRC      |
        RCC_AHB1Periph_BKPSRAM  |
        RCC_AHB1Periph_DMA1     |
        RCC_AHB1Periph_DMA2     |
        0
    };
    RCC_AHB1PeriphClockCmd(AHB1_ENB, ENABLE);
}



/*******************************************************************************
* Function Name  : InitPlatform
* Description    : Initialize the Amped RF module platform
*******************************************************************************/
static void InitPlatform(void)
{
    // Initialize Boot Ram
    if (SU_ResetMagicNumber != 0xDEADBEEF) {
        memset(SU_RamStart, 0, BOOT_RAMSTART_SIZE);
        SU_ResetMagicNumber = 0xDEADBEEF;
    }
    TM_UartDev[eTM_HciUart].Baudrate = 0;
    TM_UartDev[eTM_MainUart].Baudrate = 0;

	RCC_Config();//Enable flash buffer
    Reset_NVIC();//Reset nvic
    Reset_ABP_Peripherals();//Enable ABP clock
    Set_AHB_Peripherals();//Enable AHB clcok
	#ifndef TI2564
    GKI_rcc_ConfigMCO();
	#endif
	//GKI_rcc_SetSysClock(TM_CpuMHz);
    //GKI_uart_SetBaudrate(eTM_MainUart, 115200);
    TM_FlashInit();
 //   GKI_rcc_WaitMS(100);

#if !defined(CUSTOM_LITE) && !defined(BT43)
    SU_Determine_HSE_Speed();
#endif  // CUSTOM_LITE

    // Default GPIOs
    TM_InitPio();


    // Setup BT PWM Clock on PB0
 //   TM_BT_ClockConfig(TM_BT_CLOCK_SPEED);
}





uint32 CoreID;


//#ifndef CUSTOM_LITE
void WriteStackPattern(void)
{
    uint8 *p;

    // Clear CStack while leaving room for what's being used now
    for (p=CStackBottom; p != ((uint8 *)CStackTop-64); p++) {
        *p = 0xCD;
    }
    // Clear other stacks
    for (p=HeapBottom; p != HeapTop; p++) {
        *p = 0xCD;
    }
    for (p=IRQstackBottom; p != IRQstackTop; p++) {
        *p = 0xCD;
    }
    for (p=IRamBottom; p != IRamTop; p++) {
        *p = 0xCD;
    }
}
//#endif // CUSTOM_LITE
//------------------------------------------------------------------------------
// TC Main Function
//
// For starting the system with the Backplane as the executive.
//------------------------------------------------------------------------------
//void SU_TCMain(void)
#ifdef SDK
void bt_startup()
#else
void main()
#endif
{
    main_startup();

/****************************************************************************
//#ifndef CUSTOM_LITE
    WriteStackPattern();
//#endif
    memset(SU_LINK_DESKEY, 0, DESKEY_SIZE);
    memset(SU_UART_DESKEY, 0, DESKEY_SIZE);
#ifdef DEBUG
    debug();
#endif
    // Initialize Platform
#ifdef CUSTOM_HCI_PASSTHRU
    HciInitComplete = false;
#endif
    //-------------------------------------------------
    InitPlatform();
    InitDebugUart(115200);
    //-------------------------------------------------
    IRamArea = 0;
    TM_InitInterrupt();
    TM_SetUpWDTimer();
    //-------------------------------------------------
****************************************************************************/

/*
    void BP_InitData(void);
    GKI_putstring("-------------------------------------------------\r\n");
    char msg[]={"This is a test\r\n"};
    tUartConf MainUartConf;
    BP_InitData();
    TM_UartDriverInitialization(eTM_MainUart);
    GKI_putstring("done\r\n\r\n");
 //   GKI_uart_ITConfig(eTM_MainUart, USART_IT_TXE,  0);
 //   GKI_putstring(" -- done\r\n\r\n");
    MainUartConf.DataBits = eTM_dataBits8;
    MainUartConf.StopBits = eTM_stopBits1;
    MainUartConf.Parity   = eTM_NoParity;
    MainUartConf.Baudrate = 115200;
    TM_UartConfigure(eTM_MainUart, &MainUartConf);
    GKI_putstring("done\r\n\r\n");
    GKI_StartTxDma(eTM_MainUart, msg, strlen(msg));
    GKI_putstring("-------------------------------------------------\r\n");

    while (1)
        ;

    char msg[64];
    GKI_putstring("\r\nStartup\r\n");
    GKI_rtc_Setup();
    void RCC_ConfigurationXXX(void);
    RCC_ConfigurationXXX();
    void TIM_Config(void);
    TIM_Config();
    u32 t0 = TIM_GetCounter(TIM2);
    sprintf(msg, "t0 = %d\r\n", t0);
    SerialPutString(msg);
    for (int i=0; i<5000; i++)
        NOP;
    u32 t1 = TIM_GetCounter(TIM2);
    sprintf(msg, "t1 = %d\r\n", t1);
    SerialPutString(msg);
    TIM_SetCompare1(TIM2, t1+100);
    while (1)
        ;
    GKI_uart_Config(eTM_MainUart, 115200);
    GKI_putstring("\r\nReady\r\n");
    while (1);
        ;
*/

#ifdef LE_STK
    LOG_INIT();
    LOG_WRITE("BP_Init");
#endif

    BP_Init();                      // Init BP structures

    //---------------------------------------------------------
    //ShowClocks();
    //---------------------------------------------------------
    //void ShowConfigVars(void);
    //ShowConfigVars();
    //---------------------------------------------------------


#ifdef CUSTOM_AUDIO_WM8904
    iic_init();
    wm8904_poweron_init();
        //TM_StartI2S();
        // TM_startI2S_2(I2S_Mode_MasterTx);
#endif


    BP_Start();
	 __set_FAULTMASK(1);
	RCC_HSEConfig(RCC_HSE_OFF);
	while(RESET != RCC_GetFlagStatus(RCC_FLAG_HSERDY));
    NVIC_SystemReset();
    //fatalc(false,"OutOfBlueOS");
}



//------------------------------------------------------------------------------
// Function:    SU_SetCpuMHz
// Description: Set the CPU speed (assumes internal 8 MHz source)
//------------------------------------------------------------------------------
void SU_SetCpuHz_HSI(uint32 Hz)
{
    ENTER_CRITICAL();

    if (Hz >= 8000000) {
        //  Reset Main baudrate to reflect new MHz
        if (TM_UartDev[eTM_MainUart].Baudrate) {
            USART_Cmd(UART[eTM_MainUart], ENABLE);
            if (TM_UartDev[eTM_MainUart].Baudrate) {
                TM_SetBaud(eTM_MainUart, TM_UartDev[eTM_MainUart].Baudrate);
            }
        }
        //  Reset HCI baudrate to reflect new MHz
        if (TM_UartDev[eTM_HciUart].Baudrate) {
            USART_Cmd(UART[eTM_HciUart], ENABLE);
            if (TM_UartDev[eTM_HciUart].Baudrate) {
                TM_SetBaud(eTM_HciUart, TM_UartDev[eTM_HciUart].Baudrate);
            }
        }
    }

    EXIT_CRITICAL();
}




//------------------------------------------------------------------------------
// Function:    SU_SetCpuMHz
// Description: Set the CPU speed (assumes internal 8 MHz source)
//------------------------------------------------------------------------------
void SU_SetCpuMHz(uint16 MHz)
{
    GKI_rcc_SetSysClock(MHz * 1000000);
}




#if !defined(CUSTOM_LITE) || defined(BT43)
//------------------------------------------------------------------------------
// Function:    SU_Find_HSE_MulDiv
// Description: Find correct mul & div for HSE
//              Assume a Div2 divisor from the source
//------------------------------------------------------------------------------
#ifdef STM32F10x
uint32 SU_Find_HSE_MulDiv(sint32 TargetHz, uint32 *mul, uint32 *sysdiv, uint32 *pdiv)
{
    const uint8  PLLMul_Value[15]={2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
    const uint32 PLLMul_Mask[15]={
        RCC_PLLMul_2,  RCC_PLLMul_3,  RCC_PLLMul_4,  RCC_PLLMul_5,  RCC_PLLMul_6,
        RCC_PLLMul_7,  RCC_PLLMul_8,  RCC_PLLMul_9,  RCC_PLLMul_10, RCC_PLLMul_11,
        RCC_PLLMul_12, RCC_PLLMul_13, RCC_PLLMul_14, RCC_PLLMul_15, RCC_PLLMul_16};
    const uint16  hdiv_value[9]={1,2,4,8,16,64,128,256,512};
    const uint32  hdiv_mask[9]={
        RCC_SYSCLK_Div1,  RCC_SYSCLK_Div2,   RCC_SYSCLK_Div4,   RCC_SYSCLK_Div8,
        RCC_SYSCLK_Div16, RCC_SYSCLK_Div64,  RCC_SYSCLK_Div128, RCC_SYSCLK_Div256,
        RCC_SYSCLK_Div512};
    const uint8  PCLK_DIV_VALUE[5]={1,2,4,8,16};
    const uint16 PCLK_DIV_MASK[5]={
        RCC_HCLK_Div1, RCC_HCLK_Div2, RCC_HCLK_Div4, RCC_HCLK_Div8, RCC_HCLK_Div16};

    sint32 HSE_Div2 = (sint32)HSE_Frequency / 2;
    sint32 mval, d, DeltaSpeed;
    sint32 LastDeltaSpeed=99999999;
    uint32 MatchingSpeed=0;
    uint8 i, m;
    uint32 sysclk, hclk;

    // Default values
    *mul    = RCC_PLLMul_2;
    *sysdiv = RCC_SYSCLK_Div1;
    *pdiv   = RCC_HCLK_Div1;

    // Find closest matching MHz
    //TargetMHz *= 1000000;
    for (m=0; m<15; m++)
    {
        mval = PLLMul_Value[m];
        sysclk = mval*HSE_Div2;
        if (sysclk > 72000000) {
            break;
        }
        for (d=0; d<9; d++)
        {
            hclk = sysclk / hdiv_value[d];
            if (hclk < 1000000) {
                break;
            }

            DeltaSpeed = abs(hclk-TargetHz);

            if (DeltaSpeed<LastDeltaSpeed)
            {
                MatchingSpeed = hclk;
                LastDeltaSpeed = DeltaSpeed;
                *mul = (uint32)PLLMul_Mask[m];      // RCC_PLLMul
                *sysdiv = (uint32)hdiv_mask[d];     // RCC_SYSCLK_Div
                if (DeltaSpeed < 1000000) {
                    break;
                }
            }
        }
    }

    hclk = MatchingSpeed;

    for (i=0; i<5; i++) {
        if (hclk/PCLK_DIV_VALUE[i] <= 36000000) {
            *pdiv = PCLK_DIV_MASK[i];
            break;
        }
    }

    return MatchingSpeed;
}
#endif


// Switch to High Speed External clock
// Not used - KS 100204
void SU_UseExternalClock(void)
{
#ifdef STM32F10x
    if (TM_USE_EXT_LPO)
    {
//#ifndef NO_HSE
        RCC_HSEConfig(RCC_HSE_ON);
        SU_SetCpuMHz(TM_CpuMHz);
        //  Reset new HCI baudrate to reflect new MHz
        USART_Cmd(TM_HciUart, ENABLE);
        if (TM_UartDev[eTM_HciUart].Baudrate) {
            TM_SetBaud(TM_HciUart, TM_UartDev[eTM_HciUart].Baudrate);
        }
//#endif
    }
#endif
}


// Switch to High Speed External clock
void SU_UseInternalClock(void)
{
}




//------------------------------------------------------------------------------
// Determine HSE speed
//------------------------------------------------------------------------------
void SU_Determine_HSE_Speed(void)
{
#ifdef STM32F2xx
	InitUart();
	TRACE_PRINT("SU_Determine_HSE_Speed()\r\n");
#endif
}

#endif // CUSTOM_LITE







void TIM_Config(void)
{
    RCC_ClocksTypeDef       RCC_Clocks;
    TIM_OCInitTypeDef       TIM_OCInitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    uint16_t PrescalerValue = 0;
    static bool initialized = false;
    if (initialized)
        return;
    initialized = true;

    // Get clock frequencies
    RCC_GetClocksFreq(&RCC_Clocks);

    // Enable TIM2 clock
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);            // Enable TIM2 clock

    // Enable TIM2 Interrupt
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);                                 // Enable TIM2 Interrupt

    /* Compute the prescaler value */
    // PrescalerValue = (uint16_t) ((SystemCoreClock / 2) / 1000) - 1;
    PrescalerValue = ((RCC_Clocks.PCLK1_Frequency / 4) / 1000) - 1;

    /* Time base configuration */
    TIM_TimeBaseStructure.TIM_Period                = 0xFFFFFFFF;
    TIM_TimeBaseStructure.TIM_Prescaler             = PrescalerValue;
    TIM_TimeBaseStructure.TIM_ClockDivision         = TIM_CKD_DIV4;
    TIM_TimeBaseStructure.TIM_CounterMode           = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

    /* Output Compare Active Mode configuration: Channel1 */
    TIM_OCInitStructure.TIM_OCMode                  = TIM_OCMode_Toggle;
    TIM_OCInitStructure.TIM_OutputState             = TIM_OutputState_Disable;
    TIM_OCInitStructure.TIM_Pulse                   = TM_TICKS_PER_SECOND;
    TIM_OCInitStructure.TIM_OCPolarity              = TIM_OCPolarity_High;
    TIM_OC1Init(TIM2, &TIM_OCInitStructure);
 //  TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Disable);
 //  TIM_ARRPreloadConfig(TIM2, ENABLE);
    TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE);                         // TIM IT enable
    TIM_Cmd(TIM2, ENABLE);                                          // TIM2 enable counter
}




void IsrTim2(void)
{
    u32 t0, t1;
    static u32 tlast=0;

    t0 = TIM_GetCounter(TIM2);
    t1 = t0 + TM_TICKS_PER_SECOND;

    GKI_putstring("*Tim\r\n");
    TIM_SetCompare1(TIM2, t1);

    tlast = t0;
}




//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void ShowClks(void)
{
    RCC_ClocksTypeDef RCC_Clocks;
    RCC_GetClocksFreq(&RCC_Clocks);
    const char Fmt1[]="%8.8s: %11.11s Hz\r\n";
    const char Fmt2[]="%8.8s: %11.11s Baud\r\n";
    char buf[20], msg[64];
    #define SHCLK(fmt, name, numstr)    sprintf(msg, (char *)fmt, name,  numstr);  GKI_putstring(msg)

    GKI_putstring("   Clock        Speed\r\n");
    SHCLK(Fmt1, "HSE",      UT_PrettyNumber(buf, HSE_VALUE));
    SHCLK(Fmt1, "HSI",      UT_PrettyNumber(buf, HSI_VALUE));
    SHCLK(Fmt1, "SYSCLK",   UT_PrettyNumber(buf, RCC_Clocks.SYSCLK_Frequency));
    SHCLK(Fmt1, "HCLK",     UT_PrettyNumber(buf, RCC_Clocks.HCLK_Frequency));
    SHCLK(Fmt1, "PCLK1",    UT_PrettyNumber(buf, RCC_Clocks.PCLK1_Frequency));
    SHCLK(Fmt1, "PCLK2",    UT_PrettyNumber(buf, RCC_Clocks.PCLK2_Frequency));
    SHCLK(Fmt2, "HCI Uart", UT_PrettyNumber(buf, TM_UartDev[eTM_HciUart].Baudrate));
}



//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void ShowConfigVars(void);


//------------------------------------------------------------------------------
//
//------------------------------------------------------------------------------
void main_startup(void)
{
    WriteStackPattern();
    memset(SU_LINK_DESKEY, 0, DESKEY_SIZE);
    memset(SU_UART_DESKEY, 0, DESKEY_SIZE);
    InitPlatform();

    IRamArea = 0;

    __enable_interrupt();
    TM_SetUpWDTimer();

#ifdef USE_HSE_CLOCK
    if (RCC_WaitForHSEStartUp() == ERROR) {
        InitUart();
        GKI_putstring("FATAL ERROR: HSE is not running\r\n");
    }
#endif

    GKI_rcc_SetSysClock(TM_CpuMHz);
    GKI_uart_SetBaudrate(eTM_MainUart, 115200);
}


#endif // STM32F4xx
//------------------------------------------------------------------------------
// End of SU_TCMain.c
