3
\$\begingroup\$

I have written a code which takes two digit number from laptop and changes the PWM dutycycle to that number. It is part of a bigger requirement where I need to control motor speed over UART.

#include "io430g2553.h"
#include <stdint.h>


void PWM(uint8_t duty_cycle);
void PWM_Config();


int main( void )
{
  // Stop watchdog timer to prevent time out reset
  WDTCTL = WDTPW + WDTHOLD;
   WDTCTL = WDTPW + WDTHOLD;
  BCSCTL1 = CALBC1_1MHZ;                  // Run at 1 MHz
  DCOCTL = CALDCO_1MHZ;                   // Run at 1 MHz

   PWM_Config();
   PWM(5);
   __delay_cycles(5000000);
   PWM(15);
    __delay_cycles(5000000);
   PWM(25);
   __delay_cycles(5000000);
   PWM(50);
    __delay_cycles(5000000);
    PWM(25);
    __delay_cycles(5000000);
     PWM(15);
    __delay_cycles(5000000);
     PWM(5);
   while(1)
   {}


}


void PWM_Config()
{
  P1OUT &= 0x00; // Clearing P1OUT 
  P1SEL |= BIT6 ;
  P1SEL2 &= ~BIT6 ;
  P1DIR |= BIT6; // Configuring P1.6 as Output

}

void PWM(uint8_t duty_cycle)
{
 TA0CTL =0;
 TA0CTL |= TACLR; 
 TA0CCR1 |= (duty_cycle*100);
 TA0CCR0 |= 10000; 
 TA0CTL |= TASSEL_2 + MC_1 + ID_0;// Register TA0CTL -> SMCLK/8, Up mode
 TA0CCTL1 |= OUTMOD_7 ;//Set/Reset Mode
 TA0CCTL0 &= ~CCIE; // Interrupt Disabled
}

Edited My question on received comment:

The problem with the void PWM(uint8_t duty_cycle) function is that first time it generates the correct PWM at P1.6, next if it is given a value it changes PWM to that DC, but I can not go back to lower DC.

the fisrt 2 PWM functions in the code changes to correct duty cycle PWM(5),PWM(15) then the rest of PWM values do not produce desired dutycycle.

I am not able to troubleshoot where am I wrong, can any1 help?

\$\endgroup\$
3
  • 2
    \$\begingroup\$ The troubleshooting trick here is to remove as much code as possible to reproduce the problem. I'd try to identify whether the bug is in the PWM setting part or in the receiving commands part. Remove the PC communication and hard code couple of levels each for 3 seconds and see if output follows these changes. Reduce the problem to as few lines as possible, only few people will take the effort to try and understand long listings. \$\endgroup\$
    – jippie
    Commented Mar 8, 2013 at 8:03
  • \$\begingroup\$ @jippie Edited my question to the troubled function only.. \$\endgroup\$
    – Gaurav K
    Commented Mar 8, 2013 at 8:29
  • \$\begingroup\$ Double check the watchdog: If it is disabled, then ensure that no other interrupts in your code are timing out/using up all the cpu time. If it isn't being disabled (because your command is incorrect), then it will timeout if it is not being fed. Recommendation: leave watchdog on and feed during PWM command. \$\endgroup\$
    – stanri
    Commented Mar 8, 2013 at 8:44

1 Answer 1

8
\$\begingroup\$

Change the:

TA0CCR1 |= (duty_cycle*100);

To a simple assignment:

TA0CCR1 = (duty_cycle*100);

Otherwise you are OR'ing the previous value with the new one, eventually filling it with ones. That is why you can't go back to a lower duty cycle.

By the way, I don't know if your MSP430 has a hardware multiplier, but if it doesn't you should avoid direct multiplications whenever possible because they may take quite a few cycles to execute. Use instead powers of 2 (like 128), because you only need to left-shift the value.

\$\endgroup\$
2
  • \$\begingroup\$ This is correct because |= can set bits but not clear them, allowing you to increase motor speed but not reduce it. \$\endgroup\$
    – user16324
    Commented Mar 8, 2013 at 10:57
  • \$\begingroup\$ And since TA0CCR1 only holds the duty cycle, there is no need to mask or preserve bits, so direct assignment can be done without problems. \$\endgroup\$
    – Passerby
    Commented Mar 8, 2013 at 12:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.