How can I avoid this error "one by one" when adding an offset to a preset hardware timer?

I am writing a microcontroller interrupt that should add an offset to one of its hardware timers. However, due to the fact that the timer pre-divider is working, the naive approach may introduce a one-by-one error depending on the time the interrupt was executed relative to the clock of the pre-divider.

timing diagram of ISR off-by-one error

I am using timer 1 for ATmega328P (= arduino) for this. I configured it normally with the / 8 pre-splitter, and I use timer capture interrupt to trigger this; the purpose of the interrupt is for the timer to overflow exactly the period cycles after the event that triggers input capture (in the case of a trigger during another interrupt or in another situation in which interrupts are disabled).

(I am abusing the PWM output to run two network optotriacs with variable AC phase offset, without having to write the CPU all the time to it, the interrupt is triggered by a zero crossing detector on the network phase).

The code for the ISR will be something like this:

 uint_16 period = 16667; ISR(TIMER1_CAPT_vect){ TCNT1 = TCNT1 - ICR1 - period + (elapsed counter ticks during execution); } 

The critical interval here is the value between when TCNT1 read and when it is then written again.

As far as I know, there is no way to directly read the state of the prescaler, so I don’t think that you can just apply another offset based on ISR synchronization.

I could just reset the pre-splitter before the ISR ( GTCCR |= _BV(TSM); GTCCR |= _BV(PSRSYNC); GTCCR &= ~_BV(TSM); ) synchronize, but this still introduces a random offset to the time-dependent timer ISR.

Another approach that I am considering is to use a timer to generate an interrupt synchronized with the pre-allocator. I already use both output comparison registers on timer 1, but timer 0 is divided by a prescaler so that it can be used. However, the execution of a timer interrupt may be delayed by another interrupt or cli block, so this is not guaranteed.

How can I write my interrupt to avoid this error?

+5
source share
1 answer

If you write ISR as

 ISR(TIMER1_CAPT_vect){ int counter = TCNT1 - ICR1 - period + 3; asm("nop"); asm("nop"); TCNT1 = counter; } 

the TCNT1 record must go exactly 24 cycles after reading the register, thus in the same phase of the pre-divider. (The nop quantity can be adjusted if necessary, for example, due to differences between different types of microcontrollers). However, the decision cannot take into account the phase change of the pre-divider between setting ICR1 and reading TCNT1 .

+1
source

Source: https://habr.com/ru/post/1264367/


All Articles