gwdeveloper 275 Posted October 15, 2011 Share Posted October 15, 2011 I've created a simple program to use the Toshiba TB6612FNG motor driver (http://www.sparkfun.com/products/9457) with the MSP430. Currently, I have it configured for use on the MSP430G2553 on the Launchpad. It uses PWM output from TA0 for the left motor driver and TA1 for the right motor drive. This code is set for 50% duty cycle. 20% is the lowest speed, 100% is the fastest. Anything less than 20% duty cycle just causes the motors to whine. Of course that may vary based on motor selection and power input. The on-board button at P1.3 is used to start and stop the function for now. Make sure to follow the data sheet for connections. http://www.semicon.toshiba.co.jp/docs/datasheet/en/LinearIC/TB6612FNG_en_datasheet_080509.pdf Vcc connects to the Launchpad's vcc pin and Vm connects to the motor's power source. /****************************************************************/ /* Greg Whitmore */ /* greg@gwdeveloper.net */ /* www.gwdeveloper.net */ /****************************************************************/ /* released under the "Use at your own risk" license */ /* use it how you want, where you want and have fun */ /* debugging the code. */ /* MSP430G2553 */ /****************************************************************/ #include // TB6612FNG defines #define AIN1 BIT1 // P1.1 #define AIN2 BIT0 // P1.0 #define BIN1 BIT0 // P2.0 #define BIN2 BIT1 // P2.1 #define STANDBY BIT6 // P1.6 // button status unsigned char buttonOn; // prototype drive functions void forward(void); void reverse(void); void full_brake(void); void stop(void); void main(void) { WDTCTL = WDTPW + WDTTMSEL + WDTSSEL + WDTIS1; // WDT as interval timer for debouncing of P1.3 button // interval mode, low speed clock, /512 // enable button on P1.3 with interrupt P1OUT = BIT3; P1REN = BIT3; P1IES = BIT3; P1IE = BIT3; P1IFG = 0; // clear P1 interrupt flags // rest of gpio for motor output P1SEL = BIT2; // select TimerA0.1 PWMA output P1DIR = BIT0 + BIT1 + BIT2 + BIT6; // set P1 output bits for AIN1, AIN2 and STANDBY P2SEL = BIT2; // select TimerA1.1 PWMB output P2SEL &= ~(BIT6 + BIT7); // turn off xtal P2DIR = BIT0 + BIT1 + BIT2; // set P2 output bits for BIN1, BIN2 BCSCTL2 = SELM_0 + DIVM_0 + DIVS_0; DCOCTL = 0x00; // clear DCO bits BCSCTL1 = CALBC1_1MHZ; // Set DCO to calibrated 1MHz DCOCTL = CALDCO_1MHZ; BCSCTL1 |= XT2OFF + DIVA_0; BCSCTL3 = XT2S_0 + LFXT1S_2 + XCAP_1; IFG1 &= ~(WDTIFG); // clear WDT flags IE1 |= WDTIE; // enable WDT interrupt // left motor pwm configuration; adjust TA0CCR1 for speed, less than 20% = no motor power TA0CCTL1 = CM_0 + CCIS_0 + OUTMOD_7; // no capture, PWM reset/set TA0CCR0 = 511; TA0CCR1 = 255; // 50% duty cycle TA0CTL = TASSEL_2 + ID_0 + MC_1; // SMCLK, /1, up mode // right motor pwm configuration; adjust TA1CCR1 for speed, less than 20% = no motor power TA1CCTL1 = CM_0 + CCIS_0 + OUTMOD_7; // no capture, PWM reset/set TA1CCR0 = 511; TA1CCR1 = 255; // 50% duty cycle TA1CTL = TASSEL_2 + ID_0 + MC_1; // SMCLK, /1, up mode buttonOn = 0; __enable_interrupt(); // Set global interrupt enable forward(); // enable forward bits for testing, replace with reverse function //reverse(); while (1) { LPM0; // turn CPUOFF and keep it there } } // both motors forward; AIN1 low, AIN2 high, BIN1 high, BIN2 low // use TA0.1 & TA1.1 PWM to control speed void forward(void) { P1OUT |= AIN2; P1OUT &= ~AIN1; P2OUT &= ~BIN2; P2OUT |= BIN1; } // both motors reverse; AIN1 high, AIN2 low, BIN1 low, BIN2 high // use TA0.1 & TA1.1 PWM to control speed void reverse(void) { P1OUT |= AIN1; P1OUT &= ~AIN2; P2OUT &= ~BIN1; P2OUT |= BIN2; } // both motors brake; all high void full_brake(void) { P1OUT |= AIN1; P1OUT |= AIN2; P2OUT |= BIN1; P2OUT |= BIN2; } // both motors stop; all low void stop(void) { P1OUT &= ~AIN1; P1OUT &= ~AIN2; P2OUT &= ~BIN1; P2OUT &= ~BIN2; } #pragma vector=PORT1_VECTOR __interrupt void button_push_isr(void) { P1IFG &= ~BIT3; // clear P1.3 button flag P1IE &= ~BIT3; // clear P1.3 interrupt IFG1 &= ~WDTIFG; WDTCTL = (WDTCTL & 7) + WDTCNTCL + WDTPW + WDTTMSEL; IE1 |= WDTIE; // use button to toggle motors on/off for testing if (buttonOn == 1) { buttonOn = 0; P1OUT &= ~STANDBY; // motor driver disable } else { buttonOn = 1; P1OUT |= STANDBY; // motor driver enable } } #pragma vector=WDT_VECTOR __interrupt void watchdog_isr(void) { IE1 &= ~WDTIE; P1IFG &= ~BIT3; // clear P1.3 button flag P1IE |= BIT3; // re-enable P1.3 interrupt } We're going to use this as part of our line-follower project. http://www.43oh.com/forum/viewtopic.php?f=9&t=1701 kenemon 1 Quote Link to post Share on other sites
kenemon 29 Posted November 6, 2011 Share Posted November 6, 2011 Hey GW, Why did you pick that motor driver for the project? I am trying to get the same kind of thing working, using LP provided PWM signals to motor driver. thanks. KB Quote Link to post Share on other sites
gwdeveloper 275 Posted November 6, 2011 Author Share Posted November 6, 2011 I picked it because of price. Only $8.95 on a breakout board with the needed circuitry. It has plenty of power for the small motors included with the Magician Robot Chassis too. Works well enough that I'm considering using it to make a simple Robotics Booster Pack. Features: Power supply voltage: VM=15V max, VCC=2.7-5.5V Output current: Iout=1.2A(average) / 3.2A (peak) Standby control to save power CW/CCW/short brake/stop motor control modes Built-in thermal shutdown circuit and low voltage detecting circuit All pins of the TB6612FNG broken out to 0.1" spaced pins Filtering capacitors on both supply lines kenemon 1 Quote Link to post Share on other sites
kenemon 29 Posted November 7, 2011 Share Posted November 7, 2011 Thanks GW, What do you think of the TI DRV8833? I realize it needs a couple of components to work, but it is really cheap... By the way, thanks for sharing that code. I was stumbling around trying to figure out a way to make it work for me, and this will handle the PWM part as well as the "mode" switches. I have some success with your suggestions for the ADC component as well. They should work perfectly together for me. KB Quote Link to post Share on other sites
kenemon 29 Posted November 18, 2011 Share Posted November 18, 2011 Hi GW, I started messing around and got my motor driver to work using an adaptation of your code. I am trying to get 4 channels to deliver PWM output. Using your code, i have 2 channels working fine, but i needed to hook them up to P1.2 and P2.2 to get the desired signals. I have 2 questions please: 1) do i understand correctly that to use the PwM function of the MSP it will occupy three pins each, for example P1&2 BITS 0,1, and 2) PWM can not be controlled via "P1OUT BIT2"? Can you assign timer to multiple pins to deliver the same timer pulse to each. I have been trying to understand this for almost a year now. Thanks. KB Quote Link to post Share on other sites
gwdeveloper 275 Posted November 20, 2011 Author Share Posted November 20, 2011 KB, hardware wise you should be able to output 3 PWM channels on the 20 pin MSP430G2553 since it has 2 TimerA peripherals but no pin access for TA0.2. The 3 channels could be output on TA0.1, TA1.1 and TA1.2. You have P1.2 and P2.2 correct, TA1.2 is output on P2.4 and P2.5. If you really need 4 hardware PWM channels, you'll need to go to the 28pin version of the G2553. It has TA0.2 available on P3.0 and P3.6. That aside, you only need to use the timer pins you want to output the PWM on. For eg, to use TA0.1, you output your PWM on P1.2 but you can use P1.1 and P1.0 as GPIO or their other functions. Unless, you're wanting to output those TimerA signals. Also, somewhere on the web, I've seen 'bit-banging' pwm for the msp430 to get more channels out of the LP. Hope that all makes sense. kenemon 1 Quote Link to post Share on other sites
kenemon 29 Posted November 20, 2011 Share Posted November 20, 2011 Thanks GW, Yes. That solidifies a couple of things I have been pondering. I am working on a bit bang type code to see if i can pull it off that way. Much appreciated. KB Quote Link to post Share on other sites
voelker 10 Posted December 3, 2011 Share Posted December 3, 2011 You could save IO pins on the msp by connecting the pwm pins the following way : TA0 ---------------> AIN1 |------o> AIN2 TA0 is directly connected to AIN1 and is also connected to AIN2 through an inverter (or one NPN). Ths way, a duty cycle of 50% stop the motor, 0% makes it full speed one direction and 100% full speed the other direction. Quote Link to post Share on other sites
gwdeveloper 275 Posted December 4, 2011 Author Share Posted December 4, 2011 Hi, Voelker. Your idea makes sense to me but the connection doesn't. Can you clarify the ascii schematic? Also, with the duty cycles controlling the speed and direction, won't it lose some resolution of speed adjustment? Quote Link to post Share on other sites
voelker 10 Posted December 5, 2011 Share Posted December 5, 2011 Sorry for the bad ASCII schematic. In fact the output pin of your uc is connected directly to AIN1 and to AIN2 through an inverter (the dot on my ascii schematic). I personnaly use a single NPN transistor to make the inverter. You are right that it decreases the speed resolution, and it makes it not linear. But this method not only saves pins, it is also said to give better torque performance. I have tested this design with the MSP430g2231 + L293D for a balancing bot and it works well (even if the bot cannot keep balance at the time ...). kenemon 1 Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.