/**
  **********************************************************************************
  * @file    hal.c
  * @author  Product application department
  * @version V1.0
  * @date    2020.02.13
  * @brief   HAL层驱动.
  * @note 这个文件为应用层提供了系统操作的接口:
  *     - HAL初始化接口.
  *     - Tick接口.
  *     - 获取芯片SN接口.
  *     - 芯片恢复ROM boot启动接口.
  *     - 芯片禁止ROM boot启动接口.
  *     - 锁定禁止JTAG接口
  *     
  @verbatim
  ===================================================================================
                                  ##### 更新 #####
  ===================================================================================
  [..] 更新时间:
  [..] 更新人:
  [..] 更新内容:
        1. nothing.
  @endverbatim
  */

#include "hal.h"
#include "rtc_hal.h"
#include "psram_hal.h"
#include "cache_hal.h"

#include "LT776_gra.h"
UINT32 gSysTick_Counter;

/*** 全局变量定义 ***************************************************************/
/** @
  * @{volatile
  */

 extern unsigned int __Vectors;
 
__IO uint32_t g_tick_cnt = 0;

/** @ 
  * @}
  */
/** @ 
  * @{static
  */
/** @ 
  * @}
  */
/*** 常量定义 *******************************************************************/
/** @
  * @{const
  */
/** @ 
  * @}
  */

/*** 函数定义 *******************************************************************/
/**
 * @brief 系统初始化，包括系统时钟、Tick时钟初始化、cache初始化、debug串口打印初始化、eflash初始化.
 * @retval @ref HAL_StatusTypeDef HAL status
 */
 
 extern void HAL_CACHE_Close(void);
HAL_StatusTypeDef HAL_Init(void)
{
	HAL_StatusTypeDef retval = HAL_OK;
	CPM_ClkInitTypeDef clk_init;

	HAL_CACHE_Close();
	/*调试时钟建议打开，预防修改时钟失败导致无法仿真*/
	//delay(250000);	
    
	/*系统时钟源选择内部8M、内部400M和外部12M，推荐内部400M*/
//	clk_init.SysClkSource = HAL_SYSCLK_OSC400M;
	clk_init.SysClkSource = HAL_SYSCLK_OSC500M;

	/* 最小1分频，最大16分频  */
	clk_init.CoreClkDiv = CLK_DIV_1;

	/*最小1分频，最大256分频，当 CoreClkDiv=CLK_DIV_1时 SysClkDiv最小为2分频！，既是系统时钟最大为200MHZ*/
	clk_init.SysClkDiv = CLK_DIV_2;

	/*最小1分频，最大16分频， 当 CoreClkDiv=CLK_DIV_1同时 SysClkDiv = CLK_DIV_2时 SdramClkDiv最小为2分频！既是SDRAM时钟最大为100MHZ。*/
	clk_init.SdramClkDiv = CLK_DIV_2;

	/*最小2分频，最大16分频， 当 CoreClkDiv=CLK_DIV_1同时 SysClkDiv = CLK_DIV_2时 IpsClkDiv最小为2分频！既是IPS时钟最大为100MHZ。  */
	clk_init.IpsClkDiv = CLK_DIV_2;

	if((unsigned int)(&__Vectors) == 0x10000000)
	{
		/*初始化时钟*/
		HAL_CPM_SSI_SYSCLKConfig(&clk_init);
	}
	else
	{	
		/*初始化时钟*/
		HAL_CPM_SYSCLKConfig(&clk_init);
	}    
	/*初始化CACHE*/
	HAL_CACHE_Init();

#if 0
	/* 芯片3.3V或1.8V供电时，对功耗要求高，建议打开此接口，对功耗要求不高可以不打开; 芯片5V供电时必须屏蔽此接口,否则可能坏芯片！！！ */
	HAL_CPM_VCC5VByPass();    
#endif

	/* 初始化UART */     
	//UART_Debug_Init(UART2, g_ips_clk, 115200);

	/*初始化EFLASH*/
	HAL_EFLASH_Init(g_sys_clk);

	return retval;
}

/**
 * @brief 恢复系统初始状态.
 * @retval @ref HAL_StatusTypeDef HAL status
 */
HAL_StatusTypeDef HAL_DeInit (void)
{
	return HAL_OK;
}

/**
 * @brief 初始化Tick时钟，CORE 内核时钟(EPT).
 * @retval @ref HAL_StatusTypeDef HAL status
 */
__weak HAL_StatusTypeDef HAL_InitTick (void)
{
    return HAL_OK;
}

/**
 * @brief 增加全局变量uwTick,供应用time使用.
 * @retval NONE
 */


__weak void HAL_IncTick1(void)
{
	g_tick_cnt++;

	Show32BitValue(40,0,g_tick_cnt,grWHITE,grBLACK);
	
}

/**
 * @brief 获取Tick值,单位：ms.
 * @retval 当前Tick计数值
 */
__weak uint32_t HAL_GetTick(void)
{
	return 0;
}

/**
 * @brief 暂停Tick时钟.
 * @retval @ref HAL_StatusTypeDef HAL status
 */
__weak HAL_StatusTypeDef HAL_SuspendTick(void)
{
	return HAL_OK;
}

/**
 * @brief 恢复Tick时钟.
 * @retval @ref HAL_StatusTypeDef HAL status
 */
__weak HAL_StatusTypeDef HAL_ResumeTick(void)
{
	return HAL_OK;
}

/**
 * @brief 延时函数.
 * @param[in] Delay：延时时间长度，单位：ms.
 * @note 此延时采用了中断方式，中断嵌套使用时，请将其他模块中断优先级设为大于0
 * @retval NONE
 */
__weak void HAL_Delay(__IO uint32_t Delay)
{

}

/**
 * @brief 打印固件版本信息.
 * @retval @ref HAL_StatusTypeDef HAL status
 */
void HAL_PrintfVersion(void)
{
		RTC_TimeTypeDef rtcTime;

#ifdef ALGO_DEMO
    uint8_t *algo_ver;
    
    HAL_ALGO_GetVersion(algo_ver);
#endif
    
    printf("/**************************************************/\r\n");
		printf(" LT776 APP Project  \r\n");
    printf(" %s %s    \r\n",( char *)__DATE__,( char *)__TIME__);
		HAL_RTC_GetTime(&rtcTime);
		printf(" RTC : D-%d [%d:%d:%d]    \r\n", rtcTime.days, rtcTime.hours, rtcTime.minutes, rtcTime.seconds);

	  printf(" core clk   = %dMHz           \r\n",g_core_clk/1000000);
    printf(" system clk = %dMHz         \r\n",g_sys_clk/1000000);
    printf(" ips clk    = %dMHz         \r\n",g_ips_clk/1000000);
	  printf(" sdram clk  = %dMHz         \r\n",g_sdram_clk/1000000);
    printf("/**************************************************/\r\n");
}


/**
 * @brief 获取芯片唯一SN号.
 * @param[out] pSN：pSN：芯片SN号缓存，长度8字节，未CP的芯片返回值为全0xFF。.
 * @retval @ref HAL_StatusTypeDef HAL status
 */
HAL_StatusTypeDef HAL_GetSN(uint8_t *pSN)
{
    LIB_GetSerialNumber(pSN);
    return HAL_OK;
}

/**
 * @brief 将芯片恢复rom boot状态，芯片重新上电从rom启动.
 * @note 执行函数前请先初始化EFLASH
 * @retval NONE
 */
void HAL_RebackBoot(void)
{
	HAL_EFLASH_SetWritePermission();
	LIB_EFLASH_RecoveryToBoot();
	 
}

/**
 * @brief 将芯片禁止rom boot状态，芯片重新上电或复位从EFlash启动或SPIFLASH启动.
 * @note 执行函数前请先初始化EFLASH
 * @retval NONE
 */
void HAL_DisBoot(void)
{
	 
	LIB_EFlash_Chip_Mode(EFLASH_BOOT);
}

/**
 * @brief 系统执行软件复位.
 * @note 执行函数前请先初始化EFLASH
 * @retval NONE
 */
void HAL_LockDisJtag(void)
{
	//LIB_LockDisJtag(LOCK_JTAG_KEY);	//执行此接口，芯片将不能仿真，执行前请慎重考虑！！！
}

/*** 函数定义 *******************************************************************/
/**
 * @brief 系统初始化，包括系统时钟、Tick时钟初始化.
 * @retval @ref HAL_StatusTypeDef HAL status
 */
HAL_StatusTypeDef SysClk_SoftRstReconfig(void)
{
    HAL_StatusTypeDef retval = HAL_OK;
    CPM_ClkInitTypeDef clk_init;
 
//  /* 调试时钟建议打开，预防修改时钟失败导致无法仿真 */
   // delay(250000); 
    
    /* 系统时钟源选择内部8M、内部400M和外部12M，推荐内部400M  */
    clk_init.SysClkSource = HAL_SYSCLK_OSC400M;
 
   /* 最小1分频，最大16分频  */
   clk_init.CoreClkDiv = CLK_DIV_4;
 
    /* 最小1分频，最大256分频，当 CoreClkDiv=CLK_DIV_1时 SysClkDiv最小为2分频！，既是系统时钟最大为200MHZ。*/
    clk_init.SysClkDiv = CLK_DIV_2;
 
  /*最小1分频，最大16分频， 当 CoreClkDiv=CLK_DIV_1同时 SysClkDiv = CLK_DIV_2时 SdramClkDiv最小为2分频！既是SDRAM时钟最大为100MHZ。*/
    clk_init.SdramClkDiv = CLK_DIV_2;
 
    /* 最小2分频，最大16分频， 当 CoreClkDiv=CLK_DIV_1同时 SysClkDiv = CLK_DIV_2时 IpsClkDiv最小为2分频！既是IPS时钟最大为100MHZ。  */
    clk_init.IpsClkDiv = CLK_DIV_2;

 
  if((unsigned int)(&__Vectors) == 0x10000000)
  {
         /* 初始化时钟 */
      HAL_CPM_SSI_SYSCLKConfig(&clk_init);
  }
  else
  { 
    /* 初始化时钟 */
     HAL_CPM_SYSCLKConfig(&clk_init);
  }    
}


