(solved, thanks) CTC, clear OC0A1 on compare match

Go To Last Post
7 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have found a work around but can't understand why this isn't working the way I think it should(...maybe because it's working the way it was design to work;-). Using AVR Studio and atmega88PA

; initialize timerCounter0
	ldi temp, (1<<wgm01)|(1<<oc0a1)	; clear oc0a1 on compare match, ctc mode
	out tccr0a, temp
	ldi temp, (1<<cs00) ; no prescale on clock
	out tccr0b, temp
	ldi temp, 92     ; about 5 microseconds at 18.432 MHz
	out ocr0a, temp
	
	
	;sei								; enable global interupts

prime:
	ldi temp, (1<<pd6)
	out ddrd, temp
	sbi portd, 6

main:
	rjmp main

I would think that portd pin6 would go high and after the compare match it would go low but "sbi portd, 6" has no affect in this mode. If I set it high before initializing the timer it get's cleared after the timer is initialized. I have tried to simulate it using AVR Simulator 2 and have slowed it down with a prescale of 1024 to see if it works on the STK500 when hooked to an LED (added more code to make it flash) but the I can't seem to get the OCOA pin to go high using this timer mode.

Thanks.

Last Edited: Mon. Sep 6, 2010 - 12:04 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In any timer0 mode setting OC0A1=0 and OC0A0=0 is Normal port operation, OC0A disconnected. This is when:

SBI PORTD, 6

will actually do anything on the port pin. However, you set CTC mode with OC0A1=1 and OC0A0=0 which is Clear OC0A on Compare Match. The PORTD register pin 6 is no longer connected as soon as you set TCCR0A (it became OC0A), so your SBI PORTD that happened after the TCCR0A write has no effect on the OC0A output pin. Try this untested code:

   ldi temp, (1<<wgm01)|(1<<oc0a1)|(1<<oc0a0)   ; OC0A to set on compare match, ctc mode
   out tccr0a, temp
   ldi temp, 92     ; about 5 microseconds at 18.432 MHz
   out ocr0a, temp

   ;sei                        ; enable global interupts

prime:
   ldi temp, (1<<pd6)
   out ddrd, temp
   ldi temp, (1<<foc0a)|(1<<cs00)   ; force a compare match (set pin 6) and start timer0
   out tccr0b, temp
   ldi temp, (1<<wgm01)|(1<<oc0a1)   ; quickly change OC0A to clear on compare match, ctc mode
   out tccr0a, temp

main:
   rjmp main
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
    ldi temp, (1<<wgm01)|(1<<oc0a1)   ; clear oc0a1 on compare match, ctc mode

OC0A1 is NOT a bit in TCCR0A. I would be very surprised if the assembler did not choke on this.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

(1<<ocoa1) should be (1<<com0a1). That's how I had it in the original code, messed it up after posting it over here. Thanks for pointing that out.

Mike B, I get what you're saying with your code. Thanks for the help. Here is the code that works.

.include "m88def.inc"
.def temp = r16
.equ Tpulse = 25

.org 0x00
.cseg
rjmp reset

reset:
	; set portd pin6 as an output
	ldi temp, (1<<pd6)
	out ddrd, temp

	; ctc, set oc0a on compare match
	ldi temp, (1<<com0a0)|(1<<com0a1)|(1<<wgm01)
	out tccr0a, temp
	
	; set output compareA to desired time
	ldi temp, Tpulse
	out ocr0a, temp	

	; no prescale, force output compare
	ldi temp, (1<<foc0a)|(1<<cs00)
	out tccr0b, temp
	
	; quickly switch to clear oc0a on compare match
	ldi temp, (1<<com0a1)|(1<<wgm01)
	out tccr0a, temp

main:
	rjmp main

So, you have to 'force an output compare' while in 'set oc0a on compare match' to drive the pin high then change to 'clear oc0a on compare match' to drive the pin low on compare match.

Thanks again.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

That's how I had it in the original code, messed it up after posting it over here.

Why do you waste people's time by not posting the original code?!? Have you never heard of Ctrl-C/Ctrl-V ?

Moderator

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry. I did use Ctrl-C/Ctrl-L. When I previewed the code the comments made the code harder to read so I tried to shorten them. I deleted some of the code and retyped it. I will better check my work next time.

Thank you.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ya got me. Well I did say it was untested :)!

This variation (partial code shown) allows slightly smaller ocr0a values and prevents any interrupt responses from interfering with the required OC0A change

.def temp2 = r17

	; no prescale, force output compare in non-PWM mode only
	ldi temp, (1<<foc0a)|(1<<cs00)
	; switch to clear oc0a on compare match
	ldi temp2, (1<<com0a1)|(1<<wgm01)
	cli			; if interrupts are used, disable them
	out tccr0b, temp	; set OC0A
	out tccr0a, temp2	; make the change quickly as possible
	sei			; if used, re-enable interrupts