Pages

Thursday, July 22, 2010

Timers and Clocks and PWM! Oh My!

I am going to try and not be so wordy in this post since there is a lot to cover on this topic. I want to do it all at once too; I would rather you have fun code to play with than me do one part of just theory. At the end of this post you will have a PWM library you can use in your projects. So here it goes, let me know what you think.

A clock in embedded electronics is what controls how fast the processor ticks. The MSP430 has multiple clocks which can used for the peripherals and the CPU. MCLK is the master clock for the CPU. SMCLK is the submain clock. Both of these can be selected for use in the peripherals such as an ADC or Timer. I won't discuss ACLK here.

Why so many clocks? Power efficiency. Different clocks are turned off in different low power modes; for example LPM0 disables MCLK and the CPU but leaves SMCLK running so the peripherals hooked up to it can continue to run. These clocks can be generated from a number of different sources and can also be divided down from the clock input. For more information on this see the User Guide.

So. What is all this talk about a silly little Timer? The Timer keeps track of how many clock cycles pass without having to write specific code to keep track of time. This can be useful not only for low power modes, but also for time sensitive projects. To keep it simple and quick, a timer needs to be initialized and enabled. It will then proceed to count as the clock ticks to a predefined value and then start over. You can set the Timer to generate events at multiple times along the way to its end value; these events could be an interrupt when it hits a certain number of clock ticks, or it can toggle, set, or clear a specialized pin. Having the Timer change a pin without calling any interrupts or any specialized code is the best way to create a simple PWM.

What is PWM? Pulse Width Modulation. As far as we are concered, it is a square wave that has a duty cycle at a cetain frequency. Duty cycle is the percentage of time the wave is high across one period. How is it useful? Motor control, light control. Think of an LED, the lower the duty cycle (the less its turned on over a period of time), the dimmer it is. There are countless numbers of applications for using PWM.

More about the Timer

There are a few things you need to know before we start coding. As I said, the Timer counts clock ticks, in reality it can be that simple, but it does not need to be. For example the Timer can count up to a certain number or count up then down. The different functional modes are as follows (directly out of the User Guide).

1. Up Mode - the Timer repeatedly counts from 0 to the value set in register TACCR0

2. Continuous Mode - the Timer repeatedly counts from 0 to 0xFFFF

3. Up-Down Mode - the Timer repeatedly counts from 0 to TACCR0 and back down to 0

The picture above is a visual representation of Continuous mode (taken from the User Guide)

Personally I like Up Mode the best, so we will be using that to build our PWM library. So you can set up an interrupt for when the timer gets to TACCR0 or TACCR1, or you can toggle one of the timer.

The Test Code

Setting up the Timer

First we set up our PWM pins. The code below sets P1.2 to output and enables the pin to be the timer output bit TA0.1.

P1DIR |= BIT2; // P1.2 to output

P1SEL |= BIT2; // P1.2 to TA0.1

Next we have to set up the CCR0 and CCR1 registers, which determine when events happen and how high the clock will count to.

CCR0 = 1000-1; // PWM Period

CCTL1 = OUTMOD_7; // CCR1 reset/set

CCR1 = 250; // CCR1 PWM duty cycle (25%)

Remember, the timer depends on the clock frequency it is running on. So if you have a 1MHz SMCLK and want a PWM frequency output of 100kHz, CCR0 will have to count up to 10 leaving only 9 values for CCR1 to toggle the clock at. This limits the resolution the duty cycle can have. The default DCO (digital controlled oscillator) which is the source of the MCLK and in this case the SMCLK is approximately 1.1MHz, making the PWM frequency about 1.1kHz with a duty cycle of 25%.

Setting CCTL1 = OUTMOD_7 does two things, one of which might not be so apparent. OUTMOD_7 is the Reset/Set option,which means "The output is reset when the timer counts to the TACCRx value. It is set when the timer counts to the TACCR0 value" (From User Guide). This means that when the timer hits CCR0 it starts counting over AND sets the PWM output to 1; this also means that when the timer hits CCR1 it will set the PWM output to 0. See user guide for some nice pictures and explinations.

For this PWM program we will be using SMCLK and Up Mode for the timer. Now we have to set which clock and which mode the Timer is going to use. The following line of code sets the clock and the mode of operation.

TACTL = TASSEL_2 + MC_1; // Chooses SMCLK, and Up Mode.

In this register you can also set the interrupts to be triggered but we will not be doing that here since the PWM pin will be toggled without needing an interrupt.

That is it for the code, hopefully I explained it all throuroughly and efficiently. If you have any question or don't like how I'm writing this post, please let me know. I'm trying less opinion and more fact.

Hooking Up the Hardware

In order to visually see this in action, which I'm guessing a lot of you do, you can use either a Logic Analyzer, or ... an LED. So lets hook up the LED. Since we are limited as to which pins we can hook up to the timer using this method (we can't hook up P1.0), we will need to hook up P1.2 to one of the LEDs on the LaunchPad. I'm hoping that you have installed headers (either male or female) onto the LaunchPad already. Take out the jumper which is above one of the LEDs and then hook the LED to the pin P1.2 on the board. If you are having trouble with this, write a comment, I will help you.

Run the program, then modify away. As you change the duty cycle the LED's brightness will change. The closer CCR1 is set to CCR0, the brighter the LED will be, the farther away the darker it will be. Congratulations, you have tackled PWM and have a basic understanding of the Timer.

In a future post I will be providing libraries for some of the peripherals which you can simply include in your project; this is so you will not have to worry about all the details when using a peripheral. I could just provide those but I think you should understand how it all works before you use it, otherwise you would be programming in C# on a desktop computer. Libraries like I will provide were invaluable to me many years ago when I started with microcomputers.

Hope that was concise and made sense. Give me some feedback if you liked the style of this one better.

Warning: I am attempting to use SyntaxHighlighter for the first time with this post (Thank you for the tip Zunayed!). Please be patient if it takes me a few revisions to get the code displayed correctly (or even at all). Thanks for your patience.

Edit: I just corrected the commenting error in my code which incorrectly said ACLK. Also, below I added an image from my Logic Analyzer verifying the waveform so you guys can see what it looks like. I have P1.0 and P1.2 tied together.

@TDU,I've never heard of github.com, seems very cool! You might want to provide some more comments though up top in order to help out people who might not understand your code. From what I understand you have a PWM with a changing duty cycle every period? Also, watch out for setting LPM4 and LPM0 at the same time, I don't know how that will effect the uC. Thanks for posting your code :-)

@TDU,Out of curiosity, I checked to see what happens when you set LPM0 and LPM4 together. If you check the header files, LPM0 would put 0x0010 to the SR. LPM4 puts 0x00F0. LPM0 + LPM4 puts 0x0100, which leaves all the oscillators running and sets the V bit (which I believe is normally used to mark carry over from additions). The best thing to keep in mind is any LPM includes all the previous LPM's-- eg. LPM0 and LPM1 are subsets of LPM2. I ran some example code on my LaunchPad and confirmed that this is indeed the case; just watch the SR register in debug mode and you'll see what's happening.

@NJCHopefully you still check this even though this post is a few months old. First, thank you for the work you do on this blog. As a student I know you are very busy and I appreciate the time you sacrifice for this project.

As was already pointed out in another comment, LED2 on P1.6 can be used for pwm (P1.6 has compare functionality for Timer A). No need to mess with jumpers. Look at my code for details.

I also wanted to share some code I wrote to pulse an led.https://gist.github.com/750825

There is one oddity I noticed with my code. Upon initially flashing the launchpad it works as expected. If I then immediately re-flash and run the led stays solid. Re-flash once more and the program works again. Not sure what could be causing this. Perhaps the interrupt flag is someone surviving from the previous flash?

I had an idea while I was writing that code and I'm wondering if it would be feasible. If the chip contained another timer (some of the msp430s seem to have a Timer_B as well) would it be possible to set Timer_B to up/down mode (assume SMCLK = 1Mhz, Timer_A CCR0 = 1000), set Timer_B divider to 1000 and set Timer_A CCR1 = Timer_B TAR in order to vary the duty cycle up and down? If this would work I believe it would allow the chip to enter a lower power mode. Unfortunately I have now way of testing this as the chip included with the launchpad has only Timer_A but I would like to know if the idea is theoretically sound.

@Daniel, thanks for the post! As for the problem you are having with the LaunchPad, at first glance I have no idea what could be causing the trouble. To be honest, I have had problems with the LaunchPad's USB cable, and just loosing connection with the target chip in general. My theory is that it is the LaunchPad or the cables fault and it is nothing to worry about (it is just frustrating, I keep reminding myself this thing cost $4.30).

For your idea with the second timer it makes perfect sense and would most definitely work if implemented correctly. Though there are two ways that you could get this functionality with the chip that came with the LaunchPad. The first option is to use the WDT as a second timer, which I haven't ever worked with so I have no pointers there. The second option is to do it mathematically with a single timer. You would still be able to stay in LPM almost all the time, and would have to just add a few extra lines to keep track of your new CCR1 value in the interrupt routine. Feel free to post in 43oh.com/forum if you have any question. I'll be glad to help.

@NJCThank you for the reply. Hope that you have had a great holiday season! It occurred to me that I might be able to use the watchdog, but, looking at the Family User Guide, I see no way to set the watchdog to count up and down so I don't think I could use it as the second timer. Also, by my understanding, only Timer_A could be used to directly affect the pins, so I don't think I could have the watchdog do Timer_A's job and have Timer_A count up and down. Please correct me if I've missed something. As for a mathematical method, the only one I can think of is what I did in the code I posted above. Is there a more efficient mathematical method? Thank you for the 43oh.com recommendation. Looks like a really great forums!

I am also glad I found this blog. It has really helped me a lot! I was wonder if you ever posted on the libraries for the peripherals you mentioned. I was unable to locate that blog entry. It would really help me out as I'm still learning about micro controller programing.

It would only take a couple of quick modifications to this code to have a fixed pwm signal that is 2ms on and 20 ms off, right? I am brand spanking new to programming and this chip...but I am trying to learn as I work on a fun project.

NJC, hmmm nothing in particular actually. I was just refering to:"In a future post I will be providing libraries for some of the peripherals which you can simply include in your project; this is so you will not have to worry about all the details when using a peripheral. I could just provide those but I think you should understand how it all works before you use it, otherwise you would be programming in C# on a desktop computer. Libraries like I will provide were invaluable to me many years ago when I started with microcomputers."

I'm just getting started with micro controllers in general so I'm just browsing different projects and such and learning as I go.

@Max - I actually never made a library file for any of those like I planned on doing. The newer posts on the blog discuss functions which I would have included in a library.

@kenemon - the only way to really see the intensity change is to drastically change the values. Otherwise you would need an oscilloscope or logic analyzer (or even a high end multimeter) to tell you the duty cycle is changing.

I have a very basic question:the code above keeps the LED on and off forever, as long as there is power. Say I want to have an LED toggle for 1sec. Remain off for 2 seconds, and then have it toggle again for 1sec and so on, how can I do this with a timer.This is actually an IR application that I am trying to get working

Dominic, if I understand your question correctly, you would like to enable and disable the PWM at certain times and only for specific durations?

This can be done by incrementing a counter every timer interrupt (you have to enable the interrupt though). This allows you to keep track of how long the PWM has been running for. Once this value hits a certain threshold, you can stop the timer counter. Once you would like to start the PWM again, you just have to re-initiate the timer as I did in this example.

@Anonymous - I have not provided a library package or any specific library files, but much of the code I have provided in all of my posts can be used as libraries since I have self contained functions for almost everything. Hope that helps!

This code worked well for me. I added some code to change the duty cycle upon pressing the push-button on P1.3.

But i'm having trouble getting PWM to come out of any other pin. Because the chip (G2231) only has 1 timer and 2 CC registers does this mean i can only ever have 1 PWM with a duty cycle specified by CCR0 and CCR1?

I want to have 2 PWM signals coming out of the Launchpad that are compliments of each other, (with a little bit of dead time between them).

I tried initalising the P1.1 and P1.2 at the same time with this:

P1DIR |= 0x06;P1SEL |= 0x06;

To see if PWM would come out of both pins but it still only comes out of P1.2. I am getting confused with TA0.0 and TA0.1 from the msp430g2231 data sheet.

with some help from the TI E2E community (and a bit of reading) i was able to get two complimented PWM signals with dead-time between them. I ordered a free sample of the MSP430G2452 from the Texas Instruments website and plugged it into the launchpad, if you are going to get one make sure it is the correct package style (DIP).

If anyone is interested in doing the same thing here is a link to the post on the TI E2E website

Smoking Baby - sadly, this is not a straight forward task. You would need to manually change the compare register every interrupt and set each pin transition manually in the interrupt. If you have any questions on the implimentation, the forums at http://www.43oh.com would provide quicker answers than I would.

@Unknown - I am not sure I understand your question. If you would like to generate a PWM at higher frequencies (ex. 10kHz) you just need to set the timer and compare registers differently in the MSP430.

@1234 - If you are having trouble with modifying the code and would like to learn how to use C, I would recommend checking out the forums on 43oh.com. There are some very smart and nice people there who can help guide you. It is a bit easier to help in a forum than on a comment thread. :-)

Hi.Thank you very much for this walkthrough. Now i understand it much better. I just wondered about the same thing as Anonymous 1 did (see 3 posts above).In your Text , you say: "So lets hook up the LED. Since we are limited as to which pins we can hook up to the timer using this method (we can't hook up P1.0), we will need to hook up P1.2 to one of the LEDs on the LaunchPad" - But nowe you say "I have no problem blinking the red LED"...so what's it exactly? Why do you say, we can't hook up P1.0?

Thank you for pointing this out to me. I actually made a mistake in my response (see above). You are correct, using this method you cannot blink an LED on P1.0. The green LED will blink just fine using this method.

So, to correct my previous post:

Anonymous: If you want to blink the red LED, you cannot use the method discussed in this post. Instead you will have to manually toggle the pin in an interrupt. There are many possible reasons to why you are seeing an odd square wave on P1.0. It all depends on your program.

-Fahad,use the CCR0 value to change the frequency of the pwm: the higher its value(up to 0FFFFh) the lower the frequency you get.your output will be high from TAR=0 till TAR=CCR1. If CCR1 is close to 0 your pwm will quickly change to low. The closer CCR1 is to CCR0 the closer your duty cicle will be to 100%. (assuming output mode 7 reset/set)to get a 50% duty cicle use CCR1= (CCR0/2).I hope so, heh.

what do you mean by "vary the PWM duty cycle 10times in one PWM period"?

Hello,A quick question: if i put +ID_2 (input divider = 2) into TACTL register, ie TACTL = TASSEL_2 + MC_1 + ID_2; i will get a PWM frequency of about 550Hz ? (provided the rest of the code is left as posted in the blog)

could someone please help me with this....i need a pwm program code to drive dc motor.whenever it is switched on the motor should gradually start and should attain 1 constant speed.when it is switched off it should gradually stop instead of jerk.i m trying to build a electric wheelchair using msp430g2231.

I'm a beginner in MSP430 and I'm using G2553 ic. I would like to know how we can give a particular duty cycle? better you give an equation for it. (pardon me if nybody asks the same here). Thanks in advance..

This is the line that you will need to change. TASSEL_2 is for SMCLK, looking at the Value Line Family User's Guide on page it seems as if you cannot use MCLK as the timer clock. Typically, SMCLK is the same value as MCLK, does this not work for you?

Hi! I have to make a digital tachometer using msp430g2553 . It's an university project . Teacher said that i must generate PWM signal from a pin and then i must convert that signal into rotations per minute . After that i should display it on a 7segments display or LCD . Please help me anyone !

The short answer is yes. For devices with a hardware UART, it is quite simple. Take a look at TI examples for more information. When using a software UART, things can get a bit more complicated, but you can manually toggle pins for PWM in the timer interrupt routine. I hope that answers your question. Look for example projects, this is one of the best ways to learn.

So far, if I was using a 1MHz clock and wanted to make a delay of us microseconds, I've been using while(us--) { __delay_cycles(1); } but when measured against an oscilloscope, this approach is useless. How would you use timer and interrupt to make a more precise one?

You can a few options. If you only need a few microsecond delay, you should think of increasing the clock speed if you plan on using the timer. Otherwise, you can use __delay_cycles(us), since each clock tick is one microsecond. To use a timer, you could set the value which throws an interrupt to be your number of microseconds, and then put the CPU to sleep. When the interrupt is thrown, you can then wake the CPU up, resuming operation after a delay.

Hello, nice article in here, I learn a lot information. I have a question: can I run the MSP430 to Low Power Mode 0 where fsmclk = 1MHz and make a pwm pulse of 800kHz or 500kHz in 1.5% duty cycle. I could not understand how the precision is lost..

Thanks for the fast answer. So I can change the SMCLK speed in LM0? Because if I have SMCLK limited to 1MHz and need the pwm in 800KHz I will have only 2 available duty cycles. So my question is: If I want a high pwm signal(e.x.800kHz), I need to activate the CPU?

I would recommend calculating the clock frequency you need to achieve your desired output. From there, you can determine what clock it is possible to use on the MSP430, if it is possible at all. You can look at the family user guide and the device datasheet to see what is possible from a maximum frequency perspective.

Hi,as i try to debug, codecomposer says that CCR0, CCTL1, CCR1 and TACTL is undefined (e.g. #20 identifier "CCR0" is undefined). I am using the tutorial code on an MSP430F5438A.I am greatfull for any kind of help. Thanks in advance.

Each MSP430 has a different set of definitions for internal registers and peripherals. The best place to find these names is either in the definition header of the MSP430 Family User Guide. The Family User Guide is available for every MSP430 on the product page on TI's website. This is a great resource for understanding each peripheral and register.