Hi everyone,
I've got a 50Hz PWM signal on the F28027 LaunchPad without too many problems... few things that don't make sense though that I would like to figure out before moving on.
*SysCtrlRegs.CLKCTL.all = 0x6400; //Use internal Oscillator/ configure some stuff
*SysCtrlRegs.XCLK.all = 0x0040; //60/4 = 15MHZ
The above does not seem to prescale the clock? at least it has no impact on ePWM3 (below).
*EPwm3Regs.TBCTL.bit.CLKDIV = 0x2;
This does work but when it should be clock/4 scaler, it doesn't work like that. (The clock is not doing what (I think) it's told)
*EPwm3Regs.TBPRD = 25000;
*EPwm3Regs.CMPB = 1500*throttle+1000; //Where throttle is float from 0 to1.
This gives a very clean 50Hz PWM with a high time of between 1 and 2ms, exactly as I wanted - and it controls servos and ESCs as intended..
What doesn't make sense is my math to fill the registers. - 60/4 = 15...15/4=3.75MHz effectively for ePWM3.
so (1/50)/(1/3.75M) = 75000. But if I put this is TBPRD I get ~150Hz, same is true for CMPB.
Also, CMPA won't behave for me (hence the use of CMPB) - even in the watcher it won't accept just any values (as B does), for instance, if I put 500 (dec) in the register it resets to 256 and setting 100 goes to >9000!!!
-Back tracking from the 25000 (in TBPRD) that works to produce 50Hz I get a clock of 1.25M, and after scaling back, 10MHz, which makes no sense since there is no scaler to get from 60M to 10M? & seemingly no combinations to arrive here, which means my math is wrong, or the clock is not running at 60M?
EDIT: just realised that I don't need to explain scaling from 60 to 10M, - seems like the MCU is clocked at 10MHz if thats possible?
Thanks for any help & I hope this makes sense, fairly late in AU.
////////////////////////////////////Code/////////////////////////////////////
/* ESC Using F28027F LaunchPad. 50Hz PWM, 1-2ms * */ #include "F2802x_Device.h" // Device Headerfile and Examples Include Files //#include "DSP28x_Project.h" // DSP280x Headerfile Include File //#include "f2802x_common/include/clk.h" //#include "f2802x_common/include/flash.h" //#include "f2802x_common/include/gpio.h" //#include "f2802x_common/include/pie.h" //#include "f2802x_common/include/pll.h" //#include "f2802x_common/include/wdog.h" //#include "f2802x_headers/include/F2802x_EPwm.h" unsigned int i; float throttle = 0; float tthrottle; // Prototype statements for functions found within this file. void InitSysCtrl(void); void Gpio_setup(void); void ePWM_setup(void); void Service_Dog(void); void Disable_Dog(void); //void InitPieCtrl(void); void main(void) { InitSysCtrl(); // Initialize the CPU (FILE: SysCtrl.c) Gpio_setup(); // Initialize the shared GPIO pins (FILE: Gpio.c) //InitPieCtrl(); // Initialize and enable the PIE (FILE: PieCtrl.c) ePWM_setup(); //asm(" CLRC INTM, DBGM"); i=0; while(1) {Service_Dog(); if (throttle !=tthrottle) { tthrottle = throttle; if(throttle <=1 && throttle >=0) { EPwm3Regs.CMPB = 1500*throttle+1000; i++; } } } } void InitSysCtrl(void) { EALLOW; SysCtrlRegs.CLKCTL.all = 0x6400; SysCtrlRegs.XCLK.all = 0x0040;//040; //40 Internal OSC/4 ~15MHz //--- Configure the PLL // Note: The DSP/BIOS configuration tool can also be used to initialize the PLL // instead of doing the initialization here. // Make sure the PLL is not running in limp mode if (SysCtrlRegs.PLLSTS.bit.MCLKSTS != 1) { // PLL is not running in limp mode SysCtrlRegs.PLLSTS.bit.MCLKOFF = 1; // Turn off missing clock detect before changing PLLCR SysCtrlRegs.PLLSTS.bit.DIVSEL = 0; // DIVSEL must be 0 or 1 (/4 CLKIN mode) before changing PLLCR SysCtrlRegs.PLLCR.bit.DIV = 0x0012; // PLLx18/4 (because DIVSEL is /4) // Wait for PLL to lock. // During this time the CPU will run at OSCCLK/4 until the PLL is stable. // Once the PLL is stable the CPU will automatically switch to the new PLL value. // Code is not required to sit and wait for the PLL to lock. However, // if the code does anything that is timing critical (e.g. something that // relies on the CPU clock frequency to be at speed), then it is best to wait // until PLL lock is complete. The watchdog should be disabled before this loop // (e.g., as was done above), or fed within the loop. while(SysCtrlRegs.PLLSTS.bit.PLLLOCKS != 1) // Wait for PLLLOCKS bit to set { //SysCtrlRegs.WDKEY = 0x0055; // Service the watchdog while waiting //SysCtrlRegs.WDKEY = 0x00AA; // in case the user enabled it. Service_Dog(); } // After the PLL has locked, we are running in PLLx18/4 mode (since DIVSEL is /4). // We can now enable the missing clock detect circuitry, and also change DIVSEL // to /2. In this example, I will wait a bit of time to let inrush currents settle, // and then change DIVSEL from /4 to /2. This is only an example. The amount of // time you need to wait depends on the power supply feeding the DSP (i.e., how much // voltage droop occurs due to the inrush currents, and how long it takes the // voltage regulators to recover). SysCtrlRegs.PLLSTS.bit.MCLKOFF = 0; // Enable missing clock detect circuitry //DelayUs(20/2); // Wait 20 us (just an example). Remember we're running // at half-speed here, so divide function argument by 2. SysCtrlRegs.PLLSTS.bit.DIVSEL = 0x2; // Change to /2 mode } else { // PLL is running in limp mode // User should replace the below with a call to an appropriate function, // for example shutdown the system (since something is very wrong!). asm(" ESTOP0"); } EDIS; } /*void InitPieCtrl(void) { //--- Disable interrupts asm(" SETC INTM, DBGM"); // Disable global interrupts //--- Initialize the PIE_RAM PieCtrlRegs.PIECTRL.bit.ENPIE = 0; // Disable the PIE EALLOW; // Enable EALLOW protected register access // Step around the first three 32-bit locations (six 16-bit locations). // These locations are used by the ROM bootloader during debug, and also // by the Flash API algorithms. // memcpy((Uint16 *)&PieVectTable+6, (Uint16 *)&PieVectTableInit+6, 256-6); //UNCOMMENT EDIS; // Disable EALLOW protected register access //--- Disable all PIE interrupts PieCtrlRegs.PIEIER1.all = 0x0000; PieCtrlRegs.PIEIER2.all = 0x0000; PieCtrlRegs.PIEIER3.all = 0x0000; PieCtrlRegs.PIEIER4.all = 0x0000; PieCtrlRegs.PIEIER5.all = 0x0000; PieCtrlRegs.PIEIER6.all = 0x0000; PieCtrlRegs.PIEIER7.all = 0x0000; PieCtrlRegs.PIEIER8.all = 0x0000; PieCtrlRegs.PIEIER9.all = 0x0000; PieCtrlRegs.PIEIER10.all = 0x0000; PieCtrlRegs.PIEIER11.all = 0x0000; PieCtrlRegs.PIEIER12.all = 0x0000; //--- Clear any potentially pending PIEIFR flags PieCtrlRegs.PIEIFR1.all = 0x0000; PieCtrlRegs.PIEIFR2.all = 0x0000; PieCtrlRegs.PIEIFR3.all = 0x0000; PieCtrlRegs.PIEIFR4.all = 0x0000; PieCtrlRegs.PIEIFR5.all = 0x0000; PieCtrlRegs.PIEIFR6.all = 0x0000; PieCtrlRegs.PIEIFR7.all = 0x0000; PieCtrlRegs.PIEIFR8.all = 0x0000; PieCtrlRegs.PIEIFR9.all = 0x0000; PieCtrlRegs.PIEIFR10.all = 0x0000; PieCtrlRegs.PIEIFR11.all = 0x0000; PieCtrlRegs.PIEIFR12.all = 0x0000; //--- Acknowlege all PIE interrupt groups PieCtrlRegs.PIEACK.all = 0xFFFF; //--- Enable the PIE PieCtrlRegs.PIECTRL.bit.ENPIE = 1; // Enable the PIE } // end of InitPieCtrl() */ void Gpio_setup(void) { EALLOW;// Write EALLOW //--- Group A pins GpioCtrlRegs.GPACTRL.all = 0x00000000; // QUALPRD = SYSCLKOUT for all group A GPIO GpioCtrlRegs.GPAQSEL1.all = 0x00000000; // No qualification for all group A GPIO 0-15 GpioCtrlRegs.GPADIR.all = 0x0000001F; // GPIO 0/3 are outputs (LEDS) - Remainder Inputs GpioCtrlRegs.GPAPUD.all = 0x00000FFF;//FFF // Pullups enabled GPIO31-12, disabled GPIO11-0 GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 0; // 0=GPIO 1=EPWM1A 2=rsvd 3=rsvd GpioCtrlRegs.GPAMUX1.bit.GPIO1 = 0; // 0=GPIO 1=EPWM1B 2=rsvd 3=COMP1OUT GpioCtrlRegs.GPAMUX1.bit.GPIO2 = 0; // 0=GPIO 1=EPWM2A 2=rsvd 3=rsvd GpioCtrlRegs.GPAMUX1.bit.GPIO3 = 0; // 0=GPIO 1=EPWM2B 2=SPISOMIA 3=COMP2OUT GpioCtrlRegs.GPAMUX1.bit.GPIO4 = 1; // 0=GPIO 1=EPWM3A 2=rsvd 3=rsvd GpioCtrlRegs.GPAMUX1.bit.GPIO5 = 0; // 0=GPIO 1=EPWM3B 2=SPISIMOA 3=ECAP1 GpioCtrlRegs.GPAMUX1.bit.GPIO6 = 0; // 0=GPIO 1=EPWM4A 2=EPWMSYNCI 3=EPWMSYNCO GpioCtrlRegs.GPAMUX1.bit.GPIO7 = 0; // 0=GPIO 1=EPWM4B 2=SCIRXDA 3=ECAP2 GpioCtrlRegs.GPAMUX1.bit.GPIO8 = 0; // 0=GPIO 1=EPWM5A 2=rsvd 3=ADCSOCAO GpioCtrlRegs.GPAMUX1.bit.GPIO9 = 0; // 0=GPIO 1=EPWM5B 2=SCITXDB 3=ECAP3 GpioCtrlRegs.GPAMUX1.bit.GPIO10 = 0; // 0=GPIO 1=EPWM6A 2=rsvd 3=ADCSOCBO GpioCtrlRegs.GPAMUX1.bit.GPIO11 = 0; // 0=GPIO 1=EPWM6B 2=SCIRXDB 3=ECAP1 GpioCtrlRegs.GPAMUX1.bit.GPIO12 = 0; // 0=GPIO 1=TZ1 2=SCITXDA 3=SPISIMOB GpioCtrlRegs.GPAMUX1.bit.GPIO13 = 0; // 0=GPIO 1=TZ2 2=rsvd 3=SPISOMIB GpioCtrlRegs.GPAMUX1.bit.GPIO14 = 0; // 0=GPIO 1=TZ3 2=SCITXDB 3=SPICLKB GpioCtrlRegs.GPAMUX1.bit.GPIO15 = 0; // 0=GPIO 1=ECAP2 2=SCIRXDB 3=SPISTEB GpioCtrlRegs.GPAMUX2.bit.GPIO16 = 0; // 0=GPIO 1=SPISIMOA 2=rsvd 3=TZ2 GpioCtrlRegs.GPAMUX2.bit.GPIO17 = 0; // 0=GPIO 1=SPISOMIA 2=rsvd 3=TZ3 GpioCtrlRegs.GPAMUX2.bit.GPIO18 = 0; // 0=GPIO 1=SPICLKA 2=SCITXDB 3=XCLKOUT GpioCtrlRegs.GPAMUX2.bit.GPIO19 = 0; // 0=GPIO/XCLKIN 1=SPISTEA 2=SCIRXDB 3=ECAP1 GpioCtrlRegs.GPAMUX2.bit.GPIO20 = 0; // 0=GPIO 1=EQEP1A 2=MDXA 3=COMP1OUT GpioCtrlRegs.GPAMUX2.bit.GPIO21 = 0; // 0=GPIO 1=EQEP1B 2=MDRA 3=COMP2OUT GpioCtrlRegs.GPAMUX2.bit.GPIO22 = 0; // 0=GPIO 1=EQEP1S 2=MCLKXA 3=SCITXDB GpioCtrlRegs.GPAMUX2.bit.GPIO23 = 0; // 0=GPIO 1=EQEP1I 2=MFSXA 3=SCIRXDB GpioCtrlRegs.GPAMUX2.bit.GPIO24 = 0; // 0=GPIO 1=ECAP1 2=EQEP2A 3=SPISIMOB GpioCtrlRegs.GPAMUX2.bit.GPIO25 = 0; // 0=GPIO 1=ECAP2 2=EQEP2B 3=SPISOMIB GpioCtrlRegs.GPAMUX2.bit.GPIO26 = 0; // 0=GPIO 1=ECAP3 2=EQEP2I 3=SPICLKB GpioCtrlRegs.GPAMUX2.bit.GPIO27 = 0; // 0=GPIO 1=HRCAP2 2=EQEP2S 3=SPISTEB GpioCtrlRegs.GPAMUX2.bit.GPIO28 = 0; // 0=GPIO 1=SCIRXDA 2=SDAA 3=TZ2 GpioCtrlRegs.GPAMUX2.bit.GPIO29 = 0; // 0=GPIO 1=SCITXDA 2=SCLA 3=TZ3 GpioCtrlRegs.GPAMUX2.bit.GPIO30 = 0; // 0=GPIO 1=CANRXA 2=EQEP2I 3=EPWM7A GpioCtrlRegs.GPAMUX2.bit.GPIO31 = 0; // 0=GPIO 1=CANTXA 2=EQEP2S 3=EPWM8A //--- External interrupt selection GpioIntRegs.GPIOXINT1SEL.all = 0x0100; // GPIO4 is XINT1 source GpioIntRegs.GPIOXINT2SEL.all = 0x0100; // GPIO4 is XINT2 source GpioIntRegs.GPIOXINT3SEL.all = 0x0100; // GPIO4 is XINT3 source XIntruptRegs.XINT1CR.all = 0x0100; // XINT1 disabled XIntruptRegs.XINT2CR.all = 0x0100; // XINT2 disabled XIntruptRegs.XINT3CR.all = 0x0100; // XINT3 disabled //--- Low-power mode selection GpioIntRegs.GPIOLPMSEL.all = 0x00000000; // No pin selected for HALT and STANBY wakeup (reset default) //--- Selected pin configurations GpioCtrlRegs.GPADIR.all = 0x0000001F;//0x100F; // GPIO0-4 are outputs EDIS; } void ePWM_setup(void) { EALLOW; SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0; //Disable clock - Temp SysCtrlRegs.PCLKCR1.bit.EPWM3ENCLK = 1; // ePWM1 EDIS; //--------------------------------------------------------------------- //--- Configure ePWM1 for 50 Hz asymmetric PWM on EPWM3A pin //--------------------------------------------------------------------- EPwm3Regs.TBCTL.bit.CTRMODE = 0x3; // Disable the timer EPwm3Regs.TBCTL.all = 0xC033; // Configure timer control register // bit 15-14 11: FREE/SOFT, 11 = ignore emulation suspend // bit 13 0: PHSDIR, 0 = count down after sync event // bit 12-10 000: CLKDIV, 000 => TBCLK = HSPCLK/1 // bit 9-7 000: HSPCLKDIV, 000 => HSPCLK = SYSCLKOUT/1 // bit 6 0: SWFSYNC, 0 = no software sync produced // bit 5-4 11: SYNCOSEL, 11 = sync-out disabled // bit 3 0: PRDLD, 0 = reload PRD on counter=0 // bit 2 0: PHSEN, 0 = phase control disabled // bit 1-0 11: CTRMODE, 11 = timer stopped (disabled) EPwm3Regs.TBCTR = 0x0000; // Clear timer counter EPwm3Regs.TBPRD = 25000;//0xFFFF; //50Hz//22500;//PWM_HALF_PERIOD; // Set timer period EPwm3Regs.TBPHS.half.TBPHS = 0x0000; // Set timer phase EPwm3Regs.CMPA.half.CMPA = 0;// 0x00FF; //50Hz16875;//PWM_DUTY_CYCLE; // Set PWM duty cycle EPwm3Regs.CMPCTL.all = 0x0002; // Compare control register // bit 15-10 0's: reserved // bit 9 0: SHDWBFULL, read-only // bit 8 0: SHDWAFULL, read-only // bit 7 0: reserved // bit 6 0: SHDWBMODE, don't care // bit 5 0: reserved // bit 4 0: SHDWAMODE, 0 = shadow mode // bit 3-2 00: LOADBMODE, don't care // bit 1-0 10: LOADAMODE, 10 = load on zero or PRD match //Action when the time-base counter equals the active CMPB register and the counter is decrementing. EPwm3Regs.AQCTLA.all = 0x0102;//180; // Action-qualifier control register A // bit 15-12 0000: reserved // bit 11-10 00: CBD, 00 = do nothing // bit 9-8 00: CBU, 00 = do nothing // bit 7-6 01: CAD, 01 = clear // bit 5-4 10: CAU, 10 = set // bit 3-2 00: PRD, 00 = do nothing // bit 1-0 00: ZRO, 00 = do nothing EPwm3Regs.AQSFRC.all = 0x0000; // Action-qualifier s/w force register // bit 15-8 0's: reserved // bit 7-6 00: RLDCSF, 00 = reload AQCSFRC on zero // bit 5 0: OTSFB, 0 = do not initiate a s/w forced event on output B // bit 4-3 00: ACTSFB, don't care // bit 2 0: OTSFA, 0 = do not initiate a s/w forced event on output A // bit 1-0 00: ACTSFA, don't care EPwm3Regs.AQCSFRC.all = 0x0000; // Action-qualifier continuous s/w force register // bit 15-4 0's: reserved // bit 3-2 00: CSFB, 00 = forcing disabled // bit 1-0 00: CSFA, 00 = forcing disabled EPwm3Regs.DBCTL.bit.OUT_MODE = 0; // Deadband disabled EPwm3Regs.PCCTL.bit.CHPEN = 0; // PWM chopper unit disabled EPwm3Regs.TZDCSEL.all = 0x0000; // All trip zone and DC compare actions disabled EPwm3Regs.TBCTL.bit.CTRMODE = 0;//0x2; // Enable the timer in count up/down mode EPwm3Regs.TBCTL.bit.CLKDIV = 0x2; //Scaler OSC/4 ~15MHZ //--------------------------------------------------------------------- //--- Enable the clocks to the ePWM module. //--- Note: this should be done after all ePWM modules are configured //--- to ensure synchronization between the ePWM modules. //--------------------------------------------------------------------- EALLOW; // Enable EALLOW protected register access SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1; // TBCLK to ePWM modules enabled //SysCtrlRegs.PCLKCR1.bit.EPWM3ENCLK = 1; //SysCtrlRegs.PCLKCR1.bit.EPWM3ENCLK = 1; EDIS; // Disable EALLOW protected register access //EPwm3Regs.CMPA.half.CMPA = 500; } void Service_Dog(void) {//Clear the watchdog EALLOW; SysCtrlRegs.WDKEY = 0x0055; //Reset Counter SysCtrlRegs.WDKEY = 0x00AA; EDIS; } void DisableDog(void) { EALLOW; SysCtrlRegs.WDCR= 0x0068; EDIS; } //=========================================================================== // End //===========================================================================