Atmega328P Fast PWM OC1A Problem (again)

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

This same issue has been raised in 2017, without a verdict. The original poster seems to have finally assumed that his AVR was damaged. I have tried a few of them, they all behave the same, so damage seems an unlikely cause.

 

The problem is that I do not see how to get fastPWM working on my Atmega328 in mode 15 on OC1A while it works fine on OC1B. Please see program below. My application needs a 38kHz wave for IR transmission, with an interrupt at the end of each pulse. This makes mode 15 logical, because the wave length and the interrupt are then both defined by OCR1A. Note that I could get this to work easily in mode 14 as well, but I am just curious what is going on here, and if I misread something in the datasheet.

 

I have been using OC1B for a while already, which works perfectly fine, but my application now needs two IR transmitters. They are never active at the same time, so I could multiplex Timer 1 on PC1 and PC2. My processor runs at 8 MHz

 

Thanks for any hints,

 

Juul

 

#include <avr/pgmspace.h>

int main()
{    
#if 1
  //Not working, logic analyzer shows a flat PB1
  #define IRTX       PB1
  #define COM1IRTX   COM1A1
#else
  //Working, logic analyzer shows a lively PB2
  #define IRTX       PB2
  #define COM1IRTX   COM1B1
#endif

    PRR    &= ~(1<<PRTIM1);
    
    DDRB    = 0;
    PORTC   = 0;
    DDRB   |=  (1<<IRTX);               // OC1A/B as out, no pullup
    
    TCNT1   = 0;
    TCCR1B  = (1<<CS11);                // Prescale 8
    OCR1A   = 26;                       // Compare Match value.
    OCR1B   = 3 ;                       // Duty cycle
    TCCR1A  = (1<<WGM11) | (1<<WGM10);  // FAST PWM
    TCCR1B |= (1<<WGM13) | (1<<WGM12);  // ........
    TCCR1A |= (1<<COM1IRTX);            // set at BOTTOM, clear at OCR1B
  
    while (1){}
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Maybe I don't understand but how is #if 1 defined?

 

You should post a full program that someone may want to try out.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

To generate the 38kHz carrier, use CTC mode. PWM is not required. Then use another timer to selectively enable/disable the carrier timer. For two transmitters (good luck trying to isolate them!), use external circuitry - eg nand gate or transistor/mosfet to selectively enable/disable each of the tx leds. Other methods might be to use 555 timers to generate the carriers or a gate oscillator.

 

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


That code looks to have made the classic mistake. As far as I can see:

    TCCR1A  = (1<<WGM11) | (1<<WGM10);  // FAST PWM
    TCCR1B |= (1<<WGM13) | (1<<WGM12);  // ........

is selecting Mode 15:

 

 

Well if OCR1A is tied up being used to set TOP (output frequency/period) then it cannot actually be used as an output compare channel as well.

 

As Kartman says use CTC and your problems go away but if you are going to use PWN and want to use A and B (but still have vairable frequency) then use mode 14:

 

 

In this one it is ICR1 that is tied up setting TOP (frequency/period) so both A and B are available as outputs.

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

Kartman wrote:
To generate the 38kHz carrier,
Kartman wrote:
Other methods might be to use 555 timers to generate the carriers or a gate oscillator.

Note that some AVR8 models have provisions for carrier generation.  E.g. Mega128 family:

Output Compare Modulator (OCM1C2)OverviewThe Output Compare Modulator (OCM) allows generation of waveforms modulated with a carrierfrequency. ...

I had a giant stash of datasheets on my work computer before I retired but didn't bring them home, so I can't do the search.  I recall doing this search in the past; perhaps there is a thread.

 

Also "pulse code modulator"?

 

Wasn't there a model (Tiny26?) that had a high-drive pin for IR LED directly?

 

[edit] '328PB has a feature https://www.avrfreaks.net/forum/...

https://www.avrfreaks.net/forum/...

 

https://www.avrfreaks.net/commen...

theusch wrote:
IIRC one of the Tiny models has that feature. Ah, yes---the Tiny28.

...which refers you to https://www.avrfreaks.net/commen...

dkinzer wrote:
The mega64, mega128, mega640, mega1280, mega2560, mega1281, mega2581, AT90USB646, AT90USB647, AT90USB1286, AT90USB1287, AT90CAN32, AT90CAN64 and AT90CAN128 all have a special Output Compare Modulation mode that uses two timers to produce a modulated signal. The OCM mode is automatically enabled when both timers are set to drive the common output compare pin.

 

One could use this feature, for example, to generate the signal to drive an IR emitter for a remote control application. One timer would be set to generate the carrier (often 38KHz) and the other to generate the data.

 

https://www.avrfreaks.net/commen...

 

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.

Last Edited: Wed. Apr 17, 2019 - 12:57 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is the full program. I ran it. Changing #if 1 to #if 0 takes the other case

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

And I already told you in #4 exactly why you see the result you see (OCR1A can't be used for two things at once) so once you fix that (like switching to mode 14) you will find it works.

 

What made you pick mode 15 in the first place anyway - do you REALLY need to vary the PWM frequency as well as the duty cycle?

Last Edited: Wed. Apr 17, 2019 - 03:22 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ah, when my browser refreshed I noticed the other replies:) Thanks for that. Here is a combined answer.

 

This is for an application that I have to build ten or so instances of, so I would like to keep the component count down to not wear out my soldering iron. It also is a low power app, running for a few months on a pair of AA batteries.

For these reasons I try to avoid additional hardware like a 555, or an external demux to switch the OC1B to different IR transmitters. Low power is also the reason that I am not using CTC: I am using a low duty cycle and doing that with CTC would double my interrupt rate.

And apart from all that: the AVR is perfectly capable of doing what I want, and I can get this to work in other ways.  I just like to understand what is happening in this case, also because another poster was mystified by it, so it seems in a more general interest to clear this up.

 

On:

          Well if OCR1A is tied up being used to set TOP (output frequency/period) then it cannot actually be used as an output compare channel as well.

 

I have seen this remark in the data sheet, but could not place what it meant. First, It would hold for OC1B as well, and that mode has always worked fine for me: I am happily using the TIMER1_COMPA interrupt, which works as expected.

Second, when trying to switch to OC1A I can also enable the interrupt, and this interrupt is working at the expected rate, It is just the OC1A output pin that plays dummy. So I concluded that this remark

must have referred to updating OCR1A with the TOP value. This still leaves the silent pin mystery.

 

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

No. Look at your mode table. What registers do you see in the TOP column? Whenever you see a register name (not a fixed value like 0xFF) there then if that register is being used to set frequency it cannot be used for its "normal' function like setting duty. The B register does not appear there. By implication COMPB is always available

Last Edited: Wed. Apr 17, 2019 - 04:06 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here is the mod for using mode 14. Same problem, works for OC1A, flatlines on OC1B:

 

#include "avr/pgmspace.h" 

int main()
{    
#if 1
  //Not working
  #define IRTX       PB1
  #define COM1IRTX   COM1A1
#else
  //Working
  #define IRTX       PB2
  #define COM1IRTX   COM1B1
#endif

    PRR    &= ~(1<<PRTIM1);
    
    DDRB   |=  (1<<IRTX);               // OC1B as out. IR level on
    
    TCNT1   = 0;
    TCCR1B  =  (1<<CS11);               // Prescale 8
    ICR1    = 26;                       // Compare Match value.
    OCR1A   = 26;                       // Compare Match value.
    OCR1B   = 3;                        // Duty cycle
    TCCR1A  = (1<<WGM11);               // FAST PWM
    TCCR1B |= (1<<WGM13) | (1<<WGM12);  // ........
    TCCR1A |= (1<<COM1IRTX);            // set at BOTTOM, clear at ICR1
  
    while (1) {  }
}
 

 

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

Shouldn't it be OCR1A = 3?

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

carmel wrote:

    ICR1    = 26;                       // Compare Match value.
    OCR1A   = 26;                       // Compare Match value.

With duty value(OCR1A) the same as TOP (ICR1), the pin will not toggle!

Try a smaller value but not 0.

 

 

Jim

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
stack gold/silver https://www.onegold.com/join/713...

 

 

 

 

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

I'll ask again: do you actually need to vary the PWM frequency? If not why are you using modes with TOP variable?

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

For IR, the carrier frequency is fixed. There's no need to synchronously modulate it, so interrupting at 38kHz is not strictly necessary.

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

With duty value(OCR1A) the same as TOP (ICR1), the pin will not toggle!

Try a smaller value but not 0.

 

Now this remark led me to the resolution, thanks. It appears that in this case (probably due to some hardware quirk) when using OC1B as output the pin *does* toggle, but it does not when OC1A is set as output.

This is not how I read the datasheet. First, OCR1A should not have any effect on the output pin in mode 14. Second, it is stated that the timer is cleared the cycle after TOP is reached, so TOP equal to OCR1A should correctly raise the COMPA interrupt, as indeed it does in both cases.

 

So somehow both mode 14 and mode 15 get into trouble when OCR1A is selected, when also TOP has the same value as OCR1A. In mode 14 we can correct that by using different values, but in mode 15 these values are tied together in the same register. This is why mode 15 cannot be used for getting output on OC1A, while it works on OC1B. That seems a hardware bug to me. The fact that I also use COMPA as interrupt source is irrelevant here, that interrupt always worked perfectly well, and at the expected rate, it is the pin that refuses to work. The note#1 in the table refers to a different issue.

 

Anyway, for my app I can get away with using mode 14 instead of 15, but either lower my COMPA, or use TOV1. It is irrelevant when exactly my interrupt is raised (see later reply on questions about that)

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

A note on the datasheet: please correct me if I am wrong, but I found a few inaccuracies in the description of the timer modes. For example, in the header of the waveform mode table, it is not register OCR1X that is updated, but the output pin OC1X. I see a few other cases were these abbreviations are confused. Then I noted that  while COM1B1 is indeed non-inverting mode for OC1B, I have to select COM1A1+COM1A0 for getting OC1A in non-inverting mode. That is not what the table suggests. Then, the same table states that mode COM1A0 and COM1B0 have the exact same effect, both enabling OC1A and disabling OC1B. I have not tried it, but this sounds incorrect to me.

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

Thinking about it a bit more, the output pin is set at bottom, and cleared on any compare match (OCR1A and OCR1B). It seems that for OC1B as output when TOP equals OCR1A (or OCR1B for that matter) the set happens *after* the clear, while for OCR1A as output this sequence is reversed, immediately clearing the pin again, with the effect that it stays flat. So my remark above that OCR1A should not have any effect on the output pin was incorrect. Sorry, it was a while ago since I set this up so some bits had to mentally fall in place again.

 

@ezharkov: this value is correct, since this defines how long the pin is supposed to remain set, i.e. the duty cycle.

 

To answer the other questions: no, I do not need to change the frequency, I always need 38 kHz, but I do want the interrupts as well. The reason is that I time strobe duration not by using yet another timer, but simply by counting the individual pulses.

This is part of a larger app, running under a micro kernel that already grabs one timer for time management. I do not want to lose my last timer for such a casual reason.

So I do not really care when exactly I get the interrupt. I could have used TOV1 or COMPB as well. I just had COMPA handy because I was using mode 15, and everything seemed to work fine. But failed a year or so later when I wanted to redirect to the other pin.

Last Edited: Thu. Apr 18, 2019 - 06:27 AM