question about the phase reverse of square wave by Timer2

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

Hi, everyone,

I have a problem about phase reverse by Timer2 in 8MHz Meag128L.
I want to generate a 40KHz square wave and sometimes reverse its phase, for example, the waveform can be like:
10101010101010101010101010100101010101010101.........
bold area is the phase shift, and I want this phase reverse happened at any time, which means it can either be 010010 or 101101. Every 1 and 0 are 200 clock cycles for 8MHz crystal.
My old method for this problem is set Timer2 in CTC mode and set OCR2 = 199, which is 40KHz and toggle OC2. and in CTC interrupt, I always use a variable to remember the output value of OC2, because when I want to do the phase reverse, I have to know the current value of OC2 and then set PORTB7 to that value and then disconnect OC2, and in the next CTC interrupt I connect OC2 again to let it toggle, so that I can have a 180 degree of phase shift.
But the problem with this method is it comsum too many calculation resources. Every 200 system clock cycles I will run this interrupt once and it take at least 15 clock cycles to finish and jump back, it's just too much for doing such a small thing.
So can you tell me some better way to do it so that it can use less calculation power?

Thanks

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

Interesting question. If you were using a newer AVR with the "toggle output by writing 1 to PINx" feature, then you would not need to "remember" the state.

I believe that even though you have no control over PORTx.y when you are using the CTC, you can still read PINx.y and then do the toggle. That way you would not need to remember, and only incur a many-instruction overhead when you actually need to change the phase.

You could put an external gate to do the inversion, triggered by another I/O pin.

If the numbers were just a little different, I'd suggest using one of the programmable 16-bit timers and use a PWM mode. Then COM__ bits tell whether normal or inverted PWM and I think (without testing) that all you would have to do is change the COM__ bit(s) on the fly to change phase. But I can't think of a combination to get 40kHz out of 8MHz with PWM.

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.

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

OK, I >>can<< think of a way--I was stuck on the programmable PWM being a number of bits, but it really is a programmable TOP. So you'd set TOP to probably 399 or 400 and the OCR to 199 or 200 depending on the mode. Again you would only incur a processor penalty when the inversion is needed. (If there was nothing else to do in the ISR it could even be disabled unless the change was needed.

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.

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

Thank you, Lee.
PINB7 indeed store the current value of output of OC2, so I don't need to always run the interrupt anymore. When I want to reverse the phase, I enable the interrupt and in the ISR, I make it run just twice and then disable ISR by itself. So now it's much better, and I still just use CTC mode of Timer2.
But there is another problem now. I use portable USB DigiView Analyzer to check the output waveform, you can find it on www.tech-tools.com.
and sometimes I will got a short spike in the the stage of phase shift. So I thought it might be my code problem, I have included the C code below.
Can you check for me?

Attachment(s): 

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

I think you have a synchronization problem which may be hard to fix, since your foreground code is a simple for(...) loop. Even if you synch the foreground timing to the interrupt, you will still get a bit of a glitch, or jitter, sinve the automatic toggling of the output will occur slightly earlier than the programmed I/O reversal. If I were you I would either:
a) Use some external hardware to accomplish the phase inversion AND synchronization.
or
b) Always use the interrupt service routine to do the toggling/toggling making sure the cycle times were the same for both, while being as short as possible.

However, depending on the overall picture, there could be a differnt solution, whereby you could read the port status or maybe use another timer to achieve the synching. Or have a minimal ISR running at all times which just decrements a counter.

BTW, I think The Usch was suggesting using the "clear on x, set on y" mode for the counter timer, switching to "set on x clear on y"; rather than the "toggle on x" mode, and I think he is right in this, but you still need the foreground task to be synchronized, or you will get glitch/jitter problems.

Four legs good, two legs bad, three legs stable.

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

Quote:

BTW, I think The Usch was suggesting using the "clear on x, set on y" mode for the counter timer, switching to "set on x clear on y"; rather than the "toggle on x" mode, and I think he is right in this, but you still need the foreground task to be synchronized, or you will get glitch/jitter problems.

Actually, I was thinking of the canned PWM modes, like Fast PWM. The output can be "non-inverted" or "inverted". Even using the overflow or compare match interrupts there is still the chance of the glitch when you change phase.

There are a lot of combinations possible when "chaning phase" and what you/your app call a glitch or bad. Without that spec it is hard to comment further. My thought was to interrupt on compare match or overflow, then spin right there till the signal is in the correct postion and TCNTn is where it needs to be, then swtich the PWM sense.

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.

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

Hi,
I got it working now and there is no glitch at the output, since I have checked it by Digiview. But the problem still is I need to use a variable to keep tracking on the current output value of OC2, and it just waste too many clocks, and I don't want to physically connect OC2 to another I/O to check. So is there any other way to keep tracking on OC2 value by Mega128's hardware?

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

Here is the code which is working

Attachment(s): 

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

Quote:
got it working now and there is no glitch at the output,

I don't understand how this can be true. Surely the PWM hardware has already toggled OC2 before your ISR gets to the point where it reverses the phase? May only be a few microseconds, may not matter, but I'm pretty sure there must be a glitch.
Can you not read PINB bit 7 to determine the current state(subject to the synch delay)? The circuit indicates that reading PINB will always return the actual state of the pin, regardless of whether it is set via programmed I/O or PWM hardware.

Four legs good, two legs bad, three legs stable.

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

Can you not use the compare output mode, fast PWM modes descibed below:

Clear OCnA/OCnB/OCnC on Compare Match, set OCnA/OCnB/OCnC at TOP.

Set OCnA/OCnB/OCnC on Compare Match, clear OCnA/OCnB/OCnC at TOP.

(Copied from the Mega64 datasheet page 133 table 59)

and switch between the two? This is what I thought(wrongly) that The Usch was suggesting.

Four legs good, two legs bad, three legs stable.

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

John, I'm sure I didn't get glitch, cos the Digiview is running at 100MHz, and I can't use other mode except for CTC, cos other mode will reach MAX instead of TOP, and I need a true square wave with 50% duty cycle, be sides, my CPU is Mega128L. So maybe Mega64 will reach TOP instead of MAX.

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

I think you will find that the Mega64 and the Mega128 are similar in regards to the PWM modes. My reading of the datasheet is that the counter gos from BOTTOM to TOP(which is programmable), so I think a true square wave is obtainable.
Anyway, if you say you have no glitches then fine.

Four legs good, two legs bad, three legs stable.

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

Hi, I got it working with Timer1's Fast PWM mode now, it's really very easy, just change the COM1C0 bit and it will do the phase reverse automatically.

Thank you guys for your advice.

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

Great!
Care to post your code, so that others might benefit?

Four legs good, two legs bad, three legs stable.

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

yes, the following code do the job, in a very easy way!!!!

TCCR1A = _BV(COM1C1) | _BV(WGM11); // set Timer1 in Fast PWM mode and output pin is OC1C

OCR1C = (F_CPU/80000) - 1; // set duty cycle to 50%

ICR1 = (F_CPU/40000) - 1; // set square wave frequency to 40KHz

TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // start Timer/Counter1 in Fast PWM mode, clk/1 as prescaler

TCCR1A ^= _BV(COM1C0); // reverse the phase