Files
hpw421/component/xc6xx_drivers/Drivers/xc_driver/xc_drv_calib.c
T
2026-07-03 18:08:25 +08:00

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)