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
//===========================================================================
