Yahoo Groups archive

AVR-Chat

Index last updated: 2026-04-28 22:41 UTC

Message

Re: [AVR-Chat] Re: documentation of timer interrupts vs bugs

2005-04-21 by David Kelly

On Thu, Apr 21, 2005 at 12:49:10PM -0700, Dave Hylands wrote:
> 
> Hi David,
> 
> > Then when the interrupt is serviced it is cleared by the CPU back to
> > zero.  BTW, the docs do not say precisely WHEN during the interrupt
> > service routine....  Anyway,  the docs say repeatedly that the flag
> > can be cleared by the user BY WRITING A 1 TO THE FLAG REGISTER.  I
> > have not tried this in real life, but I would have expected that the
> > SW should write a zero to the register.  But apparently writing a 1
> > to the register that already has a 1 will reset the 1.....
> 
> The reason that writing a 1 to it clears it is because if you write a
> 1 to some other bit in the same register, you're writing a zero to all
> of the other bits.

Believe it was Tony who wrote the >> quoted section above.

As for myself we're talking too much in generalities and no enough
specifics. So here is real code:

SIGNAL( SIG_INPUT_CAPTURE3 )
{
	//  Toggle edge sensitivity in preparation for next IRQ.
	//  Manual states this should be done early in this routine.
	//  Note toggling it here inverts the meaning of relay_dir.
	TCCR3B ^= (1<<ICES3);
	
	if( relay_cnt && ((TCCR3B & (1<<ICES3)) == relay_dir) ) {
		RELAY_DRIVE_P |= RELAY_DRIVE_B;	//  drive triac gate
		ETIFR  |= (1<<OCF3B);	//  clear pending, just in case
		ETIMSK |= (1<<OCIE3B);	//  enable OC3B
		TCNT3 = 0;		//  unstick timer
		relay_cnt--;
	} else {
		RELAY_DRIVE_P &= ~RELAY_DRIVE_B; //  make sure its off
		ETIMSK &= ~(1<<OCIE3B);
	}
}

SIGNAL( SIG_OUTPUT_COMPARE3B )
{
	RELAY_DRIVE_P &= ~RELAY_DRIVE_B;	//  clear triac gate
	ETIMSK &= ~(1<<OCIE3B);		//  disable myself (OC3B)
}

void
t3_init(void)
{
	RELAY_DRIVE_DDR |= RELAY_DRIVE_B;	//  enable output
	TCCR3A = 0;				//  no OC's connected
	
	//  mode 4, div by 64
	TCCR3B = (1<<WGM32) | (1<<CS31) | (1<<CS30);

	OCR3B = XTAL/64/1000;		//  1/1000th of 1 second
	ETIFR  |= (1<<ICF3);		//  clear any pending IRQ
	ETIMSK |= (1<<TICIE3);		//  enable input capture IRQ
	AC_XC_UTIL_DDR &= ~AC_XC_UTIL_B; //  make sure its an input
}

void
engage_relay(uint8_t onoff)
{
	//  relay direction must be set first, else lockout IRQ when setting
	if( onoff ) {
		relay_dir = 0;			//  rising edge ???
		ac_relay_state = 0;		//  need to verify value
	} else {
		relay_dir = (1<<ICES3);		//  falling edge ???
		ac_relay_state = 1;		//  need to verify value
	}
	relay_cnt = 3;		//  60 Hz, 3 cycles = 50 mS
}

The above isn't complete enough to compile, some external references and
defines are missing. But I think its complete enough to read. If the
"unstick timer" line is removed then SIG_OUTPUT_COMPARE3B is never
called. I don't know how to let TCNT3 free run. Its apparently stopped
in SIG_INPUT_CAPTURE3 as its contents are zero. But writing a zero
starts it counting so that SIG_OUTPUT_COMPARE3B is called when TCNT3
equals OCR3B. Notice I'm writing to a counter, not a control register.

-- 
David Kelly N4HHE, dkelly@HiWAAY.net
========================================================================
Whom computers would destroy, they must first drive mad.

Attachments

Move to quarantaine

This moves the raw source file on disk only. The archive index is not changed automatically, so you still need to run a manual refresh afterward.