Improving timing accuracy with ATmega8

I need to blank out a VGA monitor during startup but want to show the user that something is happening.

To achieve this I thought I could use the 16Mhz ATmega8 I already have in the system to display something similar to a progress bar.

I have assigned 3 pins to this. one each for HSync, VSync and video. The video is split to the red and green channels to give a yellow bar.

I need to monitor an IR receiver, I2C and USART at the same time so decided to use the 16 bit Timer1 so I could have some spare cycles between each line. The bar is only displayed on 3 lines so generating the HSync pulse is the only thing that gets done on most Timer1 interrupts.

My problem is that there is more jitter (about 2 to 3 cycles) than I would like. My timer interrupt is this:

TIM1_OVF: ; Timer1 Overflow Handler in S,SREG push A push B

; Prepare timer1 for next timeout in A,TCNT1L ldi B,2 ; Timer1(L) add A,B ; Allow for any delay getting here ldi B,254 ; Timer1(H) out TCNT1H,B out TCNT1L,A

rcall SyncPulseH ; Generate HSync pulse rcall DrawBarLine rcall SonyGet ; Poll IR port

EndTIM1_OVF: pop B pop A out SREG,S reti

The idea was that this would correct for any small delays (a few cycles) before the interrupt is serviced but it doesn't seem to make any difference.

Does anyone have an idea of why the timing correction doesn't appear to do anything or how to improve it? Is this as good as I'm going to get?

I have tried disabling all other interrupts and removing the SonyGet call with no change.

Here is my DrawBarLine routine. Again, I thought that waiting for the timer to reach a particular value would have reduced the jitter to 1 clock cycle.

;****************************************************************** ; Draw loading bar on VGA ;****************************************************************** DrawBarLine: push A

cbi PORTC,VgaVid cpi VgaLineH,1 ; All other lines blank brne BlankLine cpi VgaLineL,80 ; Only show the bar on lines 80~82 brlo BlankLine cpi VgaLineL,83 brsh BlankLine WaitForBarStart: in A,TCNT1L ; Use timer1 to find the start cpi A,4 ; point for the bar brsh WaitForBarStart

mov A,VgaBarCnt sbi PORTC,VgaVid ; Turn on Video (Start of bar) DrawBarLoop: dec A brne DrawBarLoop cbi PORTC,VgaVid ; Turn off Video (End of bar)

BlankLine:

CheckVSync: cbr Flags,(1

Reply to
Mike Warren
Loading thread data ...

[snip...snip...]

AFAIK, the irreducible minimum jitter is the 2-3 clock cycles that you're seeing, based on the need to complete the current instruction before the interrupt is recognized.

--
Rich Webb   Norfolk, VA
Reply to
Rich Webb

Some more information:

If I put my main in a tight loop then I get only one cycle of error.

Main: rjmp Main

Even adding some nops still works ok

Main: nop nop nop nop nop nop rjmp Main

Adding a simple rcall brings the problem back Main: nop nop nop nop nop nop

rcall test rjmp Main

test: ret

--
Mike
Reply to
Mike Warren

That's why I read the timer again and do the add.

in A,TCNT1L ldi B,2 ; Timer1(L) add A,B ; Allow for any delay getting here ldi B,254 ; Timer1(H) out TCNT1H,B out TCNT1L,A

I see no visible difference between the above code and this:

ldi B,2 ; Timer1(L) ldi B,254 ; Timer1(H) out TCNT1H,B out TCNT1L,A

--
Mike
Reply to
Mike Warren

Oops. The second one should be:

ldi A,2 ; Timer1(L) ldi B,254 ; Timer1(H) out TCNT1H,B out TCNT1L,A

--
Mike
Reply to
Mike Warren

Ahhh. For some reason I thought rcall and ret used 2 cycles each. I looked them up and discovered that rcall uses 3 and ret used 4 cycles.

That plus the fact that the correction I'm doing will not help for the current interrupt will cause what I'm seeing.

I'll have to rewrite so there are no rcalls in the main loop while the timer is running.

Thanks Rich.

--
Mike
Reply to
Mike Warren

When an interrupt occurs, the current instruction is completed. Depending on the instruction this will cause a couple of cycles or so of jitter. Unavoidable I am afraid.

Ian

Reply to
Ian Bell

Yes, I have it working acceptably now by not making any rcalls in my main loop when the timer is running.

--
Mike
Reply to
Mike Warren

Why? Since the main loop is there to just loose time simply make the uC sleep at the end of the IT routine. No instruction executed = no jitter.

--
Thanks,
Fred.
Reply to
Fred Bartoli

It might be possible to set the output compare register, and let the timer hardware set a pin by itself at the right time. This will be jitter free.

Mikael

--
Mikael Ejberg Pedersen
http://www.ejberg.dk
Reply to
Mikael Ejberg Pedersen

Hmmm, I've never used the ATmega8, but the PIC MCUs don't suffer from this. They have zero jitter (for internally-generated interrupts). It doesn't mater what instruction is being executed at the time of the interrupt (either 1-cycle or 2-cycle instructions will generate the same latency as the PIC automatically compensates for the difference). For external (unsynchronized) interrupts the jitter is exactly 1 cycle (the minimum possible - can't be avoided).

--
Regards,
Costas
_________________________________________________
Costas Vlachos  Email: c-X-vlachos@hot-X-mail.com
SPAM-TRAPPED: Please remove "-X-" before replying
Reply to
Costas Vlachos

Exactly. If you want to solve this in a general case where you can't control what you're doing in the main loop, you could define an additional compare match interrupt. For instance, if you're using match A to update the VGA output at a certain time, you can define a match B timer interrupt that goes off a few cycles before A. In the match B ISR, you reenable the interrupts, and do a sleep instruction (you'll have to save state to allow reentrant interrupts).

This can even be modified to allow for other interrupts, as long as they are short, and can be stalled for a while. To do this, make the gap between match A and match B bigger than the worst case timing for other interrupts. In match B, disable all interrupts except match A, and sleep. After handling the match A interrupt, reenable the other(s).

Reply to
Arlet

I don't remember what the ATmega8's capabilities are (yes, I'm lazy) - but the "best" way to solve this sort of problem is to use a programmable capture/compare output that toggles the I/O line at the exact clock edge you selected, _then_ calls the interrupt, wherein you reprogram the CCR for the next desired edge. It's basically a (complicated) PWM application, after all.

Reply to
larwe

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.