Other Parts Discussed in Thread: DRV8323, MSP430F5529, BOOSTXL-DRV8320RS
Tool/software: Code Composer Studio
Hello,
We are developing logic for BLDC motor control using MSP430FR2355. We encountered several issues with PWM module.
The image of the same is shown below. Our desired system is to work at 20kHz switching frequency, two ADC channel for battery monitoring and speed control.
The logic for BLDC is to operate switches in two pulse mode with high side switch working in PWM fashion.
The image shown below has PWM with few other frequencies and I have kept duty to 50% but that duty is also not visible
//Header Files//
#include "msp430fr2355.h"
#include "stdint.h"
#define CALTDH0CTL1_256 *((unsigned int *)0x1A36)
/*****************************InstaSPIN**************************************/
#define PWM_PERIOD 600 //PWM Frequency (Hz) = 25MHz/((2*PWM_PERIOD)-1)
#define MAX_DUTYCYCLE 600 //relative to PWM_PERIOD
#define MIN_DUTYCYCLE 5 //relative to PWM_PERIOD
#define ACCEL_RATE 100 //Ramp up time to full scale duty cycle = (Full scale duty cycle) * ACCEL_RATE * PWM_PERIOD/PWM_Frequency
#define DEAD_TIME_MCU 1 // Dead time from MSP430 = DEAD_TIME* 0.0625 uS (for 16MHz clock)
#define Block_Rotor_Duration 800 //Blocked_rotor shut off time (s) = Block_Rotor_Duration*30000/Timer clock frequency
int LPM3_On = 0;
/*************************************program variables**********************************************/
unsigned int DC_BUS_CURRENT = 0;
unsigned int DC_Bus_Voltage = 0;
unsigned int SPEED_REF = 0;
unsigned int Temperature_feedback = 0;
unsigned int start_count = 0;
unsigned int HALL_STATE = 0;
unsigned int softstart_counter = 0;
unsigned int CurrentDutyCycle = 100;
unsigned int DIRECTION = 0 ;
unsigned int FirstADC_flag = 1;
unsigned int ADC_selection_flag = 1;
unsigned int ADC_selection_flag_1 = 1;
unsigned int Block_Rotor_Counter = 0;
unsigned int Block_Rotor_Counter_1 =0;
unsigned int ADC_RESULT = 0;
unsigned int commutation_time = 0;
unsigned int commutation_time_counter = 0;
unsigned int advance_angle_time_counter = 0;
unsigned int advance_angle_time = 0;
unsigned int commutation_done = 0;
unsigned int Previous_State = 0;
unsigned int Present_State = 0;
unsigned int PWM_DUTY = PWM_PERIOD;
unsigned int ADC_counter_flag = 0;
unsigned int BATT_V = 0;
unsigned int i = 0;
unsigned int j = 0;
void Init_Clocks (void);
void init_IO (void);
void init_WDT (void);
void init_ADC (void);
void init_TimerB (void);
void Hall_State_Change_FORWARD(void);
void Hall_State_Change_REVERSE(void);
void A_PWM(void);
void B_PWM(void);
void C_PWM(void);
void A_LOW(void);
void B_LOW(void);
void C_LOW(void);
void A_Z(void);
void B_Z(void);
void C_Z(void);
void A_HIGH(void);
void B_HIGH(void);
void C_HIGH(void);
void main (void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
_delay_cycles(1000000);
Init_Clocks (); // Initialize clocks for 25 MHz
init_ADC ();
init_TimerB ();
//init_WDT ();
init_IO ();
A_Z();
B_Z();
C_Z();
_delay_cycles(1000000);
/******************************ENABLE for DRV8323*******************************************************/
P4OUT &= ~BIT1;
_delay_cycles(2500); //100 us delay
//P4OUT |= BIT1;
_delay_cycles(250); //10 us delay
// DIRECTION = (P5IN & BIT4);
DIRECTION = 0;
HALL_STATE = ((P3IN & BIT0) + (P3IN & BIT1) + (P3IN & BIT2));
ADC_counter_flag = 0;
while(1)
{
i = 0;
if(softstart_counter >= ACCEL_RATE)
{
softstart_counter = 0;
if (CurrentDutyCycle < SPEED_REF)
{
CurrentDutyCycle ++;
}
else if (CurrentDutyCycle > SPEED_REF)
{
CurrentDutyCycle --;
}
if ( CurrentDutyCycle >= MAX_DUTYCYCLE)
{
CurrentDutyCycle = MAX_DUTYCYCLE;
}
else if (CurrentDutyCycle <= MIN_DUTYCYCLE)
{
CurrentDutyCycle = MIN_DUTYCYCLE;
}
}
if(DIRECTION == 0)
{
Hall_State_Change_FORWARD();
}
else
{
Hall_State_Change_REVERSE();
}
}
//end main
}
//WDT to restart ADC
void init_WDT (void)
{
WDTCTL = WDT_MDLY_32; // WDT 32ms from 1MHz, SMCLK, interval timer
//SFRIE1 |= WDTIE; // Enable WDT interrupt
}
void init_TimerB (void)
{
TB3CTL = TBSSEL__SMCLK | MC_3 | TBCLR; // SMCLK, up_down mode, clear TBR
TB3CCR0 = PWM_PERIOD; // PWM Period
TB3CCR1 = PWM_PERIOD; // CCR1 PWM duty cycle
TB3CCR2 = PWM_PERIOD; // CCR2 PWM duty cycle
TB3CCR3 = PWM_PERIOD; // CCR3 PWM duty cycle
TB3CCR4 = PWM_PERIOD; // CCR4 PWM duty cycle
TB3CCR5 = PWM_PERIOD; // CCR3 PWM duty cycle
TB3CCR6 = PWM_PERIOD; // CCR4 PWM duty cycle
TB3CCTL1 = OUTMOD_6; // CCR1 reset/set
TB3CCTL2 = OUTMOD_2; // CCR2 reset/set
TB3CCTL3 = OUTMOD_6; // CCR3 reset/set
TB3CCTL4 = OUTMOD_2; // CCR4 reset/set
TB3CCTL5 = OUTMOD_6; // CCR4 reset/set
TB3CCTL6 = OUTMOD_2; // CCR4 reset/set
TB3CCTL0 |= CCIE;
__bis_SR_register(GIE); // enable interrupts
__no_operation(); // For debugger
_EINT(); // Enable interrupts
}
// Clocks And Vcore
void Init_Clocks (void)
{
FRCTL0 = FRCTLPW | NWAITS_2;
__bis_SR_register(SCG0); // disable FLL
CSCTL3 |= SELREF__REFOCLK; // Set REFO as FLL reference source
CSCTL0 = 0; // clear DCO and MOD registers
CSCTL1 |= DCORSEL_7; // Set DCO = 24MHz
CSCTL2 = FLLD_0 + 731; // DCOCLKDIV = 24MHz
__delay_cycles(3);
__bic_SR_register(SCG0); // enable FLL
while(CSCTL7 & (FLLUNLOCK0 | FLLUNLOCK1)); // FLL locked
CSCTL4 = SELMS__DCOCLKDIV | SELA__REFOCLK; // set default REFO(~32768Hz) as ACLK source, ACLK = 32768Hz
// default DCOCLKDIV as MCLK and SMCLK source
}
//IO INITIALISATION//
void init_IO (void)
{
PM5CTL0 &= ~LOCKLPM5;
P2SEL0 &= ~(BIT6); //GPIO-LED3
P2SEL1 &= ~(BIT6);
P2DIR |= (BIT6); //Output-LED3
P1SEL0 |= BIT1; //A0 pin
P1SEL1 |= BIT1;
P1SEL0 |= BIT7; //A0 pin
P1SEL1 |= BIT7;
//PWM outputs
//GPIO-PWM
P6DIR |= (BIT0+BIT1+BIT2+BIT3+BIT4+BIT5); //OutputPWM
//Direction Control
P5SEL0 &= ~(BIT4); //GPIO - DIR
P5SEL1 &= ~(BIT4); //GPIO - DIR
P5DIR |= (BIT4); //Input - DIR
//Enable Gate driver
P4SEL0 &= ~(BIT1); //GPIO - DIR
P4SEL1 &= ~(BIT1); //GPIO - DIR
P4DIR |= (BIT1); //Output - DIR
//Fault input
P4SEL0 &= ~(BIT0); //GPIO - DIR
P4DIR &= ~(BIT0); //Input - DIR
//Hall Sensor inputs
P3SEL0 &= ~(BIT0+BIT1+BIT2); //GPIO - Hall sensors
P3DIR &= ~(BIT0+BIT1+BIT2); //Inputs - Hall sensors
P3IES |= ((BIT0)+(BIT1)+(BIT2)); // change the hall interrupt to falling edge to detect both the edges
P3IE |= (BIT0 | BIT1 | BIT2);
P3IFG &= ~(BIT0| BIT1 | BIT2);
__bis_SR_register(GIE);
}
void init_ADC (void)
{
// Configure ADC12
ADCCTL0 |= ADCSHT_2 | ADCON; // ADCON, S&H=16 ADC clks
ADCCTL1 |= ADCSHP; // ADCCLK = MODOSC; sampling timer
ADCCTL2 &= ~ADCRES; // clear ADCRES in ADCCTL
ADCCTL2 |= ADCRES_2; // 12-bit conversion results
ADCMCTL0 |= ADCINCH_0; // A1 ADC input select; Vref=AVCC
ADCIE |= ADCIE0; // Enable ADC conv complete interrupt
ADCCTL0 |= ADCENC | ADCSC;
}
/**************************************ADC INTERRUPT******************************************/
// ADC interrupt service routine
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=ADC_VECTOR
__interrupt void ADC_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(ADC_VECTOR))) ADC_ISR (void)
#else
#error Compiler not supported!
#endif
{
switch(__even_in_range(ADCIV,ADCIV_ADCIFG))
{
case ADCIV_NONE:
break;
case ADCIV_ADCOVIFG:
break;
case ADCIV_ADCTOVIFG:
break;
case ADCIV_ADCHIIFG:
break;
case ADCIV_ADCLOIFG:
break;
case ADCIV_ADCINIFG:
break;
case ADCIV_ADCIFG:
ADC_RESULT = ADCMEM0;
ADC_counter_flag++;
break;
default:
break;
}
}
/**************************************TIMERD0.1 INTERRUPT********************************************/
// Timer B1 interrupt service routine
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = TIMER3_B0_VECTOR
__interrupt void Timer3_B0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(TIMER3_B0_VECTOR))) Timer3_B0_ISR (void)
#else
#error Compiler not supported!
#endif
{
//PWM_DUTY = (PWM_PERIOD - CurrentDutyCycle);
PWM_DUTY = 300;
P5OUT ^= BIT4;
TB3CCR1 = PWM_DUTY; // CCR1 PWM duty cycle
TB3CCR2 = PWM_DUTY;
TB3CCR3 = PWM_DUTY; // CCR1 PWM duty cycle
TB3CCR4 = PWM_DUTY;
TB3CCR5 = PWM_DUTY; // CCR1 PWM duty cycle
TB3CCR6 = PWM_DUTY;
if (ADC_counter_flag == 1)
{
SPEED_REF = ADC_RESULT;
SPEED_REF = (SPEED_REF >>2);
ADCCTL0 &= ~ADCENC; // Disable
ADCMCTL0 = (ADCMCTL0 & ~ADCINCH) | 7;
ADCCTL0 |= ADCENC | ADCSC;
}
else if (ADC_counter_flag == 2)
{
BATT_V = ADC_RESULT;
ADCCTL0 &= ~ADCENC; // Disable
ADCMCTL0 = (ADCMCTL0 & ~ADCINCH) | 0;
ADCCTL0 |= ADCENC | ADCSC;
ADC_counter_flag = 0;
}
softstart_counter ++;
Block_Rotor_Counter_1++;
if(Block_Rotor_Counter_1>=30000)
{
Block_Rotor_Counter++;
}
if (Block_Rotor_Counter > Block_Rotor_Duration)
{
A_Z();
B_Z();
C_Z();
_disable_interrupt ();
//while (1);
}
TB3CCTL0 &= ~CCIFG;
}
/**********************************Port 1 interrupt service routine******************************/
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=PORT3_VECTOR
__interrupt void Port_3(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(PORT3_VECTOR))) Port_3 (void)
#else
#error Compiler not supported!
#endif
{
HALL_STATE = ((P3IN & BIT0) + (P3IN & BIT1) + (P3IN & BIT2));
if(DIRECTION == 0)
{
Hall_State_Change_FORWARD();
}
else
{
Hall_State_Change_REVERSE();
}
Block_Rotor_Counter = 0;
Block_Rotor_Counter_1 =0;
P3IES ^= (BIT0)+(BIT1)+(BIT2);
P3IFG &= ~(BIT0| BIT1 | BIT2);
}
/**********************************END OF ADC INTERRUPT***************************************/
// Watchdog Timer interrupt service routine
#pragma vector=WDT_VECTOR
__interrupt void WDT_ISR(void)
{
}
/**************************Commutation sequence Forward***********************************************/
void Hall_State_Change_FORWARD(void)
{
switch (HALL_STATE)
{
case 2:
C_Z();
A_PWM();
B_LOW();
break;
case 6:
B_Z();
A_PWM();
C_LOW();
break;
case 3:
A_Z();
C_PWM();
B_LOW();
break;
case 1:
B_Z();
C_PWM();
A_LOW();
break;
case 4:
A_Z();
B_PWM();
C_LOW();
break;
case 5:
C_Z();
B_PWM();
A_LOW();
break;
default:
A_Z();
B_Z();
C_Z();
break;
}
}
/**************************Commutation sequence Reverse***********************************************/
void Hall_State_Change_REVERSE(void)
{
switch (HALL_STATE)
{
case 2:
C_Z();
B_PWM();
A_LOW();
break;
case 6:
B_Z();
C_PWM();
A_LOW();
break;
case 3:
A_Z();
B_PWM();
C_LOW();
break;
case 1:
B_Z();
A_PWM();
C_LOW();
break;
case 4:
A_Z();
C_PWM();
B_LOW();
break;
case 5:
C_Z();
A_PWM();
B_LOW();
break;
default:
A_Z();
B_Z();
C_Z();
break;
}
}
/**************************Definition of PWM GPIOs***********************************************/
void A_PWM(void)
{
P6SEL0 |= BIT0;
P6SEL0 |= BIT1;
}
void B_PWM(void)
{
P6SEL0 |= BIT2;
P6SEL0 |= BIT3;
}
void C_PWM(void)
{
P6SEL0 |= BIT4;
P6SEL0 |= BIT5;
}
void A_LOW(void)
{
P6SEL0 &= ~BIT0;
P6SEL1 &= ~BIT0;
P6OUT &= ~BIT0;
P6SEL0 &= ~BIT1;
P6SEL1 &= ~BIT1;
P6OUT |= BIT1;
}
void B_LOW(void)
{
P6SEL0 &= ~BIT2;
P6OUT &= ~BIT2;
P6SEL0 &= ~BIT3;
P6OUT |= BIT3;
}
void C_LOW(void)
{
P6SEL0 &= ~BIT4;
P6OUT &= ~BIT4;
P6SEL0 &= ~BIT5;
P6OUT |= BIT5;
}
void A_Z(void)
{
P6SEL0 &= ~BIT0;
P6OUT &= ~BIT0;
P6SEL0 &= ~BIT1;
P6OUT &= ~BIT1;
}
void B_Z(void)
{
P6SEL0 &= ~BIT2;
P6OUT &= ~BIT2;
P6SEL0 &= ~BIT3;
P6OUT &= ~BIT3;
}
void C_Z(void)
{
P6SEL0 &= ~BIT4;
P6OUT &= ~BIT4;
P6SEL0 &= ~BIT5;
P6OUT &= ~BIT5;
}
void A_HIGH(void)
{
P6SEL0 &= ~BIT0;
P6OUT |= BIT0;
P6SEL0 &= ~BIT1;
P6OUT &= ~BIT1;
}
void B_HIGH(void)
{
P6SEL0 &= ~BIT2;
P6OUT |= BIT2;
P6SEL0 &= ~BIT3;
P6OUT &= ~BIT3;
}
void C_HIGH(void)
{
P6SEL0 &= ~BIT4;
P6OUT |= BIT4;
P6SEL0 &= ~BIT5;
P6OUT &= ~BIT5;
}
/**************************End****************************************************************/