Sei sulla pagina 1di 11

/*******************************************************************************

* main_open_loop C Source.
* Description: Kurban bu imdi A0'dan Vpot deerini okuyor
*
ardndan buna gre TimerA0 ile TimerA2'nin eitli registerlarnda buluna
n
*
deerleri deitirerek PWM duty cycle ayarlamas yapp ve P2.6,P2.3,P2.2 (
U|V|W) hall deerlerini
*
okuyarak komtasyonu salyor.
*
*
*
*
*
MSP430F552x
*
----------------*
/|\|
XIN|*
| |
|
*
--|RST
XOUT|*
|
|
(NFETs)
*
|
TA2.5|--> PWM5 --> LS_W
*
Speed |
TA2.1|--> PWM3 --> LS_V
*
Input-> |A0
TA0.4|--> PWM1 --> LS_U
*
|
TA0.3|--> PWM2 --> HS_V
*
|
TA0.2|--> PWM4 --> HS_U
*
|
TA0.1|--> PWM6 --> HS_W
*
|
|
*
|
P2.6|<-- Hall U | Hall
*
|
P2.3|<-- Hall V | Sensor
*
|
P2.2|<-- Hall W | Inputs
*
|
|
*
* ACLK = REF0, MCLK = SMCLK = 16MHz
* TimerA0 clock = SMLCK;
* TimerA2 clock = SMLCK;
*
* OKTAR KARA
* Yeditepe University.
* Nov 2014
* Built with CCS v6.0.1
********************************************************************************
/
#include
#include
#include
#include
#include

<msp430f5529.h>
"main_open_loop.h"
"..\F5xx_F6xx_Core_Lib\HAL_PMM.h"
"..\F5xx_F6xx_Core_Lib\HAL_UCS.h"
"hall_sensor.h"

/* Relation between the hall sequence 000-111 and the HS/LS pedriver
o/p - THIS IS FIXED for 120deg 3-ph BLDC Commutation
*/
#ifdef DIRECTION_CCW
// Direction = 0x01
unsigned char Hall_DIR_sequence[] = { 0x00,
HS_W|LS_V,
// Hall position
HS_V|LS_U,
// Hall position
HS_W|LS_U,
// Hall position
HS_U|LS_W,
// Hall position
HS_U|LS_V,
// Hall position
HS_V|LS_W,
// Hall position

001
010
011
100
101
110

0x00

};

#endif
#ifdef DIRECTION_CW
// Direction = 0x00
unsigned char Hall_DIR_sequence[] = { 0x00,
HS_V|LS_W,
HS_U|LS_V,
HS_U|LS_W,
HS_W|LS_U,
HS_V|LS_U,
HS_W|LS_V,
0x00 };
#endif

//
//
//
//
//
//

Hall
Hall
Hall
Hall
Hall
Hall

position
position
position
position
position
position

001
010
011
100
101
110

// Motor and Commutation Variables


unsigned int Desired_PWM_DutyCycle, Current_PWM_DutyCycle, PWM_BucketStep, PWM_U
pdate_Counter, ADC_Sample_Counter;
unsigned char PreDriver_Sequence,Motor_Status, Hall_State_Unknown,Hall_IN,OKTAR,
KARA;
unsigned char Motor_status;
// ADC Variables
unsigned long ADC_Results[4];
unsigned int Avg_vBUS, Avg_vPOT,k=0;
unsigned char SampleADC;
// Function definition
void PWM_update (unsigned char Next_Hall_Sequence);
void Start_Motor(void);
void Stop_Motor(void);
void Start_ADC_Conversion(void);
void main (void)
{
volatile unsigned int i;
unsigned int Temp_DutyCycle;
WDTCTL = WDTPW+WDTHOLD;

// Stop WDT

// Configure System Clock = DCO = 16Mhz


// Increase Vcore setting to level2 to support fsystem=16MHz
SetVCore(PMMCOREV_2);
// Set VCore=2 for 16MHz clock
SELECT_FLLREF(SELREF__REFOCLK);
SELECT_ACLK(SELA__REFOCLK);

// Set DCO FLL reference = REFO


// Set ACLK = REFO

Init_FLL_Settle(16000, 488);
// Configure Port pins (P1.0-P1.3) as interrupt capable input pins, Fault IN
// and Hall Sensor Inputs
// P1DIR &= BIT1; //P1.1 Button to open/close the whole code
// P1REN |= BIT1;
// P1OUT |= BIT1;
// P1IE |= BIT1;
// P1IES = 0x0;
// Trigger on rising edge
// P1IFG = 0x0;
P2DIR &= ~(BIT6+BIT3+BIT2); // Input DIR
// P2REN |= BIT6+BIT3+BIT2+BIT0+BIT1;
// P2OUT |= BIT6+BIT3+BIT2+BIT1;// Enable Pull-down Resistors (Gerek kalmad e

xternally halledildi)
// P2IE |= BIT1;
P2IES = 0x0;
P2IFG = 0x0;

// Trigger on rising edge

// Configure TimerA0,TimerA2 PWMs


// Configure Port I/O as Timer PWM output pins
P1DIR |= BIT2 + BIT3 + BIT4 + BIT5;
P1SEL |= BIT2 + BIT3 + BIT4 + BIT5;
P2DIR |= BIT4 + BIT5;
P2SEL |= BIT4 + BIT5;
// Configure TimerA0,TimerA2
TA0CTL = TASSEL_2 + TACLR; // SMCLK, clear TAR0
TA2CTL = TASSEL_2 + TACLR; // SMCLK, clear TAR2
// HSide NMOS (TA0.1/2/3) => PWM (set/reset); LSide NMOS => logic 'high'
TA0CCR0 = TIMER_PWM_PERIOD-1;
// PWM Period
TA2CCR0 = TIMER_PWM_PERIOD-1;
TA0CCTL4 = OUTMOD_0;
// OUT mode and Low
TA0CCTL1 = OUTMOD_7;
// CCR2 reset/set
TA2CCTL1 = OUTMOD_0;
// OUT mode and Low
TA0CCTL2 = OUTMOD_7;
// CCR4 reset/set
TA2CCTL2 = OUTMOD_0;
// OUT mode and Low
TA0CCTL3 = OUTMOD_7;
// CCR6 reset/set
Current_PWM_DutyCycle = MIN_PWM_DUTYCYCLE; // Initial Dutycycle 1023
// Initialize PWM outputs with initial dutycycle counts
TA0CCR1 = Current_PWM_DutyCycle;
TA0CCR2 = Current_PWM_DutyCycle;
TA0CCR3 = Current_PWM_DutyCycle;
#ifdef ANALOG_SPEEDIN
// Configure ADC12 to read Analog pot input values at A0 and Vbus at A4
P6SEL |= BIT0;
// P6.0/A0 ADC option select
//Init_ADC()
REFCTL0 &= ~REFMSTR;
l to

// Reset REFMSTR to hand over contro

// ADC12_A ref control registers


ADC12CTL0 = ADC12SHT0_2+ADC12ON+ADC12MSC; // 16x ADCCLK, ADC12 on
ADC12MCTL0 = ADC12INCH_3+ADC12SREF_0;
// channel = A3, Vr+=AVCC and Vr-=AVs
s
ADC12MCTL1 = ADC12INCH_0+ADC12SREF_0+ADC12EOS; // channel = A0 Vr+=Vref+ and V
r-=AVss, end of sequence
ADC12CTL1 = ADC12SHP+ADC12CONSEQ_3;
// Use sampling timer, repeated seq
of channels
for (i=0; i<0x30; i++);
// Delay for reference start-up
#endif
/*
// Check with Vbus is good to proceed with motor start
if (Avg_vBUS < 0xFF)
{
// Wait until vBUS increases 3.3V? -->byle mi yazlr bu daly*rak
}

*/
// Variable Initializations
PWM_Update_Counter = 0x0;
Motor_Status = Stopped;
Hall_State_Unknown = true;
SampleADC = false;
// Start Motor
if ((Motor_Status == Stopped)&&(Hall_State_Unknown == true))
Start_Motor();
__enable_interrupt();

// enable interrupts

while(1)
{
if(SampleADC == true)
{
// Trigger ADC Sampling
#ifdef ANALOG_SPEEDIN
Start_ADC_Conversion();
__bis_SR_register(LPM0_bits + GIE);

// Enter LPM4, Enable in

__no_operation();

// For debugger

terrupts
Avg_vBUS = ADC_Results[0] >> 2;
Avg_vPOT = ADC_Results[1] >> 2;
if(Avg_vPOT>=3480){
Avg_vPOT = 3480;
// 100% Dutycyle counts = 1024
}
Temp_DutyCycle = Avg_vPOT/SPEEDIN_PWM_FACTOR;
// ADC12 => 4096 ADC cou
nts = 100% speed
// 100% Dutycyle counts
= TIMER_PWM_PERIOD
// ADC Pot Counts/SPEEDI
N_PWM_FACTOR = Dutycycle counts required
#endif
if (Temp_DutyCycle < MIN_PWM_DUTYCYCLE)
// 1023
Desired_PWM_DutyCycle = MIN_PWM_DUTYCYCLE; // < Min DutyCycle %ag
e - latch to min value, 1023
else
Desired_PWM_DutyCycle = Temp_DutyCycle;
// 1023
SampleADC = false;
}
}
}
void Start_Motor(void)
{
// Read Speed Input and update dutycycle variable
#ifdef ANALOG_SPEEDIN
Start_ADC_Conversion();
__bis_SR_register(LPM0_bits + GIE);

// Enter LPM4, Enable interrupts

__no_operation();

// For debugger

Avg_vBUS = ADC_Results[0] >>2;


Avg_vPOT = ADC_Results[1] >>2;
if(Avg_vPOT>=3480){
Avg_vPOT = 3480;
// 100% Dutycyle counts = 1024
}
Desired_PWM_DutyCycle = Avg_vPOT >> 2;
speed

// ADC12 => 4096 ADC counts = 100%


// ADC Pot Counts/4 = Dutycycle co

unts required
#endif
// Read Hall inputs
OKTAR = P2IN;
KARA = P2IN;
OKTAR = ((OKTAR & 0x40)>>3);
KARA = ((KARA & 0x0C)>>1);
Hall_IN = OKTAR|KARA;
Hall_IN = ((Hall_IN & 0x0E)>>1);
// Start PWM TimerA0,TimerA1
PreDriver_Sequence = Hall_DIR_sequence[Hall_IN];
PWM_update(PreDriver_Sequence);
P2IFG = 0x0;
// Clear IFGs
P2IE |= BIT2+BIT3+BIT6;
// Enable Port ISRs
if(Current_PWM_DutyCycle < Desired_PWM_DutyCycle) // 1023
{
// Initially PWM dutycycle set to min dutycycle. If desired dutycycle <
min dutycycle, latch
// at min dutycycle, else compute #steps required to reach input speed v
alue in ~100ms
PWM_BucketStep = (Desired_PWM_DutyCycle-Current_PWM_DutyCycle)/(STARTUP_
STEPS); //1023
if(PWM_BucketStep <= 0)
{
PWM_BucketStep = 1;
}
Motor_Status = StartUp;
}
else
{
Motor_Status = Running;
}
TA0CCTL0 = CCIE;
TA0CTL |= MC_1;

// TA0CCR0 interrupt enabled


// Timer Start - UP mode

}
void Stop_Motor(void)
{
P2IFG = 0x0;
TA0CCTL0 &= ~CCIE;
TA0CTL &= ~(MC_3);
P2IE &= ~(BIT2+BIT3+BIT6);
Motor_Status = Stopped;
}

// Clear Pending interrupts


// TA0CCR0 interrupt enabled
// Stop Pre-Driver outputs
// Disable Hall Interrupts

#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void)
{
switch(__even_in_range(P1IV,16))
{
case 2: break;
case 4:
if(Motor_Status == Running)
{
Stop_Motor();
}
else if(Motor_Status == Stopped)
{
Start_Motor();
}
break;
case 6: break;
case 8: break;
case 10: break;
case 12: break;
case 14: break;
case 16: break;
default: break;
}
}
// Timer B0 interrupt service routine
#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A0_ISR(void)
{
// heart beat signal = PWM period
PWM_Update_Counter++;
ADC_Sample_Counter++;
if (Motor_Status == StartUp)
{
if((PWM_Update_Counter > DUTYCYCLE_CHANGE_PERIODS)&&(Current_PWM_DutyCyc
le < Desired_PWM_DutyCycle)) // 1023
{
Current_PWM_DutyCycle = Current_PWM_DutyCycle + PWM_BucketStep; //102
3
TA0CCR1 = Current_PWM_DutyCycle;
TA0CCR2 = Current_PWM_DutyCycle;
TA0CCR3 = Current_PWM_DutyCycle;
PWM_Update_Counter = 0x0;
}
else if(Current_PWM_DutyCycle >= Desired_PWM_DutyCycle)
//1023
{
Motor_Status = Running;
}
}
else if (Motor_Status == Running)
{
// Control Loop Dutycycle Update
if(ADC_Sample_Counter > ADC_SAMPLING_PWM_PERIODS)
{
ADC_Sample_Counter = 0x0;

SampleADC = true;
}
if (Desired_PWM_DutyCycle > Current_PWM_DutyCycle)
{
// Increment dutycycle or change dutycycle in +ve direction
Current_PWM_DutyCycle = Current_PWM_DutyCycle + MAIN_PWM_BUCKET_DC;
}
else if (Desired_PWM_DutyCycle < Current_PWM_DutyCycle)
{
// Decrement dutycycle or change dutycycle in -ve direction
Current_PWM_DutyCycle = Current_PWM_DutyCycle - MAIN_PWM_BUCKET_DC;
}
// if Desired_DutyCyle == Current_DutyCycle, dont change dutycycle value
// Update
TA0CCR1 =
TA0CCR2 =
TA0CCR3 =

PWM dutycycle values


Current_PWM_DutyCycle;
Current_PWM_DutyCycle;
Current_PWM_DutyCycle;

}
}
// Port2 interrupt service routine
#pragma vector=PORT2_VECTOR
__interrupt void Port_2(void)
{
switch(__even_in_range(P2IV,16))
{
case 2:
Stop_Motor();
break;
case
case
case
case

4: break;
6:
8:
14:

// Hall input interrupts


P2IE &= ~(BIT2+BIT3+BIT6);
-- is it required????????

// Disable Port ISRs

// Read Hall inputs


OKTAR = P2IN;
KARA = P2IN;
OKTAR = ((OKTAR & 0x40)>>3);
KARA = ((KARA & 0x0C)>>1);
Hall_IN = OKTAR|KARA;
Hall_IN = ((Hall_IN & 0x0E)>>1);
PreDriver_Sequence = Hall_DIR_sequence[Hall_IN];
// Start PWM TimerA0,TimerA2
PWM_update(PreDriver_Sequence);
P2IFG = 0x0;

// Clear IFGs - add

ed........
P2IE |= BIT2+BIT3+BIT6;
-- is it required???????
break;
case 10: break;

// Enable Port ISRs

case 12: break;


case 16: break;
default: break;
}
}
/*
PxIES = bit 0 => low to high transition capture (rising)
= bit 1 => high to low transition capture (falling)

PxIES "not the" same for both DIR0 and DIR1 (as the LUT picks
different PreDriver sequence for completing commutation)
Add if(Direction){} for P2IES bit setting - done
*/
void PWM_update (unsigned char Next_Hall_Sequence)
{
//Hall_U=> P2.6; Hall_V=> P2.3; Hall_W=> P2.2
//HS3=> P2.6; HS2=> P2.3; HS1=> P2.2
switch(Next_Hall_Sequence)
{
case HS_W|LS_V:
// Hall_IN DIR1_001 DIR0_110
// Next edge => HS3 rising, HS2 rising, HS1 falling DIR1
// Next edge => HS3 falling, HS2 falling, HS1 rising DIR0
#ifdef DIRECTION_CCW
P2IES = BIT2;
// DIR1
#else
P2IES = BIT3+BIT6;
// DIR0
#endif
TA0CCTL4
TA0CCTL1
TA2CCTL1
TA0CCTL2
TA2CCTL2
TA0CCTL3
break;

|= OUT;
= OUTMOD_7;
&= ~OUT;
= OUTMOD_0;
&= ~OUT;
= OUTMOD_0;

case HS_V|LS_U:
// Hall_IN DIR1_010 DIR0_101
// Next edge => HS3 rising, HS2 falling, HS1 rising DIR1
// Next edge => HS3 falling, HS2 rising, HS1 falling DIR0
#ifdef DIRECTION_CCW
P2IES = BIT3;
// DIR1
#else
P2IES = BIT2+BIT6; // DIR0
#endif
TA0CCTL4
TA0CCTL1
TA2CCTL1
TA0CCTL2
TA2CCTL2
TA0CCTL3
break;

&= ~OUT;
= OUTMOD_0;
|= OUT;
= OUTMOD_7;
&= ~OUT;
= OUTMOD_0;

case HS_W|LS_U:
// Hall_IN DIR1_011 DIR0_100
// Next edge => HS3 rising, HS2 falling, HS1 falling DIR1
// Next edge => HS3 falling, HS2 rising, HS1 rising DIR0

#ifdef DIRECTION_CCW
P2IES = BIT2+BIT3;
#else
P2IES = BIT6;
#endif
TA0CCTL4
TA0CCTL1
TA2CCTL1
TA0CCTL2
TA2CCTL2
TA0CCTL3
break;

// DIR1
// DIR0

&= ~OUT;
= OUTMOD_7;
|= OUT;
= OUTMOD_0;
&= ~OUT;
= OUTMOD_0;

case HS_U|LS_W:
// Hall_IN CCW_100 CW_011
// Next edge => HS3 falling, HS2 rising, HS1 rising DIR1
// Next edge => HS3 rising, HS2 falling, HS1 falling DIR0
#ifdef DIRECTION_CCW
P2IES = BIT6;
// DIR1
#else
P2IES = BIT2+BIT3;
// DIR0
#endif
TA0CCTL4 &= ~OUT;
TA0CCTL1 = OUTMOD_0;
TA2CCTL1 &= ~OUT;
TA0CCTL2 = OUTMOD_0;
TA2CCTL2 |= OUT;
TA0CCTL3 = OUTMOD_7;
break;
case HS_U|LS_V:
// Hall_IN CCW_101 CW_010
// Next edge => HS3 falling, HS2 rising, HS1 falling DIR1
// Next edge => HS3 rising, HS2 falling, HS1 rising DIR0
#ifdef DIRECTION_CCW
P2IES = BIT2+BIT6;
// DIR1
#else
P2IES = BIT3;
// DIR0
#endif
TA0CCTL4 |= OUT;
TA0CCTL1 = OUTMOD_0;
TA2CCTL1 &= ~OUT;
TA0CCTL2 = OUTMOD_0;
TA2CCTL2 &= ~OUT;
TA0CCTL3 = OUTMOD_7;
break;
case HS_V|LS_W:
// Hall_IN CCW_110 CW_001
// Next edge => HS3 falling, HS2 falling, HS1 rising DIR1
// Next edge => HS3 rising, HS2 rising, HS1 falling DIR0
#ifdef DIRECTION_CCW
P2IES = BIT3+BIT6;
// DIR1
#else
P2IES = BIT2;
// DIR0
#endif
TA0CCTL4 &= ~OUT;
TA0CCTL1 = OUTMOD_0;
TA2CCTL1 &= ~OUT;
TA0CCTL2 = OUTMOD_7;
TA2CCTL2 |= OUT;
TA0CCTL3 = OUTMOD_0;

break;
default:
Hall_State_Unknown = true;
// Stop_Motor();
break;
}
//TBR = TIMER_PWM_PERIOD-1;
//TBCCR0 = TIMER_PWM_PERIOD-1;
Hall_State_Unknown = false;
}
void Start_ADC_Conversion(void)
{
ADC_Results[0] = 0x0;
ADC_Results[1] = 0x0;
ADC12IE = 0x02;
L1)
ADC12CTL0 |= ADC12ON + ADC12ENC;
ADC12CTL0 |= ADC12SC;
}

// Enable interrupt, ADC12IFG.1 (MCT


// Enable conversion
// Start conversion

#pragma vector=ADC12_VECTOR
__interrupt void ADC12ISR (void)
{
static unsigned char index = 0;
switch(__even_in_range(ADC12IV,34))
{
case 0: break;
case 2: break;
case 4: break;
case 6: break;
case 8:
ADC_Results[0] += ADC12MEM0;
ADC_Results[1] += ADC12MEM1;
index++;
if (index == 4)
{
ADC12IE = 0x0;
ADC12CTL0 &= ~ADC12ON;
index = 0;
__bic_SR_register_on_exit(LPM0_bits);
}
break;
case 10: break;
case 12: break;
case 14: break;
case 16: break;
case 18: break;
case 20: break;
case 22: break;
case 24: break;
case 26: break;
case 28: break;
case 30: break;
case 32: break;
case 34: break;
default: break;

//
//
//
//
//
//

Vector 0: No interrupt
Vector 2: ADC overflow
Vector 4: ADC timing overflow
Vector 6: ADC12IFG0
Vector 8: ADC12IFG1
Move results

// Increment results index

// Exit active CPU


//
//
//
//
//
//
//
//
//
//
//
//
//

Vector
Vector
Vector
Vector
Vector
Vector
Vector
Vector
Vector
Vector
Vector
Vector
Vector

10:
12:
14:
16:
18:
20:
22:
24:
26:
28:
30:
32:
34:

ADC12IFG2
ADC12IFG3
ADC12IFG4
ADC12IFG5
ADC12IFG6
ADC12IFG7
ADC12IFG8
ADC12IFG9
ADC12IFG10
ADC12IFG11
ADC12IFG12
ADC12IFG13
ADC12IFG14

}
}

Potrebbero piacerti anche