simplemachines-it / mizar32

Automatically exported from code.google.com/p/mizar32
0 stars 0 forks source link

system timer sometimes gives a value wrong by one second #82

Open GoogleCodeExporter opened 8 years ago

GoogleCodeExporter commented 8 years ago
If the system timer interrupt happens while eLua is reading the system timer, 
it can happen that the code fails to handle the wraparound as it should, so 
time appears to go backwards by just under a second. It's fairly rare, but does 
happen.

Repeat-by:

do
  local old,new
  local tmrread=tmr.read
  old = tmrread(nil)
  while true do
    new = tmrread(nil)
    if new < old then
      print( old, new )
    end
    old = new
  end
end

Example output:

103825000       103000016

Original issue reported on code.google.com by martinwguy@gmail.com on 20 Mar 2012 at 12:22

GoogleCodeExporter commented 8 years ago
More output from test program:

103825000       103000016
369825000       369000016
471825000       471000016
472825000       472000016
577825000       577000016

This was happenign with a modified version if eLua that set the PWM frequency 
to 825000.  With a nominal frequency of 1000000 this still occurs: it reads the 
timer register as 1000000 (the "count" value) when it has already serviced the 
interrupt and incremented its internal "seconds" count.

The datasheet says "an interrupt is generated at the end of the
corresponding channel period."

Proper output at 1000000Hz, showing previous value and probability of 
occurrence:
do
  local old,new,last
  local tmrread=tmr.read
  local int n = 0
  old = tmrread(nil)

  while true do
    new = tmrread(nil)
    n = n + 1
    if new < old then
      print( last, old, new, n )
    end
    last = old
    old = new
  end
end

99999975        101000000       100000028       3374228
260999972       262000000       261000028       9775529
262999975       264000000       263000028       9855027
355999975       357000000       356000028       13552672
434999975       436000000       435000028       16693679

Original comment by martinwguy@gmail.com on 20 Mar 2012 at 12:44

GoogleCodeExporter commented 8 years ago
Checking for ccnt = cprd as 0 doesn't fix it either:

u64 platform_timer_sys_raw_read()
{
  u32 ccnt = AVR32_PWM.channel[ SYSTIMER_PWM_CH ].ccnt;
  if( ccnt == AVR32_PWM.channel[ SYSTIMER_PWM_CH ].cprd ) ccnt = 0;
  return ccnt;
}

80999983        80000000
81999983        81000000
105999983       105000000
111999983       111000000
205999983       205000000
234999983       234000000
246999983       246000000
341999983       341000000

It seems that, when we read the cprd register, we don't know whether the system 
timer interrupt has happened or not.

Original comment by martinwguy@gmail.com on 20 Mar 2012 at 1:09