Problem with OCR3x on a M128

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

Guyzz

I have a Olimex mt-128 board
http://www.olimex.com/dev/images...

And i'm trying to generate a 4-Khz buzzersignal , similar to this

The Buzzer is connected to =C3B & OC3C on the M128 , probably to get a "double swing" when driving the square , in opposite phases.

void BUZZER(void)
{
	while (B4==0)
    {
      	bit_clear(PORTE,BUZZ1);			//250us
      	bit_set(PORTE,BUZZ2);
      	delay_us(125);
      	bit_clear(PORTE,BUZZ2);			//250us
      	bit_set(PORTE,BUZZ1);
      	delay_us(125);
    }
} 

But i would like to use CTC to generate the square signal , but have some problems getting the buzzer to say anything.

I have a One second timer in the stop_buzzer (and it should stop the OCRxx after that time) , and i can hear a faint "click" in the buzzer every second , but no "beep".

The Xtal is 16 Mhz , and it's one of my first try's with a M128.

Can anyone give a hint ???

I must admit i haven't had a scope on yet ...

#define		T3_LOOP_125NS			(uint16_t )(((F_CPU/T3_PRESCALER) / (1000000/125)) + 0.5)

uint8_t start_buzzer(void)
{
	uint8_t sreg;
	
	//
	// Buzzer CTC Mode OC3A not used , OC3B & 0C3C Toggled (Timer3)
	//

	//
	// Mode CTC , Prescaler None , Stop Timer
	//
	TCCR3B= ((0<<ICNC3) | (0<<ICES3) | (0<<0) | (0<<WGM33) | (1<<WGM32) | (0<<CS32) | (0<<CS31) | (0<<CS30));

	//
	// Disconnect OCR3A , Toggle OCR3B & OCR3C
	//
	TCCR3A = ((0<<COM3A1) | (0<<COM3A0) | (0<<COM3B1) | (1<<COM3B0) | (0<<COM3C1) | (1<<COM3C0) | (0<<WGM31) | (0<<WGM30)); 

	//
	// Force Output compare on OC3B , to make a toggle , and make sure it is the opposite of OC3C
	//
	TCCR3C=((0<<FOC3A) | (1<<FOC3B) | (1<<FOC3C) | (0<<0) | (0<<0) | (0<<0) | (0<<0) | (0<<0));
	
	//Make these writes atomic
	sreg = SREG;
	asm("cli"); 
	TCNT3 = 0;
	OCR3B = T3_LOOP_125NS - 1;								// My Freq counter shows more accuracy when i match on 
	OCR3C = T3_LOOP_125NS - 1;								// My Freq counter shows more accuracy when i match on 
															// one less than the calculated counter value thats why i use the -1
	SREG = sreg;


	//TIMSK = (1<<OCIE0); 								// Enable CTC0 Interrupt
	//
	// Mode CTC , Prescaler 8 , Start Timer
	//
	TCCR3B= ((0<<ICNC3) | (0<<ICES3) | (0<<0) | (0<<WGM33) | (1<<WGM32) | (0<<CS32) | (1<<CS31) | (0<<CS30));
	stop_buzzer(ON);
	return(ON);
}

uint8_t stop_buzzer(uint8_t state)
{
	static uint16_t timer, buzzer;
	
	
	if(state == ON)
	{
		timer = 0;
		buzzer = ON;
	}
	
	if(buzzer == ON)
	{
		if(inttimerreached(&timer,(1 * ONE_SECOND)))
		{
			buzzer = OFF;
			//
			// Mode CTC , Prescaler None , Stop Timer
			//
			TCCR3B= ((0<<ICNC3) | (0<<ICES3) | (0<<0) | (0<<WGM33) | (1<<WGM32) | (0<<CS32) | (0<<CS31) | (0<<CS30));
		
			//
			// Disconnect OCR3A , OCR3B & OCR3C
			//
			TCCR3A = ((0<<COM3A1) | (0<<COM3A0) | (0<<COM3B1) | (0<<COM3B0) | (0<<COM3C1) | (0<<COM3C0) | (0<<WGM31) | (0<<WGM30)); 

		}
	}
	return(buzzer);
}

/Bingo
[/code]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
TCCR3C=((0<<FOC3A) | (1<<FOC3B) | (1<<FOC3C) 

This will cause both of OC3B/C to toggle, i.e. in the same direction, so
they're still identical. The "proper" way to do the setup is to set the COM
bits to Set one and Clear the other, then use FOC on both to put the OC3B/C
registers in a known state. In this particular application, it's enough to FOC one
of them once (using "toggle") after which they'll always be opposites even
if you stop and restart the timer.

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

mckenney wrote:

TCCR3C=((0<<FOC3A) | (1<<FOC3B) | (1<<FOC3C) 

This will cause both of OC3B/C to toggle, i.e. in the same direction, so
they're still identical. The "proper" way to do the setup is to set the COM
bits to Set one and Clear the other, then use FOC on both to put the OC3B/C
registers in a known state. In this particular application, it's enough to FOC one
of them once (using "toggle") after which they'll always be opposites even
if you stop and restart the timer.

I did discover that "goofer" where i did toggle both of them , but it didnt help , just setting FOC3B :-( .

But i'll try to write a 1 to OCR3B and a Zero to OCR3C.

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

Damm

Still cant make a single "beep" :-(

/Bingo

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

Are you setting OCR3A anywhere? I don't see it.

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

mckenney wrote:
Are you setting OCR3A anywhere? I don't see it.

No i'm not , i don't use OCR3A , just 3B & 3C

But should i still set OCR3A register ??

/Bingo

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

Hmmmm

It's "alive" :?: :?: :?: (Yipieee)

Why the /&"#¤%#"/" does OCR3A have anything to do with 3B & 3C

/Bingo

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

OCR3A says how high TCNT3 counts in CTC mode. For your purposes,
just set it the same as OCR3B/C.

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

Thnx mckenny.....

So OCR3A should always be >= 3B & 3C or TCNT3 would reset before those are triggered , and they will never be reached or ????

Scary stuff :-)

/Bingo

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

Here is the working code , just for completion

I did make a init_busser() routine where everything is setup

Then all i do is enable or disable the prescaler , to start & stop the buzzer

void init_buzzer(void)
{
	uint8_t sreg;
	
	//
	// Buzzer CTC Mode OC3A not used , OC3B & 0C3C Toggled (Timer3)
	//

	//
	// Mode CTC , Prescaler None , Stop Timer
	//
	TCCR3B= ((0<<ICNC3) | (0<<ICES3) | (0<<0) | (0<<WGM33) | (1<<WGM32) | (0<<CS32) | (0<<CS31) | (0<<CS30));

	//
	// Disconnect OCR3A , Toggle OCR3B & OCR3C
	//
	TCCR3A = ((0<<COM3A1) | (0<<COM3A0) | (0<<COM3B1) | (1<<COM3B0) | (0<<COM3C1) | (1<<COM3C0) | (0<<WGM31) | (0<<WGM30)); 

	//
	// Force Output compare on OC3B , to make a toggle , and make sure it is the opposite of OC3C
	//
	TCCR3C = ((0<<FOC3A) | (1<<FOC3B) | (0<<FOC3C) | (0<<0) | (0<<0) | (0<<0) | (0<<0) | (0<<0));
	
	//Make these writes atomic
	sreg = SREG;
	asm("cli"); 
	OCR3A = T3_LOOP_125NS - 1;								// My Freq counter shows more accuracy when i match on 
	OCR3B = T3_LOOP_125NS - 1;								// My Freq counter shows more accuracy when i match on 
	OCR3C = T3_LOOP_125NS - 1;								// My Freq counter shows more accuracy when i match on 
															// one less than the calculated counter value thats why i use the -1
	TCNT3 = 0;
	SREG = sreg;
}


uint8_t start_buzzer(void)
{//
	// Mode CTC , Prescaler 8 , Start Timer
	//
	TCCR3B = ((0<<ICNC3) | (0<<ICES3) | (0<<0) | (0<<WGM33) | (1<<WGM32) | (0<<CS32) | (1<<CS31) | (0<<CS30));

	stop_buzzer(ON);
	return(ON);
}

uint8_t stop_buzzer(uint8_t state)
{
	static uint16_t timer, buzzer;
	
	
	if(state == ON)
	{
		timer = 0;
		buzzer = ON;
	}
	
	if(buzzer == ON)
	{
		if(inttimerreached(&timer,(1 * ONE_SECOND)))
		{
			buzzer = OFF;
			//
			// Mode CTC , Prescaler None , Stop Timer
			//
			TCCR3B= ((0<<ICNC3) | (0<<ICES3) | (0<<0) | (0<<WGM33) | (1<<WGM32) | (0<<CS32) | (0<<CS31) | (0<<CS30));
		}
	}
	return(buzzer);
}

/Bingo

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

Hi,

Quote:
// My Freq counter shows more accuracy when i match on one less than the calculated counter value thats why i use the -1

Not sure about the mega128 but the mega169 indicates that the compare match doesn't trigger the interrupt until the first timer clock cycle >after< the match. I had a similar question here on the Freaks a couple of days ago. I wasn't sure if I was understanding that part correctly but Lee solidified that idea for me ( I think :-) ). Sorry if I am stating the obvious for you. It >seemed< the above comment in your code indicated you weren't sure of the reason for the -1.

Regards,
Steve

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

SteveN wrote:
Hi,

Quote:
// My Freq counter shows more accuracy when i match on one less than the calculated counter value thats why i use the -1

Not sure about the mega128 but the mega169 indicates that the compare match doesn't trigger the interrupt until the first timer clock cycle >after< the match. I had a similar question here on the Freaks a couple of days ago. I wasn't sure if I was understanding that part correctly but Lee solidified that idea for me ( I think :-) ). Sorry if I am stating the obvious for you. It >seemed< the above comment in your code indicated you weren't sure of the reason for the -1.

Regards,
Steve

Thanx Steve

I wasn't sure why , but just followed the freq counter.
Now i know why.

/Bingo

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

Actually, this helps me even more...because I don't have a frequency counter :-). Thanks! :-)

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

Bingo600 wrote:
Thnx mckenny.....

So OCR3A should always be >= 3B & 3C or TCNT3 would reset before those are triggered , and they will never be reached or ????

Scary stuff :-)

/Bingo

Any comments on this ???

/Bingo

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

Yes, that's correct -- if TCNT3 never reaches the OCR3B/C values, their
events will never trigger. (And setting/leaving OCR3A=0 pretty much
assures that (:-)).)

In your application (50% duty square wave), there's no reason OCR3A couldn't
do double-duty as the CTC TOP and a pin-driver, but it sounds as though you've
already done your pin assignments.

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

Is this the appropriate section of the datasheet to explain the OCR3A question?

Quote:

Clear Timer on Compare
Match (CTC) Mode

In Clear Timer on Compare or CTC mode (WGMn3:0 = 4 or 12), the OCRnA or ICRn
Register are used to manipulate the counter resolution. In CTC mode the counter is
cleared to zero when the counter value (TCNTn) matches either the OCRnA (WGMn3:0
= 4) or the ICRn (WGMn3:0 = 12). The OCRnA or ICRn define the top value for the
counter, hence also its resolution
.

I apologize if I am misunderstanding the question.

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

mckenney wrote:
Yes, that's correct -- if TCNT3 never reaches the OCR3B/C values, their
events will never trigger. (And setting/leaving OCR3A=0 pretty much
assures that (:-)).)

In your application (50% duty square wave), there's no reason OCR3A couldn't
do double-duty as the CTC TOP and a pin-driver, but it sounds as though you've
already done your pin assignments.

@mckenny
Well Olimex chose for me :-(

@SteveN
I would say that this is the correct section , and i did even read that But discarded it as i didn't use OCR3A , i never thought that they (3B & 3C) would be dependant on 3A.

Thanx guyzz

/Bingo

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

Quote:
@SteveN
I would say that this is the correct section , and i did even read that But discarded it as i didn't use OCR3A , i never thought that they (3B & 3C) would be dependant on 3A

I wouldn't have either. I only found it because of the question you asked. It was quitting time so I didn't have the opportunity to look further in the mega128 datasheet. I am curious now if it says the 3B and 3C are dependant. I will look tomorrow when I get back to work. Although, on second thought, I am sure you looked thoroughly so I am probably wasting my time.

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

SteveN wrote:
I am curious now if it says the 3B and 3C are dependant.

Using the new 03/06 ATmega128 data sheet look on page 135 Table 61 Waveform Generation Mode Bit Description. The WGM33 through WGM30 bits only have WGM32 set, so it is mode 4 on timer 3. Looking to the right on the mode 4 line under the TOP column shows OCR3A as setting the TOP value (for timer/counter 3 OCRnA is OCR3A). The entire timer/counter 3 CTC operation depends on OCR3A (TOP) being set to a non-zero value.

Now if you look at page 138 Output Compare Register 3 A – OCR3AH and OCR3AL you can see the initial value is zero. So, if you do not set OCR3A to a non-zero TOP value, timer/counter 3 will get very confused. The program is trying to count up to zero and then clear itself back to zero when TOP = zero. No wonder it did not work.

The thing is the data sheet only shows or talks about pin OC3A being used in the CTC mode. No mention was made of OC3B or OC3C (page 123 Clear Timer on Compare Match (CTC) Mode). However the page 133 Table 58 Compare Output Mode, non-PWM makes it clear you can also use the OC3B or OC3C pins (if timer/counter 3 is already running correctly, you set a valid compare value and you remember to set the pins as output pins with the DDR).

BTW, if you want OC3B and OC3C to be opposite then shouldn't you do this instead:

TCCR3C=((0<<FOC3A) | (1<<FOC3B) | (0<<FOC3C)
or
TCCR3C=((0<<FOC3A) | (0<<FOC3B) | (1<<FOC3C)
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Mike B wrote:

BTW, if you want OC3B and OC3C to be opposite then shouldn't you do this instead:

TCCR3C=((0<<FOC3A) | (1<<FOC3B) | (0<<FOC3C)
or
TCCR3C=((0<<FOC3A) | (0<<FOC3B) | (1<<FOC3C)

I have corrected that in the last code snippet :-)

There was another little "teaser" ...

At frst i did not do a "init buzzer" , but just the full_buzzer as from the top.
That made the buzzer work each 2'nd time i pressed a button.

I found out that i did the (1<<FOC3B) , but i did it again every time , meaning that each 2'nd time i had the 2 timers running in phase (2 toggles = No toggles) , so it was creating absolutely no buzz.

/Bingo

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

Quote:

... meaning that each 2'nd time i had the 2 timers running in phase (2 toggles = No toggles) , so it was creating absolutely no buzz.

It sounds like a "feature"--adding a toggle on/off at no extra expense. ;)

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.