possible to get 3 16b PWM signals from ATMEGA48?

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

Hi - I'm working on an ATMEGA48 board, and starting to think about code for it. Specifically, I need to generate 3 16b PWM signals, running at 50hz. Is there any way to do this all in hardware? My understanding of the 16b timer in the 48 is that it can only do two 16b PWM signals. Thanks!

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

Is this for 3 phase power generation?

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

ignoramus wrote:
Is this for 3 phase power generation?

Nope - it's to control 3 servo motors.

I'm fully away of ways to make unlimited PWM signals in software, but I'd really like to free up the microcontroller to do other stuff, if at all possible.

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

For a servo, do you really need a 16-bit PWM?

I don't think it's possible in the ATmegaX8 hardware then, as they
only have 2 OC registers in timer 1.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

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

dl8dtl wrote:
For a servo, do you really need a 16-bit PWM?

I don't think it's possible in the ATmegaX8 hardware then, as they
only have 2 OC registers in timer 1.


I haven't looked too carefully at how PWM works in AVRs, to be honest. My assumption was that you'd set a frequency and then set the duty cycle. Being that the max duty cycle for a servo at 50hz is 10% (2ms/20ms) and the minimum duty cycle is 5% (1ms/20ms) that would mean you'd have about 12 steps (5% * 256), which is certainly not enough for me.

Did I assume wrong? Or are there other AVRs that have more OC registers on the 16b timer? I really need to use small AVRs - was hoping to stick with a TQFP32.

Thanks!

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

If you don't mind put some chip on your board, you could add 3 AND gate.
You can use only 1 PWM generator with 3 AVR I/O pin to control 3 servo. It's all by hardware.

OC1A * I/O1 => servo1
OC1A * I/O2 => servo2
OC1A * I/O3 => servo3

Set I/O 1,2,3 could choose which servo get PWM signal.

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

bernie_w39 wrote:
If you don't mind put some chip on your board, you could add 3 AND gate.
You can use only 1 PWM generator with 3 AVR I/O pin to control 3 servo. It's all by hardware.

OC1A * I/O1 => servo1
OC1A * I/O2 => servo2
OC1A * I/O3 => servo3

Set I/O 1,2,3 could choose which servo get PWM signal.


But I don't think that's possible to do all at the hardware level - wouldn't I have to be constantly setting new OC1A values and changing the IO pin levels? I'm hoping to have a setup where I can write a couple register values and forget about it, while the rest of my code can do whatever it pleases.

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

The smallest AVR I know of which has more than 2 16-bit PWM outputs is the ATmega64. (It has 6.)

I don't know if some of the fancy waveform-generating hardware in the AT90PWM models might be useful for you or not. I haven't taken the time to get a thorough understanding of their datasheets yet.

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

> But I don't think that's possible to do all at the hardware
> level - wouldn't I have to be constantly setting new
> OC1A values and changing the IO pin levels?

It could be done quickly within an ISR. An interrupt fires
whenever the counter comes back to 0, and as you're
only using parts of the possible timing range, you've
got plenty of time to reprogram the OC1A value.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

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

16b?

JChristoff
Illinois

Last Edited: Wed. Jan 12, 2011 - 02:27 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

lfmorrison wrote:
The smallest AVR I know of which has more than 2 16-bit PWM outputs is the ATmega64. (It has 6.)

I don't know if some of the fancy waveform-generating hardware in the AT90PWM models might be useful for you or not. I haven't taken the time to get a thorough understanding of their datasheets yet.


The 64 is physically too big for me, unfortunately.

the PWM AVRs also don't come in any packages that I can work with.

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

dl8dtl wrote:
> But I don't think that's possible to do all at the hardware
> level - wouldn't I have to be constantly setting new
> OC1A values and changing the IO pin levels?

It could be done quickly within an ISR. An interrupt fires
whenever the counter comes back to 0, and as you're
only using parts of the possible timing range, you've
got plenty of time to reprogram the OC1A value.


That's how I'm doing it right now, and how I've done it in the past. The method works quite well, but I just would rather not have these interrupts firing 150 times per second.

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

jgrunt wrote:
With the mega48, I think the most servos you can control at the hardware level, ie 0 processor overhead, are two.
This is using Output Compare Registers 1A and 1B.

see this thread:
https://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=35620&start=0

Jeff

[edit] To tell how many servos a device can handle at 50Hz and enough resolution (16bit reg) with out using interrupts, in the data sheet look at the "book marks" on the left side of the pdf. Under "16 bit Timer/Counter" look at the "16 bit Register Descriptions". There, count the number of "Output Compare Register".


I know - that's why I made the thread - I was hoping there was some trick I was missing or something. I am entirely familiar with the 48's timers and output compares as I built up my first servo controller on one.

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

> ...but I just would rather not have these interrupts firing 150
> times per second.

C'mon. The following snippet:

#include 

#include 
#include 

#define NCHANS 3
#define IOPORT PORTB

uint16_t pwms[NCHANS];

ISR(TIMER1_OVF_vect)
{
        static uint8_t i;
        uint8_t port;

        if (++i == NCHANS)
                i = 0;
        port = IOPORT;
        port &= ~((1 << NCHANS) - 1);
        port |= (1 << i);
        IOPORT = port;

        OCR1A = pwms[i];
}

compiles into what I counted to be 89 clock cycles worst case.
Running it 150 times per second, that would occupy about 1.3 % of the
overall time on an ATmega48 running at 1 MHz.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

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

Quote:

I was hoping there was some trick I was missing or something

Since you mention about "trick", I suppose that means "anyway".
If you don't mind add two chip outside your ATmega48. I have an idea.

Use OC0A, OC0B, OC2A to control your servo. Set PWM width as 4ms.
That says you have 64 steps in 1-2 ms area, is that enough?

Connect OC0A, OC0B, OC2A output to three independ AND gate input.
The other input of each AND gate connect the output of a shift IC.
(for example 74LS166).

Have OC2B as 4ms clock output and connect to 74LS166 CLK. Assign
OC1A as a PWM with 4ms on time / 20 ms duty cycle. Connect OC1A
to 74LS166 DS.

Then 74LS166 will have the following output for each 4ms round.

1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 0 1
[recycle]

Connect first three output of 74LS166 as the other input of 3 AND gate.
then OC0A, OC0B, OC2A output PWM will be masked. Only 4 ms out of
20 ms will be seen.

Finally, you got a 1-2ms on time PWM (with 64 steps precision) out of
20ms duty cycle. You only have to set OCR0A, OCR0B, OCR2A
registers, everything is run by hardware. But this way run out of almost
all PWM output and have to add two extra components.

Of course, you have to be carefully the timing alignment. And pay me
the patten fee ^^ ... Just a joke.

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

I forgot to say if you want to raise the precision, you could change the 4ms
cycle to 2.5ms (even 2ms if you trust hardware so much).
Then you will get 1-2ms with 100 steps. Enjoy it.