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.

MSP430F5529 servo control

Other Parts Discussed in Thread: MSP430F5529

Hello,

I try to control a servo motor using the MSP430F5529 microcontroller as following :

Servo_Frequency  ==> 50 Hz

1   ms ====> 0   degrees
1.5 ms ====> 90  degrees
2   ms ====> 180 degrees

I use the TIMER A2 in order to generate the needed pwm signal.

TA2CCR0   = (1500 000 / 50 )                    /* CLOCK = 12000 000 , but I use a prescaler of 8 */
TA2CTL   |= TASSEL_2 | ID_3 | MC_1 | TACLR;     /* SMCLK, prescaler = 8, mode couter up, timer clear*/
TA2CCTL1 |= OUTMOD_7 | CCIE;                    /* reset/set | enable interrupt */
TA2CCR1  |= 1980;                               /* this value is calculated with the following formula :*/
                                                /* this should turn the servo motor to left */

0.001s = Duty% * FRQ(s)
FRQs   = 1 / 1500 000 = 0.00000066

Duty% = 0.001 / 0.00000066
Duty% = 1515.151

Duty% = TA2CCR0 / TA2CCR1                       /* Am I right ?*/

==> TA2CCR1 = 1980                              /* according to the 1ms , means the servo motor should start from the 0 degrees*/                          


So, despite of this calculations , the servo motor doesn't work.

Could someone help me with this ?

  • Briceag,

    You should post your complete code to see why it could refuse to work, but:

    If you use 12MHz as clock signal and divide it by 8, then it is 1.5MHz. One clock cycle is then 666.66666666666ns - to get a period of 20ms you divide

    0.02s/0.00000066666666666666s = 30.000

    This is the same as your TA2CCR0 = (1500000 / 50), so that is correct.

    1ms would mean a CCR1 value of 1.500

    1.5ms 2.250

    2ms 3.000

    This is simply done by dividing 0.001s/0.00000066666666666666s or 0.001s/(1/1.500.000). Same for the other values.

    Dennis

  • Hello,

    Thank you for your answer, here is the code in order to control the servo motor.

    P2DIR |= BIT0;
    P2SEL |= BIT0;
    
    TA1CCR0 = 30000;
    TA1CTL |= TASSEL_3 | ID_3 | MC_1 | TACLR;
    TA1CCTL0 |= OUTMOD_D | CCIE;
    TA1CCR1 = 2250;                                  /* middle state of the servo motor */
    
    
    #pragma vector = TIMER1_A1_VECTOR                    
    __interrupt void timer_isr(void)
    {
       if(TA1CCR1 == 3000)
       {
          TA1CCR1 = 1500;
       }else
       {
          TA1CCR1 += 1; 
       }
    }

    Could you tell me, how the timers are numbered according to the microcontroller ?

    I found that the msp430f5529 is able to generate pwm on four channels.

    TA1.1  -> P2.0

    TA2.2  -> P2.5

    TA2.1  -> P2.4

    TA0.4 -> P1.5

    TA0.3 -> P1.4

    So, I'm expecting to find their numbers in the header file for msp430f5529.h as following:

    TA1.1    -> TIMER1_A1_VECTOR

    TA2.2     -> TIMER2_A2_VECTOR  , and so on, but the second one doesn't exit.

    Thank you,

  • Hello again,

    Finally, I've solved the problem. It is a little bit amusing because the configuration was for TA0CTL0 while I bound the servo motor to a different pin.

    Thank you,
  • That's good!

    Have fun!
  • Hello Dennis,

    I have one more question.

    Why the ISR for this timer doesn't return ? I mean, I think it generates an interrupt for a very short time and it doesn't have enough time to go back to the other task, does it ?

    So, I saw, after I activate the CCIE flag, it enters into the ISR and get stuck there, without return from there.
    Why happens it? I have and other tasks not only to generate a PWM.

    Thank you,
  • There is no need for an interrupt service routine when working with OUTMOD_7 of the timer module. Everything is done in hardware. The only thing you have to change is CCR1. That's all.

  • Hello Dennis,

    Thank you,

  • You're welcome! No problem at all!

    Dennis
  • To also answer the question 'why dos it stuck in there': it doesn't. But inside your ISR, you do not clear the interrupt flag, so when exiting the ISR; the interrupt is still pending and the ISR is called instantly again.
    On other processors, the CPU will execute one instruction between two interrupt calls. But this would break the low-power mode mechanism of the MSP430 (halting the CPU clock in main and only executing interrupts), so on an MSP, as long as any interrupt is pending, the main code is not executed.
    There are only two ISRs that automatically clear the interrupt flag: the ADC10 interrupt and the TimerxA0 interrupt for CCR0, as they are the only ones with only one associated interrupt source. All others require an action to clear it: either by reading /writing the associated register (like TXBUF/RXBUF), reading the interrupt vector register (e.g. in a switch statement) or manually clearing the IFG bit.

    But of course Dennis is right: when using the timer for a standard PWM output, no ISR is needed at all.
    (btw: your ISR would have changed the PWM timing for each PWM pulse, which is probably too fast for the servo to follow)

**Attention** This is a public forum