[TUT] [C] Using AVR PWM Modes

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

Using AVR Timer/Counters: Pulse Width Modulation Modes

OK Freaks, thanks for your responses and suggestions after my plea (below). I've reposted the whole enchilada as a pdf with the code and makefile in a zip.

Please note: You have to log in if you want to be able to download the files and read the tutorial!

Does this work for everyone??


I'll wait a few days for comments and either repost (with a complete tutorial, or delete this and go to Instructables.

 

[Post #26 below says a couple of files are hosted at www.wrightflyer.co.uk, they aren't - they are now re-attached to this post - Cliff]

Attachment(s): 

Last Edited: Wed. Jan 15, 2020 - 09:08 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,
Thanks for the write up.

To answer your question, I would like to see a well commented, reasonably monolithic code example showing the usage of the pwm hardware.

Such an example could include the initialization of the pwm hardware, selecting prescalers (and the like) based on appropriate criteria (F_CPU being the most obvious), mode selection, output pin, duty cycle, frequency, hooking interrupts at various times in the cycle.. and so on and so forth.

ex; One large code block with many of the commonly used features represented, comments describing what each one does, and where features are mutually exclusive, only one is uncommented. The comments could also include datasheet page numbers to review for additional details.

I've always found it easier to start with something that is working, modify it, pick it apart, and learn from it while referencing a tutorial or the datasheet. The datasheet is horribly lacking a code segment pulling together and example of the usage of the hardware it is describing in the section - unless I'm just missing it. 350 pages, and very little example code.

Oh, and whatever you do, don't waste your time at Instructables. They've really gone down hill lately. So many things are turning into "Membership Benefit!"s. First we lost viewing all steps on one page, now you cannot view the other images posted for a step w/o logging in. Before long, all a person will be able to do (w/o logging in,) will be viewing the abstract of the instructable.

I'd rather not read a paragraph or two, then click on the Next button and wait for another page load just to read the next two paragraphs. Put the whole thing on one page, and remove the clutter from the rest of the page.

-Thanks.

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

Thanks for the excellent response, zphere. Hopefully, I'll get a few more opinions on this as well.

The sort of tutorial you're asking for is exactly what I have prepared and am trying to post. The first few parts that make up the posting so far are admittedly wordy, but provide the necessary background to understand the PWM modes. Not only do I have more detailed info on the PWM modes, but I have an example program that shows the modes in action and can be easily plagiarized for your own purposes. ("Show me a good programmer and I'll show you a good plagiarizer!")

I think you're a little harsh with Instructables. Your points are well taken, but here're a few counterpoints.

What's wrong with logging in? After all, we have to login in to Freaks to post, to see the Projects, and even to see the Figures that I included with my first post.

Yes, you have to click to see the next section, but you can always download the pdf version.

Finally, for the poster, Instructables handles uploaded code, figures, and files much better than whatever Forum Software it is that Freaks uses.

So here's what I'm thinking: I will actually post the Tutorial as several separate posts - one section (and no more than 3 figures or files each). I think this will work.

An alternative is to put the code, figures and diagrams in the Projects section. So a reader could download them, then read the Tutorial itself.

Any opinions or suggestions??

Thanks.

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

Quote:

An alternative is to put the code, figures and diagrams in the Projects section. So a reader could download them, then read the Tutorial itself.

Too complex - the best bet is to put the whole thing into a .PDF and attach it to a post here. (use CutePDF is you need a free PDF "printer")

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

Sounds like a good idea, I'll try it. It'll take a few hours to get the file all put together, then I'll post it.

In the mean time, I've noticed an error in the Makefile lines to enable the Clock Output. Don't use the code in my first post - I'll correct it in the new one.

Thanks again for the suggestion.

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

Quote:
Don't use the code in my first post - I'll correct it in the new one.

Edit any changes into earlier posts, too, since not everyone will read through the entire thread.

Chuck Baird

"I wish I were dumber so I could be more certain about my opinions. It looks fun." -- Scott Adams

http://www.cbaird.org

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

Done - Corrections are in the original posting.

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

All comments prior to this one were to the original (partial)post. Comments after this should be to the new pdf version and to the code that goes with it.

Hopefully, the pdf approach will be satisfactory! Thanks for your patience.

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

Thank's man now eat your whole enchilada and a few taquitos, thanks a lot

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

Thousand of thanks to u.great job man.

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

Your tutorial along with deans, are the best recipe for PWM!:D:D

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

Excellent tutorial (though I'm still mulling it over; my own app requires timer 0, so no frequency correct mode, making the examples a little less applicable for me). I did notice a mistake in Fig. 4 (p. 8): OC1A goes low when COUNT equals OCR1A and high when COUNT equals ICR1 (TOP). Text on p. 7 says, "When the COUNT is equal to the value in OCR1A, the output on OC1A will go high. As soon as the count reaches TOP, OC1A will be cleared." Sounds like just the opposite of what's shown. I know the output may easily be inverted, but the text should match the diagram.

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

If you're using just timer 0, then you have just Phase Correct Mode available. Since this mode offers the main advantages of Phase & Frequency Correct Mode, you'll be just fine and the examples I give should be fully applicable. In fact, I couldn't really come up with a good demo of P&F Mode vs. Phase Correct Mode only. P&F only helps if the behavior during a frequency transition is of great importance - usually it isn't. If you use Phase Correct Mode only in the examples I provide, you'll find the behavior is identical.

As far as Fig. 4 vs. the text, you are correct on both points. The text *should indeed* match the figure (sorry about that); and the behavior can be easily inverted. (Maybe that's what I was trying to illustrate and just didn't realize it? :)}

HTH.

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

Hi all,
seems everybody's using OC1A here... I have also tried to set pwm on OC1B of mega8 but it didn't work.
The (working) code I made for OC1A was:

void pwm_set_1A(unsigned char pulse_width)
{
DDRB |= (1<<1);         //Port B.1 as o/p (OC1A)
OCR1AL = pulse_width;   //Load Pulse width
OCR1AH = 0;
TCCR1A=((1<<COM1A1)&~(1<<COM1A0)|(1<<WGM10)&(~(1<<WGM11))); //8-bit, Non-Inverted PWM
//just a harder way to write TCCR1A = 0x81 :D
TCCR1B = 1<<CS10;             //Start PWM
}

Now, it works. Problem is with getting OC1B to work:

void pwm_set_1B(unsigned char pulse_width)
{
DDRB |= (1<<2);         //Port B.2 as o/p (OC1B)
OCR1BL = pulse_width;   //Load Pulse width
OCR1BH = 0;
TCCR1A = ((1<<COM1B1)&~(1<<COM1B0));//|(~(1<<WGM13)&(1<<WGM12))); //8-bit, Non-Inverted PWM
TCCR1B = ((1<<WGM12)&~(1<<WGM13));

TCCR1B = 1<<CS10;             //Start PWM
}

I am using these in:

while(1)
{		
	for(unsigned char i=0; i<0xff; i++)
	{pwm_set_1B(i); //pwm_set_1A(i) works here
	_delay_ms(5);
	}
	for(unsigned char i=0xff; i>0; i--)
	{pwm_set_1B(i);	
	_delay_ms(5);
	}
}

when I run it in Proteus, nothing comes on OC1B. Am I setting TCCR1A & TCCR1B the correct way??
Kind suggestions please...
-Regards,
Munish :roll:

-
Regards,
Munish

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

Quote:

Kind suggestions please...

How do you know Proteus simulates correctly?

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

Coz it is simulating OC1A correctly! and in hardware also I have connected 2 LEDs to both the OCs. OC1A lights (dims) its respective LED, while OC1B doesnt.

-
Regards,
Munish

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

Looks to me like you aren't really doing the same things to make OC1B like OC1A.
- You're making TCCR1A equal to just 1<<COM1B1. The setting of (1<<WGM10)&(~(1<<WGM11) is lost.
- Setting TCCR1B to (1<<WGM12)&(~(1<<WGM13) would select CTC mode. (See the Waveform Generation Mode Bit Description Table.)
- But that doesn't even happen since you then make TCCR1B equal to 1<<CS10 and wipe out the value of the other bits in TCCR1B.

Try this:

void pwm_set_1B(unsigned char pulse_width)
{
DDRB |= (1<<2);         //Port B.2 as o/p (OC1B)
OCR1BL = pulse_width;   //Load Pulse width
OCR1BH = 0;
TCCR1A = (1<<COM1B1) |(1<<WGM10)); //8-bit, Non-Inverted PWM

TCCR1B = 1<<CS10;             //Start PWM
} 

If you OR in the command to enable OC1B, you can keep OC1A running as well.

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

Thank you for the great+detail+ easy to understand tutorial!! Really helped me!! =)

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

Dear guyz i m getting a crrupeted zip from the link geven above? wht shld i do now?

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

is anyone one here writing bascom scripts for atmega48? This looks like all greek to me. I would pay someone to compile me a script.

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

Quote:
Dear guyz i m getting a crrupeted zip from the link geven above? wht shld i do now?

I just downloaded the zip file myself and it came in just fine. Maybe try again??

Quote:
is anyone one here writing bascom scripts for atmega48?

Sorry, I don't do bascom. Maybe someone else would be interested?

HTH.

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

thank you doctec.[b]

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

great tutorial. thanks.

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

i cant download the link either...the download never starts....can you upload it again please?

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

bolterX wrote:
i cant download the link either...the download never starts....can you upload it again please?
I cant download it either :( can you please put it again? thanks.

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

As folks seem to have problems with the two files in the first post I've re-hosted them on my website here:

http://www.wrightflyer.co.uk/CT_...
http://www.wrightflyer.co.uk/Usi...

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

Thanks for re-hosting the files, but I really can't figure out the problem. I just tried again to download them and they came down with no problem. People do understand they have to log in, right? That's the only thing I can think of that might be wrong.

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

Yeah it's odd - the very fact that I've rehosted them means I went to the first post and downloaded them - it worked for me. I would agree that the posters to this thread probably weren't logged in when they tried to download them EXCEPT that to post here they have to be logged in?!? (unless they try to download when not logged in then actually log in to post without bothering to try and download again?)

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

Hi
I'm not able to download the pdf writeup. It abruptly stops after a while downloading. Please send me one if somebody has it.

thanks

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

Quote:

It abruptly stops after a while downloading. Please send me one if somebody has it.


Did you try my link above:

http://www.wrightflyer.co.uk/Usi...

I just downloaded the one from the first post and refreshed that to make sure it's up to date - works for me.

Cliff

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

thanks it did work for me.

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

I have a question concerning PWM. I've read the tutorials and i have a question. Maybe it's written in the tutorial but i either missed it or failed to understand.

if i set a counter to Phase correct PWM and counting to top(0xff in 8 bit counter) and set OCR1A(e.g.) to 0 what kind of wave will be generated on OC1A if i specified that it is reset on count up and set on count down.

"If what you have done yesterday still looks big to you, you haven't done much today. - Mikhail Gorbachev"

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

In the data sheet under the timer mode you are interested in there will be a statement something like this:

Quote:
The extreme values for the OCR0A Register represent special cases when generating a PWM waveform output in the phase correct PWM mode. If the OCR0A is set equal to BOTTOM, the output will be continuously low and if set equal to MAX the output will be continuously high for non-inverted PWM mode. For inverted PWM the output will have the opposite logic values.
Be sure to check the data sheet of the AVR that you are using since this might not be the same for all models, and it certainly is not the same for all modes.

Regards,
Steve A.

The Board helps those that help themselves.

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

Thank you. It says exactly the same. i menaged not to see it somehow :S

"If what you have done yesterday still looks big to you, you haven't done much today. - Mikhail Gorbachev"

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

Thank you,goodtutorial

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

Figure 8 (Correction Phase/Frequency PWM) seems to fix.
I know: greater OCRxA/B, greater duty cicle (not inverted mode).

My (HW && SW) Setup: (MyAVR USB Programmer | bread-board | Butterfly | Arduino 10k | ATtiny2313 | ATmega8) && (WinAVR | AVR asm | AVRstudio)

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

Your post is very unclear, but if you mean that you think the diagram does not match the code, you are wrong. The code has the output being set on up-count and clear on down count, which means that the duty cycle decreases when OCRxA/OCRxB increases.

Regards,
Steve A.

The Board helps those that help themselves.

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

Koshchi wrote:
The code has the output being set on up-count and clear on down count, which means that the duty cycle decreases when OCRxA/OCRxB increases.

Yes, in the last example (P&F corrected PWM) it uses "inverted mode" in source code (instead of "not inverted mode" used previously) but without inform the reader.

My (HW && SW) Setup: (MyAVR USB Programmer | bread-board | Butterfly | Arduino 10k | ATtiny2313 | ATmega8) && (WinAVR | AVR asm | AVRstudio)

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

It may be useful to know that there is a general problem on word BOTTOM in AVR datasheets when describing the time of OCRx update and setting timer overflow flag.
In fast pwm mode, updating OCRx at BOTTOM means "updating OCRx when entering the BOTTOM (at the same timer clock cycle as the TCNTx is cleared)".
But in phase-frequency correct pwm mode, updating OCRx at BOTTOM means " updating OCRx when leaving the BOTTOM (at the same timer clock cycle as the TCNTx is going from BOTTOM to BOTTOM +1)".
Also timer overflow flag is set when moving from MAX or TOP to BOTTOM (entering zero) in normal, CTC and fast pwm modes.
But this is not the case for phase correct and phase-frequency correct pwm modes and the overflow flag is set when moving from BOTTOM to BOTTOM+1 (leaving zero and entering 1).
Therefore by assuming TCNTx=0, only one clock will set the overflow flag in phase-frequency correct pwm mode, because of moving TCNTx from BOTTOM to BOTTOM+1.
Atmel simply writes "BOTTOM" for all timer modes. I have informed atmel support about this problem but:

Quote:
Dear Customer,

The word "BOTTOM" in timer context refers to the lowest possible count in the timer which is 0x00. In all the timer modes, the overflow flag will be set after the timer reaches the TOP value. Can you please specify the datasheet and the section where you found the discrepancy?


Apparently, they need to read their datasheets at first.

Ozhan KD
Knowledge is POWER

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

The overflow flag is always set on the clock after the specified value (TOP or BOTTOM) is reached. This is the same in all cases, so I don't believe that there is an inconsistency here. However, the update of OCRxx for Fast PWM should be TOP to be consistent, especially since the overflow and the update happen on the same clock.

Regards,
Steve A.

The Board helps those that help themselves.

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

Final atmel response (after a long time):

Quote:
We are able to confirm that the OCR register is updated when TCNT=BOTTOM+1 in the phase and frequency correct PWM mode. We’ll post a bug in the datasheet regarding the same and we assure you that this will be corrected in the subsequent versions. Thank you taking time to report the same.

Ozhan KD
Knowledge is POWER

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

I'm trying to translate all of this (your tutorial) into assembly for the ATTiny85 and can't wrap my aged brain around the 'C' code examples you give. In fact I can't find anyone who has coded PWM functions in assembly.
If you know of anyone that has coded PWM for motor speed control in assembly and has posted some examples please let me know.

FYI the 2313 now has table 46 on page 106 (not 110) in their latest datasheet.

BADBAUD

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

Quote:

can't wrap my aged brain around the 'C' code examples you give

When setting up timers the only C involved is pretty much

SFR = val;

which directly translates to something like

LDI R16, val
OUT SFR, R15

so translating his C should be simple. I guess the only complication is his use of the _BV() macro and the fact he uses |= (OR with existing) and &= (AND with exitin, so when he uses code such as:

#define PORT_CT	PORTB
#define DDR_CT	DDRB
#define	CT1A	PB3		// OC1A
#define	CT1B	PB4		// OC1B

	DDR_CT |= _BV(CT1A) | _BV(CT1B) ;   /* Enable CT1 output pins */
	PORT_CT &= ~(_BV(CT1A) | _BV(CT1B));     /* Set them to lo - LEDs off */

I guess the direct equivalent is:

#define PORT_CT	PORTB
#define DDR_CT	DDRB
#define	CT1A	PB3		// OC1A
#define	CT1B	PB4		// OC1B
#define _BV(n) (1 << n)

IN R16, DDR_CT
ORI R16, _BV(CT1A) | _BV(CT1B)
OUT DDR_CT, R16

IN R16, PORT_CT
LDI R17, _BV(CT1A) | _BV(CT1B)
COM R17
AND R16, R17
OUT PORT_CT, R16

(there may be a way to invert R17 at assemle time instead of my COM R17 but I'm afraid I don't know the Atmel assembler that well).

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

I didn't see the BV relationship either, thanks for pointing it out.

BADBAUD

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

The pdf seems to have gone missing form here ? Any chance it could be reposted ?

 

Thanks 

 

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

madmax_7 wrote:

The pdf seems to have gone missing form here ? Any chance it could be reposted ?

 

Thanks 

 

 

THis thread is 13 years old....highly doubtful.

 

I would suggest you start a thread in the General programming forum, or if you know what AVR you are using in the appropriate forum there.

 

JIm

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

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

Perhaps, try one of these (the first link may be the doc you seek):

https://www.scribd.com/document/...

 

http://ww1.microchip.com/downloa...
 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Tue. Jan 14, 2020 - 07:43 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The pdf is archived in the Wayback Machine: https://web.archive.org/web/2015...

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

Crikey www.wrightflyer.co.uk is (or rather WAS) my domain. Hadn't realised I was involved in this - I must have copied the file from somewhere else and hosted it there at some time. But I let the domain lapse. So, anyway, I've noe collected it from the wayback machine and reattached it to post #1

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

Thank you everyone. Thanks a lot for re-posting this !!!