Society of Robots - Robot Forum

Software => Software => Topic started by: Half Shell on November 23, 2008, 10:25:58 AM

Title: PWM on Atmel AVR Amega168
Post by: Half Shell on November 23, 2008, 10:25:58 AM
I am trying to get a PWM signal for motor control working on an AVR Amega168. I've read a number of forum posts and documentation (on top of the datasheet and books) but am having trouble figuring out what I am doing wrong. I am currently using this sample code for the PWM generation:

Code: [Select]
#include <avr/io.h>

int main()
{
    DDRD |= 1 << PD6;       // Set PD6(OC0A) Output

    TCCR0A = 0b10000011;    // Compare Match Low
                            // 8 bit High Speed PWM
    TCCR0B = 0b00000101;    // clk/1024 125nsX1024=128us

    OCR0A = 128;            // Set Output Compare Register

    while (1) {
        asm("sleep"::);
    }

    return 0;

}

This generates a PWM signal with 50% duty cycle perfectly fine. I see the appropiate percentages when i modify OCR0A. The problem is the total time of the way is over too long! 250 milliseconds per wave, which means a quarter of a second. When controlling a motor, this is obviously not a smooth translation of various speeds but just an obvious pulsing of on and off for the motor. How can I make the total wave time smaller? What am I doing wrong in that regard? I think perhaps I'm just misunderstanding how the PWM module in the Amega168 works, so an explanation would also be handy to check it against my own understanding.

Thank you in advance!
Title: Re: PWM on Atmel AVR Amega168
Post by: izua on November 23, 2008, 11:22:49 AM
you need higher frequency. if you calculated it at 250 ms per phase (500 ms cycle) , that's 2 hertz.

please explain the rationale behind this comment: clk/1024 125nsX1024=128us
/ means division, not multiplication. you divide your main (crystal, osc, external, internal, whatever) clock by 1024 and that gives you the frequency of the output. quick fix: decrease prescaler.
Title: Re: PWM on Atmel AVR Amega168
Post by: Half Shell on November 23, 2008, 03:51:04 PM
you need higher frequency. if you calculated it at 250 ms per phase (500 ms cycle) , that's 2 hertz.

please explain the rationale behind this comment: clk/1024 125nsX1024=128us
/ means division, not multiplication. you divide your main (crystal, osc, external, internal, whatever) clock by 1024 and that gives you the frequency of the output. quick fix: decrease prescaler.

I said that was sample code - not mine. Same with the comments.

How can I slow down the prescaler? What register should I be modifying/looking at?
Title: Re: PWM on Atmel AVR Amega168
Post by: szhang on November 23, 2008, 04:08:25 PM
you need higher frequency. if you calculated it at 250 ms per phase (500 ms cycle) , that's 2 hertz.

please explain the rationale behind this comment: clk/1024 125nsX1024=128us
/ means division, not multiplication. you divide your main (crystal, osc, external, internal, whatever) clock by 1024 and that gives you the frequency of the output. quick fix: decrease prescaler.

That comment is right, the prescaler is 1024, so the frequency of the clock is divided by that much, which means the PERIOD is multiplied by 1024.

How can I slow down the prescaler? What register should I be modifying/looking at?

Try reducing the prescaler.  Check the datasheet, it should tell you what TCCR0B should be for a smaller prescaler.

Are you sure you're running at the right frequency?  I think the code assumes you are running at 8MHz.
Title: Re: PWM on Atmel AVR Amega168
Post by: mbateman on November 23, 2008, 05:18:24 PM
For reference, here is a link to the datasheet for the 168... http://www.atmel.com/dyn/resources/prod_documents/doc2545.pdf

Section 14 is the relevent part. Table 14-9 shows the prescale options.

The 168 by default runs at 1Mhz. So with the settings you have, you have 1Mhz with prescale /1024. That means each tick in the counter is about 1.024 mS. Then this is an 8 bit counter, so the base period of the wave would be the full cycle of the counter or 1.024*256 which is 262mS. If you use a smaller prescale, you can put this into a more reasonable base frequency.

I would suggest using the /64 prescaler to get a base frequency of 61Hz (or 16mS period). To do this, change your TCCR0B to 0b00000011.
Title: Re: PWM on Atmel AVR Amega168
Post by: Admin on November 27, 2008, 06:16:57 AM
or you can use the pwm.h and pwm.c source code for AVRlib :P
Title: Re: PWM on Atmel AVR Amega168
Post by: Half Shell on November 28, 2008, 10:27:03 PM
or you can use the pwm.h and pwm.c source code for AVRlib :P

The AVRlib that comes from Atmel or the user created AVRlibc that seems to be down right now?

After some hunting I've finally found AVRlibc and will be playing with that (why doesn't the main site host it anymore?). I can't find a pwm.h in the default AVR library that came with the eclipse avr plugin i downloaded which uses atmel libraries.
Title: Re: PWM on Atmel AVR Amega168
Post by: pomprocker on November 29, 2008, 03:13:07 AM
you can download it from this site. admin put a link somewhere
Title: Re: PWM on Atmel AVR Amega168
Post by: Half Shell on November 29, 2008, 04:52:21 PM
I managed to find AVRlibc and get it up and running, but have ran into a few issues that are quite weird.

First off, there is no PWM.c or PWM.h, so I don't know where you guys got yours. If this is some kind of addition to the library, it'd be great if someone linked me to where I could get it.

I did find PWM control functions inside of timer.h and timer.c, but this presents its own host of problems. I #include timer.h by itself and then wrote a simple program that activated PWM on one pin. The program complained that the functions were undefined, despite Eclipse syntax highlighting them correctly and even showing their code upon mouse hover-over. To fix this I #include'd timer.c, but this brings up a huge host of errors in and of itself, complaining about several things being undefined (from the looks of it, register constants). I can't seem to get these problems to go away, so any insight?

Code: [Select]
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>

#include <conf/global.h>
#include "timer.h"
#include "timer.c"


int main(void){
timer1PWMInit(10);
timer1PWMAOn();

timer1PWMASet(512); //Set the PWM to 50%. 10 bit, so 0-1023, 50% = 512

while(1){
asm("nop");
}

return 0;
}

And the error with only timer.h:

Code: [Select]
**** Build of configuration Release for project avrlibctest ****

make all
Building file: ../main.c
Invoking: AVR Compiler
avr-gcc -I/usr/avrlib -Wall -Os -fpack-struct -fshort-enums -funsigned-char -funsigned-bitfields -mmcu=atmega168 -DF_CPU=1000000UL -MMD -MP -MF"main.d" -MT"main.d" -c -o"main.o" "../main.c"
In file included from ../main.c:11:
/usr/avrlib/conf/global.h:35:1: warning: "F_CPU" redefined
<command-line>: warning: this is the location of the previous definition
Finished building: ../main.c
 
Building target: avrlibctest.elf
Invoking: AVR C Linker
avr-gcc -Wl,-Map,avrlibctest.map -mmcu=atmega168 -o"avrlibctest.elf"  ./main.o   
./main.o: In function `main':
main.c:(.text+0xa): undefined reference to `timer1PWMInit'
main.c:(.text+0xe): undefined reference to `timer1PWMAOn'
main.c:(.text+0x16): undefined reference to `timer1PWMASet'
make: *** [avrlibctest.elf] Error 1

And with timer.c added as well:

Code: [Select]

**** Build of configuration Release for project avrlibctest ****

make all
Building file: ../main.c
Invoking: AVR Compiler
avr-gcc -I/usr/avrlib -Wall -Os -fpack-struct -fshort-enums -funsigned-char -funsigned-bitfields -mmcu=atmega168 -DF_CPU=1000000UL -MMD -MP -MF"main.d" -MT"main.d" -c -o"main.o" "../main.c"
In file included from ../main.c:11:
/usr/avrlib/conf/global.h:35:1: warning: "F_CPU" redefined
<command-line>: warning: this is the location of the previous definition
In file included from ../main.c:13:
/usr/avrlib/timer.c: In function ‘timer0Init’:
/usr/avrlib/timer.c:98: error: ‘TIMSK’ undeclared (first use in this function)
/usr/avrlib/timer.c:98: error: (Each undeclared identifier is reported only once
/usr/avrlib/timer.c:98: error: for each function it appears in.)
/usr/avrlib/timer.c: In function ‘timer1Init’:
/usr/avrlib/timer.c:109: error: ‘TIMSK’ undeclared (first use in this function)
/usr/avrlib/timer.c: In function ‘timer2Init’:
/usr/avrlib/timer.c:118: error: ‘TIMSK’ undeclared (first use in this function)
/usr/avrlib/timer.c: In function ‘timer0SetPrescaler’:
/usr/avrlib/timer.c:127: error: ‘TCCR0’ undeclared (first use in this function)
/usr/avrlib/timer.c: In function ‘timer2SetPrescaler’:
/usr/avrlib/timer.c:140: error: ‘TCCR2’ undeclared (first use in this function)
/usr/avrlib/timer.c: In function ‘timer0GetPrescaler’:
/usr/avrlib/timer.c:147: error: ‘TCCR0’ undeclared (first use in this function)
/usr/avrlib/timer.c: In function ‘timer2GetPrescaler’:
/usr/avrlib/timer.c:163: error: ‘TCCR2’ undeclared (first use in this function)
/usr/avrlib/timer.c: At top level:
/usr/avrlib/timer.c:464: warning: ‘SIG_OUTPUT_COMPARE2’ appears to be a misspelled signal handler
make: *** [main.o] Error 1
Title: Re: PWM on Atmel AVR Amega168
Post by: Trumpkin on November 29, 2008, 04:59:31 PM
here is PWM.c
http://www.koders.com/c/fidFCE5C25781F27ABEDFC8DA53F7B2BF292124161D.aspx
an here is PWM.h
http://www.koders.com/c/fid06E27846D356B2DCE071D003D53635AA6776D9DA.aspx
Title: Re: PWM on Atmel AVR Amega168
Post by: Half Shell on November 29, 2008, 06:15:06 PM
here is PWM.c
http://www.koders.com/c/fidFCE5C25781F27ABEDFC8DA53F7B2BF292124161D.aspx
an here is PWM.h
http://www.koders.com/c/fid06E27846D356B2DCE071D003D53635AA6776D9DA.aspx

Thanks!


...Now, any idea on my compilation errors?
Title: Re: PWM on Atmel AVR Amega168
Post by: airman00 on November 30, 2008, 10:00:50 AM
solved all your problems
http://www.societyofrobots.com/robotforum/index.php?topic=5982.0
Title: Re: PWM on Atmel AVR Amega168
Post by: Admin on December 02, 2008, 01:59:30 AM
oops meant to say timer.h/.c . . .

Anyway, in AVRlib there is an example on how to do PWM in the examples folder.
Title: Re: PWM on Atmel AVR Amega168
Post by: Webbot on December 02, 2008, 02:27:12 AM
also check out http://www.societyofrobots.com/member_tutorials/node/228 (http://www.societyofrobots.com/member_tutorials/node/228)
Title: Re: PWM on Atmel AVR Amega168
Post by: Half Shell on December 08, 2008, 09:42:22 PM
For future reference...

I figured out the problem - timerx8.c should be used for ANY atmega XX8 controller - different registers. Oops!