This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Generating multiple CCR interrupts in one timer period



Is it possible to get a CCR to throw up its interrupt flag more than once in the same timer period?

I'm trying to output several independent PWM signals out of my Launchpad G2553's Timer_A to control 5 servos. Each CCR is set up so that the interrupt will toggle on its respective output and then increment the CCR by some amount. On the second interrupt, it is supposed to check to see if that CCR was changed from its original value, and if so, toggle the output off. I'm getting the feeling that CCR interrupts don't work that way, since it's not giving me a nice pulse.

The pulse works fine when I try to get a pulse to start on the beginning of a timer period after an overflow, but I'd like to be able to stagger the CCRs so that the current spike from the servos is spread out over each period and doesn't overwhelm my power supply.

Here is the code, in case it's actually not a CCR problem but something else. I'm using MSPGCC, not CCS.

    #include <stdlib.h>
    #include <stdbool.h>
    #include <msp430.h>
    #include <legacymsp430.h>

    #define MCLK_FREQ 12000000UL /* run @12MHz */
    
  int main() {
    WDTCTL = WDTPW | WDTHOLD;  /* Disable watchdog */
    
    DCOCTL = 0;
    BCSCTL1 = CALBC1_12MHZ;    // 12MHz MCLK
    DCOCTL = CALDCO_12MHZ;
    BCSCTL2 |= DIVS_2;        // 3MHz SMCLK
    
    P2DIR |= BIT0;
    P2SEL &= ~BIT0; // general IO
    
    TA1CCTL0 = CCIE;
    TA1CCR0 = 7000;
    
    TA1CTL = TASSEL_2 + ID_0 + MC_2 + TAIE;    // SMCLK is Timer_A's clock, SMCLK/1, continuous mode, enable interrupts
    
    __bis_SR_register(LPM0_bits + GIE);
  }
 
  interrupt(TIMER1_A0_VECTOR) CCR0_ISR() {
    unsigned int time = TAR;
    
    if(TA1CCR0 == 7000) {    // if this is the original CCR value
      P2OUT |= BIT0;        // pulse starts
      TA1CCR0 += 4500;        // increment the CCR
    }
    else            // otherwise
      P2OUT &= ~BIT0;        // pulse ends
    //CCIFG flag is automatically cleared by servicing the interrupt
  }
 
  interrupt(TIMER1_A1_VECTOR) OVERFLOW_ISR() {
    
    P2OUT &= ~BIT0;  // pull output low just in case
    while(TA1IV);    // clear TAIV
  }

I'd really appreciate having some light shed on the capabilities of the CCRs or help in an alternate approach.

  • I do not know exactly what you want to generate. Do you want 5 separate PWM signals on 5 different pins? What are the frequencies? What are the duty cycles?

    Your code is rather strange. Looks to me, it is goes through a lot just to generate a single pulse on a single pin.

  • Oops, sorry if it wasn't clear. I do eventually want to generate 6 separate PWM signals on 6 different pins, but I chopped down my code to its bare bones here so nobody would have to sift through more of it than necessary. I figured it'd be pointless to show the same faulty process for the other 5 pins, so please forgive the strangeness.

    I'm not sure which frequencies you're referring to. You probably don't mean the system's, but just in case, MCLK is 12MHz, and SMCLK is 3MHz. The PWM signal itself has a period of ~21ms, so it should have a frequency of ~47.6Hz(?)

    Duty cycles will range from 0.5ms/21ms (2.4%) to 2.5ms/21ms (11.9%), but here it is 1.5ms/21ms (7.1%). I'm trying to delay the start of the pulse by some amount using CCR0 and want to know if it's possible to increment CCR0 forward in the interrupt handler so that it can end the pulse later by throwing the same interrupt flag before the timer overflows. With my results, it appears this is not the case, but I wanted to verify here and understand why.

    The heart of the problem is if it's possible for the same CCR can cause an interrupt twice before the timer overflows, regardless of the pin or duty cycle.

  • Rufei Zhou said:
    I do eventually want to generate 6 separate PWM signals on 6 different pins


    Well, that's no problem if you have a TIMERx7 module.

    With CCR0 you define the common PWM cycle length (if it is different from a full timer cycle) and set the timer in up mode. So it counts to CCR0 (triggering a TIMERx_y0 interrupt) and then begins with 0 again.
    The other CCRx units can be set to switch their output signal (and, if you want, to trigger an interrupt) on any value between 0 and CCR0.
    However, all except CCR0 will trigger a TIMERx_y1 interrupt, and you'll need to read TyxIV register or check and reset the individual CCIFG bits to determine which one has triggered the interrupt.

    However, it is really possible to trigger more than one itnerrutp on the same CCR unit during one tiemr cycle.
    In my projects, I use one tiemr in cont mode (0..65535), clock it with 1MHz and write 1000 to CCR0. Int eh ISR for CCR0, I increase CCR0 by 1000, giving me the next interrupt 1000 timer ticks later (which is 1ms). This allow some detecting whether I missed a cycle (if the increased CCR0 is still 'below' current TAR: the difference is > the increment) and can adjust my ms-counter accordingly.

    However, this method is only suitable for low frequencies up to ~1kHz, and probably not the best approach if you want a PWM output, as it requires software intervention to 'arm' the output for the next shot. But if the timign requirements are met (most people forget about this 'little' detail), it can be done. You 'only' must ensure that the isr that sets the next trigger poiont is executed before the moment has already passed. Which is especially difficult near 0% or 100% DC, since then the two events are pretty close.

  • Rufei Zhou said:

    ... I do eventually want to generate 6 separate PWM signals on 6 different pins, ...Duty cycles will range from 0.5ms/21ms (2.4%) to 2.5ms/21ms (11.9%),...

    In this case, it is possible to do it with G2553 which has a TimerA0-A3 and a TimerA1-A3.

    Using 3MHz to clock the Timers is okay. But using 12MHz or 16MHz will give you better resolution in PWM.

    Using GPIO pins to output PWM is okay. But using Timer Output pins will give you better precision in timing.

    Here is an outline of one way to do what you want:

    Set up six Timer Output pins.

    Set up the six CCRs 3.5msec apart. Set up the six CCTL with CCIE and OUTMOD_1 

    Start the Timers in continuous mode without TAIE.

    Inside the ISR for each CCIE, do the following:

    (a) For the 1st, 3rd, 5th, etc. interrupts, add the "ON" cycles to CCR and change to "OUTMOD_1" in CCTL.

    (b) For the 2nd, 4th, 6th, etc. interrupts, add the "OFF" cycles to CCR and change to "set OUTMOD" in CCTL

    Note that the "ON" cycles must be between 0.5msec and 2.5msec. The sum of "ON" and "OFF" cycles must be exactly 21msec.

  • There are typos in my previous msg

    Inside the ISR for each CCIE, do the following:

    (a) For the 1st, 3rd, 5th, etc. interrupts, add the "ON" cycles to CCR and change to "OUTMOD_5" in CCTL.

    (b) For the 2nd, 4th, 6th, etc. interrupts, add the "OFF" cycles to CCR and change to "OUTMOD_1" in CCTL

  • You may want to see this new app note on generating multiple independent PWM frequencies on a single timer module: http://www.ti.com/general/docs/litabsmultiplefilelist.tsp?literatureNumber=slaa513 It also includes some example code for doing this. On each timer A module you could generate 3 independent PWMs by this method, so with the 2 timer A modules you ought to be able to do all 6. The tricky thing will be ensuring that the bit of extra overhead this adds doesn't make it unfeasible for the PWM frequencies you want to generate, as Jens-Michael hinted at.

    Regards,

    Katie

     

**Attention** This is a public forum