480 lines
14 KiB
C
480 lines
14 KiB
C
/*!
|
|
* \file xc_drv_calib.c
|
|
*
|
|
* \brief Target xc calib driver implementation
|
|
*
|
|
* \copyright Revised BSD License, see section \ref LICENSE.
|
|
*
|
|
* \code
|
|
*
|
|
* _ __ _ ________ _
|
|
* | |/ /(_)___ / ____/ /_ (_)___
|
|
* | // / __ \/ / / __ \/ / __ \
|
|
* / |/ / / / / /___/ / / / / /_/ /
|
|
* /_/|_/_/_/ /_/\____/_/ /_/_/ .___/
|
|
* /_/
|
|
* (C) 2022-2025 XinChip
|
|
*
|
|
* \endcode
|
|
*
|
|
* \author ( XinChip ) Alex-J
|
|
*
|
|
* \author ( XinChip )
|
|
*/
|
|
|
|
/*-----------------------------------------------------------------------------------
|
|
INCLUDE HEADE FILES
|
|
------------------------------------------------------------------------------------*/
|
|
#include "xc_drv_calib.h"
|
|
#if XC_CHECK(XC_CALIB_ENABLED)
|
|
/*------------------------------------------------------------------------------------
|
|
Macros
|
|
-------------------------------------------------------------------------------------*/
|
|
#define RC_ADJ_VAL_MIN 0x0
|
|
#define RC_ADJ_VAL_MID 0x1fff
|
|
#define RC_ADJ_VAL_MAX 0x3fff
|
|
|
|
#define RANGE_LPO_RTM 0x400
|
|
#define GEARS_HZ 1.56f
|
|
#define _32K_STAND_HZ 32000
|
|
#define _32K_STAND_300ppm_MAX 32010
|
|
#define _32K_STAND_300ppm_MIN 31990
|
|
#define CALIB_NUM 50 // ms
|
|
|
|
#define CALIB_TIME_MS 6 // ms
|
|
|
|
#define CALIB_STEP_CYCLE_32K (CALIB_TIME_MS * 32)
|
|
|
|
/*------------------------------------------------------------------------------------
|
|
Local Variables
|
|
-------------------------------------------------------------------------------------*/
|
|
static volatile uint32_t mid = RC_ADJ_VAL_MID; // MID_LPO_RTM;
|
|
|
|
/*------------------------------------------------------------------------------------
|
|
Global Variables
|
|
-------------------------------------------------------------------------------------*/
|
|
|
|
/*------------------------------------------------------------------------------------
|
|
Func Prototype
|
|
-------------------------------------------------------------------------------------*/
|
|
|
|
/*------------------------------------------------------------------------------------
|
|
Functions
|
|
-------------------------------------------------------------------------------------*/
|
|
/**
|
|
* @brief xc_rc32k_calib_init
|
|
* @details RC32k calibration initialization
|
|
*
|
|
* @param uint16_t - rc_adj_val
|
|
* @retval void
|
|
*/
|
|
|
|
void xc_rc32k_calib_init(uint16_t rc_adj_val)
|
|
{
|
|
if ((xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_32M) ||
|
|
(xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_48M)) {
|
|
|
|
cpr_ctl_pclk_grctl__ctl_pclk_gr_upd__setf(0x1UL);
|
|
cpr_ctl_pclk_grctl__ctl_pclk_gr__setf(4U);
|
|
|
|
}
|
|
else if (
|
|
#if !defined(NO_SUPPORT_HFCLK_BBPLL_96M)
|
|
(xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_64M) ||
|
|
(xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_96M)
|
|
#else
|
|
(xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_64M)
|
|
#endif
|
|
)
|
|
{
|
|
cpr_ctl_pclk_grctl__ctl_pclk_gr__setf(2U);
|
|
cpr_ctl_pclk_grctl__ctl_pclk_gr_upd__setf(0x1UL);
|
|
}
|
|
#if defined(CALIB_HFCLK_16M_CONFIG)
|
|
else if (xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_16M)
|
|
{
|
|
cpr_ctl_pclk_grctl__ctl_pclk_gr_upd__setf(0x1UL);
|
|
cpr_ctl_pclk_grctl__ctl_pclk_gr__setf(8U);
|
|
}
|
|
else if ((xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_24M))
|
|
{
|
|
cpr_ctl_pclk_grctl__ctl_pclk_gr__setf(8U);
|
|
cpr_ctl_pclk_grctl__ctl_pclk_gr_upd__setf(0x1UL);
|
|
}
|
|
#else
|
|
else if ((xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_16M) ||
|
|
(xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_24M))
|
|
{
|
|
cpr_ctl_pclk_grctl__ctl_pclk_gr__setf(8U);
|
|
cpr_ctl_pclk_grctl__ctl_pclk_gr_upd__setf(0x1UL);
|
|
}
|
|
#endif
|
|
|
|
cpr_ctlapbclken_grctl__rtc_pclk_en__setf(0x1UL);
|
|
|
|
cprao_aon_clken_grctl__rtc_clk_en__setf(0x1UL);
|
|
|
|
rtc_rccal_lfcfg_set(0x100031);
|
|
|
|
if ((xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_16M) ||
|
|
(xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_32M) ||
|
|
(xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_64M)) {
|
|
|
|
rtc_rccal_hfcfg_set(25000);
|
|
rtc_rccal_lim1_set(3);
|
|
rtc_rccal_lim2_set(13);
|
|
}
|
|
else if ((xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_24M) ||
|
|
#if !defined(NO_SUPPORT_HFCLK_BBPLL_96M)
|
|
(xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_48M) ||
|
|
(xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_96M)
|
|
#else
|
|
(xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_48M)
|
|
#endif
|
|
)
|
|
{
|
|
rtc_rccal_hfcfg_set(37500);
|
|
rtc_rccal_lim1_set(4);
|
|
rtc_rccal_lim2_set(19);
|
|
}
|
|
|
|
rtc_rccal_adj_step_set(0x1404);
|
|
rtc_rccal_adj_val_set(0x1fff);
|
|
|
|
rtc_rccal_adj_cfg_set(0x1fff4000 | rc_adj_val);
|
|
rtc_rccal_intsta_set(0x03);
|
|
rtc_rccal_inten_set(0x01);
|
|
for (uint16_t dly = 0; dly < 1000; dly++)
|
|
;
|
|
rtc_rccal_en_set(0x01);
|
|
}
|
|
|
|
/**
|
|
* @brief xc_flfclk_calcu
|
|
* @details Frequency lfclk value calculation
|
|
*
|
|
* @param uint32_t - hfcnt_val
|
|
* @retval uint16_t - f_lfclk
|
|
*/
|
|
uint16_t xc_flfclk_calcu(uint32_t hfcnt_val)
|
|
{
|
|
uint32_t hfcnt_load = rtc_rccal_hfcfg_get();
|
|
uint32_t lfdiv = rtc_rccal_lfcfg_get();
|
|
|
|
uint8_t hfcnt_dir = (hfcnt_val >> 31);
|
|
uint16_t f_lfclk = 0;
|
|
|
|
if (hfcnt_dir == 0) {
|
|
if ((xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_16M) ||
|
|
(xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_32M) ||
|
|
(xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_64M)) {
|
|
f_lfclk =
|
|
CLOCK_HFCLK_IN_16M * (lfdiv + 1) / (hfcnt_load - hfcnt_val);
|
|
}
|
|
#if !defined(NO_SUPPORT_HFCLK_BBPLL_96M)
|
|
else if ((xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_48M) ||
|
|
(xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_96M))
|
|
#else
|
|
else if (xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_48M)
|
|
#endif
|
|
{
|
|
f_lfclk = 24000000 * (lfdiv + 1) / (hfcnt_load - hfcnt_val);
|
|
}
|
|
} else {
|
|
if ((xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_16M) ||
|
|
(xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_32M) ||
|
|
(xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_64M)) {
|
|
f_lfclk = CLOCK_HFCLK_IN_16M * (lfdiv + 1) /
|
|
(hfcnt_load + hfcnt_val - 0x80000000);
|
|
}
|
|
#if !defined(NO_SUPPORT_HFCLK_BBPLL_96M)
|
|
else if ((xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_48M) ||
|
|
(xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_96M))
|
|
#else
|
|
else if (xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_48M)
|
|
#endif
|
|
{
|
|
f_lfclk =
|
|
24000000 * (lfdiv + 1) / (hfcnt_load + hfcnt_val - 0x80000000);
|
|
}
|
|
}
|
|
|
|
return f_lfclk;
|
|
}
|
|
|
|
/**
|
|
* @brief xc_rc32k_freq_scope
|
|
* @details RC32k frequency scope
|
|
*
|
|
* @param uint16_t - freq
|
|
* @retval eLFREQ_Sta - ret
|
|
*/
|
|
eLFREQ_Sta xc_rc32k_freq_scope(uint16_t freq)
|
|
{
|
|
eLFREQ_Sta ret = LFREQ_UNKNOW;
|
|
uint16_t offset = (CLOCK_RC_LFCLK_IN_32K * 2 / 100);
|
|
uint16_t rc32_offset_min = (CLOCK_RC_LFCLK_IN_32K - offset);
|
|
uint16_t rc32_offset_max = CLOCK_RC_LFCLK_IN_32K;
|
|
|
|
if (freq < rc32_offset_min)
|
|
ret = LFREQ_LOWER;
|
|
else if (freq >= rc32_offset_max)
|
|
ret = LFREQ_HIGHER;
|
|
else
|
|
ret = LFREQ_GOOD;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief RC32k_Calib_by_hw
|
|
* @details Calibrating RC32k through hardware.
|
|
*
|
|
* @param uint16_t - freq
|
|
* @retval eLFREQ_Sta - ret
|
|
*/
|
|
void xc_rc32k_calib_by_hw(void)
|
|
{
|
|
uint16_t f_lfclk = 0;
|
|
uint8_t rccal_int_sta;
|
|
eLFREQ_Sta f_lf_sta;
|
|
|
|
xc_rc32k_calib_init(mid);
|
|
|
|
while (1) {
|
|
|
|
do {
|
|
rccal_int_sta = rtc_rccal_intsta_get();
|
|
} while (!(rccal_int_sta & 0x01));
|
|
|
|
rtc_rccal_inten_set(0x00);
|
|
rtc_rccal_intsta_set(rccal_int_sta);
|
|
|
|
f_lfclk = xc_flfclk_calcu(rtc_rccal_hfcnt_val_get());
|
|
|
|
f_lf_sta = xc_rc32k_freq_scope(f_lfclk);
|
|
if (LFREQ_GOOD != f_lf_sta) {
|
|
rtc_rccal_en_set(0x00);
|
|
// XC_RTC->RCCAL_EN = 0x00;
|
|
if (f_lf_sta == LFREQ_LOWER) {
|
|
mid += 100;
|
|
if (mid > RC_ADJ_VAL_MAX) {
|
|
mid = RC_ADJ_VAL_MIN;
|
|
}
|
|
} else {
|
|
mid -= 10;
|
|
if (mid < 10) {
|
|
mid = RC_ADJ_VAL_MAX;
|
|
}
|
|
}
|
|
|
|
rtc_rccal_adj_cfg_set(0x1fff4000 | mid);
|
|
rtc_rccal_inten_set(0x01);
|
|
|
|
rtc_rccal_en_set(0x01);
|
|
} else {
|
|
DEBUG("f_lfclk: %d\n", f_lfclk);
|
|
break;
|
|
}
|
|
}
|
|
|
|
rtc_rccal_en_set(0x00);
|
|
rtc_rccal_adj_cfg_set(0x00001fff);
|
|
rtc_rccal_adj_cfg__freq_adj_offset__setf(mid);
|
|
rtc_rccal_adj_cfg__freq_adj_hw_clr__setf(0x01);
|
|
rtc_rccal_intsta_set(0x03);
|
|
|
|
for (uint16_t dly = 0; dly < 1000; dly++)
|
|
;
|
|
|
|
rtc_rccal_en_set(0x01);
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* @brief rc32k_calib_by_soft
|
|
* @details Calibrate RC32k by software.
|
|
*
|
|
* @param uint16_t - freq
|
|
* @retval eLFREQ_Sta - ret
|
|
*/
|
|
void xc_rc32k_calib_by_soft(void)
|
|
{
|
|
uint32_t f_lfclk = 0;
|
|
uint32_t t32k_cnt = 0;
|
|
uint8_t ao_intr;
|
|
mid = RC_ADJ_VAL_MID;
|
|
xc_rc32k_soft_calib_disable();
|
|
xc_rc32k_calib_init(mid);
|
|
|
|
rtc_rccal_inten_set(0x00);
|
|
rtc_rccal_intsta_set(0x03);
|
|
while (1) {
|
|
|
|
rtc_ao_timer_ctl_set(0);
|
|
rtc_ao_timer_ctl__rtc_ao_timer_value__setf(CALIB_STEP_CYCLE_32K);
|
|
rtc_ao_timer_ctl__rtc_freq_timer_en__setf(1);
|
|
|
|
do {
|
|
|
|
ao_intr = rtc_all_intr_ao_get();
|
|
} while ((ao_intr & 0x20) == 0);
|
|
|
|
t32k_cnt = rtc_freq_32k_timer_val_get();
|
|
|
|
rtc_ao_timer_ctl__rtc_ao_timer_clr__setf(0x1UL);
|
|
rtc_ao_timer_ctl_set(0);
|
|
|
|
if ((xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_16M) ||
|
|
(xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_32M) ||
|
|
(xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_64M)) {
|
|
f_lfclk = (uint32_t)((((float)((16.0) * CALIB_STEP_CYCLE_32K)) /
|
|
t32k_cnt) *
|
|
1000000);
|
|
}
|
|
else if ((xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_24M) ||
|
|
#if !defined(NO_SUPPORT_HFCLK_BBPLL_96M)
|
|
(xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_48M) ||
|
|
(xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_96M)
|
|
#else
|
|
(xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_48M)
|
|
#endif
|
|
)
|
|
{
|
|
f_lfclk = (uint32_t)((((float)((24.0) * CALIB_STEP_CYCLE_32K)) /
|
|
t32k_cnt) *
|
|
1000000);
|
|
}
|
|
|
|
if (f_lfclk > _32K_STAND_HZ) {
|
|
mid = mid - ((uint32_t)(((float)(f_lfclk - _32K_STAND_HZ)) /
|
|
(float)GEARS_HZ));
|
|
} else if (f_lfclk < _32K_STAND_HZ) {
|
|
mid = mid + ((uint32_t)(((float)(_32K_STAND_HZ - f_lfclk)) /
|
|
(float)GEARS_HZ));
|
|
}
|
|
// DEBUG("f_lfclk: %u\n", f_lfclk);
|
|
|
|
rtc_rccal_en_set(0x00);
|
|
rtc_rccal_adj_cfg_set(0x1fff4000 | mid);
|
|
|
|
rtc_rccal_en_set(0x01);
|
|
|
|
if (f_lfclk >= _32K_STAND_300ppm_MIN && f_lfclk <= _32K_STAND_300ppm_MAX)
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief xc_rc32k_soft_calib_start
|
|
* @details Calibrate RC32k by software.only for 32M
|
|
*
|
|
* @param
|
|
* @retval
|
|
*/
|
|
void xc_rc32k_soft_calib_start(void)
|
|
{
|
|
|
|
uint32_t f_lfclk = 0;
|
|
uint32_t t32k_cnt = 0;
|
|
uint8_t ao_intr;
|
|
|
|
rtc_ao_timer_ctl_set(0);
|
|
rtc_ao_timer_ctl__rtc_ao_timer_value__setf(32);
|
|
rtc_ao_timer_ctl__rtc_freq_timer_en__setf(1);
|
|
|
|
do {
|
|
ao_intr = rtc_all_intr_ao_get();
|
|
} while ((ao_intr & 0x20) == 0);
|
|
|
|
t32k_cnt = rtc_freq_32k_timer_val_get();
|
|
|
|
rtc_ao_timer_ctl__rtc_ao_timer_clr__setf(0x1UL);
|
|
rtc_ao_timer_ctl_set(0);
|
|
|
|
f_lfclk = (uint32_t)((((512000000)) / t32k_cnt)); //16.0*32
|
|
|
|
if (f_lfclk > 32000) {
|
|
mid = mid - ((uint32_t)(((float)(f_lfclk - 32000)) /
|
|
(float)GEARS_HZ));
|
|
} else if (f_lfclk < 32000) {
|
|
mid = mid + ((uint32_t)(((float)(32000 - f_lfclk)) /
|
|
(float)GEARS_HZ));
|
|
}
|
|
|
|
rtc_rccal_en_set(0x00);
|
|
rtc_rccal_adj_cfg_set(0x1fff4000 | mid);
|
|
|
|
rtc_rccal_en_set(0x01);
|
|
|
|
}
|
|
|
|
#define TIME_32K_CNT (32*2)
|
|
#define ADJ_MAX (2)
|
|
void xc_rc32k_soft_calib_enable(void)
|
|
{
|
|
rtc_ao_timer_ctl_set(0);
|
|
rtc_ao_timer_ctl__rtc_ao_timer_value__setf(TIME_32K_CNT);
|
|
rtc_ao_timer_ctl__rtc_freq_timer_en__setf(1);
|
|
NVIC_EnableIRQ(RTC_IRQn);
|
|
}
|
|
|
|
void xc_rc32k_soft_calib_disable(void)
|
|
{
|
|
rtc_ao_timer_ctl_set(0);
|
|
rtc_ao_timer_ctl__rtc_freq_timer_en__setf(0);
|
|
NVIC_DisableIRQ(RTC_IRQn);
|
|
}
|
|
|
|
void xc_rc32k_soft_calib_set(void)
|
|
{
|
|
uint32_t f_lfclk = 0;
|
|
uint32_t t32k_cnt = 0;
|
|
|
|
t32k_cnt = rtc_freq_32k_timer_val_get();
|
|
rtc_ao_timer_ctl__rtc_ao_timer_clr__setf(0x1UL);
|
|
rtc_ao_timer_ctl_set(0);
|
|
|
|
if ((xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_16M) ||
|
|
(xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_32M) ||
|
|
(xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_64M)) {
|
|
f_lfclk = (uint32_t)((((float)((16.0) * TIME_32K_CNT)) /
|
|
t32k_cnt) *
|
|
1000000);
|
|
}
|
|
#if !defined(NO_SUPPORT_HFCLK_BBPLL_96M)
|
|
else if ((xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_48M) ||
|
|
(xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_96M))
|
|
#else
|
|
else if (xc_clock_hfclk_in_get() == CLOCK_HFCLK_IN_48M)
|
|
#endif
|
|
{
|
|
f_lfclk = (uint32_t)((((float)((24.0) * TIME_32K_CNT)) /
|
|
t32k_cnt) *
|
|
1000000);
|
|
}
|
|
|
|
if (f_lfclk > 32000) {
|
|
uint32_t diff = (uint32_t)(((float)(f_lfclk - 32000)) /
|
|
(float)GEARS_HZ);
|
|
if(diff > ADJ_MAX){
|
|
diff = ADJ_MAX;
|
|
}
|
|
mid = mid - diff;
|
|
} else if (f_lfclk < 32000) {
|
|
uint32_t diff = (uint32_t)(((float)(32000 - f_lfclk)) /
|
|
(float)GEARS_HZ);
|
|
if(diff > ADJ_MAX){
|
|
diff = ADJ_MAX;
|
|
}
|
|
mid = mid + diff;
|
|
}
|
|
|
|
rtc_rccal_en_set(0x00);
|
|
rtc_rccal_adj_cfg_set(0x1fff4000 | mid);
|
|
|
|
rtc_rccal_en_set(0x01);
|
|
}
|
|
#endif // XC_CHECK(XC_CALIB_ENABLED)
|