# ATmega328P pwm generation with timer1 problem

Status
Not open for further replies.

#### Cantafford

##### Member
Hello,

I'm trying to control a DC motor with an ATmega328P. Actually I will need to control a servo motor later but I need to learn to generate PWM signals properly first. Since I need a high resolution I used timer1 which can generate 16 bit pwm resolution.

I have used 10 bit fast pwm mode and tried to implement a duty cycle of 50%. Something I don't understand though is how can I set the period(frequency) of the PWM signal. I have just started working with AVR's and I don't know how to do this. For example when programming PICs you need to set the period of the pwm signal before setting it's duty cycle. But for AVR's I have not found how to do this in the datasheet. This is how I initialized my timer1 module:
Code:
TCCR1A = 0b10111111; // fast non inverting 10 bit pwm mode
TCCR1B = 0b00001001; // 10 bit fast pwm mode, no prescaler

TCNT1H = 0xEF; // 50 duty cycle
TCNT1L = 0xFF;
When I simulate this the motor does not run at all.
Here is the full code(ignore the ADC part that's not important).
Code:
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 8000000    // CPU speed - always define prior to including util/delay.h
#include <util/delay.h>

int main()
{
DDRB = 0xFF; // PWM is output(also the LEDs)
DDRD = 0xFF;

sei(); // enable global interrupts

TCCR1A = 0b10111111; // fast non inverting 10 bit pwm mode
TCCR1B = 0b00001001; // 10 bit fast pwm mode, no prescaler

TCNT1H = 0xEF; // 50 duty cycle
TCNT1L = 0xFF;

while(1)
{

}

}

{
PORTD = ADCL; // put result of conversion on PORTB
PORTB = (ADCH << 2) & 0xFF; // get ADCH to RB3 and RB2 and also keep PWM pin unchanged
}

#### Cantafford

##### Member
So anyone knows this? . I've watched some tutorials and I still can't find my mistake

#### Jon Wilder

##### Active Member
The duty cycle is set by writing to the OCR1AH/L register pair (The equivalent of CCPRxL and DCB1 : DCB0 on a PIC)...NOT the TCNT register pair. However, in AVR-GCC, you can just write to OCR1A and the compiler takes care of the register pairing.

TCNT1H/L is the timer counter itself. These registers need not be written to.

OCR1AH/L holds the duty cycle value itself. In 10-bit PWM mode, you can write a value from 0x0000 - 0x03FF. A value of 0x1FF or 0x200 should get you close to a 50% duty cycle -

Code:
    OCR1A = 0x1FF;    // 50% duty cycle
As for setting the period, this is done with the prescaler setting/clock source select bits.

Last edited:

#### Cantafford

##### Member
The duty cycle is set by writing to the OCR1AH/L register pair (The equivalent of CCPRxL and DCB1 : DCB0 on a PIC)...NOT the TCNT register pair. However, in AVR-GCC, you can just write to OCR1A and the compiler takes care of the register pairing.

TCNT1H/L is the timer counter itself. These registers need not be written to.

OCR1AH/L holds the duty cycle value itself. In 10-bit PWM mode, you can write a value from 0x0000 - 0x03FF. A value of 0x1FF or 0x200 should get you close to a 50% duty cycle -

Code:
    OCR1A = 0x1FF;    // 50% duty cycle
As for setting the period, this is done with the prescaler setting/clock source select bits.
Thank you . I have one more question. I'm trying to control a DC motor's duty cycle via the pot connected on ADC0. I have tested the module with some LEDs and is implemented ok in 10 bit left justified result.

So I modified my adc interrupt routine like this:

Code:
ISR(ADC_vect)
{

}
The result beiing left justified. When I simulate this the motor will run full speed if the potentiometer's position is above 15% and after that point it will run full speed regardless of the position of the pot(even if I drop it all the way to 0). Why is the motor behaving like that?

#### Jon Wilder

##### Active Member
The result needs to be in right justified format.

#### Cantafford

##### Member
The result needs to be in right justified format.
I changed to that and now the motor still behaves weird. So weird I can't even explain it :.
But I'm guessing is something done with the way I set the frequency of the PWM signal(which I actually have not set up at all). Will look into that since I'm guessing if I set the frequency properly to say 1.5Khz for example then everything will run smooth.

#### Jon Wilder

##### Active Member
Even with no prescaler you're running at about 122Hz, which should be low enough for a DC motor. Assuming 8MHz Fosc -

Period = Prescale(1/Fosc) x 65536

1(1/8MHz) x 65536 = 8.192mS, or 1/122Hz

Some motors don't like PWM drive. I would consult the data sheet for the particular motor you're using and see if there's any recommended PWM parameters for it.

Do you have a digital oscilloscope so you can look at the PWM signal? If not I highly recommend getting one if you plan to stay in embedded electronics. A decent 4-channel one can be had for around $400. This is the one I use - https://www.amazon.com/Rigol-DS1054Z-Digital-Oscilloscopes-Bandwidth/dp/B012938E76 Last edited: #### Cantafford ##### Member I'm simulating the application not implementing it in hardware. Yes FOSC is 8Mhz and no prescaler as in your example there. Not sure why my motor behaves like that #### Cantafford ##### Member Even with no prescaler you're running at about 122Hz, which should be low enough for a DC motor. Assuming 8MHz Fosc - Period = Prescale(1/Fosc) x 65536 1(1/8MHz) x 65536 = 8.192mS, or 1/122Hz Some motors don't like PWM drive. I would consult the data sheet for the particular motor you're using and see if there's any recommended PWM parameters for it. Do you have a digital oscilloscope so you can look at the PWM signal? If not I highly recommend getting one if you plan to stay in embedded electronics. A decent 4-channel one can be had for around$400. This is the one I use -

https://www.amazon.com/Rigol-DS1054Z-Digital-Oscilloscopes-Bandwidth/dp/B012938E76
Could it be possible that my period is less than my duty cycle and this is why this happens?

#### Ian Rogers

##### User Extraordinaire
Forum Supporter
Could it be possible that my period is less than my duty cycle and this is why this happens?
This has always been an issue... Even when you did this on a PIC...

#### Jon Wilder

##### Active Member
I'm gonna simulate this today and look at the output on a scope. Will have screen shots. Stay tuned.

In the meantime...FYI when you have a statement with an empty function body, you can just terminate it with a semicolon instead of empty brackets. Example -

Code:
    while(1);

while(1)
{
}

#### Cantafford

##### Member
This has always been an issue... Even when you did this on a PIC...
Yes. But if that was the case here the motor's speed was supposed to be 0 at some point right(when the duty cycle value would exced that of the period)? Whereas in my case the speed doesn't drop to 0 it just does not respect the pot's position.

#### Jon Wilder

##### Active Member
When duty cycle value exceeds the period value, it should roll over to 0% and start from there as you increase the duty cycle value since it's the MSBs that are ignored.

Status
Not open for further replies.