maelli01 74 Posted September 30, 2014 Share Posted September 30, 2014 Hi thereHere is my 3phase variable speed motor drive booster packThis has been in my mind for some years, but I always thought that a 3phase variable speed inverter drive isbeyond my humble hobbyist scope. Too complicated for my old 8-bit mind ;-)Such a inverter contains:6 high voltage FETs or IGBTs, 6 gatedrives, at least one DSP, a protection concept,all the software to create the 3-phase PWM, dead time control.....Still that was for quite some time on my long-term "to do" list, with no chance to actually materialize it,not enough time, too many other things to do.When playing around with the PWM module of the TM4C123 I found out that creating a 3phase PWMsignal with this module is actually pretty easy.Combined that with an integrated Power Module such as the FSB50550 (Fairchild).So here it is: a booster pack for the Tiva Launchpad which drives big-ass 3phase motors.The booster pack contains the following:- the FSB50550 power module (6 FETs 500V 1.4Ohm, Gatedrivers, Bootstrap diodes, Temp sensor)- snubber capacitorPower supply: everything is powered from one DC source, 20V or (much) more.- 15V switchmode power supply from the high voltage side, built around a LNK304, for the FSB50550- 3.3V switchmode power supply from the 15V to power the Launchpad, built around a LT1376Measurement:- Passive voltage dividier to measure the input voltage- Sense resistor and LM339 comparator for overcurrent detectionDisplay:- Nokia 5110 displayPotentiometer for motor speed and directionThe software is based on Energia using Tiva Ware function calls for all the PWM stuff.It is still work in progress, very basic and at the moment consists of:- calculate the sinwave lookup table at startup- PWM initialisation (PWM set to 15625 Hz, deadtime 1us, sync on)- a timer interrupt run every 10uSecs, do update the 3 PWD duty cycles- ADC measurement of temperature, voltage, current (moving average)- fault interruptThe main program is very short, the display is updated twice a second and the modulation factor is calculatedout of the potentiometer speed setting and the applied DC voltage.Sudden changes in motor frequency are limited in the software, to prevent the motor to feed back energy and causeovervoltage.The motor on the picture is a 1/2hp, 900rpm, 6-pole motor, 12 kg of Italian steel and copper, probably 50 years old.For playing around, I apply about 50% of rated volt/hz, so current and maximum torque is reduced.Currently I use my dual 35V 4A lab supply, series connected, as a power source. here is the code: //simple 3phase frequency converter //27.9.2014 by maelli #define dots 192 //dots per halfhave, must be divisible with 3 #define period 5120 //80Mhz/5120 = 15625 switching frequency #define dt 80 //deadtime 80Mhz / 80 = 1uS #define PART_TM4C123GH6PM #include <stdint.h> #include <stdbool.h> #include "inc/hw_ints.h" #include "inc/hw_sysctl.h" #include "inc/hw_types.h" #include "driverlib/interrupt.h" #include "driverlib/sysctl.h" #include "driverlib/timer.h" #include "driverlib/pwm.h" #include "LCD_5110.h" #include "inc/tm4c123gh6pm.h" LCD_5110 myScreen (33,37,36,35,34,38,17); char celsius[3]={0x7f,'C',0x00}; uint16_t a,dire=0,modu,tensec; uint32_t timecount,sintable[dots]; volatile int32_t irqcount,timeset; volatile uint32_t temperature, voltage, current, poti; void setup(){ myScreen.begin(); myScreen.setBacklight(0); myScreen.text(0, 0, "3ph Converter"); for(int i=0;i<dots;i++) sintable[i]=sinf((i*3.14159)/dots)*(period/2-dt); unsigned long ulPeriod; unsigned int Hz = 10000; // interupt frequency in Hz ulPeriod = (SysCtlClockGet() / Hz); initTimer(); charge_gdu(); ROM_TimerLoadSet(TIMER0_BASE, TIMER_A,ulPeriod -1); initPWM(); } void loop(){ if (irqcount>499) { //20x per sec irqcount-=500; int32_t fsoll=732*(poti-16384); int32_t diff=fsoll-timeset; if (diff>0){ if (diff>150000) timeset+=150000; else timeset=fsoll; } else { if (diff<-150000) timeset-=150000; else timeset=fsoll; } modu=abs(timeset)/voltage/16; if (modu<(32000/voltage)) modu=32000/voltage; if (modu>256) modu=256; tensec++; if (tensec==10) { //2x per sec we display something tensec=0; myScreen.text(0, 1, mkstrg((temperature-325)/24,2)); myScreen.text(2, 1, celsius); myScreen.text(5, 1, mkstrg((voltage)/23,3)); myScreen.text(8, 1, "Volt"); myScreen.text(0, 2, mkstrg(abs(timeset)/322122,2)); myScreen.text(2, 2, "."); myScreen.text(3, 2, mkstrg(abs((timeset/32212)%10),1)); myScreen.text(4, 2, "Hz"); myScreen.text(7, 2, mkstrg(current,4)); myScreen.text(11, 2, "mA"); if (timeset<0) myScreen.text(0, 3, "links "); else myScreen.text(0, 3, "rechts"); } } } String mkstrg(int d,uint8_t l){ char display[l+1]; int q=1; display[l]=0; for (uint8_t a=l;a;a--){ display[a-1]=0x30+(d%(q*10))/q; q*=10; } return display; } void initTimer(){ ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0); ROM_TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC); // 32 bits Timer TimerIntRegister(TIMER0_BASE, TIMER_A, Timer0Isr); // Registering isr ROM_TimerEnable(TIMER0_BASE, TIMER_A); ROM_IntEnable(INT_TIMER0A); ROM_TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT); } void charge_gdu(){ ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD); ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); ROM_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_0 ); ROM_GPIOPadConfigSet(GPIO_PORTF_BASE,GPIO_PIN_0,GPIO_STRENGTH_4MA,GPIO_PIN_TYPE_STD); GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_7); //alle 3 oberen ausschalten HWREG(GPIO_PORTA_BASE + (GPIO_PIN_7 << 2)) = 0; GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_1); HWREG(GPIO_PORTD_BASE + (GPIO_PIN_1 << 2)) = 0; GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_3); HWREG(GPIO_PORTF_BASE + (GPIO_PIN_3 << 2)) = 0; GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_0); //auch die 2 letzten aus HWREG(GPIO_PORTD_BASE + (GPIO_PIN_0 << 2)) = 0; GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_2); HWREG(GPIO_PORTF_BASE + (GPIO_PIN_2 << 2)) = 0; GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_6); //den ersten unteren ein HWREG(GPIO_PORTA_BASE + (GPIO_PIN_6 << 2)) = GPIO_PIN_6; delay(1); HWREG(GPIO_PORTD_BASE + (GPIO_PIN_0 << 2)) = GPIO_PIN_0; delay(1); HWREG(GPIO_PORTF_BASE + (GPIO_PIN_2 << 2)) = GPIO_PIN_2; delay(1); } void initPWM(){ ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM1); //The Tiva Launchpad has two PWM modules (0 and 1). We are using 1 ROM_GPIOPinConfigure(GPIO_PD0_M1PWM0); ROM_GPIOPinConfigure(GPIO_PD1_M1PWM1); ROM_GPIOPinConfigure(GPIO_PA6_M1PWM2); ROM_GPIOPinConfigure(GPIO_PA7_M1PWM3); ROM_GPIOPinConfigure(GPIO_PF2_M1PWM6); ROM_GPIOPinConfigure(GPIO_PF3_M1PWM7); ROM_GPIOPinConfigure(GPIO_PF4_M1FAULT0); ROM_GPIOPinTypePWM(GPIO_PORTD_BASE, GPIO_PIN_0 | GPIO_PIN_1 ); ROM_GPIOPinTypePWM(GPIO_PORTA_BASE, GPIO_PIN_6 | GPIO_PIN_7 ); ROM_GPIOPinTypePWM(GPIO_PORTF_BASE, GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4); PWM1_0_FLTSEN_R =3; //PWM fault inverted see page 1169 GPIO_PORTF_PUR_R=0x10; //weak pullup for Pin 4 ROM_PWMGenConfigure(PWM1_BASE, PWM_GEN_0, PWM_GEN_MODE_UP_DOWN | PWM_GEN_MODE_SYNC | PWM_GEN_MODE_FAULT_LEGACY); ROM_PWMGenConfigure(PWM1_BASE, PWM_GEN_1, PWM_GEN_MODE_UP_DOWN | PWM_GEN_MODE_SYNC | PWM_GEN_MODE_FAULT_LEGACY); ROM_PWMGenConfigure(PWM1_BASE, PWM_GEN_3, PWM_GEN_MODE_UP_DOWN | PWM_GEN_MODE_SYNC | PWM_GEN_MODE_FAULT_LEGACY); ROM_PWMGenPeriodSet(PWM1_BASE, PWM_GEN_0, period); ROM_PWMGenPeriodSet(PWM1_BASE, PWM_GEN_1, period); ROM_PWMGenPeriodSet(PWM1_BASE, PWM_GEN_3, period); ROM_PWMDeadBandEnable(PWM1_BASE, PWM_GEN_0, dt,dt); ROM_PWMDeadBandEnable(PWM1_BASE, PWM_GEN_1, dt,dt); ROM_PWMDeadBandEnable(PWM1_BASE, PWM_GEN_3, dt,dt); ROM_PWMSyncTimeBase(PWM1_BASE,PWM_GEN_0_BIT |PWM_GEN_1_BIT|PWM_GEN_3_BIT); ROM_PWMGenEnable(PWM1_BASE, PWM_GEN_0); ROM_PWMGenEnable(PWM1_BASE, PWM_GEN_1); ROM_PWMGenEnable(PWM1_BASE, PWM_GEN_3); delay(1); PWMFaultIntRegister(PWM1_BASE, oh_shit); ROM_PWMIntEnable(PWM1_BASE,PWM_INT_FAULT0); ROM_PWMOutputState(PWM1_BASE, PWM_OUT_0_BIT | PWM_OUT_1_BIT | PWM1_BASE | PWM_OUT_2_BIT | PWM_OUT_3_BIT |PWM_OUT_6_BIT | PWM_OUT_7_BIT, true); } void Timer0Isr(void) { //10000x per second ROM_TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT); // Clear the timer interrupt irqcount++; timecount+=timeset; // 1 Hz is 192x256*256*256/10000=322122.5 if (timecount> 0xEFFFFFFF) timecount+=0xC0000000; if (timecount> 0xBFFFFFFF) timecount-=0xC0000000;; a=timecount>>16; a=a/(16384/(dots/3*2)); //a immer kleiner 2*dots: C000 *dots/3*2/ 4000= 12 *dots/3*2/4= 2*dots if (a<dots)ROM_PWMPulseWidthSet(PWM1_BASE, PWM_OUT_0,period/2+sintable[a]*modu/256); else ROM_PWMPulseWidthSet(PWM1_BASE, PWM_OUT_0,period/2-sintable[a-dots]*modu/256); a=a+dots*2/3; if (a>=2*dots) a-=2*dots; if (a<dots)ROM_PWMPulseWidthSet(PWM1_BASE, PWM_OUT_2,period/2+sintable[a]*modu/256); else ROM_PWMPulseWidthSet(PWM1_BASE, PWM_OUT_2,period/2-sintable[a-dots]*modu/256); a=a+dots*2/3; if (a>=2*dots) a-=2*dots; if (a<dots)ROM_PWMPulseWidthSet(PWM1_BASE, PWM_OUT_6,period/2+sintable[a]*modu/256); else ROM_PWMPulseWidthSet(PWM1_BASE, PWM_OUT_6,period/2-sintable[a-dots]*modu/256); ROM_PWMSyncUpdate(PWM1_BASE,PWM_GEN_0_BIT |PWM_GEN_1_BIT|PWM_GEN_3_BIT); switch(irqcount%10){ case 0: temperature=(temperature*127+analogRead(26))/128; break; case 1: voltage=(voltage*31+analogRead(27)*3)/32; break; case 2: current=(current*127+analogRead(25)*8)/128; break; case 3: poti=(poti*127+analogRead(28)*8)/128; break; } } void oh_shit(void) { //in case of severe overcurrent we shut down! ROM_PWMFaultIntClearExt(PWM1_BASE,PWM_INT_FAULT0); ROM_PWMOutputState(PWM1_BASE, PWM_OUT_0_BIT | PWM_OUT_1_BIT | PWM1_BASE | PWM_OUT_2_BIT | PWM_OUT_3_BIT |PWM_OUT_6_BIT | PWM_OUT_7_BIT, false); } PTB, Automate, MichelKohler and 5 others 8 Quote Link to post Share on other sites
PTB 27 Posted September 30, 2014 Share Posted September 30, 2014 Very nice !!!! Quote Link to post Share on other sites
timotet 44 Posted October 1, 2014 Share Posted October 1, 2014 Nice Work , would like to see a photo of the booster pack itself. I like the thought of controlling a "big ass" motor, just need to figure out for what. I also like the oh_shit function.... that's good. Quote Link to post Share on other sites
maelli01 74 Posted October 1, 2014 Author Share Posted October 1, 2014 @@timotet here are some more pictures. The launchpad is sandwiched between the display and my board. Not much on top, the 50550 hidden under copper heatsink (epoxied on). What looks like a big resistor is a 1mH inductor. Yes, this is the first working prototype, and it looks like this. Smallest SMDs I hand solder are 0603. The circuit diagram (Eagle) is no secret either, however, not human readable yet, since I did not find models for e.g.LNK304. So I used different componens with similar pinout in the diagram, nasty me. I loosely followed this app note: https://www.fairchildsemi.com/application-notes/AN/AN-9080.pdf Yes, the practical uses are limited... fractional-horsepower 3phase motors are rare. checked my drill press, but that has a 2 phase capacitor motor, not a real 3 phase motor with steinmetz circuit. developer_bt 1 Quote Link to post Share on other sites
timotet 44 Posted October 2, 2014 Share Posted October 2, 2014 Thanks for sharing. 0603 is plenty small if you ask me. Quote Link to post Share on other sites
morry 0 Posted October 4, 2014 Share Posted October 4, 2014 Nice project! If you add one more phase current measurement you could easily go for sensorless field oriented control with space vector pwm... Quote Link to post Share on other sites
diegolf 0 Posted February 22, 2016 Share Posted February 22, 2016 Hello Maelli01! Nice Project. You can share the Schematic and BOM of this power supply based on LNK304? i have a similar project and i am with some problems to make my power supply small. Thanks Quote Link to post Share on other sites
maelli01 74 Posted April 28, 2016 Author Share Posted April 28, 2016 it is a long time ago since I hacked this together. For the LNK304 based 15V supply I more or less followed this: https://ac-dc.power.com/design-support/reference-designs/design-examples/der-231-132-w-power-supply/ Adapt R8 and R9 for different output voltage. The UF4007 is a cheap but rather fast diode, a normal 1N4007 will NOT work. I found this LNK chips very easy to use. But yes, these things handle high voltage without potential separation. I always use a separation transformer when experimenting and keep my hands im my pockets... 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.