TMS320F28066PNT PWM Init caused PWM abnormal issue
1.Background
Based on TI PWM Demo code, to realize below function: 20% Duty, PWM1/2/3/4 synchronized
and each PWM delayed 90’ Phase(PWM1 send SYNC while TBCTR = 0; PWM2 lag PWM1 90’,
PWM3 lag PWM2 90’, PWM4 Lag PWM3 90’C); TBPRD: 2000, PWM clock is 90Mhz;
2. FIRST Time Init PWM issue
(TBCTR = TBPHS while Init)
2.1 PWM Resister Value
Step1:After Init, the TBCTR value is equal to TBPHS;
Step2:PWM1 TBCTR close to TBPRD for the first time;
Step3:PWM1 TBCTR decrease to 0 at first time and then send the SYNC to PWM2/3/4;
Step4:PWM1 TRCTR increased and closed to TBPRD:
Step5:PWM1 send SYNC for the second time after Init:
Conclusion: The TBCTR in PWM4 is abnormal, and TBCTR not followed the Up or Down
direction as defined;
2.2 Expected Normal PWM1/2/3/4 output waveform
(PWM1A-CH1/ PWM2A-CH2/ PWM3A-CH3/ PWM4A-CH4)
2.3 Clear TBCTR for each PWM, the PWM output for the
first time
(PWM1A-CH1/ PWM2A-CH2/ PWM3A-CH3/ PWM4A-CH4)
(Note: Noticed the PWM1/2/3/4 with error PWM output, but turn to Normal after the first
SYNC from PWM1)
2.4
Configure
TBCTR
=
TBPHS
PWM1/2/3/4 output for the first time
(PWM1A-CH1/ PWM2A-CH2/ PWM3A-CH3/ PWM4A-CH4)
Note: Noticed that PWM4A always to low, which is abnormal
for
each
PWM,
3. Second PWM Init issue
3.1
TBCTR of PWM1/2/3/4 not cleared which caused
the PWM1/2/3/4 output abnormal
3.2
TBCTR
cleared
to
PWM1/2/3/4 output normal
0
for
PWM1/2/3/4,
4 Test Code
//###########################################################################
// Description:
//! \addtogroup f2806x_example_list
//! <h1>ePWM Action Qualifier Module using up/down count (epwm_updown_aq)</h1>
//!
//! This example configures ePWM1, ePWM2, ePWM3 to produce an waveform with
//! independent modulation on EPWMxA and EPWMxB. The compare values CMPA
//! and CMPB are modified within the ePWM's ISR. The TB counter is in up/down
//! count mode for this example.
//!
//! Monitor ePWM1-ePWM3 pins on an oscilloscope as described
//!
//! \b External \b Connections \n
//! - EPWM1A is on GPIO0
//! - EPWM1B is on GPIO1
//! - EPWM2A is on GPIO2
//! - EPWM2B is on GPIO3
//! - EPWM3A is on GPIO4
//! - EPWM3B is on GPIO5
//
//###########################################################################
// $TI Release: F2806x C/C++ Header Files and Peripheral Examples V141 $
// $Release Date: January 19, 2015 $
// $Copyright: Copyright (C) 2011-2015 Texas Instruments Incorporated //
http://www.ti.com/ ALL RIGHTS RESERVED $
//###########################################################################
#include "DSP28x_Project.h"
// Device Headerfile and Examples Include File
// Prototype statements for functions found within this file.
void Init_PWM(void);
void ReInit_PWM(void);
__interrupt void epwm1_isr(void);
// Configure the period for each timer
#define EPWM1_TIMER_TBPRD 2000
#define EPWM2_TIMER_TBPRD 3000
#define EPWM1_MIN_CMPA
#define EPWM1_MAX_CMPB
// Period register
// Period register
(EPWM1_TIMER_TBPRD*0.2f+0.5f)
(EPWM1_TIMER_TBPRD*0.2f+0.5f)
// To keep track of which way the compare value is moving
#define EPWM_CMP_UP 1
#define EPWM_CMP_DOWN 0
/*PWM interrupt cnt*/
unsigned long m_ulPwmIsrCnt = 0;
void main(void)
{
// Step 1. Initialize System Control:
// PLL, WatchDog, enable Peripheral Clocks
// This example function is found in the F2806x_SysCtrl.c file.
InitSysCtrl();
// Step 2. Initalize GPIO:
// This example function is found in the F2806x_Gpio.c file and
// illustrates how to set the GPIO to it's default state.
//Init_Gpio(); // Skipped for this example
// For this case just init GPIO pins for ePWM1, ePWM2, ePWM3
// These functions are in the F2806x_EPwm.c file
InitEPwm1Gpio();
InitEPwm2Gpio();
InitEPwm3Gpio();
InitEPwm4Gpio();
// Step 3. Clear all interrupts and initialize PIE vector table:
// Disable CPU interrupts
DINT;
// Initialize the PIE control registers to their default state.
// The default state is all PIE interrupts disabled and flags
// are cleared.
// This function is found in the F2806x_PieCtrl.c file.
InitPieCtrl();
// Disable CPU interrupts and clear all CPU interrupt flags:
IER = 0x0000;
IFR = 0x0000;
// Initialize the PIE vector table with pointers to the shell Interrupt
// Service Routines (ISR).
// This will populate the entire table, even if the interrupt
// is not used in this example. This is useful for debug purposes.
// The shell ISR routines are found in F2806x_DefaultIsr.c.
// This function is found in F2806x_PieVect.c.
InitPieVectTable();
// Interrupts that are used in this example are re-mapped to
// ISR functions found within this file.
EALLOW; // This is needed to write to EALLOW protected registers
PieVectTable.EPWM1_INT = &epwm1_isr;
EDIS;
// This is needed to disable write to EALLOW protected registers
// Step 4. Initialize all the Device Peripherals:
// This function is found in F2806x_InitPeripherals.c
// InitPeripherals(); // Not required for this example
// For this example, only initialize the ePWM
Init_PWM();
// Step 5. User specific code, enable interrupts:
// Enable CPU INT3 which is connected to EPWM1-3 INT:
IER |= M_INT3;
// Enable EPWM INTn in the PIE: Group 3 interrupt 1-3
PieCtrlRegs.PIEIER3.bit.INTx1 = 1;
// Enable global Interrupts and higher priority real-time debug events:
EINT; // Enable Global interrupt INTM
ERTM; // Enable Global realtime interrupt DBGM
// Step 6. IDLE loop. Just sit and loop forever (optional):
for(;;)
{
if(1000 == m_ulPwmIsrCnt)
{
//ReInit_PWM();
}
if(EPwm1Regs.TBCTR >= 1990)
{
m_ulPwmIsrCnt++;
}
else if(EPwm1Regs.TBCTR <= 10)
{
m_ulPwmIsrCnt++;
}
__asm("
NOP");
}
}
__interrupt void epwm1_isr(void)
{
// Update the CMPA and CMPB values
//update_compare(&epwm1_info);
m_ulPwmIsrCnt++;
// Clear INT flag for this timer
EPwm1Regs.ETCLR.bit.INT = 1;
// Acknowledge this interrupt to receive more interrupts from group 3
PieCtrlRegs.PIEACK.all = PIEACK_GROUP3;
}
void Init_PWM(void)
{
EALLOW;
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0;
EDIS;
// Disable PWM output
EPwm1Regs.TZFRC.bit.OST = 1;
EPwm2Regs.TZFRC.bit.OST = 1;
EPwm3Regs.TZFRC.bit.OST = 1;
EPwm4Regs.TZFRC.bit.OST = 1;
//////PWM1//////
// Setup TBCLK
EPwm1Regs.TBPRD = EPWM1_TIMER_TBPRD;
EPwm1Regs.TBPHS.half.TBPHS = 0x0000;
EPwm1Regs.TBCTR = 0x0000;
// Set Compare values
EPwm1Regs.CMPA.half.CMPA = EPWM1_MIN_CMPA;
EPwm1Regs.CMPB = EPWM1_MAX_CMPB;
// Setup counter mode
EPwm1Regs.TBCTL.bit.SYNCOSEL = TB_CTR_ZERO;
// Set timer period 801 TBCLKs
// Phase is 0
// Clear counter
// Set compare A value
// Set Compare B value
EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // Count up
EPwm1Regs.TBCTL.bit.PHSDIR = TB_DOWN;
EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE;
// Disable phase loading
EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;
// Clock ratio to SYSCLKOUT
EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV1;
// Setup shadowing
EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
EPwm1Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO_PRD;
EPwm1Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO_PRD;
// Set actions
EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR;
count
EPwm1Regs.AQCTLA.bit.CAD = AQ_SET;
count
EPwm1Regs.AQCTLB.bit.CBU = AQ_CLEAR;
EPwm1Regs.AQCTLB.bit.CBD = AQ_SET;
count
// Load on Zero
// Set PWM1A on event A, up
// Clear PWM1A on event A, down
// Set PWM1B on event B, up count
// Clear PWM1B on event B, down
// Interrupt where we will change the Compare Values
EPwm1Regs.ETSEL.bit.INTSEL = ET_CTR_PRD; // Select INT on Zero event
EPwm1Regs.ETSEL.bit.INTEN = 0;
// Enable INT
EPwm1Regs.ETPS.bit.INTPRD = ET_1ST;
// Generate INT on 3rd event
//////PWM2//////
// Setup TBCLK
EPwm2Regs.TBPRD = EPWM1_TIMER_TBPRD;
// Set timer period 801 TBCLKs
EPwm2Regs.TBPHS.half.TBPHS = EPWM1_TIMER_TBPRD/2; // Phase PI/2
EPwm2Regs.TBCTR = EPWM1_TIMER_TBPRD/2;
// Clear counter
// Set Compare values
EPwm2Regs.CMPA.half.CMPA = EPWM1_MIN_CMPA;
EPwm2Regs.CMPB = EPWM1_MAX_CMPB;
// Set compare A value
// Set Compare B value
// Setup counter mode
EPwm2Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_IN;
EPwm2Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // Count up
EPwm2Regs.TBCTL.bit.PHSDIR = TB_DOWN;
EPwm2Regs.TBCTL.bit.PHSEN = TB_ENABLE;
// Disable phase loading
EPwm2Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;
// Clock ratio to SYSCLKOUT
EPwm2Regs.TBCTL.bit.CLKDIV = TB_DIV1;
// Setup shadowing
EPwm2Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
EPwm2Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
EPwm2Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO_PRD;
EPwm2Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO_PRD;
// Set actions
EPwm2Regs.AQCTLA.bit.CAU = AQ_CLEAR;
count
EPwm2Regs.AQCTLA.bit.CAD = AQ_SET;
count
EPwm2Regs.AQCTLB.bit.CBU = AQ_CLEAR;
EPwm2Regs.AQCTLB.bit.CBD = AQ_SET;
count
// Load on Zero
// Set PWM1A on event A, up
// Clear PWM1A on event A, down
// Set PWM1B on event B, up count
// Clear PWM1B on event B, down
// Interrupt where we will change the Compare Values
EPwm2Regs.ETSEL.bit.INTSEL = ET_CTR_PRD;
// Select INT on Zero event
EPwm2Regs.ETSEL.bit.INTEN = 0;
// Enable INT
EPwm2Regs.ETPS.bit.INTPRD = ET_1ST;
// Generate INT on 3rd event
//////PWM3//////
// Setup TBCLK
EPwm3Regs.TBPRD = EPWM1_TIMER_TBPRD;
// Set timer period 801 TBCLKs
EPwm3Regs.TBPHS.half.TBPHS = EPWM1_TIMER_TBPRD; // Phase PI/2
EPwm3Regs.TBCTR = EPWM1_TIMER_TBPRD;
// Clear counter
// Set Compare values
EPwm3Regs.CMPA.half.CMPA = EPWM1_MIN_CMPA;
EPwm3Regs.CMPB = EPWM1_MAX_CMPB;
// Set compare A value
// Set Compare B value
// Setup counter mode
EPwm3Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_IN;
EPwm3Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // Count up
EPwm3Regs.TBCTL.bit.PHSDIR = TB_DOWN;
EPwm3Regs.TBCTL.bit.PHSEN = TB_ENABLE;
// Disable phase loading
EPwm3Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;
// Clock ratio to SYSCLKOUT
EPwm3Regs.TBCTL.bit.CLKDIV = TB_DIV1;
// Setup shadowing
EPwm3Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
EPwm3Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
EPwm3Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO_PRD;
// Load on Zero
EPwm3Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO_PRD;
// Set actions
EPwm3Regs.AQCTLA.bit.CAU = AQ_CLEAR;
count
EPwm3Regs.AQCTLA.bit.CAD = AQ_SET;
count
EPwm3Regs.AQCTLB.bit.CBU = AQ_CLEAR;
EPwm3Regs.AQCTLB.bit.CBD = AQ_SET;
count
// Set PWM1A on event A, up
// Clear PWM1A on event A, down
// Set PWM1B on event B, up count
// Clear PWM1B on event B, down
// Interrupt where we will change the Compare Values
EPwm3Regs.ETSEL.bit.INTSEL = ET_CTR_PRD;
// Select INT on Zero event
EPwm3Regs.ETSEL.bit.INTEN = 0;
// Enable INT
EPwm3Regs.ETPS.bit.INTPRD = ET_1ST;
// Generate INT on 3rd event
//////PWM4//////
// Setup TBCLK
EPwm4Regs.TBPRD = EPWM1_TIMER_TBPRD;
// Set timer period 801 TBCLKs
EPwm4Regs.TBPHS.half.TBPHS = EPWM1_TIMER_TBPRD/2; // Phase PI/2
EPwm4Regs.TBCTR = EPWM1_TIMER_TBPRD/2;
// Clear counter
// Set Compare values
EPwm4Regs.CMPA.half.CMPA = EPWM1_MIN_CMPA;
EPwm4Regs.CMPB = EPWM1_MAX_CMPB;
// Set compare A value
// Set Compare B value
// Setup counter mode
EPwm4Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_IN;
EPwm4Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // Count up
EPwm4Regs.TBCTL.bit.PHSDIR = TB_UP;
EPwm4Regs.TBCTL.bit.PHSEN = TB_ENABLE;
// Disable phase loading
EPwm4Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;
// Clock ratio to SYSCLKOUT
EPwm4Regs.TBCTL.bit.CLKDIV = TB_DIV1;
// Setup shadowing
EPwm4Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
EPwm4Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;
EPwm4Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO_PRD;
EPwm4Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO_PRD;
// Set actions
EPwm4Regs.AQCTLA.bit.CAU = AQ_CLEAR;
EPwm4Regs.AQCTLA.bit.CAD = AQ_SET;
// Load on Zero
// Set PWM1A on event A, up count
// Clear PWM1A on event A, down
count
EPwm4Regs.AQCTLB.bit.CBU = AQ_CLEAR;
EPwm4Regs.AQCTLB.bit.CBD = AQ_SET;
count
// Set PWM1B on event B, up count
// Clear PWM1B on event B, down
// Interrupt where we will change the Compare Values
EPwm4Regs.ETSEL.bit.INTSEL = ET_CTR_PRD;
// Select INT on Zero event
EPwm4Regs.ETSEL.bit.INTEN = 0;
// Enable INT
EPwm4Regs.ETPS.bit.INTPRD = ET_1ST;
// Generate INT on 3rd event
EALLOW;
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1;
EDIS;
EPwm1Regs.ETSEL.bit.INTEN = 1;
// Enable INT
// Enable PWM output
EPwm1Regs.TZCLR.bit.OST = 1;
EPwm2Regs.TZCLR.bit.OST = 1;
EPwm3Regs.TZCLR.bit.OST = 1;
EPwm4Regs.TZCLR.bit.OST = 1;
}
void ReInit_PWM(void)
{
EALLOW;
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0;
EDIS;
EPwm1Regs.ETSEL.bit.INTEN = 0;
EPwm1Regs.ETSEL.bit.INTSEL = ET_CTR_PRDZERO;
//////PWM1//////
// Setup TBCLK
EPwm1Regs.TBPRD = EPWM2_TIMER_TBPRD;
EPwm1Regs.TBPHS.half.TBPHS = 0x0000;
//EPwm1Regs.TBCTR = 0x0000;
// Set timer period 801 TBCLKs
// Phase is 0
// Clear counter
//////PWM2//////
// Setup TBCLK
EPwm2Regs.TBPRD = EPWM2_TIMER_TBPRD;
// Set timer period 801 TBCLKs
EPwm2Regs.TBPHS.half.TBPHS = EPWM2_TIMER_TBPRD/2; // Phase PI/2
//EPwm2Regs.TBCTR = 0x0000;
// Clear counter
//////PWM3//////
// Setup TBCLK
EPwm3Regs.TBPRD = EPWM2_TIMER_TBPRD;
// Set timer period 801 TBCLKs
EPwm3Regs.TBPHS.half.TBPHS = EPWM2_TIMER_TBPRD; // Phase PI/2
//EPwm3Regs.TBCTR = 0x0000;
// Clear counter
//////PWM4//////
// Setup TBCLK
EPwm4Regs.TBPRD = EPWM2_TIMER_TBPRD;
// Set timer period 801 TBCLKs
EPwm4Regs.TBPHS.half.TBPHS = EPWM2_TIMER_TBPRD/2; // Phase PI/2
//EPwm4Regs.TBCTR = 0x0000;
// Clear counter
// Enable PWM1 ISR
EPwm1Regs.ETSEL.bit.INTEN = 1;
// Enable INT
EALLOW;
SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1;
EDIS;
}
//===========================================================================
// No more.
//===========================================================================
© Copyright 2026 Paperzz