/***********************************************************************
 * Copyright (c)  2017 - 2020, Unicmicro Co.,Ltd .
 * All rights reserved.
 * Filename    : system_um321xA.c
 * Description : system config source file (for example: clock config.....)
 * Author(s)   : Dan
 * version     : V1.0
 * Modify date : 2019-04-10
 ***********************************************************************/
#include  "system_um321xA.h"
#include  "config.h"

uint32_t SystemCoreClock = 0;   //core时钟，HCLK  (uint:Hz)
uint32_t SRCClock = 32000000;   //源时钟,clk_src, (uint:Hz)
uint32_t PCLK = 0;     		    //APB时钟/PCLK,外设时钟 (uint:Hz)
uint32_t RCLClock = 32000;   	//RCL时钟,clk_src, (uint:Hz)

/************************************************************************
 * function   : div_cal
 * Description: div_cal
 * input : 
 		   需要分频的分频比
 * return: 推算后的的实际分频值
 ************************************************************************/
uint8_t div_cal(uint8_t div)
{
	uint8_t ret;
	switch (div)   							
	{
		case 0x01: ret = 0; break;
		case 0x02: ret = 1; break;
		case 0x04: ret = 2; break;
		case 0x08: ret = 3; break;
		case 0x10: ret = 4; break;
		case 0x20: ret = 5; break;
		case 0x40: ret = 6; break;
		case 0x80: ret = 7; break;
		default	 : ret = 0; break;              //如果以上分频都没有，则设为32M
	}
	return ret;
}

/************************************************************************
 * function   : clock_init
 * Description: clock init, initil several clock variables
 * input : 
 		   uint32_t system_clk_mhz: expected system core clock
 * return: none
 ************************************************************************/
void clock_init(uint32_t system_clk_hz)
{
	uint8_t wait_time=0;
	uint8_t i,regdata;
	uint8_t div=0;
	uint8_t div_cal_val;
	uint32_t temp,rch32m,rcl32k;
	
	div_cal_val=SRCClock/system_clk_hz;
	div=div_cal(div_cal_val);
	
	REG_SCU_CTRLPROTECT = 0xA5A55A5A;				 //清除SYSCTRL0的写保护
	temp = REG_SCU_CTRL0 & (~(3<<17));              
	temp &= ~(3<<9);
	REG_SCU_CTRL0 = temp|CLK_DIV_RCH|CLK_DIV_APB;	//RCH时钟源和APB分频配置

	REG_SCU_CTRLPROTECT = 0xA5A55A5A;		 		//清除SYSCTRL0的写保护
	REG_SCU_CTRL0 = (REG_SCU_CTRL0&(~(7<<6)))|(div<<6);	//HCLK分频配置
	
	
	REG_SCU_CTRLPROTECT = 0xA5A55A5A;		 		//清除SYSCTRL0的写保护
	REG_SCU_CTRL0 |= 1<<0;					 		//RCH时钟使能
	while((REG_SCU_OSCCTRL&0x400) == 0x00);  		//等待时钟稳定
	
	REG_SCU_CTRLPROTECT = 0xA5A55A5A;		 		//清除SYSCTRL0的写保护
	REG_SCU_CTRL0 &= ~(1<<14);				 		//系统时钟来源为系统高速时钟
	
	REG_SCU_CTRLPROTECT = 0xA5A55A5A;				//清除SYSCTRL0的写保护
	REG_SCU_CTRL0 &= ~(1<<13);				 		//高频时钟选择内部高速时钟RCH

				 
	//系统时钟频率
	rch32m = (*(volatile uint32_t *)(0x01010034));
	if ((rch32m <= 34000000) && (rch32m >= 30000000)) SystemCoreClock = rch32m;
    else SystemCoreClock = system_clk_hz;

	div = 1;
	regdata = ((REG_SCU_CTRL0>>9)&0x03);
	for(i=0; i<regdata; i++)
	{
		div = div*2;	
	}
	
    PCLK = SystemCoreClock/div;		

	//RCL时钟频率
	rcl32k = (*(volatile uint32_t *)(0x01010038));
	rcl32k = rcl32k/100;
	if ((rcl32k <= 34000) && (rcl32k >= 30000)) RCLClock = rcl32k;
	
	/*EFC配置*/
	REG_SCU_PERICLKEN |= (1<<20);
	REG_EFC_CTRL = (REG_EFC_CTRL &(~(0x0f<<3))) | (wait_time << 3);
	
}

 void io_status_init(void)
{
	REG_SCU_IOCTRLPROTECT = 0xA5A55A5A; //清除IO写保护
	
	/*配置所有端口为复位默认功能*/
    REG_SCU_PASEL = 0x00000000;
	REG_SCU_PBSEL = 0x00000000;
    REG_SCU_PCSEL = 0x01100000;    
	REG_SCU_PDSEL = 0x00000000;
	REG_SCU_PESEL = 0x00000000;
	
	/*所有io上拉*/
	REG_SCU_PADPU0 = 0xFFFFFFFF;
	REG_SCU_PADPU1 = 0xFFFFFFFF;
	
	/*所有io输入使能*/
	REG_SCU_PADIE0 = 0xFFFFFFFF;
	REG_SCU_PADIE1 = 0xFFFFFFFF;
    
    REG_SCU_IOCTRLPROTECT = 0xffffffff; //开启IO写保护
    while((REG_SCU_IOCTRLPROTECT & 0x01) == 0x01)      //读IO控制保护寄存器的写使能状态
    {
        REG_SCU_IOCTRLPROTECT = 0xffffffff; //开启IO写保护
    }	
	

}

/************************************************************************
 * function   : SystemInit
 * Description: SystemInit
 * input : none
 * return: none
 ************************************************************************/
void SystemInit(void)
{
    clock_init(FCLK);   //时钟初始化设置
	io_status_init();   //io状态初始化
}

void SystemCoreClockUpdate(void)
{
    //SystemCoreClock=FCLK;
}
/*****************************************************************************
Function Name	sys_entersleep
Function Definition	void sys_entersleep (void)
Function Description	Enter sleep mode
Input Parameters	    No
Return Value	        No
Condition	            No
Function called	-
*****************************************************************************/
void sys_entersleep(void)
{
	//Sleep
	SCB->SCR &= ~(1<<2);			    //sleep	
	//issue sleep command
  /*1.WFI*/  
//	__WFI();	//enter sleep
  /*2.WFE*/ 
    __WFE();
    __WFE();
	return;
}
/*****************************************************************************
Function Name	sys_enterdeepsleep
Function Definition	void sys_enterdeepsleep (void)
Function Description	Enter deepsleep mode
Input Parameters	    No
Return Value	        No
Condition	            No
Function called	-
*****************************************************************************/
void sys_enterdeepsleep(void)
{
	//Deep Sleep
	SCB->SCR |= (1<<2);					//deep sleep
	//issue deep sleep command
    /*1.WFI*/
	//__WFI();	//enter deep sleep
  /*2.WFE*/ 
    __WFE();
    __WFE();     
	__NOP();
	__NOP();
	__NOP();
	__NOP();
	__NOP();
	return;
}
/*****************************************************************************
Function Name	sys_enterstop
Function Definition	void sys_enterstop (void)
Function Description	Enter stop mode
Input Parameters	    No
Return Value	        No
Condition	            No
Function called	-
*****************************************************************************/
void sys_enterstop(void)
{
	
	REG_SCU_STOPMODESEL = 0xA5A50001;	//STOP停止模式有效	
	
	SCB->SCR |= (1<<2);	
    /*1.WFI*/	
	//__WFI();	//enter stop
   /*2.WFE*/ 
    __WFE();
    __WFE();    
     
	return;
}
