MSP430 3Ph

Simple 3 Phase driver for MSP430. Written for the MSP430G2232, but should work on bigger chips.

Some features don't really work correctly, but alas.

```
/*
 * P1.0: L1  / L1A
 * P1.1: L2  / L1B
 * P1.2: L3  / L2A
 * P1.3: Com / L2B
 * P1.4: Speed Pot
 * P1.5: Speed Duty
 * P1.6: Voltage Sense
 * P1.7: Voltage Ref
 * P2.0: Voltage Control
 * P2.1: Out1
 * P2.2: Direction
 * P2.3: Sin/Square
 * P2.4: 3/2 Phase
 * Clock: 32kHz.
 * Phase_Div=0, Out=1kHz
 * Phase_Div=16, Out=62.5Hz
 * Phase_Div=1000, Out=1Hz
 * VfDuty controls the duty-cycle decay, and is scaled by phase_div.
 * Larger dividers mean more duty-cycle decay at low frequencies.
 */

#include <msp430.h>

typedef unsigned char byte;
typedef unsigned int uint;
typedef unsigned long ulong;

#if 0
const byte sintab[64]= {
		128, 140, 152, 165, 176, 188, 198, 208,
		218, 226, 234, 240, 245, 250, 253, 254,
		255, 254, 253, 250, 245, 240, 234, 226,
		218, 208, 198, 188, 176, 165, 152, 140,
		128, 115, 103,  90,  79,  67,  57,  47,
		 37,  29,  21,  15,  10,   5,   2,   1,
		  0,   1,   2,   5,  10,  15,  21,  29,
		 37,  47,  57,  67,  79,  90, 103, 115
};
#endif

const byte sintab1_2[64]= {
		128, 167, 184, 196, 206, 215, 223, 229,
		235, 240, 244, 247, 250, 252, 254, 255,
		255, 255, 254, 252, 250, 247, 244, 240,
		235, 229, 223, 215, 206, 196, 184, 167,
		128,  88,  71,  59,  49,  40,  32,  26,
		 20,  15,  11,   8,   5,   3,   1,   0,
		  0,   0,   1,   3,   5,   8,  11,  15,
		 20,  26,  32,  40,  49,  59,  71,  88
};

short phase_cnt;
short phase_div;
short phase_pot;

byte phofs[4];
byte phcnt[4];
byte phduty[4];

byte phase;
byte dutysc;			//duty-cycle scale
byte madutysc;			//master duty-cycle scale

uint vfduty;			//VF duty drop-off

byte phcnt2[2];
byte phduty2[2];

byte dacm;
byte vcsense;
byte vcref;
byte vcphase;

byte (*func)(byte ph);
void (*updatePhase)(byte ph);
void (*updatePhaseB)(byte ph);

byte fix_sin8(byte ph)
{
	return(sintab1_2[(byte)(ph>>2)]);
}

byte fix_cos8(byte ph)
{
	return(sintab1_2[(byte)((ph+64)>>2)]);
}

byte fix_sqr8(byte ph)
{
	return((byte)(((signed char)ph)>>7));
}

void updateDutyVfDecay(void)
{
	uint i;
	i=(((ulong)phase_div)*vfduty+128)>>8;
	if(i>255)i=255;
	i=((255-i)*madutysc)>>8;
	dutysc=i;
}

#if 1
void updatePhase1(byte ph)
{
	int ds;
	ds=func(phase+phofs[ph]);
//	ds=(ds*dutysc)>>8;
	ds=(((ds-128)*dutysc)>>8)+128;
	phduty[ph]=ds;
}

void updatePhase1C(byte ph)
{
	phduty[ph]=128;
}

void updatePhase2(byte ph)
{
	int ds;
	ds=func(phase+phofs[ph]);
	ds=(ds<<1)-256;
	if(ph&1)ds=-ds;
	if(ds<0)ds=0;
	ds=(((unsigned int)ds)*dutysc)>>8;
//	ds=(((ds-128)*dutysc)>>8)+128;
	phduty[ph]=ds;
}
#endif

void updateVreg(void)
{
	int i;
	if(vcsense<vcref)
	{
		i=phduty2[0]-1;
		if(i<16)i=16;
		phduty2[0]=i;
	}else if(vcsense>vcref)
	{
		i=phduty2[0]+1;
		if(i>240)i=240;
		phduty2[0]=i;
	}
}

void updatePin1(byte ph)
{
	int i;
//	i=phcnt[ph]+sintab[(byte)(phase+phofs[ph])];
	i=phcnt[ph]+phduty[ph];
	phcnt[ph]=i;
	if(i&0x100)
		{ P1OUT|=1<<ph; }
	else
		{ P1OUT&=~(1<<ph); }
}

void updatePin2(byte ph)
{
	int i;
	i=phcnt2[ph]+phduty2[ph];
	phcnt2[ph]=i;
	if(i&0x100)
		{ P2OUT|=1<<ph; }
	else
		{ P2OUT&=~(1<<ph); }
}

void clearPhases(void)
{
	phduty[0]=0;	phduty[1]=0;
	phduty[2]=0;	phduty[3]=0;
	phduty2[0]=0;	phduty2[1]=0;
	P1OUT&=~15;
	P2OUT&=~3;
}

byte st, lst, nph;

struct phaseMode_s {
	byte phofs[4];
	byte (*func)(byte ph);
	void (*updatePhase)(byte ph);
	void (*updatePhaseB)(byte ph);
	byte nph;
};

const struct phaseMode_s phaseMode[]={
{	0, 85, 171, 0, fix_sin8,
	updatePhase1, updatePhase1C, 3},
{	171, 85, 0, 0, fix_sin8,
	updatePhase1, updatePhase1C, 3},
{	0, 85, 171, 0, fix_sqr8,
	updatePhase1, updatePhase1C, 3},
{	171, 85, 0, 0, fix_sqr8,
	updatePhase1, updatePhase1C, 3},
{	0, 0, 64, 64, fix_sin8,
	updatePhase2, updatePhase2, 4},
{	64,	64,	0,	0, fix_sin8,
	updatePhase2, updatePhase2, 4},
{	0, 0, 64, 64, fix_sqr8,
	updatePhase2, updatePhase2, 4},
{	64,	64,	0,	0, fix_sqr8,
	updatePhase2, updatePhase2, 4}
};

void setPhaseMode(byte mode)
{
	struct phaseMode_s *phm;

	st=mode;
	lst=st;
	phm=(struct phaseMode_s *)(&(phaseMode[st]));

	phofs[0]=phm->phofs[0];
	phofs[1]=phm->phofs[1];
	phofs[2]=phm->phofs[2];
	phofs[3]=phm->phofs[3];
	func=phm->func;
	updatePhase=phm->updatePhase;
	updatePhaseB=phm->updatePhaseB;
	nph=phm->nph;
}

void updateMainPhase(void)
{
	int i;

	phase=phase+8;
	phase_cnt=phase_div;

	updateDutyVfDecay();

	updatePhase(0);
	updatePhase(1);
	updatePhase(2);
	updatePhaseB(3);

	i=P2IN;
	st=(i>>2)&7;
	if(st!=lst)
	{
		lst=st;
		setPhaseMode(st);
	}
}

void updateMainPhase2(void)
{
	if(!(vcphase++))
	{
		updateVreg();
	}

	if(phase_cnt<=0)
	{
		if(phase_div>1012)
		{
			clearPhases();
			while(phase_div>1012)
				__bis_SR_register(CPUOFF + GIE);
			return;
		}

		updateMainPhase();
	}
}

int main(void)
{
	BCSCTL1 = CALBC1_16MHZ;
	DCOCTL = CALDCO_16MHZ;

//	WDTCTL=WDTPW|WDTHOLD;

	WDTCTL = WDT_MDLY_0_5;		//0.5ms at 1MHz (2kHz), 0.03125ms (32kHz) at 16MHz
//	WDTCTL = WDT_MDLY_0_064;
	IE1 |= WDTIE;

	//	P1DIR|=0x07;
	P1DIR|=0x0F;
	P2DIR|=0x03;
	P1OUT=0;
	P2OUT=0;

	P2REN|=0x1C;

//	ADC10CTL0 = SREF_1 + ADC10SHT_2 + ADC10ON + ADC10IE + REF2_5V + REFON;
	ADC10CTL0 = ADC10SHT_2 + ADC10ON + ADC10IE + REF2_5V + REFON;
	ADC10CTL1 = INCH_4;
	ADC10AE0 |= 0x10;

	phase_div=16;

	setPhaseMode(0);

	dutysc=255;
	madutysc=255;
	vfduty=192;
	dacm=0;
	ADC10CTL0 |= ENC + ADC10SC;

	__bis_SR_register(GIE);

	for(;;)
	{
		updatePin1(0);
		updatePin1(1);
		updatePin1(2);
		updatePin1(3);

		updatePin2(0);
		updatePin2(1);

		updateMainPhase2();
	}

//	return 0;
}

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(ADC10_VECTOR))) ADC10_ISR (void)
#else
#error Compiler not supported!
#endif
{
	unsigned long i;
	__bic_SR_register_on_exit(CPUOFF);

#if 1
	switch(dacm)
	{
	case 0:
		phase_pot=ADC10MEM;
		i=1023-phase_pot;
		i=(i*i+512)>>10;
//		i=(i*i*i)>>20;
		phase_div=i;
		dacm=1;
		break;
	case 1:
//		dutysc=ADC10MEM>>2;
//		madutysc=ADC10MEM>>2;
		dacm=2;
		break;
	case 2:
		vcsense=ADC10MEM>>2;
		dacm=3;
		break;
	case 3:
		vcref=ADC10MEM>>2;
		dacm=0;
		break;
	default:
		dacm=0;
		break;
	}
#endif

//	phase_div=1024-ADC10MEM;
//	phase_div=16383-(ADC10MEM<<4);

	ADC10CTL1 = (ADC10CTL1&0x0FFF)|((4+dacm)<<12);
	ADC10AE0 = 0x10<<dacm;
	ADC10CTL0 |= ENC + ADC10SC;
}

// Watchdog Timer interrupt service routine
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=WDT_VECTOR
__interrupt void watchdog_timer(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(WDT_VECTOR))) watchdog_timer (void)
#else
#error Compiler not supported!
#endif
{
	phase_cnt--;
}

```