Other Parts Discussed in Thread: TMDSCNCD280049C, , C2000WARE, SYSCONFIG
Hello all,
I am trying to generate a PWM signal with my C2000 microcontroller. However, when I use the HRPWM, I see that the output jitters. For configuration I used .syscfg in CCS and I do not understand what I am doing wrong.
I am using the TMS320F280049C which is integrated into a control card (TMDSCNCD280049C). I am using Code Composer Studio version 12.1.0.00007 for programming.
I want to implement a PWM frequency up to 10 MHz with a constant duty cycle of 50% and a configurable dead time. The frequency needs to be set with high resolution. I get jitter when I enable HRPWM period control (in .syscfg or with the driverlib function HRPWM_enablePeriodControl(PWM_base)).
I am aware that jitter can occur when there is a sync event or when the time base period is changed, but in my case there is neither. (At least I think I have disabled all sync events).
Please find below a minimal example where I tried to realize a HRPWM with 2.10 MHz. I used the up-down-count mode and set the output pins when the counter equals CMPA. To generate an accurate PWM signal, enabled High Resolution for CMPA (MEP controls both rising and falling edges) as well as High Resolution Period with automatic HRMSTEP scaling. I took a screenshot with my oscilloscope showing the jitter.
Measuring the time deviation of the jitter gives a delta t of 10 ns, which is exactly the clock of the C2000 used. So it seems to me that the HRPWM is not working at all.
Additionally I noticed that the jitter only occurs, when the HR period control is enabled - independent of the CMPAHR.
Many thanks!
### Code: ###
main.c:
// main.c
#include "board.h"
void main(void)
{
// Device Initialization
Device_init();
Board_init();
while(1)
{
}
}
autogenerated board.h:
/* * Copyright (c) 2020 Texas Instruments Incorporated - http://www.ti.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #ifndef BOARD_H #define BOARD_H // // Included Files // #include "driverlib.h" #include "device.h" #define GPIO_PIN_EPWM1_A 0 #define GPIO_PIN_EPWM1_B 1 #define PWM_BASE EPWM1_BASE void Board_init(); void EPWM_init(); void SYNC_init(); void PinMux_init(); #endif // end of BOARD_H definition
autogenerated board.c:
/*
* Copyright (c) 2020 Texas Instruments Incorporated - http://www.ti.com
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "board.h"
void Board_init()
{
EALLOW;
PinMux_init();
SYNC_init();
EPWM_init();
EDIS;
}
void PinMux_init()
{
//
// EPWM1 -> PWM Pinmux
//
GPIO_setPinConfig(GPIO_0_EPWM1_A);
GPIO_setPinConfig(GPIO_1_EPWM1_B);
}
void EPWM_init(){
HRPWM_setEmulationMode(PWM_BASE, EPWM_EMULATION_FREE_RUN);
HRPWM_setClockPrescaler(PWM_BASE, EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1);
EPWM_setTimeBasePeriod(PWM_BASE, 23);
HRPWM_setTimeBaseCounter(PWM_BASE, 0);
HRPWM_setTimeBaseCounterMode(PWM_BASE, EPWM_COUNTER_MODE_UP_DOWN);
HRPWM_disablePhaseShiftLoad(PWM_BASE);
HRPWM_setPhaseShift(PWM_BASE, 0);
HRPWM_setSyncOutPulseMode(PWM_BASE, EPWM_SYNC_OUT_PULSE_DISABLED);
EPWM_setCounterCompareValue(PWM_BASE, EPWM_COUNTER_COMPARE_A, 11);
HRPWM_setCounterCompareShadowLoadMode(PWM_BASE, EPWM_COUNTER_COMPARE_A, EPWM_COMP_LOAD_ON_CNTR_ZERO_PERIOD);
EPWM_setCounterCompareValue(PWM_BASE, EPWM_COUNTER_COMPARE_B, 0);
HRPWM_setCounterCompareShadowLoadMode(PWM_BASE, EPWM_COUNTER_COMPARE_B, EPWM_COMP_LOAD_ON_CNTR_ZERO);
HRPWM_setActionQualifierAction(PWM_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
HRPWM_setActionQualifierAction(PWM_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD);
HRPWM_setActionQualifierAction(PWM_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
HRPWM_setActionQualifierAction(PWM_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);
HRPWM_setActionQualifierAction(PWM_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB);
HRPWM_setActionQualifierAction(PWM_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPB);
HRPWM_setActionQualifierAction(PWM_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
HRPWM_setActionQualifierAction(PWM_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD);
HRPWM_setActionQualifierAction(PWM_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
HRPWM_setActionQualifierAction(PWM_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);
HRPWM_setActionQualifierAction(PWM_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB);
HRPWM_setActionQualifierAction(PWM_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPB);
HRPWM_setDeadBandDelayPolarity(PWM_BASE, EPWM_DB_FED, EPWM_DB_POLARITY_ACTIVE_LOW);
HRPWM_setDeadBandDelayMode(PWM_BASE, EPWM_DB_RED, true);
HRPWM_setRisingEdgeDelayCount(PWM_BASE, 10);
HRPWM_setDeadBandDelayMode(PWM_BASE, EPWM_DB_FED, true);
HRPWM_setFallingEdgeDelayCount(PWM_BASE, 10);
HRPWM_setDeadBandCounterClock(PWM_BASE, EPWM_DB_COUNTER_CLOCK_HALF_CYCLE);
HRPWM_enableAutoConversion(PWM_BASE);
HRPWM_setMEPEdgeSelect(PWM_BASE, HRPWM_CHANNEL_A, HRPWM_MEP_CTRL_RISING_AND_FALLING_EDGE);
HRPWM_setHiResCounterCompareValueOnly(PWM_BASE, HRPWM_COUNTER_COMPARE_A, 230);
HRPWM_setCounterCompareShadowLoadEvent(PWM_BASE, HRPWM_CHANNEL_A, HRPWM_LOAD_ON_CNTR_ZERO_PERIOD);
HRPWM_enablePeriodControl(PWM_BASE);
HRPWM_setHiResTimeBasePeriodOnly(PWM_BASE, 205);
}
void SYNC_init(){
SysCtl_setSyncOutputConfig(SYSCTL_SYNC_OUT_SRC_EPWM1SYNCOUT);
// For EPWM1, the sync input is: SYSCTL_SYNC_IN_SRC_EXTSYNCIN1
SysCtl_setSyncInputConfig(SYSCTL_SYNC_IN_EPWM4, SYSCTL_SYNC_IN_SRC_EPWM1SYNCOUT);
SysCtl_setSyncInputConfig(SYSCTL_SYNC_IN_EPWM7, SYSCTL_SYNC_IN_SRC_EPWM1SYNCOUT);
SysCtl_setSyncInputConfig(SYSCTL_SYNC_IN_ECAP1, SYSCTL_SYNC_IN_SRC_EPWM1SYNCOUT);
SysCtl_setSyncInputConfig(SYSCTL_SYNC_IN_ECAP4, SYSCTL_SYNC_IN_SRC_EPWM1SYNCOUT);
SysCtl_setSyncInputConfig(SYSCTL_SYNC_IN_ECAP6, SYSCTL_SYNC_IN_SRC_EPWM1SYNCOUT);
// SOCA
SysCtl_enableExtADCSOCSource(0);
// SOCB
SysCtl_enableExtADCSOCSource(0);
}
Syscfg-File:
/**
* These arguments were used when this file was generated. They will be automatically applied on subsequent loads
* via the GUI or CLI. Run CLI with '--help' for additional information on how to override these arguments.
* @cliArgs --device "F28004x" --package "F28004x_100PZ" --part "F28004x_100PZ" --product "C2000WARE@4.01.00.00"
* @versions {"tool":"1.14.0+2667"}
*/
/**
* Import the modules used in this configuration.
*/
const epwm = scripting.addModule("/driverlib/epwm.js");
const epwm1 = epwm.addInstance();
const sync = scripting.addModule("/driverlib/sync.js");
/**
* Write custom configuration values to the imported modules.
*/
epwm1.epwmTimebase_hsClockDiv = "EPWM_HSCLOCK_DIVIDER_1";
epwm1.epwmTimebase_counterMode = "EPWM_COUNTER_MODE_UP_DOWN";
epwm1.epwmTimebase_syncOutPulseMode = "EPWM_SYNC_OUT_PULSE_DISABLED";
epwm1.epwmActionQualifier_EPWM_AQ_OUTPUT_A_shadowMode = true;
epwm1.epwmDeadband_polarityFED = "EPWM_DB_POLARITY_ACTIVE_LOW";
epwm1.epwmDeadband_controlShadowMode = true;
epwm1.epwmDeadband_deadbandCounterClockRate = "EPWM_DB_COUNTER_CLOCK_HALF_CYCLE";
epwm1.epwmActionQualifier_EPWM_AQ_OUTPUT_A_ON_TIMEBASE_UP_CMPA = "EPWM_AQ_OUTPUT_HIGH";
epwm1.epwmActionQualifier_EPWM_AQ_OUTPUT_A_ON_TIMEBASE_DOWN_CMPA = "EPWM_AQ_OUTPUT_LOW";
epwm1.hrpwm_HRLoadA = "HRPWM_LOAD_ON_CNTR_ZERO_PERIOD";
epwm1.epwmCounterCompare_shadowLoadModeCMPA = "EPWM_COMP_LOAD_ON_CNTR_ZERO_PERIOD";
epwm1.epwmTimebase_emulationMode = "EPWM_EMULATION_FREE_RUN";
epwm1.epwmDeadband_enableRED = true;
epwm1.$name = "PWM";
epwm1.epwmDeadband_enableFED = true;
epwm1.epwmDeadband_delayRED = 10;
epwm1.epwmDeadband_delayFED = 10;
epwm1.hrpwm_enable = true;
epwm1.hrpwm_autoConv = true;
epwm1.useInterfacePins = ["EPWM#_A","EPWM#_B"];
epwm1.hrpwm_edgeModeA = "HRPWM_MEP_CTRL_RISING_AND_FALLING_EDGE";
epwm1.hrpwm_periodEnable = true;
epwm1.epwmTimebase_period = 23;
epwm1.hrpwm_tbprdHR = 205;
epwm1.epwmCounterCompare_cmpA = 11;
epwm1.hrpwm_cmpaHR = 230;
epwm1.epwm.$assign = "EPWM1";
/**
* Pinmux solution for unlocked pins/peripherals. This ensures that minor changes to the automatic solver in a future
* version of the tool will not impact the pinmux you originally saw. These lines can be completely deleted in order to
* re-solve from scratch.
*/
epwm1.epwm.epwm_aPin.$suggestSolution = "GPIO0";
epwm1.epwm.epwm_bPin.$suggestSolution = "GPIO1";

