[TUT] [C] Newbie's Guide to AVR PWM (Incomplete)

Last post
119 posts / 0 new

Pages

Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is a continuation of my Timers tutorial and assumes the reader has read and understood that text before beginning this one.

Part Nine - Pulse Width Modulation (PWM)

The previous sections of the timers tutorial have been dealing with a simple task - flashing a LED. We've managed to accomplish that task using a variety of methods which all center around the "Clear On Timer Compare" (or CTC) method of using the timer, in both software and hardware. But what if we want to dim the LED instead? Now we are getting into a new timer concept, that of Pulse Width Modulation, abbreviated to PWM for short.

Pulse Width Modulation allows us to interface our digital components with the analogue world. We can use PWM to adjust a motor's speed, a LED's brightness or a speaker's tone. PWM is a very important concept, which is used all throughout the world of digital electronics. It is a way of approximating an analogue source, which with a little filtering can be used as a real analogue source (albeit with a few limitations).

It's important to note that PWM does not change our AVR's limitations; the signal sent out by the timer is still a true digital signal. However, by altering the on and off time of the signal at a given frequency, we can adjust the average on time to give an approximate analogue signal. This signal is good enough for immediate use in many applications - including motor speed control and LED dimming - without any extra filtering, or with the addition of a capacitor the output can be smoothed to a real analogue wave.

Let's start with a picture representing the different types of signals (modified from Wikipedia):

The top waveform is a traditional analogue signal, varying smoothly from GND to VCC volts. The bottom waveform is a digital representation of the top, using PWM.

PWM allows us to set an overall frequency, and then vary the on and off time (called the duty cycle) of the output within each timer cycle. A longer duty cycle gives a longer on time, resulting in an analogue representation closer to the VCC voltage. A duty cycle of 100% (on for the entire cycle) gives a VCC output, while a duty cycle of 0% (off for the entire cycle) gives a GND output.

When we use the CTC timer mode, what we are actually doing is essentially PWM, but with a fixed duty cycle of 50%, and a variable frequency. For this example, we're using PWM and will conversely be using a fixed frequency and varying the duty cycle to dim our LED.

There are several different PWM modes that the AVR timers can be initialized in, each with slightly different characteristics. These are as follows:

    1) Fast PWM (8, 9 or 10 bit) 2) Phase Correct PWM
    3) Phase and Frequency Correct PWM

Before we can explore the different modes, we need to understand a little of the timer terminology. Frequency, as we know, is the number of cycles per second that the timer runs at - a higher frequency gives us a faster timer. In the PWM world, having a faster PWM frequency gives us finer control over the output, as we can respond faster to new PWM duty cycles. This is especially important when using PWM to produce audio from digital samples; a faster PWM frequency is required to give the full output frequency range by varying the duty cycle.

Next, we have the BOTTOM value. This is the lowest value that the timer will reach in the current mode. In all timer modes on all AVRs, this will be zero. Accompanying BOTTOM is TOP, which is the maximum value that the timer will reach before either (depending on the mode) resetting back to 0x00 or begin counting in reverse back to BOTTOM. For the normal mode, TOP is equal to the maximum value the timer can reach. For CTC mode, TOP is user settable, which gives us our control over the timer period. We are now using PWM, thus TOP is now set to give the PWM frequency.

Finally, we have our PWM COMPARE value. This sets the duty cycle - when this value is reached the waveform is inverted from its current state. Varying the COMPARE value will give us our varying duty cycle.

Now, let's get down to business and go into the three PWM modes.

Fast PWM

Fast PWM is useful for outputting PWM values quickly, at a loss of phase correctness - changes to the duty cycle will be reflected immediately, with the new signal being phase incorrect. When selected, the timer will count up from BOTTOM to TOP, with TOP being fixed at the bit-width of the fast PWM -- we are given a choice of 8, 9 or 10 bits depending on the timer bit width (8 bit timers will obviously not offer Fast PWM in more than 8-bits). The timer, when started, will count up continuously until TOP is reached, when it wraps back to BOTTOM and starts again. Inside this period when the counter reaches the COMPARE value, the output pin is set when the correct value is reached (and cleared when the timer wraps back from TOP to BOTTOM), so that varying COMPARE we get a PWM of a fixed frequency but a variable duty cycle.

This gives us the ability to change the duty cycle rapidly, in applications where the phase change does not matter. Applications such as motor control are particular about the phase, so we need to use the Phase Correct PWM mode.

Phase Correct PWM

Phase correct PWM gives phase-correct output as the duty cycle changes. The concept of phase is foregn to some, so we'll take a look graphically at how phase-incorrect (Fast PWM) and phase-correct PWM waveforms differ:

Notice the difference? In the case of Fast PWM, the high points are always aligned to the start of each period, with a smaller duty cycle resulting in a shorter ON time. Phase Correct PWM by contrast aligns the high points to the center of each period, so that a smaller duty cycle results in a shorter ON time -- but the ON times of all signals are aligned. As inducated in the Fast PWM explanation, this mode is useful in applications where the phase of the signals should not change, even if the duty cycles do. Phase Correct is slower than Fast PWM (as the name of the latter implies) due to the way Phase Correct PWM works.

When selected, the timer will count up from BOTTOM to TOP, and then start counting downwards back to BOTTOM before repeating. When upcounting, reaching COMPARE will turn on the output pin, while reaching the same value when downcounting will turn the output off. This results in the timer period being twice as long as Fast PWM mode (since the timer also has to count back to BOTTOM rather than just wrapping) but produces a phase-correct signal.

In Phase Correct PWM, the TOP value is variable and so the mode supports a variable PWM frequency. For generating simple audio tones from a speaker it is common to use the variable frequence of this mode to change the note pitch, and use the duty cycle to change the volume; a higher duty cycle results in a longer ON timer for the speaker, and so produces a louder sound.

SECTION INCOMPLETE - More updates soon.

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

Hi all,
Firstly I have to say the Dean is a gentleman and a scholar for providing such an educational tutorial.
Secondly, if anyone is interested here is some PWM code I wrote in AVR Studio. It uses UART commands from the PC for triggering the PWM on or off. It uses the Mega32 @10MHz and sets up the PWM for motor control with the frequency set at ~20kHz @ 75% duty cycle using Timer 0

void PWM_Init()
{
	TCCR0 = (0<<WGM01)|(1<<WGM00)|(1<<CS00);//setup PMW, no prescaler
	OCR0 = 0xC0; //set 75% duty cycle
	DDRB |= (1<<DDB3);
}
void main()
{
   unsigned char PWM_on;
   unsigned char PWMON[]="PWM on Pin 4";
   unsigned char PWMOFF[]="PWM off Pin 4";
   PWM_on = 0;
   PWM_Init();
   while (1)
   {
      switch (Received_Command)
      {
        case '3':			
        if (PWM_on == 1)
        {
        TCCR0 ^=(1<<COM01); //disable OC0
        PWM_on = 0;
        UART_putstring(PWMOFF);
        USART_Transmit(LF);
        Received_Command = '0';
        }
        else
        {
        TCCR0 ^=(1<<COM01);
//Clear OC0 on compare match when up-counting. Set OC0 on compare match when downcounting.
        PWM_on = 1;
        UART_putstring(PWMON);
        USART_Transmit(LF);
        Received_Command = '0';
        }
   }//end while(1)
}




I won't bother with the UART code as there is a tute for this.
Enjoy :)

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

Presumably this is cut from something larger? Otherwise what's the point of a switch() with only one case: ?

(also this is presumably only going to do 20KHz if F_CPU matches yours?)

 

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

Yep it's huge, I just cut and pasted something that would work.

Quote:
(also this is presumably only going to do 20KHz if F_CPU matches yours?)

yes 20KHz will work only at 10MHz F_CPU with this setup - hence all the info.

Cheers

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

Man, I can't wait for him to finish this tutorial!!!

Does anyone know of any other PWM lessons that are relevant to AVR users?

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

Simply beautiful, Dean. :D That explanation of Phase Correct PWM is the best I've ever read. Truly, a picture is worth a thousand words. (Not your words, of course. :) )

Quote:
As this tutorial chain gets a lot of discussion and questions I'd think that moving all the tutorials to a new thread which is then locked would make sense.

I concur with what JohanEkdahl suggests. In addition, some navigation tabs (index page) so the reader can quickly jump to the desired chapter/section.

If you think education is expensive, try ignorance.

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

I still don't see the benefit to going to a phase corrected PWM and I don't agree that you get a shorter ON time with the phase corrected PWM. The only thing is that by decreasing your frequency you will have a wider range to work with, but the minimum pulse width will remain the same and the duty cycle percentage will appear smaller because you are comparing the minimum on time to a longer period. So it seems like phase correction is be done with the fast PWM and introducing a delay to achieve the correction. Can anybody give me some insight on this?

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

I still don't see the benefit to going to a phase corrected PWM and I don't agree that you get a shorter ON time with the phase corrected PWM. The only thing is that by decreasing your frequency you will have a wider range to work with, but the minimum pulse width will remain the same and the duty cycle percentage will appear smaller because you are comparing the minimum on time to a longer period. So it seems like phase correction can be done with the fast PWM and introducing a delay to achieve the correction. Can anybody give me some insight on this?

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

@new2atmel

I tried to understand your code, but what means DDRB |= (1<<DDB3); and ^=

Thx in advance

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

Quote:
I tried to understand your code, but what means DDRB |= (1<<DDB3); and ^=

You need to read this ("101") tutorial thread first:

http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=37871

 

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

Thx that makes sense I think :)

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

I would love to see an organized note on specific AVRs such as the mega128 with all the registers and code organized for timer use for all the modes. It could use a base clock of say 8Mhz and show PWM frequencies possible, etc.

Al Welch :)

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

Dean (ABCMini),

Any chance of seeing the rest of this tutorial including some code. I have to say I love your "top down, fill in the pieces" style for tutorial writing.

I am trying to pick up the pieces and write an independent PWM motor control "module" so that I can have one or N motors. I am doing a project to control the motors on my son's ride on toy, where the lack of control causes burned up motors and stripped gears.

Thanks for the tutorial, I read the entire timer tutorial last night and other than the fact that I am still not fluent on the C bit operators it was an easy read which says a lot about your style.

Thanks,

JWColby
AVRNubee
www.ColbyConsulting.com

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

Quote:

Any chance of seeing the rest of this tutorial including some code. I have to say I love your "top down, fill in the pieces" style for tutorial writing.

Thanks! It's been a while since I wrote any tutorials, so I'll try to pick it up again. My personal projects are starting to slow down, which is unfortunate for me but should be to the benefit to others.

I'm currently in the middle of end-of-year University exams, so I won't be able to work on this just yet. My future depends on me knowing how to do series-series feedback analysis by tomorrow.

Quote:

Thanks for the tutorial, I read the entire timer tutorial last night and other than the fact that I am still not fluent on the C bit operators it was an easy read which says a lot about your style.

Always good to know what I write is readable. I'm not always certain; it's very difficult to think from a complete new user's perspective when writing tutorials, and not sink into the depths of assumed knowledge.

For the C bit operators, read EW's "Programming 101" tutorial in the tutorials forum.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

can i get this code in ATmega8??????????

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

I am thinking you can. I am hoping to get an Atmega8 running just a single PWM channel, which I will mount on a PC board with the HBridge to control a single motor. Then link it via two wire or RS232 to a central controller that actually runs my app.

Unfortunately I am still struggling to find code that I can get working. The unfortunate part is that according to my dev notes I had PWM code controlling a motor a year and a half ago but I lost the hard drive. :oops:

JWColby
AVRNubee
www.ColbyConsulting.com

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

Here is a simple ATMEGA16 (IIRC) example code. It's actually a DAC - digital audio in on Port D and PWM output for a speaker on the Timer 1 compare output.

#include 

int main (void)
{
	// Speaker as output
	DDRB   |= (1 << 1);
	
	// DAC inputs as input, pullup
	PORTD  |= 0xFF;
	
	// Set on match, clear on TOP
	TCCR1A  = ((1 << COM1A1) | (1 << COM1A0));

	// Phase + Frequency Correct PWM, Fcpu speed
	TCCR1B  = ((1 << CS10) | (1 << WGM13));

	// TOP is 0xFF for 8-bit audio
	ICR1    = 0xFF;

	for (;;)
	  OCR1A = ((int8_t)PIND + 0x7F);
}

Phase and Freq correct mode only, but should get you started.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

thanx a lot for the tutorials on timer. was having great problems in beginning with timers and interrupt. ur tutorial was pretty easy and coool to begin with. thanx again. my best wishes for ur exams

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

thanx a lot for the tutorials on timer. was having great problems in beginning with timers and interrupt. ur tutorial was pretty easy and coool to begin with. thanx again. my best wishes for ur exams

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

Hi freaks,
First of all thank you Dean for making life so easy for newbies like me. Your tutorials are so simple and easy to follow. Hats off to you.
Coming to the problem, I am using atmega8 to design a robot. I have to use PWM to control two motors that control the two wheels of the robot. This is what I have done so far:
- Read your timer tutorial and PWM tutorial
- Read the missing part of PWM from Data Sheet
- Wrote a code to initalize PWM and test the motors
The code is as follows:

#include
#include
#include
#define Delay( x ) _delay_loop_2( x )

#define F_CPU 1000000UL


pwm_init()
{
     TCCR1A |= (1<< COM1A1) | (1<< COM1B1) | (1<< COM1A0) | (1<< COM1B0) | (1<< WGM10)| (1<< WGM11) ;// 10 bit PWM phase correct
     TCCR1B |= (1<< CS10); // no prescaling
     //TCCR1B |= (1<< CS10) | (1<< CS12) ;
     TCNT1 = 0x0000;
}

void pwm_set( int left_speed, int right_speed )
{
     OCR1A = left_speed;
     OCR1B = right_speed;
}
int main ()
{
   unsigned int i;
   DDRD = 0xff;
   PORTD = 0x00;
   DDRB = 0xff;

// PD0 and PD1 - right motor
// PD7 and PD6 - left motor
//  1       0 forward
//  1       1 brake (both outputs low)
//  0       1 reverse
//  0       0 coast (both outputs off =high impedance?)

     PORTB |= (1 << PB1) | (1 << PB2);
     PORTD |= (1 << PD7) | (0 << PD6) | (1 << PD0) | (0 << PD1);

pwm_init();
while(1)
{
for(i=1;i<256;i++)
{
pwm_set(i,i);
Delay(5000); //20000 cycles
}
for(i=255;i>0;i--)
{
pwm_set(i,i);
Delay(5000);
}
}
}

What I don't understand is:
- When does OC1A and OC1B gets set or clear? In this PWM mode the TOP value is 0x03FF. And I am putting values ranfing from 1 to 255 and 255 to 1 in OCR1A and OCR1B. According to me, this code should change the speed of the motors, first increase and then decrease, or vice versa.
- Also how do I set duty cycle? Why would I need it? Suppose I want to use the duty cycle of 50%, that means i put half the value of 0x03FF into OCR1A...is that right?
- I want my robot to turn 90 degrees. I think this should be done by stopping one motor and rotating the other one. But for how long should I rotate the other one so that it turns 90 degrees. As in how do I fix the time for which a particular motor runs?
-How does prescaling affect PWM? I saw that changing prescaler values made the code not run any more.
Please consider my questions. I might look ignorant to some of you. Also if this was the wrong place to post please let me know and I will post in AVR Forums. I just had to thank Dean, so I posted here.

Regards.
Sid

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

Quote:
When does OC1A and OC1B gets set or clear?

This depends on what mode you are in and how you have the COMx bits set. In your code (Phase correct and COMx bits set to 0b11) they will be set on compare match when the timer is counting up, and cleared on compare match when the timer is counting down.
Quote:

Also how do I set duty cycle?

By setting OCRxx registers.
Quote:
Suppose I want to use the duty cycle of 50%, that means i put half the value of 0x03FF into OCR1A...is that right?

Yes.
Quote:
Why would I need it?

In the case of your motors, the higher the duty cycle, the faster the motor turns.
Quote:
I want my robot to turn 90 degrees. I think this should be done by stopping one motor and rotating the other one. But for how long should I rotate the other one so that it turns 90 degrees. As in how do I fix the time for which a particular motor runs?

This depends purely on the mechanics of how your robot is set up (how big the wheels are, how far they are apart, speed range of the motors, etc).
Quote:
How does prescaling affect PWM? I saw that changing prescaler values made the code not run any more.

Changing the prescaler will only affect the frequency of the PWM. What frequency you want depends on what it is driving.

Regards,
Steve A.

The Board helps those that help themselves.

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

Sid,

I am no expert on this but basically what is going on is that the motor acts as inductance (a coil in electronics) and "changes" the waveform that you feed it into a "DC voltage". How effectively it does that for any given frequency is determined by the motor itself, i.e. the size of the wire, the number of turns, and possibly even the standing magnetic fields caused by the motor magnets.

Thus for any given motor, there is an inductance caused by the the specific items mentioned above for that exact motor.

Now, you apply a square wave of some frequency to that motor. If the frequency is too low, the motor just passes the wave form through and does not perform the "AC to DC conversion".

As the frequency goes up, the inductance of the motor is more and more efficient at converting the waveform to a DC voltage, so the wave starts to deform from a square wave to a sawtooth, and eventually (at a high enough frequency) the sawtooth turns into AC ripple on top of a DC voltage.

Because of the DV voltage, a DC current starts to flow in one direction through the motor and the motor tries to turn.

Now... what determines how fast the motor turns is the "on" time vs the "off" time. Obviously if you are feeding a square wave with only a millisecond of on time and 999 milliseconds of off time, the "DC VOLTAGE" applied to the motor is going to be very low. As you increase the ON time of the waveform, the DC voltage gets higher and higher, and so the DC current gets higher and higher.

This is in VERY "layman" terms. But essentially, at least up to a point, the higher the frequency, the more efficiently the motor will turn the signal from a square wave to a DC voltage. The higher the percentage of on time, the higher the DC voltage created, and the faster the motor turns.

There does reach a point of diminishing returns IIRC where higher frequencies actually causes losses in the wire of the motor, and instead of being turned into a DC voltage, the wire just becomes a big radio transmitter radiating significant amounts of power out as a radio signal. At too low a frequency, there is heating in the wire and power is lost to heat.

Thus there is a balancing act where you try to find out what frequency your specific motor most efficiently transforms the frequency you apply to the motor into rotational power (DC voltage).

Someone with more knowledge of motors will no doubt jump in and tell me I am all wet (which to some extent is no doubt true) but at least this should get you started in understanding what the parts the frequency and on / off times do for you.

JWColby
AVRNubee
www.ColbyConsulting.com

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

Dear Koshchi,
Thank you for your detailed response. Had a few questions:

Quote:

This depends on what mode you are in and how you have the COMx bits set. In your code (Phase correct and COMx bits set to 0b11) they will be set on compare match when the timer is counting up, and cleared on compare match when the timer is counting down.

-But when you say compare match do you mean a compare match between TCNT1 and OCR1A? For example to get a duty cycle of 50%, I will put 0x01FF in OCR1A. So TCNT1 will count from 0 to 0x03FF while upcounting and as soon at it reaches 0x01FF the OC1A output will be set.I have attached an image to show my understanding of the above.Is this right? If it is then what is the difference between this mode (i.e PWM Phase correct with TOP as 0x03FF) and mode 11 (i.e PWM Phase correct with TOP as OCR1A).
-Also to make a motor run for a certain time, say 10 seconds, and then stop it, how will I implement this in code? Should I put delays up to 10 seconds?

Again thank you so much for your kind help and time. I really appreciate.
Regards.
SID

Attachment(s): 

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

Dear jwcolby,
Thank you so much for your response.

Quote:
This is in VERY "layman" terms. But essentially, at least up to a point, the higher the frequency, the more efficiently the motor will turn the signal from a square wave to a DC voltage. The higher the percentage of on time, the higher the DC voltage created, and the faster the motor turns.

This is exactly what I wanted to clear my basic understanding. Thank you so much once again :)
Regards.
SID

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

Quote:
I have attached an image to show my understanding of the above.Is this right?

Yes.
Quote:
If it is then what is the difference between this mode (i.e PWM Phase correct with TOP as 0x03FF) and mode 11 (i.e PWM Phase correct with TOP as OCR1A).

In this mode OCR1A is TOP, therefore it can not be used to set the duty cycle. You will only be able to get PWM on OC1B (using OCR1B to set the duty cycle). In the modes with a fixed number for TOP, both OC1A and OC1B may be used as PWM outputs (with independent duty cycles, but using the same frequency).

Regards,
Steve A.

The Board helps those that help themselves.

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

Sorry, I was in the wrong topic.
I've found my solution in the ADC tutorial
( to the Mod. You may delete this if you want ) :oops:

First, do what you can - then, do what's possible - suddenly, you'll do the impossible. (Thadëus Judas )

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

Dean, my man, you are awesome. If I had a sister she would be yours for the taking :)

Instead of that I shall try to express my appreciation with words. Thank you.

Code, justify, code - Pitr Dubovich

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

Quote:
Dean, my man, you are awesome. If I had a sister she would be yours for the taking

How about this - you take mine away, and we call it even? :lol:

Must remember to finish this during my holidays.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

I'd feel tempted, but I'd anticipate problems as well.
Other then that, if things keep going the way I want them to go, I might be able to actually finish this lasertag project.

Code, justify, code - Pitr Dubovich

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

Will this ever be completed? This and the preceding tutorial are by far the best I've found and it's a shame it isn't finished.

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

Quote:

Will this ever be completed? This and the preceding tutorial are by far the best I've found and it's a shame it isn't finished.

One day! I've had a lot more on my plate these holidays than I expected (read: I actually managed to get a job) which hasn't left me the motivation to finish it in the spare time I've had.

Perhaps I'll have a crack at it tomorrow, since I haven't got anything scheduled.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

*holds breath in anticipation*

good on you for finding a job - I left finding my summer job until after exams, which was right when the so-called recession began and now no-one is looking to hire.

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

well after a bit of reading the datasheet, PWM is in fact as straightforward as hoped - took as long to find the typo in my code as it did to write it

just one question: frequency and phase correct mode - are not all modes frequency correct? It may take a bit of fiddling to get the desired frequency without too great a compromise in resolution, but I fail to see how we can have a phase (but not frequency) correct PWM signal

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

As of getting the robot to turn you can do as you said, but another way of making a robot turn is, to reverse the direction of one of the motors... The your robot will truely turn in a 90 degree angle :D

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

Pardon my ignorance, but I cannot figure out how to set the PMW to 8-bit rather than 10. Also, the duty cycle can be set as an integer... right?

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

Quote:
Pardon my ignorance, but I cannot figure out how to set the PMW to 8-bit rather than 10.

This depends somewhat on which AVR and which timer you are using. But it is really just a matter of setting the correct mode.
Quote:
Also, the duty cycle can be set as an integer... right?

Of course, what else would it be?

Regards,
Steve A.

The Board helps those that help themselves.

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

I just assumed it had be be set as a hex rather than a 'counting number'

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

I just assumed it had be be set as a hex rather than a 'counting number'

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

Quote:
I just assumed it had be be set as a hex rather than a 'counting number'

But hex is a counting number, it just goes up to 15 instead of 9 for each digit.

The AVR only knows binary and the compiler will always transform whatever human readable form the number is in to binary.

Regards,
Steve A.

The Board helps those that help themselves.

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

How do I generate PWM from two Pins which go to a H-Bridge to stall a DC motor?What care is to be taken when motor is to be stalled?(I would refer to this as 1-1 state :stalled or brake,where 1-0 corresponds to say clock wise,0-1 to anti and 0-0 to off)

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

Can you tell us a little more about your motors and how they're connected? I assume they're DC motors and connected to an HBridge of some sort, but how is the PWM connected in? A diagram might help?

Your outputs (OC1A,B) will set when compare match on upcounting and clear down counting. So if OCR1A has 200 in it and TOP is 0x3ff, the OC1A will go high when COUNT (the value in TCNT1) reaches 200 on upcounting, and will go low when TCNT reaches 200 downcounting.

The duty cycle is simply the time the output is high divided by the total cycle time. So your total cycle time is 2048 clock ticks and if your OCR1A has 200 in it, then your duty cycle is (2*(1024-200))/2048 = 80%. Putting in 0x1ff in OCR1A will indeed give a 50% duty cycle.

Making your robot turn a given amount depends on your individual robot, motors, gearing, etc. Assuming your motors are running and being controlled as you expect them to be, then this is just a matter of calibration. You have to figure out how long the motor has to be on in order to turn a measured amount.

Changing the prescaler value merely changes the speed the timer/counter runs at. Has no effect on duty cycle, so you're correct that the PWM is not affected.

Hope that helps.

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

Looks like I misunderstood how this forum thing worked. The preceeding was in response to murder01's question on page 1. Sorry about that, but I hope this is useful anyway. I still don't see any diagram of the circuit being used and how the PWM is applied.

Also, assuming you're using an AVR with "timer/counter 1", you can use ICR1 as TOP, and have both OCR1A and OCR1B available to control OC1A and OC1B respectively. This gives full control of Cycle Length, and Duty Cycle for two outputs.

Another point: Frequency correctness comes about in Phase and Frequency Correct mode because the updates to the OCR registers occur only at BOTTOM and you can avoid having any "odd length cycles" during the changes. This is a minor and obscure point (IMHO); phase correctness is a much bigger deal for stepper motor control anyway.

In case you all may not have noticed, I'm attempting a tutorial on PWM Modes (building on Dean's excellent work), but I'm having problems getting it entered in this forum. Please take a minute to read it over and give me some guidance on whether or not it is worth trying to post it here or not. Thanks!

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

youthreewire wrote:
How do I generate PWM from two Pins which go to a H-Bridge to stall a DC motor?What care is to be taken when motor is to be stalled?(I would refer to this as 1-1 state :stalled or brake,where 1-0 corresponds to say clock wise,0-1 to anti and 0-0 to off)

Could some one please guide me?

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

youthreewire wrote:
How do I generate PWM from two Pins which go to a H-Bridge to stall a DC motor?What care is to be taken when motor is to be stalled?(I would refer to this as 1-1 state :stalled or brake,where 1-0 corresponds to say clock wise,0-1 to anti and 0-0 to off)

The specifics depend entirely on which particular AVR you are using, but I presume what you want to do is set two channels to be on at the same time while the other two are off. Which two and how you go about it will further depend on your circuit...

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

I have an atmega8 connected to a H-Bridge for driving a single motor which has two signal pins for the input.Now I want to stall the motor.How shall I do it?

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

Quote:
How do I generate PWM from two Pins which go to a H-Bridge to stall a DC motor?

This discussion should really be taken to a separate thread in general AVR forum. This thread should be limited to questions or comments regarding the tutorial itself, not questions about the application of the tutorial in any specific circumstance.

Regards,
Steve A.

The Board helps those that help themselves.

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

hey great stuff dude! I went thru all your timer tutorials and it's very well written.

Just curious are you an engineeering student? I am as well and in university - you must be a top gun at uni then if you know how to program the AVR :)

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

knadoor wrote:
hey great stuff dude! I went thru all your timer tutorials and it's very well written.

Just curious are you an engineeering student? I am as well and in university - you must be a top gun at uni then if you know how to program the AVR :)

I'm currently in my third year of a double degree in Computer Science/Electronics Engineering at Latrobe University. I've been working with AVRs for longer than that however - since I was in early highschool.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

doctek wrote:

The duty cycle is simply the time the output is high divided by the total cycle time. So your total cycle time is 2048 clock ticks and if your OCR1A has 200 in it, then your duty cycle is (2*(1024-200))/2048 = 80%. Putting in 0x1ff in OCR1A will indeed give a 50% duty cycle.

Sorry for a stupid question but if 1024 is the max value of TOP, then shouldn't it be 1024 clock ticks? Can you please explain how you calculated the duty cycle with a figure? Why did you multiply by 2? If you use just (1024-200)/1024, you still get the same answer. Appreciate your help.

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

This and the timer are a excellent tutorial
i am newbie and currently working on this
hope to see the continuous part on this tut!

Pages

Topic locked