Timebase timer problem in the STR75x port?

jorick23 wrote on Tuesday, April 15, 2008:

I have an STR75x application (IAR compiler) in a syringe pump that uses a FreeRTOS that I’ve customized in order to use interrupts more efficiently.  I just downloaded version 5.0.0 and am merging in my changes.  I’ve come to a point where the timebase timer is set up and I don’t think I understand how the auto reload value is computed in the prvSetupTimerInterrupt function in port.c.

The 60 MHz processor clock is fed through a divide-by-20 prescaler, giving the timebase timer an input frequency of 3 MHz.  My application needs a 1 millisecond tick (configTICK_RATE_HZ = 1000) so it has an auto reload value of (configCPU_CLOCK_HZ / portPRESCALE) / configTICK_RATE_HZ, or (6 MHz / 20) / 1000 = 3000 counts.  3 MHz / 3000 counts = 1 mS between interrupts.  I’ve done timing runs on the pump to insure the flow is accurate and my clock, which runs off the timer hook, runs very accurately with this setting (I’ve compared it with an external clock).

The FreeRTOS version 5 timebase setup still feeds a 60 MHz processor clock through a divide-by-20 prescaler so the input frequency into the timebase timer is still 3 MHz.  But the auto reload value in version 5 is computed as ((configCPU_CLOCK_HZ / (portPRESCALE + 1)) / configTICK_RATE_HZ) + 1 which is (6 MHz / 21) / 1000 + 1, or 2858 counts, rounded.  This means the clock is running at an actual tick rate of 1050 Hz instead of the expected 1000 so the clock would be running too fast, adding one second every 20 seconds.  Is this correct or am I missing something here?

I’m going to leave my 3000 count setup alone since it’s working fine.

davedoors wrote on Tuesday, April 15, 2008:

I cannot see anything different with the port layer code in the STR750. Are you saying the code that sets up the time has changed, or that the same code is giving different timing results?

richard_damon wrote on Tuesday, April 15, 2008:

While I am not familiar with that particular processor, but from what that formula looks like, it wants portPRESCALE to not be the scale factor but the value of the prescaling port, which is typically 1 less than the divide ratio. A divide by 20 would count from 19 down to 0 and restart.

You would need to look at how the value of portPRESCALE is used elsewhere to confirm.

jorick23 wrote on Wednesday, April 16, 2008:

I found it!  In port.c in the prvSetupTimerInterrupt function, the code currently reads:

    TB_InitStructure.TB_Prescaler = portPRESCALE;
    TB_InitStructure.TB_AutoReload = ( ( configCPU_CLOCK_HZ / ( portPRESCALE + 1 ) ) / configTICK_RATE_HZ ) + 1;

where configCPU_CLOCK_HZ = 60,000,000, portPRESCALE = 20, and configTICK_RATE_HZ = 1000.

The correct code should be:

    TB_InitStructure.TB_Prescaler = portPRESCALE - 1;
    TB_InitStructure.TB_AutoReload = ( configCPU_CLOCK_HZ / portPRESCALE ) / configTICK_RATE_HZ;

The Prescaler register expects the prescaler value to be zero-based so a prescaler of 20 needs to be written as 19.  The current method in FreeRTOS is essentially correct when using a prescaler of 21 but a slight inaccuracy is introduced because 60 MHz / 21 is a fractional number that gets rounded to an integer.  This rounding, plus the addition of 1 at the end, causes an inaccuracy of .03% (one second in 55 minutes), not enough to worry about for the vast majority of applications out there, but it’s too much for mine so I use the corrected version.

My first post assumed an error of one second every 20 seconds but that was because I forgot that my prescaler was set to a different value.

rtel wrote on Wednesday, April 16, 2008:

Thanks for the feedback - I have updated the files in SVN.


jorick23 wrote on Wednesday, October 14, 2009:

I just downloaded version 5.4.2 and I see that the prescaler code has been updated but the auto reload value hasn’t.  I’m still off by around 5% in the timing so I’m going to modify Port.c in my project to give me the correct timing.  I’ll be using ( configCPU_CLOCK_HZ / portPRESCALE ) / configTICK_RATE_HZ.

Was there some reason it wasn’t changed in the new version?  And will it be changed in version 6?  Thanks!

rtel wrote on Thursday, October 15, 2009:

Simply an error.  I will correct for V6.