#include "trim_option.h"
#include "system_um321xA.h"
#include "stdio.h"
#include  "eflash.h"


#define VADJ_ACT   	0
#define VTRIM_ACT   2

#define VADJ_STANDBY   	8
#define VTRIM_STANDBY   10

uint8_t manual_cal_trim(struct trim_type* trim_tab)
{
	uint32_t temp = 0;
	if(trim_tab == NULL)
	{
		return 1;
	}   
/*==============1.手动写LDOTRIM值================*/
	uint8_t act_vtrim, act_vadj;
	uint8_t stby_vtrim, stby_vadj;
	
	/*可以手动修改下列参数值*/
	/*=以下参数设置不设边界保护，请自行注意参数值的数据位宽长度=*/
	stby_vtrim =  0x07;   	//默认值为4’h7 （长度4个位）
	stby_vadj  =  0x03;	 	//默认值为2’h3
	act_vtrim  =  0x15;	 	//(ldo微调)默认值为5’h10（长度5个位）,用于微调ldo电压
	act_vadj   =  0x03;	 	//(ldo粗调)默认值为2’h3，用于粗调ldo电压
	/*=====================================================*/
	/*	（细调）                （粗调）
	STANDBY trim值设定	|	STANDBY 档位设定 (SELLP 模式下)
	ACTIVE trim值设定	|	ACTIVE 档位设定  (正常模式下) */
	temp |= ((stby_vtrim << VTRIM_STANDBY)|(stby_vadj << VADJ_STANDBY)\
		 |	 (act_vtrim << VTRIM_ACT)	  |(act_vadj << VADJ_ACT));
	/*=====================================================*/
	
    REG_EFC_LDOTRIM = temp;       //手动TRIM到1.5v
	trim_tab->ldo_trim = temp;    //输出到函数外
	
	
	
/*==============2.手动写RCHTRIM值================*/
   temp = 0;
   uint8_t rch_trim_wide;	//粗调值
   uint8_t rch_trim_narrow;	//细调值
   
  /*=以下参数设置不设边界保护，请自行注意参数值的数据位宽长度=*/
  //默认值为10’h6f （长度10个位）
	rch_trim_wide 	=  0x0B; 	//  REG_EFC_RCHTRIM->ISEL[9:5]	
	rch_trim_narrow	=  0x08;	// 	REG_EFC_RCHTRIM->ISEL[4:0]
	
    temp |=  ((rch_trim_wide << 5)|(rch_trim_narrow << 0)); // temp = 0x169;
  
    REG_EFC_RCHTRIM = temp;       //手动TRIM到32MHz
	trim_tab->rch_trim = temp;	  //输出到函数外
	
	return 0;
	
}

uint8_t auto_cal_trim(struct trim_type* trim_tab)
{
	uint32_t temp = 0;
	if(trim_tab == NULL)
	{
		return 1;
	}   
/******1.自动算出LDOTRIM值******/
	
	//....
	trim_tab->ldo_trim = temp;    //输出到函数外
	
/******2.自动算出RCHTRIM值******/
   
	//...
	trim_tab->rch_trim = temp;	  //输出到函数外
	
	return 0;
	
}

uint8_t write_nvr(uint32_t ldo_addr, uint32_t rch_addr, struct trim_type* trim_tab)
{
	uint32_t ldo_trim_tmp = 0;
	uint32_t rch_trim_tmp = 0;
	if(trim_tab == NULL)
	{
		return 1;
	} 
	ldo_trim_tmp = trim_tab->ldo_trim;
	rch_trim_tmp = trim_tab->rch_trim;
	
	eflash_erase_page(EFlashNVR1BaseAddr);
	
	
	/*NVR1 区如果不是只读，就往下执行*/
	if( (*(volatile uint32_t *)(SM_OTP1_EN_ADDR)) != 0x55aa77ef)	
	{
		/*****LDO trim值写入NVR1*******/
		eflash_write_word(ldo_addr, ((~ldo_trim_tmp) << 16) | ldo_trim_tmp);
		if (eflash_read_word(ldo_addr) != (((~ldo_trim_tmp) << 16) | ldo_trim_tmp))return 1;
		
		
		eflash_write_word(rch_addr, ((~rch_trim_tmp) << 16) | rch_trim_tmp);    
		if (eflash_read_word(rch_addr) != (((~rch_trim_tmp) << 16) | rch_trim_tmp))return 1;

		
		eflash_write_word(SM_TRIM_NVR1_ENABLE, 0xb33b3bb3);	
		if (eflash_read_word(SM_TRIM_NVR1_ENABLE) != 0xb33b3bb3) return 1;
		
	}
	else
	{
		return 1;
	}
	
	return 0;
	
}

uint8_t gpio_pc2_clkout(void)
{
	uint32_t temp = 0;
	/*----配置PC2为时钟输出----*/
	/*因为系统寄存器SYSCTRL0[27:29]默认是0，所以此时PC2引出的是HCLK，后续功能见下文*/
    REG_SCU_IOCTRLPROTECT = 0xA5A55A5A; //清除IO写保护

	REG_SCU_PCSEL &= ~(7<<8);	//先清空该字段[8:10]写0	
    REG_SCU_PCSEL |= (7<<8);	//PC2复用为CLKOUT

    REG_SCU_IOCTRLPROTECT = 0xffffffff; //开启IO写保护
	
	/*等待，确保每个受保护的寄存器，最后被保护的*/
    while((REG_SCU_IOCTRLPROTECT & 0x01) == 0x01)      //读IO控制保护寄存器的写使能状态
    {
        REG_SCU_IOCTRLPROTECT = 0xffffffff; //开启IO写保护
    }	  
    /*------------------*/
	
	/*--------PC2配置为HCLK输出----------*/
    REG_SCU_CTRLPROTECT = 0xA5A55A5A;		 //清除SYSCTRL0,SYSCTRL1的写保护  
    temp = REG_SCU_CTRL0 & (~(7<<27));       //功能字段写0
    REG_SCU_CTRLPROTECT = 0xA5A55A5A;		 //清除SYSCTRL0,SYSCTRL1的写保护
    REG_SCU_CTRL0 = temp;	                 //PC2作为HCLK_OUT 系统时钟输出	 
	
	
	return 0;
	
}


void trim_opt(void)
{
	struct trim_type g_trim_val[1] = {0};  //LDOTRIM , RCHTRIM
	
	manual_cal_trim(g_trim_val);   //手动设置LDO、时钟TRIM值，然后写入到EFC中并应用到系统
	
//	gpio_pc2_clkout();			   //使能PC2脚为时钟输出，设定为HCLK输出
	
	write_nvr(SM_LDO_TRIM_ADDR,SM_RC64M_TRIM_ADDR,g_trim_val);
}




