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
*(volatile uint32_t*)0x900D0008 = 0x00;
*(volatile uint32_t*)0x900D0018 = 327;
*(volatile uint32_t*)0x900D0008 = 0x60;
*(volatile uint32_t*)0x900D0008 = 0xE0;
- (4.61 KiB) Downloaded 10 times