EmbeddedRelated.com
Forums

Improving timing accuracy with ATmega8

Started by Mike Warren October 21, 2006
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<<VSyncFlag)
	cpi	VgaLineL,(FrameSync-1)
	brlo	EndCheckVSync
	cpi	VgaLineH,2
	brne	EndCheckVSync
SetVSync:
	sbr	Flags,(1<<VSyncFlag)	; Prepare to start VSync at next HSync
	dec	VgaBarDly
	brne	EndCheckVSync
	ldi	A,4		; delay (frames) before incrementing barcount
	mov	VgaBarDly,A
	inc	VgaBarCnt
	ldi	A,40		; number of steps in the bar
	cp	VgaBarCnt,A
	brlo	EndCheckVSync
	ldi	A,1
	mov	VgaBarCnt,A
EndCheckVSync:

	dec	VgaLineL
	brne	DrawrBarLineExit
	dec	VgaLineH
	brne	DrawrBarLineExit
NewFrame:
	cbr	Flags,(1<<VSyncFlag)
	ldi	VgaLineH,2	; 1 Frame = 448 lines
	ldi	VgaLineL,FrameSync	; 256 + 192
	rcall	BarTimer	; Check for timeout and auto switch to SBC

DrawrBarLineExit:
	pop	A
	ret

-- 
Mike
On 22 Oct 2006 00:42:33 GMT, "Mike Warren"
<miwa-not-this-bit@or-this-csas.net.au> wrote:

>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:
[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
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
Rich Webb wrote:

> 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.
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
Mike Warren wrote:

> 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
Oops. The second one should be: ldi A,2 ; Timer1(L) ldi B,254 ; Timer1(H) out TCNT1H,B out TCNT1L,A -- Mike
Rich Webb wrote:
> 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.
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
Mike Warren wrote:
> My problem is that there is more jitter (about 2 to 3 cycles) than I > would like. My timer interrupt is this: >
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
Ian Bell wrote:

> 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.
Yes, I have it working acceptably now by not making any rcalls in my main loop when the timer is running. -- Mike
Ian Bell a &#4294967295;crit :
> Mike Warren wrote: >> My problem is that there is more jitter (about 2 to 3 cycles) than I >> would like. My timer interrupt is this: >> > > 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. >
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.
On Sun, 22 Oct 2006 07:37:47 +0100, Ian Bell <ruffrecords@yahoo.co.uk>
wrote:

>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.
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