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.

Sin Look Up Table to ePWM via DMA

Other Parts Discussed in Thread: CONTROLSUITE, TMS320F28335

Hi All,

I am attempting to feed 1000 values from a sin LUT into EPWM2 via DMA. I am finding the wrap/burst/transfer process confusing. My current thinking is that 1 burst, which will be 1 value from the LUT, will be transferred each time TBCTR=0. This will continue on until 1000 values have been copied, at which point the wrap function will reset the source addr back to sin[0] and the process will repeat indefinitely. This is not working, so I must be missing something.

Relevant code:

void EPWM2_Config()
{
        EALLOW;
        SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0;              //Disable TBCLKSYNC
        SysCtrlRegs.MAPCNF.bit.MAPEPWM = 1;      			//Remap ePWMs for DMA access
	EDIS;

	EPwm2Regs.TBPRD = 624;		       					//for 240KHz set to 625
	EPwm2Regs.CMPA.half.CMPA = 600;						//this will change with sine table
	EPwm2Regs.CMPB = 156;								//ADC will sample here, needs testing
	EPwm2Regs.TBCTR =0;

	EPwm2Regs.TBCTL.bit.PRDLD = TB_SHADOW;	        	//use shadow register
	EPwm2Regs.TBPHS.half.TBPHS = 0;

	EPwm2Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP;			//single ramp mode
	EPwm2Regs.TBCTL.bit.PHSEN = TB_DISABLE;				//because this is the master to epwm3
	EPwm2Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_DISABLE;		//timers are software synced when TBCLKSYNC bit is set so this is not used
	EPwm2Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1;			//TBCLK, time base clock, - HSPCLKDIV, high speed peripheral clock
	EPwm2Regs.TBCTL.bit.CLKDIV = TB_DIV1;				//TBCLK=SYSCLKOUT/(HSPCLKDIV x CLKDIV)

	EPwm2Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;			//use shadow register
	EPwm2Regs.CMPCTL.bit.SHDWBMODE = CC_SHADOW;			//use shadow register
	EPwm2Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;		//load new value on CTR=0
	EPwm2Regs.CMPCTL.bit.LOADBMODE = CC_CTR_ZERO;		//load new value on CTR=0

	EPwm2Regs.AQCTLA.bit.ZRO = AQ_SET;                  //output EPwm2A goes high when TBCTR=0;
	EPwm2Regs.AQCTLA.bit.CAU = AQ_CLEAR;				//output EPwm2A goes low when TBCTR=CMPA;
	EPwm2Regs.AQCTLB.bit.ZRO = AQ_CLEAR;				//output EPwm2B goes low when TBCTR=CMPB;
	EPwm2Regs.AQCTLB.bit.CAU = AQ_SET;                  //output EPwm2B goes high when TBCTR=0;

	EPwm2Regs.ETSEL.bit.SOCASEL = 1;					//ADCSOCA on TBCTR=0
	EPwm2Regs.ETPS.bit.SOCAPRD = 1;						//Generate SOCA on 1st event
	EPwm2Regs.ETSEL.bit.SOCAEN = 1;						//Enable SOCA generation
}

void DMACH1Config(void)
{
	EALLOW;

	// Set up MODE Register:
	DmaRegs.CH1.MODE.bit.PERINTSEL = 20;			// ePWM2 SOCA as peripheral interrupt source
	DmaRegs.CH1.MODE.bit.PERINTE = 1;       		// Peripheral interrupt enabled
	DmaRegs.CH1.MODE.bit.ONESHOT = 0;       		// 1 burst per SW interrupt
	DmaRegs.CH1.MODE.bit.CONTINUOUS = 1;    		// Do not stop after each transfer
	DmaRegs.CH1.MODE.bit.SYNCE = 0;         		// No sync signal
	DmaRegs.CH1.MODE.bit.SYNCSEL = 0;       		// No sync signal
	DmaRegs.CH1.MODE.bit.DATASIZE = 0;				// 16-bit data size transfers
	DmaRegs.CH1.MODE.bit.CHINTMODE = 0;				// Generate interrupt to CPU at the beg of transfer
	DmaRegs.CH1.MODE.bit.CHINTE = 0;        		// Channel Interrupt to CPU enabled

	// Set up BURST registers:
	DmaRegs.CH1.BURST_SIZE.all = 0;					// Number (N-1) of 16-bit words transferred in a burst
	DmaRegs.CH1.SRC_BURST_STEP = 0;					// Not needed since BURST_SIZE = 0
	DmaRegs.CH1.DST_BURST_STEP = 0;					// Not needed since BURST_SIZE = 0

	// Set up TRANSFER registers:
	DmaRegs.CH1.TRANSFER_SIZE = 0x03E7;					// Bursts (N-1) per transfer
	DmaRegs.CH1.SRC_TRANSFER_STEP = 1;				// Not needed since TRANSFER_SIZE = 0
	DmaRegs.CH1.DST_TRANSFER_STEP = 0;   			// Not needed since TRANSFER_SIZE = 0

	// Set up WRAP registers:
	DmaRegs.CH1.SRC_WRAP_SIZE = 0x03E7;				// wrap after 1000 bursts (n-1)
	DmaRegs.CH1.DST_WRAP_SIZE = 0;					// No destination wrap-around
	DmaRegs.CH1.SRC_WRAP_STEP = 1;
	DmaRegs.CH1.DST_WRAP_STEP = 0;

	// Set up SOURCE address:
	DmaRegs.CH1.SRC_ADDR_SHADOW = (Uint32) &sin[0];	// Point to variable in RAM
	DmaRegs.CH1.SRC_BEG_ADDR_SHADOW= (Uint32) &sin[0]; 							// Source Begin Address Shadow Register

	// Set up DESTINATION address:
	DmaRegs.CH1.DST_ADDR_SHADOW = (Uint32) &EPwm2Regs.CMPA.half.CMPA;	// Point to ePWM2 CMPA register remapped for DMA
																
	// Clear any spurious flags:
	DmaRegs.CH1.CONTROL.bit.PERINTCLR = 1;  		// Clear any spurious interrupt flags
	DmaRegs.CH1.CONTROL.bit.SYNCCLR = 1;    		// Clear any spurious sync flags
	DmaRegs.CH1.CONTROL.bit.ERRCLR = 1; 			// Clear any spurious sync error flags

	EDIS;
}

Does this look right for what I'm expecting?

Thanks,

Aron

  • Hi Aron,

    Which device are you using?
    There are examples for EPWM-DMA in controlsuite for each device.
    ex: C:\ti\controlSUITE\device_support\f2833x\v140\DSP2833x_examples_ccsv5\epwm_dma

    On a quick look - Your configuration seems to be correct.
    What exactly is the behavior you are observing?

    -Bharathi.

  • Hi Bharathi,

    I am using the TMS320F28335. I get no output from EPWM2 when DMA is enabled. If I disable it I get the expected output from the initialized CMPA register values. I enable the DMA CPU interrupt and put a pin toggle in there and I can observe the interrupt firing repeatedly even though there is no activity from EPWM2.

    Thanks,

    Aron

  • Aron,

    Did you refer to the example in controlsuite, i mentioned above related to this?
    For test purposes - can you just do single trigger to DMA and check if the CMPA register inside EPWM is getting updated?


    -Bharathi.

  • Bharathi,

    Typically the first thing I do is review the examples. They can be very frustrating to get running as the CCS linker system is overly complex and confusing. That said, I did review the epwm to dma example. That example was originally the source for my config, but ultimately it slowed me down. Turns out the problem was DmaRegs.CH1.DST_BEG_ADDR_SHADOW  needed to be defined. This was not shown in the example. My final, working, config:

    void DMACH1Config(void)
    {
    	EALLOW;
    
    	// Set up MODE Register:
    	DmaRegs.PRIORITYCTRL1.bit.CH1PRIORITY=1;		//ch1 highest priority
    	DmaRegs.CH1.MODE.bit.PERINTSEL = 20;			// ePWM2 SOCA as peripheral interrupt source
    	DmaRegs.CH1.MODE.bit.PERINTE = 1;       		// Peripheral interrupt enabled
    	DmaRegs.CH1.MODE.bit.ONESHOT = 0;       		// 1 burst per SW interrupt
    	DmaRegs.CH1.MODE.bit.CONTINUOUS = 1;    		// Do not stop after each transfer
    	DmaRegs.CH1.MODE.bit.SYNCE = 0;         		// No Sync signal
    	DmaRegs.CH1.MODE.bit.SYNCSEL = 0;       		// SRC wrap counter controller
    	DmaRegs.CH1.MODE.bit.DATASIZE = 0;			// 16-bit data size transfers
    	DmaRegs.CH1.MODE.bit.CHINTMODE = 0;			// Generate interrupt to CPU at the beg of transfer
    	DmaRegs.CH1.MODE.bit.CHINTE = 1;        		// Channel Interrupt to CPU enabled
    
    	// Set up BURST registers:                                      //only one var per burst
    	DmaRegs.CH1.BURST_SIZE.all = 0;					// Number (N-1) of 16-bit words transferred in a burst
    	DmaRegs.CH1.SRC_BURST_STEP = 0;					// Not needed since BURST_SIZE = 0
    	DmaRegs.CH1.DST_BURST_STEP = 0;					// Not needed since BURST_SIZE = 0
    
    	// Set up TRANSFER registers:
    	DmaRegs.CH1.TRANSFER_SIZE = 0x03E7;				// Bursts (N-1) per transfer
    	DmaRegs.CH1.SRC_TRANSFER_STEP = 1;				// one var per step
    	DmaRegs.CH1.DST_TRANSFER_STEP = 0;   			        // Not needed since TRANSFER_SIZE = 0
    
    	// Set up WRAP registers:
    	DmaRegs.CH1.SRC_WRAP_SIZE = 0x03E7;				// wrap after 1000 bursts (n-1).......no change
    	DmaRegs.CH1.DST_WRAP_SIZE = 0;					// No destination wrap-around
    	DmaRegs.CH1.SRC_WRAP_STEP = 0;
    	DmaRegs.CH1.DST_WRAP_STEP = 0;
    
    	// Set up SOURCE address:
    	DmaRegs.CH1.SRC_ADDR_SHADOW = (Uint32) &sin[0];	        // Point to variable in RAM
    	DmaRegs.CH1.SRC_BEG_ADDR_SHADOW= (Uint32) &sin[0]; 	// Source Begin Address Shadow Register
    
    	// Set up DESTINATION address:
    	DmaRegs.CH1.DST_ADDR_SHADOW = (Uint32) &EPwm2Regs.CMPA.half.CMPA;	// Point to ePWM2 CMPA register remapped for DMA
    	DmaRegs.CH1.DST_BEG_ADDR_SHADOW = (Uint32) &EPwm2Regs.CMPA.half.CMPA;
    																
    	// Clear any spurious flags:
    	DmaRegs.CH1.CONTROL.bit.PERINTCLR = 1;  		// Clear any spurious interrupt flags
    	DmaRegs.CH1.CONTROL.bit.SYNCCLR = 1;    		// Clear any spurious sync flags
    	DmaRegs.CH1.CONTROL.bit.ERRCLR = 1; 			// Clear any spurious sync error flags
    
    	EDIS;
    }

    Thanks,

    Aron