cancel
Showing results for 
Search instead for 
Did you mean: 

STM32G0B0REx RTC smooth calibration

Moreno_Ortolan
Visitor

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:

 Moreno_Ortolan_0-1754035040817.png

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

1 REPLY 1
TDK
Super User

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?

If you feel a post has answered your question, please click "Accept as Solution".