cancel
Showing results for 
Search instead for 
Did you mean: 

Massive Analog/Digital clock time delay in TouchGFX clock examples

Louie88
Associate III

Board STM32H7474I-DISCO, TouchGFX V4.24.2.

If you keep the analog/digital clock examples running (in the evaluatation board) for (say) 10 minutes then the clock on the LCD screen will be more than 15-25 seconds behind your watch. This is a massive delay: 15-25 seconds delay during 600 seconds is not nothing.

Probably reasons (my ideas)

  1. The SystemTick (VSYNC = 60Hz, 16.6667ms) is not accurate and it is not generated by an MCU Timer. Hard to believe it.
  2. All the examples update the hour/minute/second display (on the LCD) from the TouchGFX's handleTickEvent() interrupt service routine. The update runs once in every second. I can imagine that updating the LCD takes more than 16.6667ms so when the next system tick interrupt occurs the interrupt service is still in service. This way we can miss a couple of system ticks.

It would be nice to know which statement is right and how to resolve this issue.

I tried to open TouchGFX Academy Tutorial3 example in STMCubeMX and create a new, dedicated timer with 20ms interrupt for the LCD update, but STMCubeMX did not allow to edit any Timer: properties of any enabled timers were empty. I also do not know how I can consume a Timer Interrupt in TouchGFX.Thanks for your help.
Louis

PS: I also would like to mention that TouchGFX Academy/Tutorial 3 increments the minute counter in every second... not in every minute. This is not a big issue but it should be fixed in the tutorial.

 

 

1 ACCEPTED SOLUTION

Accepted Solutions

Just sync it periodically with the RTC.

I call this in my screen view handleTickEvent():

    //clock
    //When every N tick execute C++ code
    //Execute C++ code
    tm const* timeinfoPtr = nullptr;
    static tm timeinfoOld = tm();// {0};
    
    #ifdef SIMULATOR
    	time_t rawtime;	
    
    	time(&rawtime);
    	timeinfoPtr = localtime(&rawtime);
    #else
    	//tm timeinfo={};
    	//timeinfoPtr = &timeinfo;
    
    	timeinfoPtr = getTimeStruct();
    #endif
    
    
    if (timeinfoPtr != nullptr)
    {
    	bool timeChanged = 	timeinfoPtr->tm_sec!= timeinfoOld.tm_sec||
    				timeinfoPtr->tm_min != timeinfoOld.tm_min ||
    				timeinfoPtr->tm_hour != timeinfoOld.tm_hour;
    
    
    	bool dateChanged = 	timeinfoPtr->tm_mday != timeinfoOld.tm_mday ||
    				timeinfoPtr->tm_mon != timeinfoOld.tm_mon ||
    				timeinfoPtr->tm_year != timeinfoOld.tm_year;
    
    	timeinfoOld = *timeinfoPtr;
    
    
    	
    	static bool timeInitialized = false;
    	
    	if (!timeInitialized)
    	{
    		timeInitialized = true;
    		// disable animation the first time to prevent arms from rotating a lot
    		analogClock1.initializeTime24Hour(timeinfoPtr->tm_hour, 
    							timeinfoPtr->tm_min, 
    							timeinfoPtr->tm_sec);
    	}
    	else
    	{
    		// analogClock need to be updated more than 1 time per second to allow animation
    		analogClock1.setTime24Hour(timeinfoPtr->tm_hour, 
    						timeinfoPtr->tm_min, 
    						timeinfoPtr->tm_sec);
    	}
    	
    	if (timeChanged)
    	{
    		digitalClock1.setTime24Hour(	timeinfoPtr->tm_hour, 
    							timeinfoPtr->tm_min, 
    							timeinfoPtr->tm_sec);
    	}
    	
    
    	if(dateChanged)
    	{
    		Unicode::snprintf(dateBuffer, DATE_SIZE, 
    						"%04d-%02d-%02d", 
    						timeinfoPtr->tm_year + TM_YEAR_BASE, 
    						timeinfoPtr->tm_mon - TM_MONTH_OFFSET, 
    						timeinfoPtr->tm_mday);
    			
    		date.resizeToCurrentText();
    		date.invalidate();
    	}
    }

 

 

Kudo posts if you have the same problem and kudo replies if the solution works.
Click "Accept as Solution" if a reply solved your problem. If no solution was posted please answer with your own.

View solution in original post

13 REPLIES 13
Louie88
Associate III

I investigated a bit, and as I expected STM supports the performance measurement. (Thanks for that STM) In STM32H474I-DISCO board' PJ8 = RENDER_TIME and PJ3 = VSYNC_FREQ. These port pins are available on the CN6 ARDUINO connector (easy access). You need a scope and you can mesaure the VSYNC frame rate and the time is necessary to render graphics on the LCD screen.

On the attached 20250119_125653.bmp screenshot the yellow trace is the VSYNC_FREQ = 58.96Hz. It is not 60.0 Hz! This is the reason of the not accurate time measurement. The blue trace the time is necessary to render a label and a floating-point number (system tick increment time) on LCD. To render some text and a float number we need more than 15ms which just fit into the refresh rate. There is no LCD rendering overflow.

On the other screenshot (20250119_130344.bmp) the LCD is updated in every second (yellow). The blue rendering time is running time of the code which checks whether the 1 second (or more) elapsed in the handleTickEvent() interrupt service routine.

Therefore, supposing that if we increment a counter in every TouchGFX's handleTickEvent() interrupt service routine and check whether its value = 60 means 1 second is faulty and cannot be used. For accurate clock we need to keep track the elapsed time (float) and show HH:mm:ss digital clock value from the elapsed time. The only problem is you have to specify the exact VSYNC (system tick) frequency for the app.

Rather than specifying the VSYNC frequency it would be better solution using a dedicated TIMER of the MCU which generates (say) 20ms interrupt and updates the LCD from that interrupt instead of handleTickEvent().

I think if I open the TouchGFX project's IOC file in STM32CubeMX, then I can create an auto repeat timer with enabled interrupt. The question is how I can use the Timer interrupt in TouchGFX?

I have no idea about that.

Louis

Hello @Louie88 ,

 

The tick timer is meant to enable 60 fps, therefore it is not extremely accurate as it is not meant to be used as a real clock.

To a timer interrupt in TouchGFX, you have look at these videos :

 

Basically, there is 2 ways when you receive your interrupt, either you use a task from your RTOS that will change your time or you just set a value and react to that value in the model.cpp.

 

Regards,

Gaetan Godart
Software engineer at ST (TouchGFX)

Primary problem ... TGFX is ollllld utility and when first example for clock is created on some first board, maybe display and oscilator used on it can use VSYNC and was perfect. But autors dont warning , not use it always.

Result is many next examples and users do same mistake. Stop use this example as working code. 

Stop use any timers = for this exist RTC and on networked boards combination with NTP.

 

Hi Gaetan,

I thought the examples are for demonstrating the features not for an accurate product. But should not we (users especially beginners) be warned that the clock is not accurate, it just an example how to implement the GUI and show the time and it is not intended to be an Apple watch?

Thanks for the reply and the links. They seem to be very useful. 

If I find the way how the clock works right (accurate time) then I will post. it.

Thanks,

Louis

 

Louie88
Associate III

Hi MM..1,

Thanks for your notes. The reason why I implement my own digital clock was to be familiar with TGFX and how I can use the MCU peripherals in TGFX to show date in a nice form. The digital/analog clock app seemed to be perfect pick for this purpose. But when I got 20s delay for 10 minutes, I wanted to understand why it happens, then I wanted to correct it. Yes, I know the MCU has a dedicated RTC but using it in TGFX seemed to be impossible for a beginner with 30+ years practice (with Intel 8051, Silicon Labs Ti, STM MCUs) in embedded systems.

Louis

 

 


@Louie88 wrote:

should not we ... be warned that the clock is not accurate, it just an example how to implement the GUI


Yes, I think so - especially as you're not the first to be caught out by this!

@GaetanGodart 

Louie88
Associate III

Hi guys,

I created 20ms time base by using Timer1 in H7474I-DISCO board:
Clock = 200MHz
Prescaler = 40 000
Counter = 100
Resulting 50Hz Timer1 interrupt.

In main.c from the HAL_TIM_PeriodElapsedCallback() I toggle PK1 port (Available on CN5.3 pin) and I increment lcdUpdateTick variable to show how many times the Timer 1 interrupt happened. The plan is to check if (lcdUpdateTick % 50) = 50 * 20ms = 1 sec, in mainView.cpp somehow and update the clock display.

...
uint32_t lcdUpdateTick = 0;
...

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	// Existing system tick code
	if (htim->Instance == TIM6) {
		HAL_IncTick();
	}   

	// My added code to toggle PK1 pin
	if (htim->Instance == TIM1) {
		lcdUpdateTick++;
		HAL_GPIO_TogglePin(GPIOK, GPIO_PIN_1);
	}
}

On scope I got 25.0000Hz, which is right because PK1 is toggled in every interrupt so the 50Hz is divided by 2 = 25Hz, I attached the screenshot.

Now my problem is how can detect this TIMER 1 interrupt in mainView.cpp? I guess I should:

  1. Create a queue with os_create_queue()
  2. Send this message with os_send_message()
  3. Form mainvView.cpp receive the message os_receive_message()
  4. Update the clock.

Would you please send me an example how to do this right? (Maybe I wrong and there is better solution for this job...)


Thanks,
Louis

HW interrupt is in real world delayd based on priority etc. But counter will show valid value, then simply in screenview tick check 

 

if( (lcdUpdateTick/50) != lastshowedsec ) shownewsec... 

 

and this require be

 

volatile uint32_t lcdUpdateTick = 0;

 

 because is updated in ISR. And in view extern "C" it.

PS> Name it lcdUpdateTick is inappropriate.