Part Number: LAUNCHXL-F28379D
Tool/software: Code Composer Studio
Hello,
This post is not exactly a request but instead, I would like to share some issues that I did not found mentionned on the spruhm8i technical reference manual (I may have missed them).
So, the goal is to set a fast PWM with a fixed duty cycle of 50% and a period that could be trimmed. The main problem I meet is a jitter of about 1 EPWMCLK cycle appearing randomly. What I discovered is that it was due to numerous factor:
- I can't use a divider of 1 between PLLSYSCLK and EPWMCLK (EPWMCLKDIV=1 is mandatory) (page 115 of the manual)
- If I do not wait for SFO() to complete its first cycle, the jitter appears and does not disappear after the completion of the function. The following code solved the problem
while(status == 0) // Call until complete
{
status = SFO();
if (status == 2)
{
ESTOP0;
}
}
- Finally, the fact that I use an up and down counter with set and reset on 0 and TBPRD leads to the jitter appearing but I don't know why. I solved this by comparing with the example from hrpwm_prdupdown_sfo_v8 which uses CMPA/B and it's the only thing that differ from the programms that affect the results.
Also, if find it strange that when SYNCOSEL=0, the external sync signal which synchronises the different EPWM comes from Input5 X-bar which is connected to .... EPWM1A by default (page 1967 it's written in the footnotes that a sync pulse will introduce jitter). But maybe I didn't understand well ?
Thanks for reading and If you have comments/help/hints, I would be glad to hear them.
From here, a simple code that was used:
// La doc utilise comme indicateur est: TMS320F2837xD Dual-Core Microcontrollers Technical Reference Manual
#include "F28x_Project.h"
//Include pour la mise en place de la pwm haute resolution
#include "F2837xD_Device.h" // F28x7x Headerfile
#include "F2837xD_EPwm_defines.h" // init defines
#include "SFO_V8.H" // SFO lib functions (needed for HRPWM)
// Function Prototypes
void InitEPwm1Example(void);
int i=0;
int status=0;
Uint16 periode = 50; //FPWM=FTBCLK/(2*periode) avec FTBCLK=100MHz tel que regle actuellement
Uint16 dureeDeadBand=15;
int MEP_ScaleFactor = 0; //scale factor value
volatile struct EPWM_REGS *ePWM[] = {0, &EPwm1Regs};
void main(void)
{
EALLOW;
InitSysCtrl();
CpuSysRegs.PCLKCR2.bit.EPWM1=1;
CpuSysRegs.PCLKCR0.bit.HRPWM=1; //On active l'horloge de la PWM haute resolution
EDIS;
InitEPwm1Gpio();
EALLOW;
GpioCtrlRegs.GPAMUX1.bit.GPIO6 = 3; //On envoie le bit de synchro sur P6 au lieu de PWM4
EDIS;
DINT;
InitPieCtrl();
EALLOW;
IER = 0x0000;
IFR = 0x0000;
InitPieVectTable();
while(status == 0) // Call until complete
{
status = SFO();
if (status == 2)
{
ESTOP0;
}
}
InitEPwm1Example();
EPwm1Regs.TBPRDHR=0x3333;
//EPwm1Regs.TBPRDHR=0x4333;
SFO();
IER |= M_INT3;
PieCtrlRegs.PIEIER3.bit.INTx1 = 1;
PieCtrlRegs.PIEIER3.bit.INTx2 = 1;
PieCtrlRegs.PIEIER3.bit.INTx3 = 1;
PieCtrlRegs.PIEIER3.bit.INTx4 = 1;
EINT; // Enable Global interrupt INTM
ERTM; // Enable Global realtime interrupt DBGM
// Step 6. IDLE loop. Just sit and loop forever (optional):
for(;;)
{
}
}
/*########################################################################################*/
//Routine de configuration
void InitEPwm1Example()
{
int period=periode;
EALLOW; //Ne pas oublier que le registre est protege !!!
ClkCfgRegs.PERCLKDIVSEL.bit.EPWMCLKDIV=1; //On ne divise PAS par 2 l'horloge EPWMCLK par rapport à PLLSYSCLK (voir page 115)
SyncSocRegs.SYNCSELECT.bit.SYNCOUT=0; //On envoie le top de synchronisation de PWM1 sur le Xbar de sortie (debug purpose)
InputXbarRegs.INPUT5SELECT=22; //Le GPIO 22 est connecte sur extsyncin1 plutot que la P0 qui etait la pwm1 et foutait le boxon en faisant apparaitre des tops de synchro
EDIS;
if (0) //Part that doesn't work because of toogling method that doesn't use CMPA register (jitter appear if selected)
{
EPwm1Regs.TBPRD = periode; // On compte jusqu'a 50
// Setup TBCLK
EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // Compte en montant puis en descendant
EPwm1Regs.TBPHS.bit.TBPHS =0; // Dephasage de 0
EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; // Clock ratio to SYSCLKOUT -> Attention, le systeme utilise une horloge SYSCLOCKOUT qui donne une horloge EPWMCLK (via le registre EPWMCLKDIV) qui donne une horloge TBCLK
EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV1; // Attention a bien mettre les 2: HSPCLKDIV et CLKDIV (page 1983 TBCLK = EPWMCLK / (HSPCLKDIV x CLKDIV).)
EPwm1Regs.TBCTL.bit.PRDLD=0; // Permet d'ecrire au bon moment dans le registre pour ne pas perturber le module (shadow sur mise a jour de TBPRD, page 1874)
EPwm1Regs.TBCTL.bit.SYNCOSEL=0; // On genere un top synchro lorsque le registre vaut 0
// Set actions
// Pareil ici, on defini les actions a faire lorsque le compteur atteint les valeurs CMPA. Comme ce n'est pas utilise, je vais plutot definir les actions lorsqu'il atteint TBPRD et 0
// page 2022 de la doc
EPwm1Regs.AQCTLA.bit.PRD=AQ_CLEAR; //On toogle la sortie de la PWMA lorsque le commpteur atteint la valeur de la periode.
EPwm1Regs.AQCTLA.bit.ZRO=AQ_SET; //Pareil lorsqu'il atteint 0
EPwm1Regs.AQCTLB.bit.PRD=AQ_CLEAR; //On toogle la sortie de la PWMB
EPwm1Regs.AQCTLB.bit.ZRO=AQ_SET;
// // Active Low PWMs - Setup Deadband (it works properly)
// EPwm1Regs.DBCTL.bit.HALFCYCLE=1; //Permet d'etre 2* plus precis sur la gestions des temps morts
// EPwm1Regs.DBCTL.bit.OUT_MODE = DB_FULL_ENABLE; //On active les temps morts à la monte et à la descente (page 1994)
// EPwm1Regs.DBCTL.bit.POLSEL = DB_ACTV_HIC; //Inverse sortie B (pages 1905 et 1994 de la doc)
// EPwm1Regs.DBCTL.bit.IN_MODE = DBA_ALL; //La PWMA est utilisee comme reference pour avoir le rising edge et le falling edge (page 1993) (situation par defaut)
// EPwm1Regs.DBCTL.bit.SHDWDBREDMODE=1; //On active le shadow mode qui sert de buffer pour eviter de modifier les valeurs au mauvais moment
// EPwm1Regs.DBCTL.bit.SHDWDBFEDMODE=1;
//
// // Gestion de la duree des temps morts
// EPwm1Regs.DBRED.bit.DBRED = dureeDeadBand;
// EPwm1Regs.DBFED.bit.DBFED = dureeDeadBand;
// Configuration des registres haute resolution
EALLOW;
EPwm1Regs.HRCNFG.all = 0x0;
//imaginons que l'on veuille mettre au milieu du pas disponible en mode normal, il faut ajouter un nombre de pas MEP=0.5*67=34 puis decaller de 8:
EPwm1Regs.TBPRDHR=0x3333; // En considerant un pas MEPS de 180ps (56 position par coup d'horloge EPWMCLK), cela doit augmenter la periode de 20*180=7.2ns
EPwm1Regs.CMPCTL.bit.LOADAMODE=2;
EPwm1Regs.HRCNFG.bit.HRLOAD=2;
EPwm1Regs.HRCNFG.bit.AUTOCONV=1;
EPwm1Regs.HRCNFG.bit.EDGMODE=3;
EPwm1Regs.HRPCTL.bit.TBPHSHRLOADE=1;
EPwm1Regs.TBCTL.bit.PHSEN =1; // Prise en compte du dephasage
EPwm1Regs.HRPCTL.bit.HRPE=1; // Enable high resolution period control
}
//################################################################################################################
if (1) //Part which works (comes from hrpwm_prdupdown_sfo_v8)
{
EPwm1Regs.TBCTL.bit.PRDLD = TB_SHADOW; // set Shadow load
EPwm1Regs.TBPRD = period; // PWM frequency = 1/(2*TBPRD)
EPwm1Regs.CMPA.bit.CMPA = period / 2; // set duty 50% initially
EPwm1Regs.CMPA.bit.CMPAHR = (1 << 8); // initialize HRPWM extension
EPwm1Regs.CMPB.bit.CMPB = period / 2; // set duty 50% initially
EPwm1Regs.CMPB.all |= 1;
EPwm1Regs.TBPHS.all = 0;
EPwm1Regs.TBCTR = 0;
EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // Select up-down
// count mode
EPwm1Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_DISABLE;
EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;
EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV1; // TBCLK = SYSCLKOUT
EPwm1Regs.TBCTL.bit.FREE_SOFT = 11;
EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO; // LOAD CMPA on CTR = 0
EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;
EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
EPwm1Regs.AQCTLA.bit.CAU = AQ_SET; // PWM toggle high/low
EPwm1Regs.AQCTLA.bit.CAD = AQ_CLEAR;
EPwm1Regs.AQCTLB.bit.CBU = AQ_SET; // PWM toggle high/low
EPwm1Regs.AQCTLB.bit.CBD = AQ_CLEAR;
EALLOW;
EPwm1Regs.HRCNFG.all = 0x0;
EPwm1Regs.HRCNFG.bit.EDGMODE = HR_BEP; // MEP control on
// both edges.
EPwm1Regs.HRCNFG.bit.CTLMODE = HR_CMP; // CMPAHR and TBPRDHR
// HR control.
EPwm1Regs.HRCNFG.bit.HRLOAD = HR_CTR_ZERO_PRD; // load on CTR = 0
// and CTR = TBPRD
EPwm1Regs.HRCNFG.bit.EDGMODEB = HR_BEP; // MEP control on
// both edges
EPwm1Regs.HRCNFG.bit.CTLMODEB = HR_CMP; // CMPBHR and TBPRDHR
// HR control
EPwm1Regs.HRCNFG.bit.HRLOADB = HR_CTR_ZERO_PRD; // load on CTR = 0
// and CTR = TBPRD
EPwm1Regs.HRCNFG.bit.AUTOCONV = 1; // Enable autoconversion for
// HR period
EPwm1Regs.HRPCTL.bit.TBPHSHRLOADE = 1; // Enable TBPHSHR sync
// (required for updwn
// count HR control)
EPwm1Regs.HRPCTL.bit.HRPE = 1; // Turn on high-resolution
// period control.
}
CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 1; // Enable TBCLK within
// the EPWM
EPwm1Regs.TBCTL.bit.SWFSYNC = 1; // Synchronize high
// resolution phase to
// start HR period
EDIS;
}