2025-08-01 1:03 AM
Dear all,
I'm calibrating the STM32G0B0RE RTC clocked by an external 32.768 oscillator using the following guide:
https://community.st.com/t5/stm32-mcus/how-to-calibrate-the-stm32-s-real-time-clock-rtc/ta-p/744958
Below is my debug code:
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_RTC_Init();
MX_USART1_UART_Init();
MX_I2C1_Init();
/* USER CODE BEGIN 2 */
char msg[256];
strcpy(msg, "********************************************* RTC trimming *********************************************\r\n\r\n");
HAL_UART_Transmit(&huart1, (uint8_t *)msg, strlen(msg), HAL_MAX_DELAY);
strcpy(msg, "Output waveform is 512Hz on PA4 (RTC_OUT2)\r\n");
HAL_UART_Transmit(&huart1, (uint8_t *)msg, strlen(msg), HAL_MAX_DELAY);
strcpy(msg, "You need to insert the time of 32-wave interval. (32 rising edge and 32 falling edge)\r\n");
HAL_UART_Transmit(&huart1, (uint8_t *)msg, strlen(msg), HAL_MAX_DELAY);
strcpy(msg, "Waiting \"TIME=value\" command [ms] to apply trimming... (i.e., TIME=62.4995)\r\n");
HAL_UART_Transmit(&huart1, (uint8_t *)msg, strlen(msg), HAL_MAX_DELAY);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
uint8_t rx_buffer[64];
uint16_t rx_len = 0;
while (1)
{
uint8_t rx;
if (HAL_UART_Receive(&huart1, &rx, 1, HAL_MAX_DELAY) == HAL_OK)
{
rx_buffer[rx_len ++] = rx;
if (rx_len > 1 && rx_buffer[rx_len - 2] == '\r' && rx_buffer[rx_len - 1] == '\n') // end of line
{
rx_buffer[rx_len - 1] = 0; // null-terminate
rx_len = 0;
if (strncmp((char*)rx_buffer, CMD_PREFIX, strlen(CMD_PREFIX)) == 0)
{
char *value_str = strchr((char*)rx_buffer, '='); // Cerca il simbolo '='
if(value_str != NULL)
{
value_str++; // Skip '=' character to point to the number
double time = atof(value_str); // Convert string to double (time in ms)
// Print the inserted time period
sprintf(msg, "> Time period inserted is %.6f ms.\r\n", time);
HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
// Sample interval is fixed at 32
strcpy(msg, "> Sample interval number is 32.\r\n");
HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
// Calculate average frequency in Hz: frequency = 1 / (period / 32)
// period is in ms, convert to seconds dividing by 1000
double frequencyAverageHz = 32.0 / (time / 1000.0);
sprintf(msg, "> Frequency average is %.6f Hz.\r\n", frequencyAverageHz);
HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
// The expected RTC frequency (target)
double rtcFrequencyHz = 32768.26215;
sprintf(msg, "> RTC frequency is %.6f Hz.\r\n", rtcFrequencyHz);
HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
// Calculate PPM error based on average frequency (512 Hz is reference)
double ppmError = ((frequencyAverageHz - 512.0) / 512.0) * 1e6;
sprintf(msg, "> PPM (Part Per Million) error is %.6f.\r\n", ppmError);
HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
// Use wider types for CALM and CALP to avoid truncation errors
uint16_t calmInt = 0;
uint8_t calpInt = 0;
// Desired frequency (nominal LSE)
double fcal = 32768.0;
// Actual frequency before calibration, based on measured average frequency times sample count (64)
double frtcclk = frequencyAverageHz * 64.0;
// Decide CALP value based on whether measured frequency is lower or higher than desired
// If measured freq < desired freq, CALP=1 to add pulses (increase freq)
// Else CALP=0 to decrease or no change
if(frtcclk < fcal)
{
calpInt = 1;
}
else
{
calpInt = 0;
}
double calp = (double)calpInt;
// Calculate ratio (fcal / frtcclk - 1)
double ratio = (fcal / frtcclk) - 1.0;
// Calculate CALM using formula from STM32 ref manual, rearranged for stability
double calm = (calp * 512.0 - ratio * pow(2, 20) + ratio * calp * 512.0) / (1.0 + ratio);
// Clamp CALM to valid range 0..0x1FF (9 bits)
if(calm < 0.0) calm = 0.0;
if(calm > 0x1FF) calm = 0x1FF;
// Use uint16_t to hold CALM to preserve full range
calmInt = (uint16_t)calm;
sprintf(msg, "> Calculated CALM is %.6f.\r\n", calm);
HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
sprintf(msg, "> Obtained CALM = 0x%03X and CALP = 0x%02X.\r\n", calmInt, calpInt);
HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
strcpy(msg, "> ...\r\n");
HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
// Recalculate frequency after calibration with formula from ref manual
double fcalRecalculated = frtcclk * (1.0 + (calpInt * 512.0 - calmInt) / (pow(2, 20) + calmInt - calpInt * 512.0));
sprintf(msg, "> Calculated new frequency trimmed FCAL is %.6f Hz.\r\n", fcalRecalculated);
HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
sprintf(msg, "> Calculated new frequency average is %.6f Hz.\r\n", fcalRecalculated / 64);
HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
// Recalculated ppm error using FCAL and 512 Hz reference
double ppmErrorRecalculated = ((fcalRecalculated / 64.0 - 512.0) / 512.0) * 1e6;
sprintf(msg, "> Calculated new PPM (Part Per Million) error is %.6f.\r\n", ppmErrorRecalculated);
HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
strcpy(msg, "> ...\r\n");
HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
// Set smooth calibration register on RTC
HAL_StatusTypeDef status = HAL_RTCEx_SetSmoothCalib(&hrtc,
RTC_SMOOTHCALIB_PERIOD_32SEC,
(calpInt == 1) ? RTC_SMOOTHCALIB_PLUSPULSES_SET : RTC_SMOOTHCALIB_PLUSPULSES_RESET,
calmInt);
if(status == HAL_OK)
{
sprintf(msg, "> RTC smooth calibration register updated successfully [0x%04X].\r\n\r\n", (unsigned int)hrtc.Instance->CALR);
}
else
{
strcpy(msg, "> ERROR updating RTC smooth calibration register!\r\n\r\n");
}
HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
}
}
else
{
strcpy(msg, "Unknown command received.\r\n");
HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
}
}
if (rx_len >= sizeof(rx_buffer))
rx_len = 0; // avoid overflow
}
}
}
/* USER CODE END 3 */
}
The following output is generated via the UART interface:
Afterward, I monitor the signal on the RTC_OUT2 pin, but the waveform remains unchanged, even after a long wait.
So, how can I verify if the RTC has been trimmed correctly?
Is there anything wrong with my procedure?
Thanks and best regards,
Moreno
2025-08-01 4:49 AM
Your instruments are going to detect a change from 511.982 Hz to 512.000 Hz? What are you using to measure? What frequency is the measurement?