| ??? 10/16/03 19:58 Read: times |
#56776 - Timer interrupt response (LONG) Responding to: ???'s previous message |
"Oleg Sergeev wrote:
------------------------------- Hi, Some rules about timer-for-time I use in my projects when I need with real clock ticks without unexpected divergence: - set the maximal priority level for a timer interrupt; another ones should have lower level." Unless you are using an auto-reload mode, increased interrupt priority alone, does not solve the accumulated drift problem (see below). "- never stop a timer! ..." There is no problem stopping a timer, providing you account for the time (ticks) while the timer is stopped (see below). In case anyone missed my comment here, or did not understand it, or just simply disagree with it, please consider this deeper explanation of the problem in this RTC-like application when not using a timer in an auto-reload mode. This time I will explain it in a scenario where the conditions are the most favorable; that is, assuming that the timer interrupt is the only enabled interrupt source in the system and that the program never disables interrupts. Some of what I'll present is quoted directly from a so-called "bible" volume. First, let's get some definitions out of the way: A machine cycle, assuming 12 oscillator periods, consists of 6 states ('S'). Each state is divided into a Phase 1 half ('P1') and a Phase 2 half ('P2'). Thus a machine cycle consists of 12 oscillator periods, numbered S1P1 through S6P2. "How Interrupts Are Handled The interrupt flags are sampled at S5P2 of every machine cycle. The samples are polled during the following machine cycle. If one of the flags was in a set condition at S5P2 of the preceding cycle, the polling cycle will find it and the interrupt system will generate an LCALL to the appropriate service routine, provided this hardware-generated LCALL is not blocked by any of the following conditions:
Any of these three conditions will block the generation of the LCALL to the interrupt service routine. Condition 2 ensures that the instruction in progress will be completed before vectoring to any service routine. Condition 3 ensures that if the instruction in progress is RETI or any access to IE or IP, then at least one more instruction will be executed before any interrupt is vectored to." This next quoted part describes interrupt latency in the context of external interrupts, which is an important context for it, but the issue of response latency applies to internal interrupts also, as you now understand from the quote above. "Response Time The INT0 and INT1 levels are inverted and latched into IE0 and IE1 at S5P2 of every machine cycle. The values are not actually polled by the circuitry until the next machine cycle. If a request is active and conditions are right for it to be acknowledged, a hardware subroutine call to the requested service routine will be the next instruction to be executed. The call itself takes two cycles. Thus, a minimum of three complete machine cycles elapse between activation of an external interrupt request and the beginning of execution of the first instruction of the service routine. A longer response time would result if the request is blocked by one of the 3 previously listed conditions. If an interrupt of equal or higher priority level is already in progress, the additional wait time obviously depends on the nature of the other interrupts service routine. If the instruction in progress is not in its final cycle, the additional wait time cannot be more the 3 cycles, since the longest instructions (MUL and DIV) are only 4 cycles long, and if the instruction in progress is RETI or an access to IE or IP, the additional wait time cannot be more than 5 cycles (a maximum of one more cycle to complete the instruction in progress, plus 4 cycles to complete the next instruction if the instruction is MUL or DIV). Thus, in a single-interrupt system, the response time is always more than 3 cycles and less than 9 cycles. So, in my scenario with a single timer interrupt and never disabling interrupts, you still have variable latency getting into the ISR to reload your timer. One can never account for variable latency by reloading the timer with a fixed value. If, for example, your application calls for 10ms-or-thereabouts interrupt interval to sample some hardware (e.g., keypad), you'd be fine, but if your application calls for RTC-like functionality (I realize that the main oscillator introduces its own drift), then you must adopt a technique that accounts for this "more than 3 cycles and less than 9 cycles" variability that you have no control over unless your code is comprised only of 1-cycle instructions! The issues up to this point also apply to systems that have multiple interrupt sources enabled, but have the timer interrupt as the sole high priority interrupt source. Now, when you go adding the need to disable interrupts globally, or disable the timer interrupt alone, for the purposes of getting a snapshot of the HH:MM:SS RTC values like Michael talks about here, or for any other reasons, you have added more variability to the timer ISR latency. How do you solve this problem? Well, use the resources at your disposal -- take advantage of the fact that after Tn overflowed, it continued to count up past zero, coincidentally counting the machine cycles for you! Once you get into the ISR, disable other higher priority interrupt sources (if any), you've got the timer right where you want it; that is, holding the (variable) count of machine cycles you CPU took to finally get there after setting TFn. Don't just blindly reload the timer with a fixed value, subtract the dynamic latency value in the timer from your fixed value and use that to reload the timer. ;** The reload definition factors in how long the timer is stopped to perform
;* the dynamic reload operation.
;**
RELOAD EQU -(9216-7) ; -((11059200/12/100)-7) = 10ms
Tn_ISR: PUSH PSW
PUSH ACC
CLR EA
CLR TR0
MOV A,TL0 ; 1
ADD A,#LOW RELOAD ; 1
MOV TL0,A ; 1
MOV A,TH0 ; 1
ADDC A,#HIGH RELOAD ; 1
MOV TH0,A ; 1
SETB TR0 ; 1 = 7~ timer reload compensation.
SETB EA
;** Code to increment HH:MM:SS goes here...
POP ACC
POP PSW
RETI
|



