Symmetric (Complementary) square wave outputs

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

Is there an easy way of generating symmetric outputs from a timer on a Mega168? I'm using timer0 at ctc mode to generate a symmetric 100 kHz output at OC0A and OC0B.

I just can't think of a better way than the one below, but even this one is showing a 1 cycle (125 ns @ 8MHz) overlap on both edges. Why are the outputs being updated 1 cycle apart?

#include 

int main (void)
{
	// OC0A and OC0B as outputs;
	DDRD = (1<<PD5) | (1<<PD6);

	// Setup Timer 0 for CTC @ 100 khz at OC0A
	OCR0A  = 39;
	TCCR0A = (1<<COM0A0) | (1<<WGM01);

	// Clear interrupt flags
	TIFR0  = 0x00;

	// Start timer0
	TCCR0B = (1<<CS00);

	// wait for the first toggle of OC0A to enable toogle OC0B
	while( !(TIFR0 & (1<<OCF0A)) );
	TCCR0A |= (1<<COM0B0);
	
	while(1);
}

Attachment(s): 

Felipe Maimon

Last Edited: Sun. Jan 31, 2010 - 01:42 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The B output has it's own compare register, it will not toggle in unison with the A output. The B compare register is likely still 0, and B toggles when TCNT=0 while A toggles when TCNT=39.

I'm fairly sure adding OCR0B=39; fixes it.

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

Thank you! You nailed it. Forgot completely of OCR0B :oops:

Anyway. Is there any other way to get symmetric outputs without having to wait for OC0A to trigger before enabling OC0B?

Felipe Maimon

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

Use the force... first set compare mode for ch A to 'low at compare match', ch B to 'high at compare match'. Then set the FOC0A and FOC0B bits in TCCR0B and set both compare modes back to toggle. That should do it.

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

Some AVR models have symmetric complementary outputs, with or without dead-time generation. Could you use one of those models?

Quote:

Is there any other way to get symmetric outputs without having to wait for OC0A to trigger before enabling OC0B?

I don't understand what you are saying. If you are going to use a timer on (say) the Mega168 to generate complementary outputs (is that what you mean by "symmetric"?) then you set up two compare channels the same way and one will have the inverse trigger.

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.

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

If you use toggle mode for a compare match, the output might be in a wrong state, you might end up with both output not being each others inverse. This is what the force compare strobe bits are for. You can set the initial state exactly as you want before enabling everything.

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

theusch wrote:
Some AVR models have symmetric complementary outputs, with or without dead-time generation. Could you use one of those models?

I'm just using what I have. The only ones with complementary outputs I have is the tiny45, but it has fewer pins than I need, and I don't want to use one just to generate the outputs...

theusch wrote:
Quote:

Is there any other way to get symmetric outputs without having to wait for OC0A to trigger before enabling OC0B?

I don't understand what you are saying. If you are going to use a timer on (say) the Mega168 to generate complementary outputs (is that what you mean by "symmetric"?) then you set up two compare channels the same way and one will have the inverse trigger.

I'm just asking if there is a better way to do it without having to do it like this:

   // wait for the first toggle of OC0A to enable toogle OC0B
   while( !(TIFR0 & (1<<OCF0A)) );
   TCCR0A |= (1<<COM0B0);

Full code is in the first post...

Felipe Maimon

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

jayjay1974 wrote:
If you use toggle mode for a compare match, the output might be in a wrong state, you might end up with both output not being each others inverse. This is what the force compare strobe bits are for. You can set the initial state exactly as you want before enabling everything.

Just did that. Thank you again.

#include 

int main (void)
{
	// OC0A and OC0B as outputs;
	DDRD = (1<<PD5) | (1<<PD6);

	// Setup Timer 0 for CTC @ 100 khz
	// OC0A to set on match and OC0 to clear -> setup initial states
	OCR0A  = 39;
	OCR0B  = 39;
	TCCR0A = (1<<COM0A0) | (1<<COM0A1) | (1<<COM0B1) | (1<<WGM01);
	TCCR0B = (1<<FOC0A) | (1<<FOC0B);
	
	// OC0A and OC0B to toggle
	TCCR0A = (1<<COM0A0) | (1<<COM0B0) | (1<<WGM01);

	// Start timer0
	TCCR0B = (1<<CS00);

	while(1);
}

Felipe Maimon

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

Quote:

I'm just asking if there is a better way to do it without having to do it like this:

Now jayjay probably has the "right" answer, but if you have your timer stopped, and the pins disconnected, and you set the two outputs to complementary values, and you clear TCNT, and you set the two OCRs to the same value, and you set the timer for Fast PWM and one channel inverted and the other normal, and then you connect the pins and start the timer (whew--but one does all the steps anyway) -- aren't you going to get the desired behaviour without any "waiting"?

And wouldn't it work also with CTC and toggle-on-compare-match?

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.

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

The compare unit has a separate flipflop to store the current output state. On a match a different FF is toggled, not the normal port one. Figure 31 in the m48 datasheet.

So setting the output using PORT to the desired initial state, then enabling toggle-on-compare might not work as a different flipflip is muxed to the output pin. Using force compare match initialises the right flipflop; the one of the compare unit.

But getting complementary outputs should work with fast PWM as you describe. The initial state does not matter then because they are 'hard' set during the complete PWM cycle, not merely toggled.

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

Felipe, is this topic related to adding ESR measurement to your Elmcie ?

Nard

A GIF is worth a thousend words   They are called Rosa, Sylvia, Tricia, and Ulyana. You can find them https://www.linuxmint.com/

Dragon broken ? http://aplomb.nl/TechStuff/Dragon/Dragon.html for how-to-fix tips

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

Plons wrote:
Felipe, is this topic related to adding ESR measurement to your Elmcie ?

It is in the firsts stages of planning, but yes.

I'm doing it with another mega168, but I'll integrate it in the future in my Elmcie. Probably with it's own PCB! :D

Felipe Maimon

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

theusch wrote:
Now jayjay probably has the "right" answer, but if you have your timer stopped, and the pins disconnected, and you set the two outputs to complementary values, and you clear TCNT, and you set the two OCRs to the same value, and you set the timer for Fast PWM and one channel inverted and the other normal, and then you connect the pins and start the timer (whew--but one does all the steps anyway) -- aren't you going to get the desired behaviour without any "waiting"?

And wouldn't it work also with CTC and toggle-on-compare-match?

Looks like jayjay method is easier...

But setting the initial state by writting to the PORT doesn't work. It was my first try, before noticing in the datasheet that the compare match uses a different flip-flop.

Felipe Maimon

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

Quote:

Looks like jayjay method is easier...

OK, I'll bite: List the "hard" parts of my method. Control registers A & B, count register(s), and compare register(s) are set in any case.

So, for the CTC case is setting the outputs to the desired state harder than messing with FOC bits? How is that?

For the PWM case, how is selecting inverted PWM for one channel "harder" than FOC?

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.

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

theusch wrote:
Quote:

Looks like jayjay method is easier...

OK, I'll bite: List the "hard" parts of my method. Control registers A & B, count register(s), and compare register(s) are set in any case.

So, for the CTC case is setting the outputs to the desired state harder than messing with FOC bits? How is that?

For the PWM case, how is selecting inverted PWM for one channel "harder" than FOC?

Easier to understand, not to do it, at least reading your description in your previous post. Reading it lead me to believe that enabling PWM mode was necessary to create the complementary outputs before changing to CTC.

I've used the CTC method, as you can see in the code of my previous post. This is the one described jayjay.

For PWM, you missed the 100 kHz part of my requirements. You just can't do it and generate 2 complementary outputs, as you need OCR0A to use it as TOP, so only OC0B is generating anything.

Felipe Maimon

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

Quote:

For PWM, you missed the 100 kHz part of my requirements. You just can't do it and generate 2 complementary outputs, as you need OCR0A to use it as TOP, so only OC0B is generating anything.

As I mentioned, when you boil it down it involves setting the timer registers. Those are done in any case.

First "requirement" was a Mega168. Going on, timer0 was used--I didn't realize that "requirement"; of course with timer1 there is more flexibility.

So we want a Fast PWM mode such that 128 clock ticks is 5 milliseconds. (Well, 256 have to be 10 milliseconds; if we ended up with a 48%/52% duty cycle noone will probably be upset.)

OK, so that means we need a clock tick at 25600 Hz. There are prescalers on timer0 of /1 /8 /64 /256 and /1024.

That would mean a main clock speed of 25kHz, 204 kHz, 1.6384 MHz, 6.5536 MHz, or 16 MHz. 6.5536 MHz sounds good...

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.

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

theusch wrote:
First "requirement" was a Mega168. Going on, timer0 was used--I didn't realize that "requirement"; of course with timer1 there is more flexibility.

So we want a Fast PWM mode such that 128 clock ticks is 5 milliseconds. (Well, 256 have to be 10 milliseconds; if we ended up with a 48%/52% duty cycle noone will probably be upset.)

OK, so that means we need a clock tick at 25600 Hz. There are prescalers on timer0 of /1 /8 /64 /256 and /1024.

That would mean a main clock speed of 25kHz, 204 kHz, 1.6384 MHz, 6.5536 MHz, or 16 MHz. 6.5536 MHz sounds good...

It's 100 kHz, not Hz. The maximum frequency that you can get using full resolution, ie OCR0A free to generate it's square wave, even with a 20 MHz crystal (I'm using the 8 MHz internal RC), is about 78 kHz. Still below what I want...

Felipe Maimon

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

I've only just looked at this thread, but why not simply run a timer in CTC mode and have the isr toggle two port pins by writing 1's to the PIN register? Obviously, set the two port bits to opposite states initially. Granted, it requires the isr to work, but that's not too many cycles.

Roger

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

laserman wrote:
I've only just looked at this thread, but why not simply run a timer in CTC mode and have the isr toggle two port pins by writing 1's to the PIN register? Obviously, set the two port bits to opposite states initially. Granted, it requires the isr to work, but that's not too many cycles.

It is a valid method. At first I've thought in doing just that, buy why waste cycles with an ISR if the hardware can do it for you?

Felipe Maimon

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

Exactly, if you need 100KHz output rate, you need interrupts at 200KHz which sucks up a lot of the processor bandwidth, adds jitter and is totally unnecessary because the timers were invented for exactly this application.