这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » 国产MCU » APM32E103XE通过HSE校准LSI的方法

共1条 1/1 1 跳转至

APM32E103XE通过HSE校准LSI的方法

院士
2025-10-13 20:25:25     打赏
问题:使用APM3E103XE芯片内部LSI时钟驱动内部RTC,每天误差超过1小时。是否可以通过外部时钟HSE 8MHz进行LSI校准,使RTC一天内的偏差不超过5分钟?
答案:可以。AMP32E103XE可通过HSE作为参考,对LSI进行校准(RTC 24小时最多86.4秒)
实验效果实验思路:PCBA上有外部HSE晶振,可以使用HSE晶振校准内部LSI。具体思路是使用内核SYSTICK定时器做计数校准。实验使用E103RET6芯片+DEMO板+SDK例程验证。实验结果:在极海官网SDK例程的基础上修改程序后验证2PCS,确认不同芯片+不同主频情况下,LSI校准后RTC秒中断每秒最多偏差1ms,RTC 24小时最多偏差1ms*60*60*24=86.4秒。 校准方法原理、步骤、代码1方法:main函数代码本文后面有提供,直接将提供的代码替换到极海APM32E103XE SDK的RTC例程中的main.c就可以验证。烧录后可以通过串口打印出秒中断时间。 2、校准原理:LSI是内部低速RC振荡器(30k-60kHz,典型值40kHz),芯片间的一致性不高。校准的核心是以高精度的HSE作为参考时钟,通过内核自带的systick定时器获取基于LSI信号的秒中断时间,计算出其实际频率,再通过软件调整RTC预分频器参数实现正确的分频。 3详细步骤:具体如下,主要分4步:① 配置SYSTICK,实现每1ms中断一次并统计系统时间。(实际使用中如果有RTOS,此步骤可跳过,直接获取RTOS系统时间戳使用)② 配置串口,用于打印信息。(实际使用中此步骤可跳过)③ 获取LSI实测频率。④ 验证基于实测频率下的秒中断时间(实际使用中此步骤可跳过,直接按照实测频率配置RTC分频即可)       4实际代码与注解
/************************************* Copyright(C)******************************
** @FileName   : main.c
** @brief      : 使用SYSTICK校准LSI
** @author     : 
** @version    : V1.0
** @date       : 
********************************************************************************/
/* Includes */
#include "main.h"
#include "stdio.h"
 
 
volatile uint32_t sys_ms=0;    //全局变量,系统时间
volatile uint32_t test_time;   //测试用时间
 
 
/****************************** BEGIN ********************************
**@name       : USART1_Init
**@Brief      : 配置串口,方便打印信息
**@Author     : 
**@Version    : V1.0
**@time       :
******************************** END *********************************/
 
void USART1_Init(void)
{
    USART_Config_T USART_ConfigStruct;
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_USART1);
    USART_ConfigStruct.baudRate = 115200;
    USART_ConfigStruct.hardwareFlow = USART_HARDWARE_FLOW_NONE;
    USART_ConfigStruct.mode = USART_MODE_TX_RX;
    USART_ConfigStruct.parity = USART_PARITY_NONE;
    USART_ConfigStruct.stopBits = USART_STOP_BIT_1;
    USART_ConfigStruct.wordLength = USART_WORD_LEN_8B;
    USART_Config(USART1, &USART_ConfigStruct);
 
    GPIO_Config_T GPIO_configStruct;
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOA);
    GPIO_configStruct.mode = GPIO_MODE_AF_PP;
    GPIO_configStruct.pin = GPIO_PIN_9;
    GPIO_configStruct.speed = GPIO_SPEED_50MHz;
    GPIO_Config(GPIOA, &GPIO_configStruct);
    GPIO_configStruct.mode = GPIO_MODE_IN_FLOATING;
    GPIO_configStruct.pin = GPIO_PIN_10;
    GPIO_Config(GPIOA, &GPIO_configStruct);
 
    USART_Enable(USART1);
 
}
 
 
/****************************** BEGIN ********************************
**@Name       : LSI_Calibration
**@Brief      : LSI校准,返回LSI频率
**@Author     :
**@Version    : V1.0
**@Time       : 
******************************** END *********************************/
 
uint32_t LSI_Calibration(void)
{
    uint32_t lsi_freq=32767;
    uint32_t time;
    
    //LSI RTC配置
    RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_PMU);
    PMU_EnableBackupAccess();
    RCM_EnableLSI();
    while (RCM_ReadStatusFlag(RCM_FLAG_LSIRDY) == RESET);
    RCM_ConfigRTCCLK(RCM_RTCCLK_LSI);
    RCM_EnableRTCCLK();
    RTC_WaitForSynchro();
    RTC_WaitForLastTask();
    RTC_ConfigPrescaler(lsi_freq);
    RTC_WaitForLastTask();
    RTC_ConfigCounter(0);
    RTC_WaitForLastTask();
    
    //获取1000ms实际计数
    time=sys_ms;
    RTC_ClearStatusFlag(RTC_FLAG_SEC);
    RTC_WaitForLastTask();
    while (RTC_ReadStatusFlag(RTC_FLAG_SEC)==0);
    time=sys_ms-time;
    printf("before_calibration_time: %dms\r\n", time);
    lsi_freq=lsi_freq*1000/time;
    printf("lsi_freq: %d\r\n", lsi_freq);
    
    //RTC disable
    RTC_ClearStatusFlag(RTC_FLAG_SEC);
    RTC_WaitForLastTask();
    RCM_DisableLSI();
    RCM_DisableAPB1PeriphClock((RCM_APB1_PERIPH_T)RCM_APB1_PERIPH_PMU);
    return lsi_freq;
}
 
 
 
/****************************** BEGIN ********************************
**@Name       : LSI_Verify
**@Brief      : LSI按照输入频率分频后验证秒中断时间
**@Author     : 
**@Version    : V1.0
**@Time       : 
******************************** END *********************************/
 
void LSI_Verify(uint32_t prescaler)
{
    RCM_EnableAPB1PeriphClock((RCM_APB1_PERIPH_T)RCM_APB1_PERIPH_PMU);
    PMU_EnableBackupAccess();
    RCM_EnableLSI();
    while (RCM_ReadStatusFlag(RCM_FLAG_LSIRDY) == RESET);
    RCM_ConfigRTCCLK(RCM_RTCCLK_LSI);
    RCM_EnableRTCCLK();
    RTC_WaitForSynchro();
    RTC_WaitForLastTask();
    RTC_ConfigPrescaler(prescaler);
    RTC_WaitForLastTask();
    RTC_ConfigCounter(0);
    RTC_WaitForLastTask();
    test_time=sys_ms;
    
    //开启中断
    RTC_EnableInterrupt(RTC_INT_SEC);
    RTC_WaitForLastTask();
    NVIC_EnableIRQRequest(RTC_IRQn, 0, 0);
}
 
 
int main(void)
{
    uint32_t lsi_freq;
    SysTick_Config(RCM_ReadSYSCLKFreq()/ 1000);    //配置systick,1ms中断一次
    USART1_Init();
    
    printf("LSI_CAL_TEST\r\n");
    printf("SYS CLK: %d MHZ\r\n", RCM_ReadSYSCLKFreq()/1000000);  
    
    lsi_freq=LSI_Calibration();
    LSI_Verify(lsi_freq);
 
    while (1)
    {
    }
}
 
 
void SysTick_Handler(void)
{
    sys_ms++;
}
 
 
void RTC_IRQHandler(void)
{
    if (RTC_ReadIntFlag(RTC_INT_SEC) != RESET)
    {
        printf("after_calibration_time: %dms\r\n", sys_ms-test_time);
        test_time=sys_ms;
        RTC_ClearIntFlag(RTC_INT_SEC);
        RTC_WaitForLastTask();
    }
}
 
 
int fputc(int ch, FILE* f)
{
    /* send a byte of data to the serial port */
    USART_TxData(USART1, (uint8_t)ch);
 
    /* wait for the data to be send  */
    while (USART_ReadStatusFlag(USART1, USART_FLAG_TXBE) == RESET);
 
    return (ch);
}





关键词: HSI     校准    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]