/********************************** (C) COPYRIGHT ******************************* * File Name : main.c * Author : WCH * Version : V1.0.0 * Date : 2024/02/21 * Description : Main program body. ********************************************************************************* * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. * Attention: This software (modified or not) and binary are used for * microcontroller manufactured by Nanjing Qinheng Microelectronics. *******************************************************************************/ /* * @note * The code initializes the RTC (Real-Time Clock) and TIM1 (Timer 1) modules, waits for a calibration * flag to be set, and then prints the calibration value and adjust the HSI's calibration register */ #include "debug.h" /* Global define */ #define ADJUST_STEP 17000 /* Global Variable */ /* Exported_Functions */ volatile uint8_t SampleFlag = 0; volatile uint32_t rtc_cnt = 0; volatile uint16_t RTC_DIV_VAL = 512; void TIM1_UP_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast"))); void TIM1_UP_IRQHandler() { rtc_cnt = RTC_GetCounter(); SampleFlag = 1; RTC_SetCounter(0); TIM_ClearITPendingBit(TIM1, TIM_IT_Update); } /********************************************************************* * @fn RTC_Init * * @brief Initializes RTC collection. * * @return 1 - Init Fail * 0 - Init Success */ u8 RTC_Init(void) { u8 temp = 0; RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); PWR_BackupAccessCmd(ENABLE); /* Is it the first configuration */ BKP_DeInit(); RCC_HSEConfig(RCC_HSE_ON); while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET && temp < 250) { temp++; Delay_Ms(20); } if (temp >= 250) return 1; RCC_RTCCLKConfig(RCC_RTCCLKSource_HSE_Div128); RCC_RTCCLKCmd(ENABLE); RTC_WaitForLastTask(); RTC_WaitForSynchro(); RTC_ITConfig(RTC_IT_SEC, ENABLE); RTC_WaitForLastTask(); RTC_EnterConfigMode(); RTC_SetPrescaler(0); RTC_WaitForLastTask(); RTC_ExitConfigMode(); BKP_WriteBackupRegister(BKP_DR1, 0XA1A1); return 0; } /********************************************************************* * @fn TIM1_Base_Init * * @brief Initializes TIM1 output compare. * * @param arr - the period value. * psc - the prescaler value. * ccp - the pulse value. * * @return none */ void TIM1_Base_Init(u16 arr, u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure = {0}; NVIC_InitTypeDef NVIC_InitStructure = {0}; RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); TIM_TimeBaseInitStructure.TIM_Period = arr; TIM_TimeBaseInitStructure.TIM_Prescaler = psc; TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStructure); NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_Init(&NVIC_InitStructure); TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE); RTC_SetCounter(0); TIM_Cmd(TIM1, ENABLE); } /********************************************************************* * @fn main * * @brief Main program. * * @return none */ int main(void) { GPIO_InitTypeDef GPIO_InitStructure = {0}; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); SystemCoreClockUpdate(); Delay_Init(); USART_Printf_Init(115200); printf("SystemClk:%d\r\n", SystemCoreClock); printf("ChipID:%08x\r\n", DBGMCU_GetCHIPID()); printf("RTC Test\r\n"); #ifdef CH32V20x_D6 if((*(uint32_t *)0x40022030) & 0x0F000000) RTC_DIV_VAL = 128; #endif /* The above code is configuring the GPIO pin PA8 as an alternate function push-pull output with a maximum speed of 50MHz. It also enables the clock for GPIOA and configures the MCO (Microcontroller Clock Output) to use the HSI (High-Speed Internal) clock as the source. */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); RCC_MCOConfig(RCC_MCO_HSI); /* The above code is initializing the TIM1 timer and the RTC (Real-Time Clock) module. It then waits for a calibration flag to be set. Once the flag is set, it prints the calibration value. */ RCC_ClocksTypeDef RCC_Clocks; RCC_GetClocksFreq(&RCC_Clocks); printf("TIM1 Freq: %d\r\n", RCC_Clocks.PCLK2_Frequency); RTC_Init(); Delay_Ms(100); TIM1_Base_Init(10000, RCC_Clocks.PCLK2_Frequency / 100000 - 1); /* The code is performing a calibration of the HSI (High-Speed Internal) clock frequency. */ static int last_Adjust_val = 16, Adjust_val = 16; static uint32_t Meas_Freq = 0, last_Meas_Freq = 0; printf("Primary adjust val: %d\r\n", last_Adjust_val); /* The code block is a do-while loop that performs a calibration of the HSI (High-Speed Internal) clock frequency. */ do { if (SampleFlag) { SampleFlag = 0; Meas_Freq = (uint32_t)((float)HSI_VALUE * ((float)(HSE_VALUE / RTC_DIV_VAL / 10) / (float)rtc_cnt)); printf("HSI Freq: %d\r\n", Meas_Freq); Adjust_val = last_Adjust_val; last_Adjust_val += (int)(HSI_VALUE - (int)(Meas_Freq)) / ADJUST_STEP; last_Adjust_val &= 0x0000001f; printf("Adjust val: %d\r\n", last_Adjust_val); RCC_AdjustHSICalibrationValue(last_Adjust_val); Delay_Ms(100); last_Meas_Freq = (uint32_t)((float)HSI_VALUE * ((float)(HSE_VALUE / RTC_DIV_VAL / 10) / (float)rtc_cnt)); printf("Adjusted HSI Freq: %d\r\n", last_Meas_Freq); } } while ((int)(HSI_VALUE - (int)(last_Meas_Freq)) / ADJUST_STEP); if ((HSI_VALUE - (int)last_Meas_Freq) * (HSI_VALUE - (int)Meas_Freq) > 0) { while ((HSI_VALUE - (int)last_Meas_Freq) * (HSI_VALUE - (int)Meas_Freq) > 0) { SampleFlag = 0; while (!SampleFlag); Adjust_val = last_Adjust_val; Meas_Freq = last_Meas_Freq; last_Adjust_val - Adjust_val < 0 ? (last_Adjust_val -= 1) : (last_Adjust_val += 1); RCC_AdjustHSICalibrationValue(last_Adjust_val); Delay_Ms(100); last_Meas_Freq = (uint32_t)((float)HSI_VALUE * ((float)(HSE_VALUE / RTC_DIV_VAL / 10) / (float)rtc_cnt)); } } /* This code block is comparing the difference between the measured frequency (`last_Meas_Freq`) and the target frequency (`Meas_Freq`). It calculates the absolute difference between the two frequencies and checks if the difference of `last_Meas_Freq` is greater than the difference of `Meas_Freq`. */ if (((HSI_VALUE - last_Meas_Freq) > 0 ? HSI_VALUE - last_Meas_Freq : last_Meas_Freq - HSI_VALUE) > ((HSI_VALUE - Meas_Freq) > 0 ? HSI_VALUE - Meas_Freq : Meas_Freq - HSI_VALUE)) { last_Adjust_val = Adjust_val; RCC_AdjustHSICalibrationValue(last_Adjust_val); } while (1) { Delay_Ms(1000); } }