This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CCS: Problem scoping PWM with frequency 1kHz from LAUNCHXL-F28069M

Tool/software: Code Composer Studio

Dear sirs,

The main I use is below :

//------------------------------------------------------------------------------------
//  FILE:   AsymmetricPWM-Main.c
//          (Up, Single Edge Asymmetric Waveform, With Independent Modulation
//          on EPWM2A and EPWM2B)
//
//  Description:    This program sets up the EV TIMER2 to generate complimentary
//          PWM waveforms. The user can then observe the waveforms using an scope from
//          ePWM2A and ePWM2B pins.
//          - In order to change the PWM frequency, the user should change
//           the value of"period".
//          - The duty-cycles can independently be adjusted by changing compare
//          values (duty_cycle_A & duty_cycle_B) for ePWM2A and ePWM2B.
//          - For further details, please search for the SPRU791.PDF
//          (TMS320x28xx, 28xxx Enhanced Pulse Width Modulator Module) at ti.com
//
//  Target: TMS320F2806x or TMS320F2803x families (F28069)
//
//------------------------------------------------------------------------------------
//  $TI Release:$   V1.0
//  $Release Date:$ 11 Jan 2010 - VSC
//------------------------------------------------------------------------------------
//
// PLEASE READ - Useful notes about this Project

// Although this project is made up of several files, the most important ones are:
//   "AsymmetricPWM .c",    this file
//      - Application Initialization, Peripheral config
//      - Application management
//      - Slower background code loops and Task scheduling
//   "AsymmetricPWM-DevInit_F28xxx.c"
//      - Device Initialization, e.g. Clock, PLL, WD, GPIO mapping
//      - Peripheral clock enables
// The other files are generally used for support and defining the registers as C
// structs. In general these files will not need to be changed.
//   "F2806x_RAM_AsymmetricPWM.CMD" or "F2806x_FLASH_AsymmetricPWM.CMD"
//      - Allocates the program and data spaces into the device's memory map.
//   "F2806x_Headers_nonBIOS.cmd" and "F2806x_GlobalVariableDefs.c"
//      - Allocate the register structs into data memory.  These register structs are
//        defined in the peripheral header includes (F2806x_Adc.h, ...)
//
//----------------------------------------------------------------------------------

#include "PeripheralHeaderIncludes.h"
#include "F2806x_EPwm_defines.h"        // useful defines for initialization
//#include "PWM_1ch_Cnf.c"

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// FUNCTION PROTOTYPES
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

void DeviceInit(void);
void InitFlash(void);
void MemCopy(Uint16 *SourceAddr, Uint16* SourceEndAddr, Uint16* DestAddr);

void PWM_1ch_CNF(int16 n, Uint16 period, int16 mode, int16 phase);


//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// VARIABLE DECLARATIONS - GENERAL
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


volatile struct EPWM_REGS *ePWM[] =
                  { &EPwm1Regs,         //intentional: (ePWM[0] not used)
                    &EPwm1Regs,
                    &EPwm2Regs,
                    &EPwm3Regs,
                    &EPwm4Regs,
                    &EPwm5Regs,
                    &EPwm6Regs,
                    &EPwm7Regs,
                  };


// Used for running BackGround in flash and the ISR in RAM
extern Uint16 RamfuncsLoadStart, RamfuncsLoadEnd, RamfuncsRunStart;


//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// MAIN CODE - starts here
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void main(void)
{

//=================================
//  INITIALISATION - General
//=================================

    DeviceInit();   // Device Life support & GPIO mux settings

// Only used if running from FLASH
// Note that the variable FLASH is defined by the compiler (-d FLASH)

//-------------------------------------------------------------

    for(;;)
        {
    if(GpioDataRegs.GPADAT.bit.GPIO19 == 0)
            {
    PWM_1ch_CNF(1,3600,1,0);
    PWM_1ch_CNF(2,3600,0,1705);
            }
        }
}

PWM_1ch_CNF.c code is below : 

//----------------------------------------------------------------------------------
//	FILE:			PWM_1ch_config.c
//
//	Description:	Single (A output) channel PWM configuration function
//					Configures the PWM channel in UP Count mode. 
//
//  Target:  		TMS320F2803x, 
//
// The function call is:
//
// 		PWMDRV_1ch_config(int16 n, int16 period, int16 mode, int16 phase)
//
// Function arguments defined as:
//-------------------------------
// n = 		Target ePWM module, 1,2,...16.  e.g. if n=2, then target is ePWM2
// period = PWM period in Sysclks
// mode =	Master/Slave mode, e.g. mode=1 for master, mode=0 for slave
// phase =	phase offset from upstream master in Sysclks,
//			applicable only if mode=0, i.e. slave
//--------------------------------------------------------------------------------
#include "PeripheralHeaderIncludes.h"
#include "F2806x_EPWM_defines.h"

extern volatile struct EPWM_REGS *ePWM[];
Uint16 duty_cycle_A=500;	// Set duty initially
Uint16 duty_cycle_B=500;	// Set duty initially

void PWM_1ch_CNF(int16 n, Uint16 period, int16 mode, int16 phase) {
    
	// Time Base SubModule Registers	
	(*ePWM[n]).TBCTL.bit.PRDLD = TB_IMMEDIATE; 	// set Immediate load
	(*ePWM[n]).TBPRD = period - 1; 				// PWM frequency = 1 / period
	(*ePWM[n]).TBPHS.half.TBPHS = 0;
	(*ePWM[n]).TBCTR = 0; //Configure the PWM time-base counter (TBCTR) frequency or period.
	(*ePWM[n]).TBCTL.bit.CTRMODE = TB_COUNT_UP;  //Set the mode for the time-base counter:
	(*ePWM[n]).TBCTL.bit.HSPCLKDIV = TB_DIV1;   // TBCLK = SYSCLK
	(*ePWM[n]).TBCTL.bit.CLKDIV = TB_DIV1;      // Set the clock rate

	if (mode == 1) { // config as a Master
		(*ePWM[n]).TBCTL.bit.PHSEN = TB_DISABLE;  // Phase loading disabled, master module
		(*ePWM[n]).TBCTL.bit.SYNCOSEL = TB_CTR_ZERO; // sync "down-stream"
	}
	if (mode == 0) { // config as a Slave (Note: Phase+2 value used to compensate for logic delay)
		(*ePWM[n]).TBCTL.bit.PHSEN = TB_ENABLE; // Slave module
		(*ePWM[n]).TBCTL.bit.SYNCOSEL = TB_SYNC_IN; // sync flow-through

		if ((0 <= phase) && (phase <= 2))
			(*ePWM[n]).TBPHS.half.TBPHS = (2 - phase); // Set Phase register to "(2 - phase)"
		else if (phase > 2)
			(*ePWM[n]).TBPHS.half.TBPHS = (period - phase + 2); // Set Phase register to "(period - phase + 2)"
	}

	// Counter Compare Submodule Registers
	(*ePWM[n]).CMPA.half.CMPA = duty_cycle_A; // set duty initially
	(*ePWM[n]).CMPB = duty_cycle_B; // set duty initially
	(*ePWM[n]).CMPCTL.bit.SHDWAMODE = CC_SHADOW; // Shadow mode. Operates as a double buffer.
	(*ePWM[n]).CMPCTL.bit.LOADAMODE = CC_CTR_PRD; // load on CTR=PRD

	// Action Qualifier SubModule Registers
	(*ePWM[n]).AQCTLA.bit.ZRO = AQ_TOGGLE; // toggle actions for EPWM1A
	(*ePWM[n]).AQCTLA.bit.CAU = AQ_CLEAR; // clear actions for EPWM1A

	(*ePWM[n]).AQCTLB.bit.ZRO = AQ_NO_ACTION; //no action for EPWM1B
	(*ePWM[n]).AQCTLB.bit.CAU = AQ_NO_ACTION; //no action for EPWM1B
	(*ePWM[n]).AQCTLB.bit.PRD = AQ_NO_ACTION; //no action for EPWM1B
}

I want 2 pwm signals with 1kHz frequency. But my min epwm frequency was 22kHz when period was  3600 => PWM_1ch_CNF(1,3600,1,0);

I have read the pdf document, I know that I need "TBCTL.bit.HSPCLKDIV = 0x4;" and "TBCTL.bit.CLKDIV = 0x4;" kind of codes but when I added those, the signal was gone. 

What is wrong? is that about duty cycles? or period value? because I know that period is a 16-bit value which should be 65535 max.

Thanks for your attention.

  • Hi Troodon,

    When you provide a period of 3600 to the PWM_1ch_CNF function, you should see a period of 25kHz (90M/3600).  You're saying that you are seeing 22kHz.  I'd start by validating this.

    ===

    Your plan of dividing down the ePWM clock largely makes sense. 

    You seem to be re-configuring your ePWMs every time through your for(;;) loop.  You should only need to configure these ePWM registers once.  Configuring these registers over and over might be part of the issue you are seeing.

    I would also recommend setting TBCLKSYNC to 0, running all your ePWM configuration functions, and then finally setting TBCLKSYNC to 1.  This is what is advised in the datasheet.


    Thank you,
    Brett