View previous topic :: View next topic |
Author |
Message |
njepsen
Joined: 13 Aug 2007 Posts: 469
|
Posted: Thu Dec 27, 2018 1:29 am Post subject: RTC and interrupts |
|
|
I am using timer 3 to generate a 1sec int to synchronize my RTC. Timer 0 does nothing except flash a heartbeat LED
A global long called "Local_secL" is incremented every second by T3, which in turn is used to generate the date and time variables.
Every 15 minutes, i do a data upload to a server via cellular, and there is a standard HTTP response from the server, which includes GMT.
The GMT response from the server is decoded and the date$/time$ variables are corrected if necessary.
The RTC is kept to local time by decoding the return from the server every 15 minutes, in the sub below.
The problem I have is about once per month, an upload get missed completely, and I have been trying to find the cause for several months.
I suspect that the Var TTRN is simply not getting set, and the server upload is missed because of this.
I am also confused about interrupt priority. The help says that Quote: |
When an interrupt is serviced no other interrupts can occur because the processor(not the compiler) will disable all interrupts by clearing the master interrupt enable bit.
|
Does this mean that it is possible that one of my timer int is missed because the processor could be away doing the other timer int ? This would explain why TTRN doesnt get set sometimes?
The code is as follows. I have only included the relevant parts because the code is 6000 lines long. Code: |
'*******************************************************************************
$regfile = "m1284pdef.dat"
$crystal = 9830400
$framesize = 800
$hwstack = 550
$swstack = 550
$frameprotect = 1
'---------------------------------------------------------------------
'Config the RTC
'RTC is incremented by incrementing a flag local_secL
Config Clock = User
Config Date = Dmy , Separator = Slash 'dd/mm/yy
'-----------------------------------------------------------
'Timer 0 = 8 bit counter, 9.8304mhx xtal, 1024 prescaler = overflows 37.5 times per sec
'Flashes the heartbeat led
Config Timer0 = Timer , Prescale = 1024
Enable Timer0
'Start Timer0
On Timer0 Timer0overflow Nosave 'happens 37.5 times/sec
'---------------------------------------------------------------------------------
'Timer 3 = 16 bit rolls over every 1 second,set by timer preset in the ISR
'This timer checks TTRN
'takes care of the RTC
Config Timer3 = Timer , Prescale = 1024 'Counts 9830400/1024 = 9600 ck pulses per sec '
'
On Timer3 Timer3overflow
Enable Timer3
Start Timer3
dim local_secL as long
dim TTRN as byte
dim Dn5 as byte ' done
TTRN = 0
'-------------------------------------------------------------------------------
'MAIN LOOP
DO
If TTRN = 1 then
' do lots of things
'upload to server. 'The standard server HTTP GMT response (with junk removed) is now in "responseSTR
verify_time(responsestr) 'function
call UpdatemyRTC
TTRN = 0
end if
LOOP
'*****************************************************************************
Function Verify_time(byval Responsestr As String) As String
'input dd/MM/yyyy,HH:mm:ss,nnnnnnnnnn and is 30 bytes long
'output dd/MM/yyyy,HH:mm:ss,nnnnnnnnnn 30 bytes long OR "null"
Local Error As Byte
Error = 1
If Len(responsestr) = 30 Then
If Mid(responsestr , 3 , 1) = "/" Then
If Mid(responsestr , 6 , 1) = "/" Then
If Mid(responsestr , 14 , 1) = ":" Then
If Mid(responsestr , 17 , 1) = ":" Then
If Mid(responsestr , 7 , 2) = "20" Then
If Mid(responsestr , 11 , 1) = "," Then
If Mid(responsestr , 20 , 1) = "," Then
Error = 0 'no errors, no changes to responsestr
Print #1 , ">> good verify"
End If
End If
End If
End If
End If
End If
End If
End If
If Error <> 0 Then
Responsestr = "null"
Print #1 , "time from server failed at function verify_time "
End If
Verify_time = Responsestr
End Function
'***************************************************************************
sub updatemyRTC()
'format is now dd/MM/yyyy,HH:mm:ss,nnnnnnnnnn and needs to be dd/MM/yy,HH:mm:ss,nnnnnnnnnn
If Len(responsestr) = 30 Then
Delchar responsestr , 7 'delete y
Delchar responsestr , 7 'delete y string is now dd/MM/yy,HH:mm:ss .. etc
Time$ = Mid(responsestr , 10 , 8) 'HH:mm:ss
Date$ = Left(responsestr , 8) 'dd/MM/yy
Local_secl = Syssec() 'this is local time i.e. includes DST
Print #1 , ">> local_secL=" ; Local_secl:
Else
Print #1 , ">> bad local time response length from server. Len was" ; Len(responsestr)
End If
end sub
'*****************************************************************************
Sub Check_ttrn()
'is it TTRN (time to read noise).
'This sub called once every sec under interrupt of timer3
'Dn5 lets ttrn->1 happen only once per 15 min
'TTRN is latched in this sub and unlatched when data is sent
If Dn5 = 0 Then
If _min = 0 Or _min = 15 Or _min = 30 Or _min = 45 Then
Dn5 = 1
Ttrn = 1 'time to read noise
Print #1 , ">> time to read 15min noise"
End If
Else
If Ttrn = 0 And _min <> 0 And _min <> 15 And _min <> 30 And _min <> 45 Then
Dn5 = 0
End If
End If
End Sub
'****************************************************
Timer0overflow:
'called 37 x per second
'flashes heartbeat LED once per sec
$asm
push r24 ;save r24
in r24, sreg ;r24<-sreg
push r24 ;save status register to stack
lds r24, {btimer0} ;load direct
inc r24
cpi r24,37 ;compare
brlo timer0ovf ;br if r24 < 37
clr r24 ;clear r24
sbi heartbeat_pin,heartbeat_bit ; write 1 to pin = toggle led
Timer0ovf:
sts {btimer0},r24 ;store btimer0 <- r24
pop r24
Out Sreg , R24 'get Sregister back
pop r24
$end Asm
Return
'******************************************************************************
Timer3overflow:
'T3 rolls over every 1 second
Timer3 = 55936 '65536 - 9600x1
Call Check_ttrn 'is it time to read the noisemeter
Incr Local_secl
Time$ = Time(local_secl) 'calculate time & update RTC
Return
'*******************************************************************************
End |
(BASCOM-AVR version : 2.0.7.9 , Latest : 2.0.8.1 ) _________________ Neil |
|
Back to top |
|
|
Paulvk
Joined: 28 Jul 2006 Posts: 1257 Location: SYDNEY
|
Posted: Thu Dec 27, 2018 11:40 am Post subject: |
|
|
I have a one second tic for real time on many of my projects
I try to do as little as possible in the interrupt
In my web server project I update from the time servers
I use bascoms inbuilt time constant, system second
below is the basic isr
Regards Paul
Code: |
Config Timer0 = Timer , Prescale = 1024
On Ovf0 Tim0_isr 'Define ISR handler
Tim0_isr:
Bres = Bres + 262144 '262144 = prescaler:1024 * timer0:256
If Bres > 8000000 Then '8 000 000 = xtal frequency
Bres = Bres - 8000000
'Top = 1
'Set Portd.6 'top test 1 second
' Waitms 10
'Reset Portd.6
End If
Return
|
|
|
Back to top |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Thu Dec 27, 2018 9:18 pm Post subject: Re: RTC and interrupts |
|
|
njepsen wrote: | Does this mean that it is possible that one of my timer int is missed because the processor could be away doing the other timer int ? |
Interrupt flags memorize one trigger event, the corresponding (enabled) interrupt is executed as soon interrupts are globally (re-)enabled, return from an ISR re-enable interrupts.
As there's only one bit per flag, two or more of the same triggers - while blocked - lead to only one executed corresponding interrupt.
However, it does not look like the timer interrupts may block out each other for that long.
Did you think about what may happen as local_secl can be accessed from main-code and from interrupt?
local_secl is a 4-byte variable and an 8bit processor can handle only one byte at one time.
Race-conditions anyone?
Some subs look like interrupt-related only, I would pack them into the ISR directly. |
|
Back to top |
|
|
njepsen
Joined: 13 Aug 2007 Posts: 469
|
Posted: Thu Dec 27, 2018 9:35 pm Post subject: |
|
|
MWS - Thanks for the insight into timer interrupts. You raise the ? of race condition, good point. Yes - Local_sec1 can be changed both in the timer ISR and in the sub, but this would cause a max error of 1 sec ?. What I dont show is that the "Update RTC" sub only gets called once every 15 minutes.
But for TTRN to not get set, the _min variable would need to be set to not equal 0,15,30,45 or 60, which would take an error of 60sec with the 1 second tic. I'm struggling to see how this might happen. _________________ Neil |
|
Back to top |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Fri Dec 28, 2018 1:58 am Post subject: |
|
|
A) If you would know the culprit, you would not ask.
B) You can not solve unknown bugs, if you don't care about the obvious first.
Quote: | What I dont show is that the "Update RTC" sub only gets called once every 15 minutes. |
You actually did show it through your code and I was aware of it.
Assume your RTC is a bit off, then you may have every 15 minutes an error bigger than one second.
Considering a 'long' is built of 4 bytes, and double access may create some chimera from both, it should be obvious there can be a problem.
Another potential issue may be, if the newly fetched GMT is wrong, but made it through your check-routines.
Is the time difference between the last good upload and the next good exactly 30 minutes?
Did you try syncing time only at startup and the rest of the month without re-sync?
Last, may the upload fail simply because of wireless connection problems?
By adding a field 'time of previous upload attempt' to your upload data, you will know. |
|
Back to top |
|
|
njepsen
Joined: 13 Aug 2007 Posts: 469
|
Posted: Fri Dec 28, 2018 2:48 am Post subject: |
|
|
Thanks MWS. I am assuming that the bug is failure to set TTRN. The only way this can happen is if _min <>0,15,30 or 45, which could happen if at the next 15 minute correction, the correct time was 1 minute faster than Time$. If that happened, then _min could theoretically jump from 59 to 01, or 14 to 16 for example.
[quote]
Another potential issue may be, if the newly fetched GMT is wrong, but made it through your check-routines.
[\quote]
Yes thats possible but I'm guessing that the cellular response has some sort of error checking in the HTTP protocol. I think its pretty unlikely that the response would pass the checks i am looking for but then again - you could be right. i dont know.
Yes it can happen that communications fails for an hour or so, but that has never happened prior to the issue I'm bugged by.
Quote: |
Did you try syncing time only at startup and the rest of the month without re-sync?
| No I havent - thats easy to do. I do know (from tests) that after a month I would be a minute or so out because my system Xtal is nothing special, and I dont make any attempt to trim it to frequency.
Quote: |
Last, may the upload fail simply because of wireless connection problems? | This doesnt matter, and is taken care of in code. The RTC of course just trucks on, til next interval. I have tested this for several days and it works fine.
Quote: | By adding a field 'time of previous upload attempt' to your upload data, you will know. | I do log everything I can, and when there is a failure, the two uploads on either side of the missing one a exactly on the correct time.
Quote: |
Considering a 'long' is built of 4 bytes, and double access may create some chimera from both, it should be obvious there can be a problem. | Hmm possible but the next upload would be 'anywhere!' and this doesnt happen.
Thanks MWS for helping with this - my best guess at the moment is that TTRN isnt being set, and one possibility as I said earlier is that the server upload is causing time to 'jump over' my _min check.
To test this I will do a range check, 5 minutes wide at each 15 min interval, and see if the problem changes. _________________ Neil |
|
Back to top |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Fri Dec 28, 2018 9:59 am Post subject: |
|
|
njepsen wrote: | I am assuming that the bug is failure to set TTRN. |
You assumed that from the very start, and it can be.
If you want understand the mechanism of a bug, you need to scrutinize its origin and eliminate every potential bug on this way.
But it's your bug, so surely you can approach it as you like.
Tell me: are you able to compile the shown code from your entry post?
Nowhere in this code you dim Responsestr, but you use it in
Code: | verify_time(responsestr) |
which should throw an error.
Code: | Function Verify_time(byval Responsestr As String) As String |
creates a local copy of the string on the frame, which must be considered void after the function exits.
Even if you actually use a global variable with same name 'Responsestr' I would avoid such double-naming.
If you condense code for the purpose of showing the basics, that's ok, but at least it should be functional, i.e. represent the actual problem. |
|
Back to top |
|
|
laborratte
Joined: 27 Jul 2005 Posts: 299 Location: Berlin
|
Posted: Sat Dec 29, 2018 12:37 am Post subject: |
|
|
You are accessing both Local_secl and time$ in main and isr. For non-byte-vars that are changed in a isr every access has to be blocked from interrupt in main:
Code: |
disable interrupts
Time$ = Mid(responsestr , 10 , 8) 'HH:mm:ss
Date$ = Left(responsestr , 8) 'dd/MM/yy
Local_secl = Syssec() 'this is local time i.e. includes DST
enable interrupts
|
This is mandatory, even if you are reading vars. In your case you access a pseudo-var time$ which is actually a subroutine. This makes it even worse as there is a good chance that this routine is not reentrant. |
|
Back to top |
|
|
njepsen
Joined: 13 Aug 2007 Posts: 469
|
Posted: Sat Dec 29, 2018 4:45 am Post subject: |
|
|
Thankyou MWS and Laborratte. Great responses, and easy fix. I will do the suggested and get back to the thread in a week or three, when I am confident that a good test has been made.
many thx both of you. _________________ Neil |
|
Back to top |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum You cannot attach files in this forum You cannot download files in this forum
|
|