Due to the U.S. Thanksgiving holiday, please expect delayed responses during the week of 11/22.

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.

MSP432P401R: MSP432P401R: Open Loop BLDC

Part Number: MSP432P401R

Hello, my project idea is to rotate a BLDC motor by imposing a certain duty cycle value (which I change with Launchpad buttons) and setting a period value (in this case 1 ms) that allows me to make transitions between 6 states where in each state a high transistor and a low transistor are turned on at the same time while the other 4 transistors are turned off. The transitions are as follows:
State 1: high transistor of phase A and low transistor of phase B are on.
State 2: high transistor of phase A and low transistor of phase C are on.
State 3: high transistor of phase B and low transistor of phase C are on
State 4: high transistor of phase B and low transistor of phase A are on
State 5: high transistor of phase C and low transistor of phase A are on
State 6: high transistor of phase C and low transistor of phase B are on
For the high transistors I have applied a PWM type signal and for the low transistors a GPIO signal that is simply held high or low, all depending on the state. My problem is that, although the transitions are done correctly (as I have been able to observe in the Analog Discovery that I use to visualize the time signal), I get a certain Jitter that makes me overlap transistor switching that should not be seen, marked with red circles in the image (as they belong to different states) and that, therefore, would cause that if I connect the motor there may be moments of time when I have 4 transistors working and will cause me big problems. To sum up, I would really like that there would not be any possibility of transistors overlapping between states and maybe even that there would be a certain short delay to make sure of it at each transition, but I can't think how to do it. I copy my code in case someone is able to tell me where the failure could be or what solution could solve it. Thanks in advance.

How transitions should be:

What I am getting on the Analog Discovery: 

My code is the following:

  1. #include "msp.h"
  2. #include <stdint.h>
  3. #include <stdio.h>
  4. #define PWM 0x70 // 0111 0000
  5. #define GPIO 0x07 // 0000 0111
  6. volatile uint8_t estado = 0; 
  7. volatile uint8_t duty_cycle_inv = 150; // By setting this value we get approximately 50% Duty Cycle
  8. void pulsadores(void){ // Use pushbuttons S2 (P1.4) and S1 (P1.1) to increase or decrease Duty Cycle by 10% respectively.
  9.     P1SEL0 &= ~(BIT4 | BIT1); // I/O
  10.     P1SEL1 &= ~(BIT4 | BIT1);
  11.     P1DIR &= ~(BIT4 | BIT1); 
  12.     P1REN |= (BIT4 | BIT1);
  13.     P1OUT |= (BIT4 | BIT1); 
  14.     P1IES |= (BIT4 | BIT1); 
  15.     P1IFG &= ~(BIT4 | BIT1); 
  16.     P1IE |= (BIT4 | BIT1); 
  17. }
  18. void inicializaciones(void){
  19.     /* TA: P7.4; TB: P7.5; TC: P7.6
  20.      * BA: P7.0; BB: P7.1; BC: P7.2
  21.      */
  22.     // Pines Transistores HIGH (PWM) // We configure pins P7.4 (TA1.4), P7.5 (TA1.3) and P7.6 (TA1.2) for Timer output.
  23.     P7SEL0 |= PWM; 
  24.     P7SEL1 &= ~PWM;
  25.     P7DIR |= PWM; 
  26.     // Pines Transistores LOW (GPIO)
  27.     P7SEL0 &= ~GPIO;
  28.     P7SEL1 &= ~GPIO;
  29.     P7DIR |= GPIO; 
  30. }
  31. void TimerA1_PWM(void){ // Timer to control the 3 PWM pins
  32.     TA1CCR0 = 299; // (300-1) PWM Tperiod: 10 us -> As SMCLK = 3MHz, the counter counts in Up Mode every 1/3MHz = 0.333us. Therefore, 300 - 0.333us = 100 us
  33.     TA1CTL |= TASSEL_2 | MC_3 | TACLR; // SMCLK clock with a frequency of 3 MHz; MC_3: Up-Down Mode; TACLR: Clear TA1R register
  34.     TA1CCTL2 |= OUTMOD_6; // Modo CCR2: Toggle/Set
  35.     TA1CCTL3 |= OUTMOD_6; // Modo CCR3: Toggle/Set
  36.     TA1CCTL4 |= OUTMOD_6; // Modo CCR4: Toggle/Set
  37. }
  38. void TimerA0(void){
  39.     // This timer will be used to change states during the sequence.
  40.     TA0CCR0 = 374; // (375-1) PWM period: 1 ms
  41.     TA0CTL |= TASSEL_2 | ID_3 | MC_1 | TACLR; // SMCLK clock with a frequency of 3 MHz and with a frequency divider of 8, Up Mode
  42.     TA0CCTL0 |= CCIE; // Enables interrupts when the value of TA0CCR0 is reached.
  43. }
  44. void TimerA2_Antirebotes(void){ 
  45.     TA2CCR0 = 1023; // (1024-1) To obtain 250 ms of anti-rebounds -> The counter counts in Up Mode every 1/(4.096 kHz) = 0.244 ms. Therefore, 1024 - 0.244 ms = 250 ms
  46.     TA2CTL |= TASSEL_1 | ID_3 | MC_1 | TACLR; // ACLK clock with a frequency of 32.768 kHz and with a frequency divider of 8, Up Mode -> fACLK = 4.096 kHz
  47. }
  48. void init_interrupciones(void){
  49.     NVIC_EnableIRQ(TA0_0_IRQn);
  50.     NVIC_EnableIRQ(TA2_0_IRQn); 
  51.     NVIC_EnableIRQ(PORT1_IRQn);  
  52.     __enable_irq(); // Enable global interrupt
  53. }
  54. void main(void)
  55. {
  56.     WDT_A->CTL = WDT_A_CTL_PW | WDT_A_CTL_HOLD;     // stop watchdog timer
  57.     pulsadores();
  58.     inicializaciones();
  59.     TimerA1_PWM();
  60.     TimerA0();
  61.     TimerA2_Antirebotes();
  62.     init_interrupciones();
  63.     while(1){
  64.         switch(estado){
  65.             case 0: { // TA y BB HIGH
  66.                 TA1CCR4 = duty_cycle_inv; // TA HIGH
  67.                 TA1CCR3 = 0;
  68.                 TA1CCR2 = 0;
  69.                 P7OUT |= BIT1; // 0000 0010, as P7.1 (BB) será HIGH
  70.                 break;
  71.             }
  72.             case 1: { // TA y BC HIGH
  73.                 TA1CCR4 = duty_cycle_inv; // TA HIGH
  74.                 TA1CCR3 = 0;
  75.                 TA1CCR2 = 0;
  76.                 P7OUT |= BIT2; // 0000 0100, as P7.2 (BC) será HIGH
  77.                 P7OUT &= ~BIT1;
  78.                 break;
  79.             }
  80.             case 2: { // TB y BC HIGH
  81.                 TA1CCR4 = 0;
  82.                 TA1CCR3 = duty_cycle_inv; // TB HIGH
  83.                 TA1CCR2 = 0;
  84.                 break;
  85.             }
  86.             case 3: { // BA y TB HIGH
  87.                 TA1CCR4 = 0;
  88.                 TA1CCR3 = duty_cycle_inv; // TB HIGH
  89.                 TA1CCR2 = 0;
  90.                 P7OUT |= BIT0; // 0000 0001, as P7.0 (BA) será HIGH
  91.                 P7OUT &= ~BIT2;
  92.                 break;
  93.             }
  94.             case 4: { // BA y TC HIGH
  95.                 TA1CCR4 = 0;
  96.                 TA1CCR3 = 0;
  97.                 TA1CCR2 = duty_cycle_inv; // TC HIGH
  98.                 break;
  99.             }
  100.             case 5: { // BB y TC HIGH
  101.                 TA1CCR4 = 0;
  102.                 TA1CCR3 = 0;
  103.                 TA1CCR2 = duty_cycle_inv; // TC HIGH
  104.                 P7OUT |= BIT1; // 0000 0010, as P7.1 (BB) será HIGH
  105.                 P7OUT &= ~BIT0;
  106.                 break;
  107.             }
  108.         }
  109.     }
  110. }
  111. void TA0_0_IRQHandler(void){ // Interrupt Timer A0
  112.     TA0CCTL0 &= ~CCIFG; 
  113.     estado++; // we change state
  114.     if(estado > 5){
  115.         estado = 0;
  116.     }
  117. }
  118. void TA2_0_IRQHandler(void){ // Interrupt Timer A2
  119.     TA2CCTL0 &= ~CCIFG; 
  120.     P1IFG &= ~(BIT4 | BIT1); // we lower the flag of the pushbutton so that it does not remain depressed
  121.     P1IE |= BIT4; // We reactivate interruptions on pushbutton P1.4
  122.     P1IE |= BIT1;
  123. }
  124. void PORT1_IRQHandler(void) // Interrupt Port P1
  125. {
  126.     if(P1IFG & BIT4){ // With pushbutton P1.4 we REDUCE the Duty Cycle
  127.         P1IE &= ~BIT4; 
  128.         if(duty_cycle_inv >= 250){
  129.             duty_cycle_inv = 250;
  130.         }
  131.         else{
  132.             duty_cycle_inv += 10; 
  133.         }
  134.         P1IFG &= ~BIT4; // we lower the flag so that it does not stay pressed down
  135.     }
  136.     else if(P1IFG & BIT1){ // With pushbutton P1.1 we INCREASE the Duty Cycle
  137.         P1IE &= ~BIT1; 
  138.         if(duty_cycle_inv <= 80){
  139.             duty_cycle_inv = 80; // To make sure that we NEVER get a value less than zero
  140.         }
  141.         else{
  142.             duty_cycle_inv -= 10; 
  143.         }
  144.         P1IFG &= ~BIT1;
  145.     }
  146.     TA2CCTL0 |= CCIE; // enable interrupt on Timer A2_0
  147. }
  • Hello Alex,

    As you have noticed, the exact timing of the switching signals is quite important to these motor drive applications.  I'm not an expert on them myself, and most our customers use a DRVxxx motor drive chip in between the MSP430 and the motor.   I know that C2000 have devices specifically designed for these types of control applications, and have high-performance PWM generators.  

    As for the glitches you are seeing, My best guess is that that may come from changing the CCRx registers.  The MSP432 doesn't have buffered CCRx registers as far as I'm aware, so the CCRx changes will happen in real time, which can sometimes cause glitches in the outputs depending on where the timer counter is.  As a test, could you try stopping the timer while you update the CCRx registers and then start it again?  (I know this may slow/stretch your overall timing, but may help narrow down the root cause.) 

    Thanks,

    JD