Page 1 of 1

Timing issues with the CX II

Unread postPosted: 28 Oct 2020, 17:18
by SixBeeps
Hello all,

I'm writing a program on my Nspire CX II that is rather draw-heavy, and it overall performs terribly. Now, a lot of that is my fault, but something I've noticed is that when I run this program, the timer goes noticeably out of sync. I don't think it's a code issue:

Code: Select all
from time import *
...
start_time = ticks_ms()
while True:
  current_time = ticks_ms() - start_time
  ...


Also, here's a video of the program running. Notice the 4-5 second offset by the end of the video. https://www.youtube.com/watch?v=Gpx0eC43tW0
So I think there might be some kind of error with the timer. I plan on purchasing a Hub and using its timer instead so that this issue doesn't occur, but I'd like to hear some other opinions.

Re: Timing issues with the CX II

Unread postPosted: 28 Oct 2020, 19:43
by Vogtinator
Looks like it really just calls TMT_Retreive_Clock, so the OS directly.

The error seems to be 32768 Hz (common clock frequency) vs. 32000 Hz. It seems like the OS expects the timer to run at 32768Hz, but it actually runs at 32000Hz:

187.610s * 32768Hz / 32000Hz = 192.112s

Re: Timing issues with the CX II

Unread postPosted: 29 Oct 2020, 14:09
by Vogtinator
SixBeeps wrote:
Vogtinator wrote:Looks like it really just calls TMT_Retreive_Clock, so the OS directly.

The error seems to be 32768 Hz (common clock frequency) vs. 32000 Hz. It seems like the OS expects the timer to run at 32768Hz, but it actually runs at 32000Hz:

187.610s * 32768Hz / 32000Hz = 192.112s


Very interesting indeed. So, does the OS always report the wrong millisecond reading?


Most likely. I just wrote a quick test program which waits for 10s using the RTC (second resolution only) and shows a diff of the systick (supposed to be 100Hz).
The result is a constant 976 ticks per 10s, which means 97.6Hz instead of 100Hz. This assumes that the RTC is correct, but the difference matches your video.

The OS configures Timer1 of the second timer at 0x900D0000 to interrupt every 20 cycles with a divider of 16, giving 320 cycles total.
Assuming a 100Hz systick, this means the OS expects the timer to run at 32000Hz.
Assuming the RTC is correct, the timer actually runs at 97.6*320 = 31232Hz (???)

I also see that some other functions convert ms to a timer value by doing value << 15 / 1000, which results in a 32768Hz tick. So it's a bit messy.

If so that's concerning :|

For tracking of absolute time there's the RTC and outside of that being ~2.4% slow isn't that bad.

Re: Timing issues with the CX II

Unread postPosted: 29 Oct 2020, 17:52
by SixBeeps
Vogtinator wrote:Assuming the RTC is correct, the timer actually runs at 97.6*320 = 31232Hz (???)

Even stranger. I kinda wonder if TI knew about this or if it was just some kind of overlooked detail.
Vogtinator wrote:For tracking of absolute time there's the RTC and outside of that being ~2.4% slow isn't that bad.

I was primarily concerned because these kinds of calculators are used for scientific purposes, so having an inaccurate timer could potentially mess something up. I guess having a real timer instead of using a calculator would make much more sense on a professional scale, but still.

In other news, I stuck a "correctional factor" of 1.024 on the current_time variable and it looks like everything is synced properly. Thanks for doing the dirty work of finding out the exact difference!

Re: Timing issues with the CX II

Unread postPosted: 29 Oct 2020, 17:56
by Vogtinator
I think I got it: It's caused by how the SP804 timer implements the periodic mode in combination with prescaling.

The good news is that this is perfectly reproducible in Firebird as well, so it's possible to look "inside" the timer.

The OS configures Timer1 of the second timer at 0x900D0000 to interrupt every 20 cycles with a divider of 16, giving 320 cycles total.

Is actually wrong! When the timer reaches 0, it does not immediately start again at 20. It only does this reloading on the next tick. The trap here is that this tick is prescaled as well.

As a result, the time between interrupts is actually not (20 * 16) + 1 cycles, but (20 + 1) * 16 cycles. This matches the results as well:

32768Hz / ((20 + 1) * 16) = ~97,52 Hz

To get a proper 100Hz timer with a prescaler of 16, the load value would have to be between 19 and 20, which is not possible. Without prescaler, it's possible to get it much closer:

32768Hz / ((327 + 1) * 1) = ~99,90 Hz

I was able to confirm that using that instead of the OS's own configuration does indeed result in 1000 ticks per 10s, instead of 976.

This little program reconfigures the timer during runtime, so just run it once and the systick should be more accurate:

Code: Select all
#include <stdint.h>

int main()
{
        *(volatile uint32_t*)0x900D0008 = 0x00;
        *(volatile uint32_t*)0x900D0018 = 327;
        *(volatile uint32_t*)0x900D0008 = 0x60;
        *(volatile uint32_t*)0x900D0008 = 0xE0;
}

Re: Timing issues with the CX II

Unread postPosted: 29 Oct 2020, 19:32
by parrotgeek1
Does this also affect the CX 1?

Could ndless itself apply this fix, or would that mess up existing software's speed?

Re: Timing issues with the CX II

Unread postPosted: 29 Oct 2020, 20:18
by Vogtinator
Does this also affect the CX 1?


According to Firebird, yes. (I don't have any HW to test that on at the moment)

Could ndless itself apply this fix, or would that mess up existing software's speed?


Only software using the OS timers would be affected, so not Ndless applications. Except for Python or Lua using that value for something long running, it wouldn't really be noticable and even then, 2.4% aren't that much. So I'd say it's not really necessary, especially because it appears like nobody noticed this until now.