MSP430 Timer Tutorial Launchpad article

MSP430 Timer PWM Tutorial

 

In this MSP430 timer PWM tutorial the basic workings of the on board timer peripheral will be explained, along with some C code examples which can be downloadable at the end of the tutorial.  Additionally the video below demonstrates the examples ‘A picture paints a thousand words, a video displays a thousand pictures’.

The MSP430G2253 will be used as it has two timers opposed to the MSP430G2231 which only has one timer, this will allow for different examples to be shown.  All the code in the MSP430 timer tutorial is written in Code Composer Studio (CCS) v5.5.  As the tutorial will be using the MSP430G2253 as the test microcontroller, downloading the datasheet for this maybe of use and can be found here.

Before reading further if you are having trouble understanding how the registers work, and how the C code updates the individual register settings?  It would be worth reading my MSP430 Programming Tutorial, Part 1 covers the basics and Part 2 gives clear examples.  You can find them here Part 1 and Part 2.

The MSP430G2253 has two 16 bit timers, Timer0 and Timer1 both are Timer_A variants with three capture/compare registers.  The MSP430 family guide lists two types of 16 bit timer, Timer_A and Timer_B.  For the most part they are very similar except Timer_A has up to three capture/compare registers, were as Timer_B has up to seven.  The MSP430G2253 also has a watchdog timer which can be used detect system malfunctions, but will not be covered in this tutorial. The feature list for Timer_A is shown below:

  • Asynchronous 16 bit timer/counter with four operating modes
  • Selectable configurable clock source
  • Up to three configurable counter/compare registers
  • Configurable as outputs for PWM
  • Asynchronous input and output latching
  • Interrupt vector register for fast decoding of all Timer_A interrupts

Asynchronous 16 Bit Timer

The 16 bit timer increments or decrements a value from the Timer_A register (TAR), every rising edge of the clock pulse.  The TAR value can be read or written with software, and an interrupt can be enabled to generate when it overflows.  If the timer is run asynchronous to the CPU clock, any reading from the TAR should occur while the timer is not running, as the result is likely to be unpredictable.

The four modes of operation for the timer are:

Stop – The timer is stopped

Up – The timer counts from zero to the value of TACCR0

Continuous – The timer counts from zero to 0FFFFh

Up/Down – The timer repeatedly counts from zero up to the value of TACCRO (+1) and then back down to zero.

Configurable Clock Source

The clock source for the timer can be from ACLK, SMCLK or from an external source via TACLK or INCLK (Device specific).  The clock source selected can be then divided by 1, 2, 4 or 8.

Counter Compare Registers

The capture/compare blocks inside Timer_A are all identical.  Any of the TACCRx blocks may be used to capture timer data or generate intervals.  When in capture mode the Capture Compare inputs CCIxA and CCIxB, can be connected to external pins or internal signals. They can be configured to capture on a rising, falling or both edges.  The compare mode is used to generate PWM output signals, or interrupts at specific time intervals.  Each capture/compare block has an output unit, which is used to to generate output signals like PWM.

Interrupt Vector Register

The Timer_A module has two interrupt vectors linked to it: TACCR0 interrupt vector TACCR0 Capture Compare Interrupt Flag (CCIFG) and Timer_A Interrupt Vector Register (TAIV) for all CCIFG flags and Timer_A Interrupt Flag (TAIFG).  The TACCR0 CCIFG has the highest priority of all the interrupts for Timer_A.  The TAIV is used to prioritise and combine the TACCR1 CCIFG, TACCR2 CCIFG and TAIFG flags.

Timer_A Registers

The Timer_A module is configured with software by setting the bits inside the various registers, which alter the timers parameters.  The image below list the various registers associated with the Timer_A module.

MSP430 Timer Tutorial Guide Timer_A Registers

Timer_A Control

This register determines where the clock is sourced from and how the clock is divided either by 1, 2, 4 or 8.  The timers control mode is also set here, whether it’s stopped, counts up, continuous or up/down.  The TAR , clock divider and count direction can also be reset with the TACLR bit being set.  Lastly the Timer_A interrupt enable/disable and interrupt pending flag are also found here.  A typical command for this register looks like this TA0CTL = TASSEL_2 + MC_1; or TA1CTL = TASSEL_2 + MC_1;

Timer_A Counter

The Timer_A registers or TAR holds the count of Timer_A.  A command using this register could look something like this depending on your application TAR = 4500-1;

Timer_A Capture/Compare 0

The Timer_A capture/compare register 0 or TACCR0, is used in two cases.  In compare mode this holds the value for comparison with the timer value in the TAR.  When in capture mode, the value in the TAR is copied into the TACCR0 when a capture is performed.  An example of the register code would be as follows TA0CCR0 = 200-1;. 

Timer_A Capture/Compare Control 0

The Timer_A capture/compare control register 0 or TACCTL0, is a 16 bit register used to determine how the TACCR0 is set-up.  The register controls whether the timer module is set to capture or compare.  The trigger edge for the capture mode can be set, as well as where the source originates from, either internal or external.  Asynchronous or synchronous operation can determined, as well as synchronised capture or compare input.  There are various output modes, which are used to determine the operation of PWM signals for example.  Also this register allows interrupts to enabled for the timer module.  An example of the register code would be as follows TA0CCTL0 = OUTMOD_7 + CCIE;.

Timer_A Capture/Compare 1

The Timer_A capture/compare register 1 or TACCR1.  Has the same operation as TACCR0.  An example of the register code would be as follows TA0CCR1 = 200-1;. 

Timer_A Capture/Compare Control 1

The Timer_A capture/compare control register 1 or TACCTL1, is a 16 bit register used to determine how the TACCR1 is set-up.  Has the same operation as TACCTL0.  An example of the register code would be as follows TA0CCTL1 = OUTMOD_7;.

Timer_A Capture/Compare 2

The Timer_A capture/compare register 2 or TACCR2.  Has the same operation as TACCR0.  An example of the register code would be as follows TA0CCR2 = 200-1;. 

Timer_A Capture/Compare Control 2

The Timer_A capture/compare control register 2 or TACCTL2, is a 16 bit register used to determine how the TACCR2 is set-up.  Has the same operation as TACCTL0.  An example of the register code would be as follows TA0CCTL2 = CCIE;. 

Timer_A Interrupt Vector

The Timer_A interrupt vector register or TAIV, is used to prioritise and combine the remaining interrupt flags.  When reading the TAIV it will give the value of the current interrupt, as well as clearing that interrupts flag.

 

Timer Example 1

This first example demonstrates the use of one timer, which is used to flash the MSP430G2253 Launchpad LED’s on and off.  The code snippet below only shows the timer set-up and the interrupt handler, as these are the most relevant parts.

The code is fairly short and quite simple to walk through, in line 5 we first load the TA0CCR0 with the value 3000.  Line 6 turns the interrupt on for the TA0CCR0 when it overflows.  Line 7 sets the clock source to ACLK (12kHz) and the counter to count-up mode.  So the interrupt is generated every 250mS approximately.  Line 9 sets the MSP430 to low power mode and enables interrupts.  Lines 12 to 22 are the interrupt handler for Timer0_A, this interrupt automatically clears when called.  Inside the interrupt handler, the variable Control is used to ensure the green LED flashes once for every time the red LED flashes four times.  The closing brace marks the end of the main function.

Example 1 Code

The link below contains the zip file with the full example C code, there is a small advert page first via Adfly, which can be skipped and just takes a few seconds, but helps me to pay towards the hosting of the website.

MSP430 Timer Tutorial Timer Example 1

I take great care when writing all the tutorials and articles, ensuring all the code is fully tested to avoid issues for my readers.  All this takes time and a great deal of work, so please support the site by using the Adfly links etc.  If you have found this useful or have any problems implementing, please feel free to leave a comment and I will do my best to help.

Timer Example 2

The second example demonstrates the use of two timers, which are used to output PWM signals on GPIO pins P1.2 and P2.1.  The timer set-up code and also the GPIO set-up code is shown below.  The clock was set to 8MHz for this example.

Before walking through the code, the image below is extracted from the MSP430G2253 datasheet, this shows GPIO pin P1.2 and it’s functions.  The line which is highlighted demonstrates P1.2 can be used as an input and output for Timer0_A.

MSP430 Timer Tutorial GPIO Pin Functions

Walking through the code starting with line 5, this sets GPIO pin P1.2 as an output.  Line 6 selects the function for GPIO pin P1.2, and in this case it is used for PWM.  Lines 7 and 8 perform the same operation, except they are for GPIO pin P2.1.  line 11 the TA0CCR0 is loaded with 200, this sets the PWM frequency to 40kHz approximately.  Line 12 sets the output mode to reset/set.  Line 13 sets the count value of TA0CCR1, which determines the PWM duty cycle, in this case 50%. Line 14 sets the clock used by the TA0CTL to SMCLK and the counter to count-up mode.  Lines 17 to 20 set-up Timer1_A in the same way as Timer0_A, except the frequency is set to 8kHz approximately.

The image below shows a capture from the oscilloscope for this code, GPIO pin P1.2 is shown on channel 1 and P2.1 is shown by channel 2.

MSP430 Timer Tutorial Dual PWM example

Example 2 Code

The link below contains the zip file with the full example C code, there is a small advert page first via Adfly, which can be skipped and just takes a few seconds, but helps me to pay towards the hosting of the website.

MSP430 Timer Tutorial Timer Example 2

I take great care when writing all the tutorials and articles, ensuring all the code is fully tested to avoid issues for my readers.  All this takes time and a great deal of work, so please support the site by using the Adfly links etc.  If you have found this useful or have any problems implementing, please feel free to leave a comment and I will do my best to help.

Timer Example 3

The third example demonstrates the use of two timers, using PWM generated by Timer0_A and a timed interrupt on Timer1_A to alter the duty cycle.  The PWM output is configured to output on GPIO pin P1.6.  As with the previous code examples, only the timer set-up code is shown. The clock was set to 1MHz for this example.

Lines 5 to 8 in this example are almost identical to lines 5 to 8 in the example 2 code.  The main difference is the PWM frequency is set to 1kHz (clock set to 1MHz) and the duty cycle is initially set to 0.1%.  Lines 11 to 13 set-up Timer1_A, this has a count of 4000 so generates an interrupt every 4mS.  Line 15 sets the MSP430 to low power mode and enables interrupts.

Lines 18 to 25 are the interrupt handler for Timer1_A, as with the first example this interrupt automatically clears when called.  Inside the interrupt the value stored in TA0CCR1 is added to the variable IncDec_PWM which is multiplied by 2 every time the interrupt handler is called.  IncDec_PWM is a global variable and assigned the value 1.  This equates to the value in TA0CCR1 being incremented or decremented by 2, therefore the duty cycle changes by 2 or (0.2%) every time the interrupt handler is called.  This equates to a transition time of approximately two seconds from high to low and low to high.  The final if statement inside the interrupt handler reverses the direction of the duty cycle, causing the LED to decrease in brightness until a value greater than 998 is reached, and increase in value when a value less than 2 is reached.

Example 3 Code

The link below contains the zip file with the full example C code, there is a small advert page first via Adfly, which can be skipped and just takes a few seconds, but helps me to pay towards the hosting of the website.

MSP430 Timer Tutorial Timer Example 3

I take great care when writing all the tutorials and articles, ensuring all the code is fully tested to avoid issues for my readers.  All this takes time and a great deal of work, so please support the site by using the Adfly links etc.  If you have found this useful or have any problems implementing, please feel free to leave a comment and I will do my best to help.

There is also one more additional example for the timer, which demonstrates the capture mode.  This is actually part of a another tutorial based around switch debouncing, the timer is used to capture the undesired pulses generated by a noisy switch.  You can find the additional code by browsing to the end of my Switch Debouncing Tutorial Pt/1.

38 thoughts on “MSP430 Timer PWM Tutorial

  1. Kemalettin ASLAN

    Hi. I had tried Timer Example 3 on CCS an IAR and I’d obtained hex codes. There is not problem so far. But When I loadet it on proteus I wasn’t able to see results. No results on pins. What is the reason? Can anybody explain this to me?

    Reply
  2. erron anderson

    Ant,
    your work has proven useful to me as a novice in programming. Furthermore, I was unable
    to follow the cookie as I am of the old school(cookies are to be eaten, gay is happy, etc.).
    Anyway, I appreciate the clarity and thoroughness of your work.

    EA

    Reply
    1. Ant Post author

      Hi Erron,

      Thanks for the comment and really glad some of my ramblings have been of use 🙂

      Regards,
      Ant

      Reply
  3. sanket

    i want to count heart beat for 1 minute using counter and timer can you help me with the code please..
    im using msp430g2553

    thanks

    Reply
    1. Ant Post author

      Hi,

      I have a frequency counter example using a Stellaris on the website, a similar setup can be used on the MSP430. The below post is originally for the MSP430F550x series, but I contributed some code for a MSP430G2553 frequency counter.

      MSP430 based frequency counter

      What you need to be aware of is your are reading a much slower frequency, so your sampling period needs to be longer. I don’t know what your signal looks like from the heart rate monitor, but assuming it can be turned into a relatively clean pulse for the microcontroller avoiding incorrect readings, you can try something like this:

      Set the sample period to be a fifteen second period, add the samples up and then multiply by 4 and you then have a beats per minute (bpm), you could change this to one minute if required. If you have this you can then try different sampling periods and averaging, or sample for 4 fifteen second periods and just add then together.

      Cheers,
      Ant

      Reply
  4. Hasan

    Hi Ant,

    Thanks for the nice tutorial. I am using MSP430F5438A. I have a question regarding it. I got the idea about generation of PWM signal using timer A. But, if I ended the program with an endless loop, LPM0 or a command LPM3, does the output will vary? please let me know if possible. Thanks.

    Hasan

    Reply
    1. Ant Post author

      Hi Hasan,

      The timer should still run as when you send the CPU into low power mode the timer can still run the PWM.

      Regards,
      Ant

      Reply
  5. rwalsh

    Great examples; thanks you! I seem to also be having problems with downloading the full code. About 40% of the time Firefox warns me the sight is a threat (either malware or phishing, I’m guessing the former), and the other 60% of the time, the file that’s available for download is “Setup_ODM.exe” which is not what I expected. I’m not sure how adf.ly works, but I cannot (and do not want to) download and install that. I fully support paid work, so I’m not complaining, but just letting you know. It’d be nice if there was another avenue to get compensation. Either way, the code posted above is useful, so thanks again. (Also, the explanations are top-notch; very succinct.)

    Reply
    1. Ant Post author

      Hi,

      Thanks for the comments and information about Adfly. I was not aware there might be phishing links associated with Adfly or unwanted .exe file downloads. I have a bit more time now and considering updating all the links and removing Adfly, your comments make me think I need to do this sooner rather than later.

      It’s not easy as like posting all the information but takes a fair amount of time putting it altogether, I just wish less people used Adblockers, as all the free content out there often relies on this as a small source of revenue (that’s my little rant).

      Thanks again,

      Ant

      Reply
    1. Ant Post author

      Hi,

      If its a single pulse you could pull a pin high for a time determined by a timer and the low again once the count is reached. There are basic examples that come with Code Composer Studio which can be modified.

      Reply
  6. praveen

    hi ant,
    its really a nice tutorial. i want find the pulse width continuously which is generated from the function generator. please suggest me what kind of method can i use.

    Reply
    1. Ant Post author

      Hi Praveen,

      It is possible to measure the pulse width in the following way:
      Enable a port as an input and interrupt enabled to trigger on the leading edge of the pulse. When the interrupt is initiated start a counter, you will then need to wait for the leading edge of the pulse and once this triggers a further interrupt, stop the counter.

      The count value will give a good indication of the pulse width, there will obviously be some inaccuracy as there is a certain overhead of clock pulses due to the interrupts being serviced. If you have the microcontroller running at at a faster frequency this will help service the interrupt quicker. A well calibrated clock source and good understanding of the clock cycles overhead will also help with accuracy. I am unsure what frequency of the pulse you are measuring, but you will need to store the count value somewhere or it may get over written, or possibly take multiple readings and average them.

      Cheers,
      Ant

      Reply
  7. Binz

    Hi Ant,
    its an great work, i really appreciates your effort. but i try to download the full code with different browsers but its not opening. Can you provide any other link. I really want to know all the instructions for PWM generation.
    pls Help

    Reply
  8. monaalex21

    Great Post. Can i use Timer1 to count the rising edge of Timer0? Lets say i want to output a pulse of 50us for ‘1’ bit and 100us for ‘0’. So if i set Timer0 to 40KHz and duty cycle of 25us. I can count two rising edges of Timer0 for ‘1’ bit and four rising edges for ‘0’. Is this possible?

    Reply
    1. Ant Post author

      Hi,

      I think you would be better off writing a function to perform this task, then manually tune the GPIO timings to perform what you need. Not sure what your end application is or what trigger you need to perform this pulse, but you can use an interrupt to monitor a port pin and act as required.

      Cheers,
      Ant

      Reply
        1. Ant Post author

          Hi,

          Ok this is bit more information than before and sheds some more light on your problem!

          This is basically a protocol with a bit stream of data to control various assets for a model railway. These two links provide more detail about the protocol, timing diagrams etc.

          http://www.nmra.org/sites/default/files/s-92-2004-07.pdf

          http://www.nmra.org/sites/default/files/s-9.3.2_2012_12_10.pdf

          You have several routes you can take from here;

          I would first research the protocol a good start is the links I have provided, see if there are any existing microcontroller examples you can find that other people have implemented and you can learn from.

          I would probably post a question on the 430h forum, but do some research first and show some willing to actually understand the issue and possible solutions. For any question provide background information so the reader can quickly understand what you are trying to do, some images from the PDF links will definitely help with that. I think as far as coding a timer is not the way to go, bit banging or the use of the USI or USCI module is probably preferable. I only have limited experience of using the USI and USCI, although I intend to change that over the coming months, so your best bet for advice on this would be the 43oh forum.

          Hope this helps,
          Ant

          Reply
  9. Yeshwanth Kumar J

    Hello Ant,

    Is it possible to do frequency comparison using the capture mode(Compare it with a preset frequency for a minimal time of 100ms) and cause interrupt if there is any change between the frequencies?? If yes, give me some idea on how to do abt it..

    Reply
    1. Ant Post author

      Hi,

      You should be able to capture pulses and I have code for the MSP430 in my debounce tutorial, counting them and then calculating the frequency is not difficult and a basic example is shown in my Stellaris frequency counter tutorial. However instead of displaying the frequency you want to compare that frequency against a set value or ensure it falls between two values to allow for any inaccuracies in your readings and give the system a tolerance.

      Then it is falls within your desired frequency nothing happens, if it’s out generate and interrupt or use some other flag.

      Hope this helps,
      Ant

      Reply
      1. Yeshwanth Kumar J

        Hello Ant,
        Thanks for your reply, I did try your suggestion for past two days but in futile.
        The basic problem I faced is in the allocation of registers(Setting up the counter for rising edge, and setting another timer for 200ms and stoping the counter etc.) I tried to understand it from the datasheet but I did not find the bit wise allocation procedure( I am using MSP430fr5969).
        Could you suggest some way that I could get out with??

        Thanks
        Yeshwanth Kumar

        Reply
        1. Ant Post author

          Hi Yeshwanth.

          No problem. Ok I can only offer advise at the moment simply due to other commitments, this is how I would approach the problem:

          A) The debouce tutorial part 1 has some basic code for counting falling edges, I would confirm you can get this working and adjust for your leading edge.

          B) With the code in the first part working what you need to do is set-up another timer to count and generate an interrupt say every 500mS. I would test this my toggling one of the on board LED’s as it’s an easy way to test

          Ensure both code A and B are working, then you need to bring them together. Basically what you want to do is have ‘A’ running all the time, then when ‘B’ generates an interrupt, inside the interrupt have the following code
          {
          copy the value held in the count register of the ‘A’ code into a variable then reset the count register for ‘A’ to zero.
          }

          Using the copied count value you can then calculate the frequency and use this to carry out the rest of your code. The counter register is cleared and begins to count again until the interrupt is generated and the process begins again.

          You will need to tune it for accuracy and note your maximum frequency as the counter will only hold a certain value, which is dependant on how quickly your timer interrupt fires.

          Cheers,
          Ant

          Reply
  10. Nolan

    Ant,

    Very useful tutorial for some one brand new at this. I am using a MSP430fr5969 for a robotics application that requires the use of two servos. Since the board only has one hardware pwm, i think i need a piece of code like this to generate a software pwm on a second pin.

    First I am unsure of how to combine your .c files and my main code i wrote in energia together.

    Second, When changing the pins used in the first pwm example (in order to use the pins on my board with the correct timers attached) where can i find the proper names? I have only seen them called by the pin maps online (P1_2) but never as just a plain “P2…”

    Any help would be appreciated.

    Thanks,
    Nolan

    Reply
    1. Ant Post author

      Hi Nolan,

      Good you found the tutorial useful.

      I have not worked with Energia as wanted to understand the MSP430G’s from the ground up, Energia is very good so I have heard but you are a little removed from what exactly is going on in the registers.

      Pretty sure the MSP430FR5956 can generate more than 1 hardware PWM, I have used a software PWM before and its not advisable unless it’s you only option. To try and answer your questions see below:

      1) I am not sure how the Energia code and any C code will interact, but I would have thought if the Energia code sets up a timer in a certain way, then the C code is executed and changes that timer the last executed code will take precedence. No guarantees this will work but try using Energia to set-up the 1st PWM check it works, then use the C code for the 2nd and test again, bit of trial an error here but might be your best route, just break it down and test each step so you can then trace back to where the error was introduced.

      2) Energia should have a guide explaining how the functions work, it’s based on Arduino libraries which have similar guides or comments, finding this is not always easy but there must be a wiki or something similar. As far as the C code register commands for the MSP430 series find the family guide and look through the relevant peripheral sections, I have listed some in the tutorial. The code can appear cryptic, but if you look in the family guide it does explain how each register is used. My other guide on programming the MSP430 may be of use here, as a good understanding on bitwise operations in C will help.

      This link may help from a quick search on Google, looks like code for 2 PWM’s on a MSP430FR5956 HERE

      Regards,
      Ant

      Reply
  11. Kal

    I believe the paragraph headers for Timer_A Capture/Compare and Timer_A Capture/Compare Control should be switched. This change needs to be propagated through for registers 0, 1 and 2.

    Other than that, well done.

    Reply
    1. Ant Post author

      Hi Kal,

      Thank you very much for the feedback and pointing that little mistake out, I have amended the paragraph titles.

      Cheers
      Ant

      Reply
  12. Marinho Augusto

    Hi All,
    How can I set the timerA in a continuous mode? for example, to get a sequence of 4 pulses (10, 70, 90 e 20%) repeats at 4 Mhz every 0,25ms. Fclk= 2MHz. I want to know which values go to TACCR0, TACCR1 e TACCR2. How can I calculate them?

    Thank you,

    Mario

    Reply
    1. Ant Post author

      Hi Marinho,

      It sounds like an unusual application.

      I guess you need one timer to generate the PWM frequency, then a second timer to generate an interrupt every 250uS. Inside the interrupt place your code to change the counter which determines the duty cycle.

      If you need the duty cycle to change at a precise time, then you may need to have the timer interrupt fire every 240uS, which will then allow the duty cycle code to execute and update. This will be a bit of trial and error, but using an oscilloscope will help you capture the pulse timing to tune it.

      Regards,
      Ant

      Reply
    1. Ant Post author

      Hi,

      Well if you look at the MSP430G2553 for example which comes with the basic launchpad, browsing the datasheet look at the ‘Terminal Functions’ section which lists each physical pins functions. The link below will also help clarify the MSP430G2553 capabilities.
      http://forum.43oh.com/topic/2647-msp430g2553-pwm-outputs/

      Failing the SMD version I would look at one of the MSP430F family Launchpads.

      Cheers,
      Ant

      Reply
  13. Rohan

    The explanation was fantastic..I loved it…It would be really helpfull if you could make me avaliable with the full code of the above examples..I am not able to access it in the link provided.. Thank you !!

    Reply
    1. Ant Post author

      Hi Rohan,

      Glad you found them useful, all the links work 100% please check your browser is not blocking Adfly. If it is you can try and open the link in another browser, I have the links as it helps to pay towards the hosting costs for the site.

      Best regards,
      Ant

      Reply

Leave a Reply