cancel
Showing results for 
Search instead for 
Did you mean: 

Smooth RTC calibration issue in STM32l431

RFlod.2
Associate III

I cannot get smooth calibration to work in STM32l431. This is the code:

 

void HW_RTC_Init(void)
{
	LL_RTC_TimeTypeDef time;
	LL_RTC_DateTypeDef date;

	LL_RCC_LSI_Enable();

	while(LL_RCC_LSI_IsReady() == 0)
	{

	}
	LL_RCC_SetRTCClockSource(LL_RCC_RTC_CLKSOURCE_LSI);
	__HAL_RCC_RTC_ENABLE();
	LL_RTC_WaitForSynchro(RTC);

	//Set the default date to 2000-01-01 00:00:00:000
	date.Year = 0;
	date.Day = 1;
	date.Month = 1;
	date.WeekDay = 6;
	time.Hours = 0;
	time.Minutes = 0;
	time.Seconds = 0;


	/* Configure RTC */
	RTCHandle.Instance = RTC;
	/* Set the RTC time base to 1s */
	/* Configure RTC prescaler and RTC data registers as follow:
	- Hour Format = Format 24
	- Asynch Prediv = Value according to source clock
	- Synch Prediv = Value according to source clock
	- OutPut = Output Disable
	- OutPutPolarity = High Polarity
	- OutPutType = Open Drain */
	RTCHandle.Init.HourFormat = RTC_HOURFORMAT_24;
	RTCHandle.Init.AsynchPrediv = 127;
	RTCHandle.Init.SynchPrediv = 255;
	RTCHandle.Init.OutPut = RTC_OUTPUT_DISABLE;
	RTCHandle.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
	RTCHandle.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;

	HAL_RTC_Init(&RTCHandle);

	LL_RTC_TIME_SetFormat(RTC, LL_RTC_HOURFORMAT_24HOUR);
	LL_RTC_TIME_Init(RTC, LL_RTC_FORMAT_BIN, &time);
	LL_RTC_DATE_Init(RTC, LL_RTC_FORMAT_BIN, &date);

	rtcSet = false;
}


void GPS_CalibrateRTCClock()
{
	int32_t frequency;
	// GPS clock
	printf("GPS %u %u => RTC %u %u\n\r", gpsCalibStart, gpsCalibEnd, rtcCalibStart, rtcCalibEnd);
	int32_t gpsDiff = (int32_t)(gpsCalibEnd - gpsCalibStart);
	printf("Diff GPS: %d seconds\n\r", gpsDiff);

	// RTC
	int32_t rtcDiff = (int32_t)(rtcCalibEnd - rtcCalibStart);
	printf("Diff STM32: %d seconds\n\r", rtcDiff);

	if(gpsDiff < 300 || rtcDiff < 200 || rtcCalibrationDone == true)
	{
		return;
	}
	rtcCalibrationDone = true;
	int diff = gpsDiff - rtcDiff;
	int percent = 100 * 100 * diff / rtcDiff;   // procent med 2 decimaler

	printf("=> %d seconds = %d %% \n\r", diff, percent);

	int originalFrequency = 32000;	// LSI frequency på RTC
	int preferedFrequency = originalFrequency + (originalFrequency * percent) / 10000;
	//int preferedFrequency = originalFrequency - (originalFrequency * percent) / 10000;
	printf("Prefered frequency %d\n\r", preferedFrequency);
	rtcCalibrationDone = HW_RTC_CalculateCalibrationParameters(originalFrequency, preferedFrequency);
}


 

 

When I run the code I get the following output:

GPS 1759492828 1759493307 => RTC 1759500022 1759500494
Diff GPS: 479 seconds
Diff STM32: 472 seconds
=> 7 seconds = 148 %    // this is 1.48%
Prefered frequency 32473
Smooth Pos 30 Neg 55 => 32473 Hz    // 1.48% faster than 32000 Hz (LSI clock)

 

When apply this values I do not see any change in RTC clock compared to GPS clock

In desperation I tested to set an insane value 

Setting Pos 500 Neg 55 => 42332 Hz

to verify if I can get RTC clock to go faster then GPS reference clock but result is same:

 

GPS: 2025-10-03 12:50:50
RTC: 2025-10-03 14:50:43

Timediff 7 second

 

GPS: 2025-10-03 13:03:26
RTC: 2025-10-03 13:03:07

Timediff 19 second

RTC clock has drifted slower then GPS clock for 12 seconds in 13 minutes.

 

What am I doing wrong here?

 

 

 

 

 

1 REPLY 1
mbarg.1
Senior III

We use H7xx but should be the same hw.

We use high level HAL to make things easy - there is very min difference to LL in performance:

/*	set RTC cal to stored value		*/
HAL_RTCEx_SetSmoothCalib(&hrtc, hSntpRtcApp.freqErrorCorrection & 0x1ff,	hSntpRtcApp.freqErrorCorrection & 0x8000, 0);
/*   set Date */
HAL_RTC_SetDate(&hrtc, &sdatestructure, RTC_FORMAT_BIN);

in functions like

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    mb_update_RTC_Time_Date		                     PORTABLE C       */
/*                                                                        */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Mike Bargauan														  */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function updates STM32 RTC time & date						  */
/*		using global variable hSntpRtcApp.processedTimestamp.			  */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    none																  */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    none - Completion status managed inside							  */
/*                                                                        */
/*	GLOBALS referenced													  */
/* 		SntpRtcApp							SNTP RTC App strucrute		  */
/*		hrtc								RTC structure				  */
/*              														  */
/*  CALLS                                                                 */
/*              														  */
/*		seconds2tm							Convert uint64 to struct tm	  */
/*		snprintf							Easy way to convert to BCT	  */
/*		HAL_RTC_SetDate												 	  */
/*		HAL_RTC_SetTime													  */
/* 		errorSntp														  */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    mb_sntp_client_receive_time_update							      */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*                                                                        */
/**************************************************************************/
void mb_update_RTC_Time_Date(sntpRtcClient_t * hSRA) {
	uint32_t tb;
	RTC_DateTypeDef sdatestructure = { 0 };
	RTC_TimeTypeDef stimestructure = { 0 };

	/*	reduce used subsecond bits number from SNTP to RTC - 16 to 8		*/
	tb = (uint32_t)(hSRA->referenceTimestamp);
	/*	convert from UTC to HAL structs		*/
	mb_utc_to_HalRtcTime(tb, &sdatestructure, &stimestructure);
	if (HAL_RTC_SetDate(&hrtc, &sdatestructure, RTC_FORMAT_BIN) != HAL_OK) {
		errorSntp("ERROR in HAL_RTC_SetDate of rtcU64TimeUpdate - CONTINUE\n");
	}
	if (HAL_RTC_SetTime(&hrtc, &stimestructure, RTC_FORMAT_BIN) != HAL_OK) {
		errorSntp("ERROR in HAL_RTC_SetTime of rtcU64TimeUpdate - CONTINUE\n");
	}
}

 For trimming, we make coarse adjustement with above mb_update_RTC_Time_Date(), then we move to max correction untill less than 12 msec error, than we trim the correction from 0 to what required one step every minute, at beginnung, one ste every 1 hour at the end and works fine.

You can have a look at one board live online 

http://o6.mb-international.net/GetSntpRtcStatusHtml.html ipv6 or 

http://a.mb-international.net:9743/GetSntpRtcStatusHtml.html ipv4

We fine tune with SNTP internet.

we are inside a ThreadX thread and code use some global to store values:

		if(event & SNTP_RTC_SNTP_MSG_RCVD){
			debugSntp("SNTP event - sntp reply received\n");
			mb_sntp_receive_process(&hSntpRtcApp.nx_sntp_client_udp_socket);

			/*	we were able to send and got a reply - reset retry counter		*/
			hSntpRtcApp.retrySend = 0;

			if (hSntpRtcApp.status == NX_SUCCESS){
				/*	inform other process we have a valid RTC		*/
				hSntpRtcApp.valid = 1;
				/*	good packet - set error to wait for next request 	*/
				hSntpRtcApp.status = SNTP_RTC_WAIT_RESEND;
				/*	set time before send new request to stored value	*/
				hSntpRtcApp.loopTime = hSntpRtcApp.sendRequestTime;
				/*	good packet - did we update RTC?	*/
				if(hSntpRtcApp.rtcUpdated == 1){
					/* we had an RTC update - wait loopTime timeout before sending next SNTP request	*/
					/*	set error value to compare next 	*/
					hSntpRtcApp.zeroError = hSntpRtcApp.diffVal;
					/*	we are not zeroing	*/
					hSntpRtcApp.zeroingDiff = SNTP_DRIFT_STOP;
					/*	we use stored freq correction	*/
					HAL_RTCEx_SetSmoothCalib(&hrtc, hSntpRtcApp.freqErrorCorrection & 0x1ff,
							hSntpRtcApp.freqErrorCorrection & 0x8000, 0);
					/*	reset stored loop time to min	*/
					hSntpRtcApp.sendRequestTime = SNTP_MIN_WAIT_TIME_REQUEST;
					/*	set time before send new request to min value	*/
					hSntpRtcApp.loopTime = SNTP_MIN_WAIT_TIME_REQUEST;
					/*	we were able to send and got a valid recply - reset retry errors countrer	*/
					hSntpRtcApp.retryError = 0;
					debugSntp("SNTP - reset after RTC update\n");
				}else{
					/*	good packet - no update - set loopTime to sendRequestTime	*/
					hSntpRtcApp.loopTime = hSntpRtcApp.sendRequestTime;
					/*	correct zero error with freq adjust if not already 	*/
					if(hSntpRtcApp.zeroingDiff == SNTP_DRIFT_STOP){
						/*	diff negative - positive adjust - diff large enough to correct ?	*/
						if(hSntpRtcApp.diffVal < (- SNTP_MAX_CENTER_ERROR)){
							/*	start zeroingDiff positive	*/
							hSntpRtcApp.zeroingDiff = SNTP_DRIFT_DOWN;
							/*	set RTC cal to max positive	*/
							HAL_RTCEx_SetSmoothCalib(&hrtc, 511, RTC_SMOOTHCALIB_PLUSPULSES_RESET, 0);
							/*	reset loop time to min	*/
							hSntpRtcApp.sendRequestTime = SNTP_MIN_WAIT_TIME_REQUEST;
							/*	set time before send new request to min value	*/
							hSntpRtcApp.loopTime = SNTP_MIN_WAIT_TIME_REQUEST;
							debugSntp("SNTP - start zeroingDiff positive - cal 0x%lx\n",  hrtc.Instance->CALR);
						}
						/*	diff positive -negative adjust - diff large enough to correct ?		*/
						if(hSntpRtcApp.diffVal > SNTP_MAX_CENTER_ERROR){
							/*	start zeroingDiff negative	*/
							hSntpRtcApp.zeroingDiff = SNTP_DRIFT_UP;
							/*	set RTC cal to max negative	*/
							HAL_RTCEx_SetSmoothCalib(&hrtc, 0, RTC_SMOOTHCALIB_PLUSPULSES_SET, 0);
							/*	reset loop time to min	*/
							hSntpRtcApp.sendRequestTime = SNTP_MIN_WAIT_TIME_REQUEST;
							/*	set time before send new request to min value	*/
							hSntpRtcApp.loopTime = SNTP_MIN_WAIT_TIME_REQUEST;
							debugSntp("SNTP - start zeroingDiff negative - cal 0x%lx\n",  hrtc.Instance->CALR);
						}
					}else{
						/*	zeroing - check if small enough to stop	*/
						if((abs((int32_t)hSntpRtcApp.diffVal)) < (SNTP_MAX_CENTER_ERROR / 2)){
							/*	stop zeroingDiff	*/
							hSntpRtcApp.zeroingDiff = SNTP_DRIFT_STOPPING;
							/*	set RTC cal to stored value		*/
							HAL_RTCEx_SetSmoothCalib(&hrtc, hSntpRtcApp.freqErrorCorrection & 0x1ff,	hSntpRtcApp.freqErrorCorrection & 0x8000, 0);
							/*	reset loop time - redundant	*/
							hSntpRtcApp.sendRequestTime = SNTP_MIN_WAIT_TIME_REQUEST;
							/*	set time before send new request to min value	*/
							hSntpRtcApp.loopTime = SNTP_MIN_WAIT_TIME_REQUEST;
							debugSntp("SNTP - stop zeroingDiff - cal 0x%lx\n",  hrtc.Instance->CALR);
						}
					}
					/*	no update, if no centering, trim center freq or increase loop time	*/
					if(hSntpRtcApp.zeroingDiff == SNTP_DRIFT_STOP){
						if(hSntpRtcApp.zeroError != hSntpRtcApp.diffVal){
							if(hSntpRtcApp.zeroError > hSntpRtcApp.diffVal){
								/* increase freq	*/
								hSntpRtcApp.freqErrorCorrection ++;
								if(hSntpRtcApp.freqErrorCorrection > 511){
									hSntpRtcApp.freqErrorCorrection = 511;
								}
								HAL_RTCEx_SetSmoothCalib(&hrtc, hSntpRtcApp.freqErrorCorrection & 0x1ff,	hSntpRtcApp.freqErrorCorrection & 0x8000, 0);
								debugSntp("SNTP - increased frequency - cal %lx\n", hrtc.Instance->CALR);
							}
							if(hSntpRtcApp.zeroError < hSntpRtcApp.diffVal){
								/* decrease freq	*/
								hSntpRtcApp.freqErrorCorrection --;
								if(hSntpRtcApp.freqErrorCorrection < -511){
									hSntpRtcApp.freqErrorCorrection = -511;
								}
								HAL_RTCEx_SetSmoothCalib(&hrtc, hSntpRtcApp.freqErrorCorrection & 0x1ff,	hSntpRtcApp.freqErrorCorrection & 0x8000, 0);
								debugSntp("SNTP - decreased frequency - cal %lx\n", hrtc.Instance->CALR);
							}
						}else{
							/*	increase loop delay	*/
							hSntpRtcApp.sendRequestTime *= 2;
							if(hSntpRtcApp.sendRequestTime > SNTP_MAX_WAIT_TIME_REQUEST){
								hSntpRtcApp.sendRequestTime = SNTP_MAX_WAIT_TIME_REQUEST;
							}
							hSntpRtcApp.loopTime = hSntpRtcApp.sendRequestTime;
						}
					}
					/*	prepare for next request		*/
					/*	set error value to compare next 	*/
					hSntpRtcApp.zeroError = hSntpRtcApp.diffVal;
					if(hSntpRtcApp.zeroingDiff == SNTP_DRIFT_STOPPING){
						hSntpRtcApp.zeroingDiff = SNTP_DRIFT_STOP;
					}
					hSntpRtcApp.retryError = 0;
				}
			}else{					/* we had an error in reply - retry sending request or try another server	*/
				if((hSntpRtcApp.retryError++) > SNTP_MAX_SEND_RETRY){
					/*	too many retries - try with another server	*/
					debugSntp("SNTP WARNING - too many (%d) errors with this server 0x%lx\n",
							hSntpRtcApp.retryError, hSntpRtcApp.sanityTest);
					if((status = tx_event_flags_set(&hSntpRtcApp.sntp_rtc_client_events,SNTP_RTC_LINK_CHANGED, TX_OR)) != TX_SUCCESS){
						Error_HandlerT("SNTP ERROR - App_Sntp_Rtc_Thread_Entry - tx_event_flags_set\n");
					}
					hSntpRtcApp.status = SNTP_RTC_WAIT_LINK;
				}else{
					/*	retry send		*/
					debugSntp("SNTP WARNING - bad SNTP event or packet, error 0x%lx\n", hSntpRtcApp.sanityTest);
					hSntpRtcApp.sendRequestTime = hSntpRtcApp.sendRequestTime >> 1;
					if(hSntpRtcApp.sendRequestTime < SNTP_MIN_WAIT_TIME_REQUEST){
						hSntpRtcApp.sendRequestTime = SNTP_MIN_WAIT_TIME_REQUEST;
					}
					if(hSntpRtcApp.valid == 1){
						/*	we have a valid RTC - we can wait 		*/
						hSntpRtcApp.loopTime = SNTP_MIN_WAIT_TIME_REQUEST;
					}else{
						/*	we want minumum time as RTC is not set		*/
						hSntpRtcApp.loopTime = SNTP_WAIT_FOR_REPLY;
					}
					hSntpRtcApp.status = SNTP_RTC_WAIT_CONGESTION;
				}
			}
			/*	if we had an update		*/
			if(hSntpRtcApp.rtcUpdated){
				/*	read timedate registers		*/
				mb_rtc_get_timeDate(&hRtcServer.td);
				/* fill HAL struct and strings		*/
				mb_timeDate_2_Hal();
			}
	    	monitorSntp("SNTP\t%s %s Diff %ld Cal 0x%lx Interval %ld Mode %d \n", hRtcServer.dateString, hRtcServer.timeString,
	    			(uint32_t)hSntpRtcApp.diffVal,  hrtc.Instance->CALR, hSntpRtcApp.loopTime, hSntpRtcApp.zeroingDiff);
	    	logSntp("%s %s SNTP\tD %ld\tZ %d\tcal 0x%lx\tL %ld\n", hRtcServer.dateString, hRtcServer.timeString,
	    			(uint32_t)hSntpRtcApp.diffVal, hSntpRtcApp.zeroingDiff,  hrtc.Instance->CALR, hSntpRtcApp.loopTime);
#if HISTORY_SNTP
	    	hSntpRtcApp.historyLast = (hSntpRtcApp.historyLast + 1) & ( HISTORY_SNTP_SIZE - 1);
	    	hSntpRtcApp.historyTime[hSntpRtcApp.historyLast] = (uint32_t)(hSntpRtcApp.referenceTimestamp);
	    	hSntpRtcApp.historyError[hSntpRtcApp.historyLast] = (int16_t)hSntpRtcApp.diffVal;
	    	hSntpRtcApp.historyCalibration[hSntpRtcApp.historyLast] = (int16_t)hSntpRtcApp.freqErrorCorrection;
	    	if(hSntpRtcApp.historyLast == hSntpRtcApp.historyStart){
		    	hSntpRtcApp.historyStart = (hSntpRtcApp.historyStart + 1) & ( HISTORY_SNTP_SIZE - 1);
	    	}
	    	if(hSntpRtcApp.historyTime[(hSntpRtcApp.historyStart - 1) & ( HISTORY_SNTP_SIZE - 1)] == 0){
	    		hSntpRtcApp.historyStart = (hSntpRtcApp.historyStart + 1) & ( HISTORY_SNTP_SIZE - 1);
	    	}
#endif 	/*	HISTORY_SNTP		*/

		}