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.

TMS320F280039C: Synchronizing ADC readings using DMA with PWM outputs

Part Number: TMS320F280039C

Hi Experts:

                 I am successfully reading 2 ADC channels in a continuous way using DMA with 2 alternate buffers at a sample rate of 960Ks/s. Also, I have 4 PWMs channels running at 48Khz that will drive two bridges

So, I have 20 samples of the ADC channels per PWM cycle. The thing is that I need to synchronize the DMA transfers to the buffers of 20 samples with one of the PWMs channels. The ADC channels are triggered by another EPWM channel. The EPWM channels for the PWMs are in UP mode. To sum up, I need that the first sample of each buffer is taken at the start of the PWM cycle

                Unfortunately, I didn't find how to configure the DMA, the ADC, and the PWM in order to have all of them synchronized. I have tried using the Syncro signals of the PWM modules and the way I start these modules, but It didn't work.

Regards,

Fernando

  • Hi Fernando,

    Have you tried looking at triggering the DMA transfer through DMASRCSELx register?  You can select the particular PWM channel to trigger DMA transfer of the ADC sample results.  DMASRCSELx can be configured to accept triggers from different peripherals.  Refer to table 12-1 in the Technical Reference Manual.  You can use the EPWM SOCx signals as DMA trigger sources.

    Regards,

    Joseph

  • Hi Joseph:

                    Thanks for the help.

    I have reviewed the DMA documentation.

    The only way I see to get synchronized the DMA transfer with the PWM cycle of 48Khz is to configure the DMA in DMA_CFG_CONTINUOUS_DISABLE, so having all the PWMs channels ( the one I use to trigger the SOCA and the one for the PWM) in Syncro, I enable the interruption of the main PWM when reaches zero, and inside the INT, I must enable the transfer of the DMA.

    The drawback of this method is that as the transfer is enabled by software, I must be sure that the PWM interruption is attended before the ADCs ended the conversion, if not I will lose a sample. Probably there could be another way but I can't find it.

                              Regards,

                             Fernando

                           

  • Hi Fernando,

    Any way you can share snippet of your ADC channel, INT, SOC as well as PWM and DMA setup?  Probably better to look at the code and see if we can come up with suggestions.

    Thanks and regards,

    Joseph

  • Hi Joseph.

                     Of course, I can share with you all the snippets

    Here is the code generated for the ADC by Syscfg

    void ADC_init(){
    	//ADC_Voltages initialization
    
    	// ADC Initialization: Write ADC configurations and power up the ADC
    	// Configures the ADC module's offset trim
    	ADC_setOffsetTrimAll(ADC_REFERENCE_INTERNAL,ADC_REFERENCE_3_3V);
    	// Configures the analog-to-digital converter module prescaler.
    	ADC_setPrescaler(ADC_Voltages_BASE, ADC_CLK_DIV_1_0);
    	// Sets the timing of the end-of-conversion pulse
    	ADC_setInterruptPulseMode(ADC_Voltages_BASE, ADC_PULSE_END_OF_CONV);
    	// Powers up the analog-to-digital converter core.
    	ADC_enableConverter(ADC_Voltages_BASE);
    	// Delay for 1ms to allow ADC time to power up
    	DEVICE_DELAY_US(5000);
    
    	// SOC Configuration: Setup ADC EPWM channel and trigger settings
    	// Disables SOC burst mode.
    	ADC_disableBurstMode(ADC_Voltages_BASE);
    	// Sets the priority mode of the SOCs.
    	ADC_setSOCPriority(ADC_Voltages_BASE, ADC_PRI_ALL_ROUND_ROBIN);
    	// Start of Conversion 0 Configuration
    	// Configures a start-of-conversion (SOC) in the ADC and its interrupt SOC trigger.
    	// 	  	SOC number		: 0
    	//	  	Trigger			: ADC_TRIGGER_EPWM5_SOCA
    	//	  	Channel			: ADC_CH_ADCIN0
    	//	 	Sample Window	: 20 SYSCLK cycles
    	//		Interrupt Trigger: ADC_INT_SOC_TRIGGER_NONE
    	ADC_setupSOC(ADC_Voltages_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM5_SOCA, ADC_CH_ADCIN0, 20U);
    	ADC_setInterruptSOCTrigger(ADC_Voltages_BASE, ADC_SOC_NUMBER0, ADC_INT_SOC_TRIGGER_NONE);
    	// Start of Conversion 1 Configuration
    	// Configures a start-of-conversion (SOC) in the ADC and its interrupt SOC trigger.
    	// 	  	SOC number		: 1
    	//	  	Trigger			: ADC_TRIGGER_EPWM5_SOCA
    	//	  	Channel			: ADC_CH_ADCIN1
    	//	 	Sample Window	: 20 SYSCLK cycles
    	//		Interrupt Trigger: ADC_INT_SOC_TRIGGER_NONE
    	ADC_setupSOC(ADC_Voltages_BASE, ADC_SOC_NUMBER1, ADC_TRIGGER_EPWM5_SOCA, ADC_CH_ADCIN1, 20U);
    	ADC_setInterruptSOCTrigger(ADC_Voltages_BASE, ADC_SOC_NUMBER1, ADC_INT_SOC_TRIGGER_NONE);
    	// ADC Interrupt 1 Configuration
    	// 		SOC/EOC number	: 1
    	// 		Interrupt Source: enabled
    	//		Continuous Mode	: enabled
    	ADC_setInterruptSource(ADC_Voltages_BASE, ADC_INT_NUMBER1, ADC_SOC_NUMBER1);
    	ADC_enableInterrupt(ADC_Voltages_BASE, ADC_INT_NUMBER1);
    	ADC_clearInterruptStatus(ADC_Voltages_BASE, ADC_INT_NUMBER1);
    	ADC_enableContinuousMode(ADC_Voltages_BASE, ADC_INT_NUMBER1);
    
    	//ADC_Currents initialization
    
    	// ADC Initialization: Write ADC configurations and power up the ADC
    	// Configures the ADC module's offset trim
    	ADC_setOffsetTrimAll(ADC_REFERENCE_INTERNAL,ADC_REFERENCE_3_3V);
    	// Configures the analog-to-digital converter module prescaler.
    	ADC_setPrescaler(ADC_Currents_BASE, ADC_CLK_DIV_1_0);
    	// Sets the timing of the end-of-conversion pulse
    	ADC_setInterruptPulseMode(ADC_Currents_BASE, ADC_PULSE_END_OF_ACQ_WIN);
    	// Sets the timing of early interrupt generation.
    	ADC_setInterruptCycleOffset(ADC_Currents_BASE, 0U);
    	// Powers up the analog-to-digital converter core.
    	ADC_enableConverter(ADC_Currents_BASE);
    	// Delay for 1ms to allow ADC time to power up
    	DEVICE_DELAY_US(5000);
    
    	// SOC Configuration: Setup ADC EPWM channel and trigger settings
    	// Disables SOC burst mode.
    	ADC_disableBurstMode(ADC_Currents_BASE);
    	// Sets the priority mode of the SOCs.
    	ADC_setSOCPriority(ADC_Currents_BASE, ADC_PRI_ALL_ROUND_ROBIN);
    	// Start of Conversion 0 Configuration
    	// Configures a start-of-conversion (SOC) in the ADC and its interrupt SOC trigger.
    	// 	  	SOC number		: 0
    	//	  	Trigger			: ADC_TRIGGER_EPWM5_SOCA
    	//	  	Channel			: ADC_CH_ADCIN0
    	//	 	Sample Window	: 20 SYSCLK cycles
    	//		Interrupt Trigger: ADC_INT_SOC_TRIGGER_NONE
    	ADC_setupSOC(ADC_Currents_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM5_SOCA, ADC_CH_ADCIN0, 20U);
    	ADC_setInterruptSOCTrigger(ADC_Currents_BASE, ADC_SOC_NUMBER0, ADC_INT_SOC_TRIGGER_NONE);
    	// Start of Conversion 1 Configuration
    	// Configures a start-of-conversion (SOC) in the ADC and its interrupt SOC trigger.
    	// 	  	SOC number		: 1
    	//	  	Trigger			: ADC_TRIGGER_EPWM5_SOCA
    	//	  	Channel			: ADC_CH_ADCIN1
    	//	 	Sample Window	: 20 SYSCLK cycles
    	//		Interrupt Trigger: ADC_INT_SOC_TRIGGER_NONE
    	ADC_setupSOC(ADC_Currents_BASE, ADC_SOC_NUMBER1, ADC_TRIGGER_EPWM5_SOCA, ADC_CH_ADCIN1, 20U);
    	ADC_setInterruptSOCTrigger(ADC_Currents_BASE, ADC_SOC_NUMBER1, ADC_INT_SOC_TRIGGER_NONE);
    	// ADC Interrupt 1 Configuration
    	// 		SOC/EOC number	: 1
    	// 		Interrupt Source: enabled
    	//		Continuous Mode	: enabled
    	ADC_setInterruptSource(ADC_Currents_BASE, ADC_INT_NUMBER1, ADC_SOC_NUMBER1);
    	ADC_enableInterrupt(ADC_Currents_BASE, ADC_INT_NUMBER1);
    	ADC_clearInterruptStatus(ADC_Currents_BASE, ADC_INT_NUMBER1);
    	ADC_enableContinuousMode(ADC_Currents_BASE, ADC_INT_NUMBER1);
    			
    	// PPB Configuration: Configure high and low limits detection for ADCPPB
    	// Post Processing Block 1 Configuration
    	// 		Configures a post-processing block (PPB) in the ADC.
    	// 		PPB Number				: 1
    	// 		SOC/EOC number			: 0
    	// 		Calibration Offset		: 0
    	// 		Reference Offset		: 2048
    	// 		Two's Complement		: Disabled
    	// 		Trip High Limit			: 0
    	// 		Trip Low Limit			: 0
    	// 		Clear PPB Event Flags	: Disabled
    	ADC_setupPPB(ADC_Currents_BASE, ADC_PPB_NUMBER1, ADC_SOC_NUMBER0);
    	ADC_disablePPBEvent(ADC_Currents_BASE, ADC_PPB_NUMBER1, (ADC_EVT_TRIPHI | ADC_EVT_TRIPLO | ADC_EVT_ZERO));
    	ADC_disablePPBEventInterrupt(ADC_Currents_BASE, ADC_PPB_NUMBER1, (ADC_EVT_TRIPHI | ADC_EVT_TRIPLO | ADC_EVT_ZERO));
    	ADC_setPPBCalibrationOffset(ADC_Currents_BASE, ADC_PPB_NUMBER1, 0);
    	ADC_setPPBReferenceOffset(ADC_Currents_BASE, ADC_PPB_NUMBER1, 2048);
    	ADC_disablePPBTwosComplement(ADC_Currents_BASE, ADC_PPB_NUMBER1);
    	ADC_setPPBTripLimits(ADC_Currents_BASE, ADC_PPB_NUMBER1, 0, 0);
    	ADC_disablePPBEventCBCClear(ADC_Currents_BASE, ADC_PPB_NUMBER1);
    	// Post Processing Block 2 Configuration
    	// 		Configures a post-processing block (PPB) in the ADC.
    	// 		PPB Number				: 2
    	// 		SOC/EOC number			: 1
    	// 		Calibration Offset		: 0
    	// 		Reference Offset		: 2048
    	// 		Two's Complement		: Disabled
    	// 		Trip High Limit			: 0
    	// 		Trip Low Limit			: 0
    	// 		Clear PPB Event Flags	: Disabled
    	ADC_setupPPB(ADC_Currents_BASE, ADC_PPB_NUMBER2, ADC_SOC_NUMBER1);
    	ADC_disablePPBEvent(ADC_Currents_BASE, ADC_PPB_NUMBER2, (ADC_EVT_TRIPHI | ADC_EVT_TRIPLO | ADC_EVT_ZERO));
    	ADC_disablePPBEventInterrupt(ADC_Currents_BASE, ADC_PPB_NUMBER2, (ADC_EVT_TRIPHI | ADC_EVT_TRIPLO | ADC_EVT_ZERO));
    	ADC_setPPBCalibrationOffset(ADC_Currents_BASE, ADC_PPB_NUMBER2, 0);
    	ADC_setPPBReferenceOffset(ADC_Currents_BASE, ADC_PPB_NUMBER2, 2048);
    	ADC_disablePPBTwosComplement(ADC_Currents_BASE, ADC_PPB_NUMBER2);
    	ADC_setPPBTripLimits(ADC_Currents_BASE, ADC_PPB_NUMBER2, 0, 0);
    	ADC_disablePPBEventCBCClear(ADC_Currents_BASE, ADC_PPB_NUMBER2);
    
    	//ADC_Low_Speed initialization
    
    	// ADC Initialization: Write ADC configurations and power up the ADC
    	// Configures the ADC module's offset trim
    	ADC_setOffsetTrimAll(ADC_REFERENCE_INTERNAL,ADC_REFERENCE_3_3V);
    	// Configures the analog-to-digital converter module prescaler.
    	ADC_setPrescaler(ADC_Low_Speed_BASE, ADC_CLK_DIV_1_0);
    	// Sets the timing of the end-of-conversion pulse
    	ADC_setInterruptPulseMode(ADC_Low_Speed_BASE, ADC_PULSE_END_OF_CONV);
    	// Powers up the analog-to-digital converter core.
    	ADC_enableConverter(ADC_Low_Speed_BASE);
    	// Delay for 1ms to allow ADC time to power up
    	DEVICE_DELAY_US(5000);
    
    	// SOC Configuration: Setup ADC EPWM channel and trigger settings
    	// Disables SOC burst mode.
    	ADC_disableBurstMode(ADC_Low_Speed_BASE);
    	// Sets the priority mode of the SOCs.
    	ADC_setSOCPriority(ADC_Low_Speed_BASE, ADC_PRI_ALL_ROUND_ROBIN);
    	// Start of Conversion 0 Configuration
    	// Configures a start-of-conversion (SOC) in the ADC and its interrupt SOC trigger.
    	// 	  	SOC number		: 0
    	//	  	Trigger			: ADC_TRIGGER_SW_ONLY
    	//	  	Channel			: ADC_CH_ADCIN0
    	//	 	Sample Window	: 20 SYSCLK cycles
    	//		Interrupt Trigger: ADC_INT_SOC_TRIGGER_NONE
    	ADC_setupSOC(ADC_Low_Speed_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_SW_ONLY, ADC_CH_ADCIN0, 20U);
    	ADC_setInterruptSOCTrigger(ADC_Low_Speed_BASE, ADC_SOC_NUMBER0, ADC_INT_SOC_TRIGGER_NONE);
    	// Start of Conversion 1 Configuration
    	// Configures a start-of-conversion (SOC) in the ADC and its interrupt SOC trigger.
    	// 	  	SOC number		: 1
    	//	  	Trigger			: ADC_TRIGGER_SW_ONLY
    	//	  	Channel			: ADC_CH_ADCIN1
    	//	 	Sample Window	: 20 SYSCLK cycles
    	//		Interrupt Trigger: ADC_INT_SOC_TRIGGER_NONE
    	ADC_setupSOC(ADC_Low_Speed_BASE, ADC_SOC_NUMBER1, ADC_TRIGGER_SW_ONLY, ADC_CH_ADCIN1, 20U);
    	ADC_setInterruptSOCTrigger(ADC_Low_Speed_BASE, ADC_SOC_NUMBER1, ADC_INT_SOC_TRIGGER_NONE);
    	// Start of Conversion 2 Configuration
    	// Configures a start-of-conversion (SOC) in the ADC and its interrupt SOC trigger.
    	// 	  	SOC number		: 2
    	//	  	Trigger			: ADC_TRIGGER_SW_ONLY
    	//	  	Channel			: ADC_CH_ADCIN2
    	//	 	Sample Window	: 20 SYSCLK cycles
    	//		Interrupt Trigger: ADC_INT_SOC_TRIGGER_NONE
    	ADC_setupSOC(ADC_Low_Speed_BASE, ADC_SOC_NUMBER2, ADC_TRIGGER_SW_ONLY, ADC_CH_ADCIN2, 20U);
    	ADC_setInterruptSOCTrigger(ADC_Low_Speed_BASE, ADC_SOC_NUMBER2, ADC_INT_SOC_TRIGGER_NONE);
    	// Start of Conversion 3 Configuration
    	// Configures a start-of-conversion (SOC) in the ADC and its interrupt SOC trigger.
    	// 	  	SOC number		: 3
    	//	  	Trigger			: ADC_TRIGGER_SW_ONLY
    	//	  	Channel			: ADC_CH_ADCIN3
    	//	 	Sample Window	: 20 SYSCLK cycles
    	//		Interrupt Trigger: ADC_INT_SOC_TRIGGER_NONE
    	ADC_setupSOC(ADC_Low_Speed_BASE, ADC_SOC_NUMBER3, ADC_TRIGGER_SW_ONLY, ADC_CH_ADCIN3, 20U);
    	ADC_setInterruptSOCTrigger(ADC_Low_Speed_BASE, ADC_SOC_NUMBER3, ADC_INT_SOC_TRIGGER_NONE);
    	// Start of Conversion 4 Configuration
    	// Configures a start-of-conversion (SOC) in the ADC and its interrupt SOC trigger.
    	// 	  	SOC number		: 4
    	//	  	Trigger			: ADC_TRIGGER_SW_ONLY
    	//	  	Channel			: ADC_CH_ADCIN4
    	//	 	Sample Window	: 20 SYSCLK cycles
    	//		Interrupt Trigger: ADC_INT_SOC_TRIGGER_NONE
    	ADC_setupSOC(ADC_Low_Speed_BASE, ADC_SOC_NUMBER4, ADC_TRIGGER_SW_ONLY, ADC_CH_ADCIN4, 20U);
    	ADC_setInterruptSOCTrigger(ADC_Low_Speed_BASE, ADC_SOC_NUMBER4, ADC_INT_SOC_TRIGGER_NONE);
    	// Start of Conversion 5 Configuration
    	// Configures a start-of-conversion (SOC) in the ADC and its interrupt SOC trigger.
    	// 	  	SOC number		: 5
    	//	  	Trigger			: ADC_TRIGGER_SW_ONLY
    	//	  	Channel			: ADC_CH_ADCIN5
    	//	 	Sample Window	: 20 SYSCLK cycles
    	//		Interrupt Trigger: ADC_INT_SOC_TRIGGER_NONE
    	ADC_setupSOC(ADC_Low_Speed_BASE, ADC_SOC_NUMBER5, ADC_TRIGGER_SW_ONLY, ADC_CH_ADCIN5, 20U);
    	ADC_setInterruptSOCTrigger(ADC_Low_Speed_BASE, ADC_SOC_NUMBER5, ADC_INT_SOC_TRIGGER_NONE);
    	// Start of Conversion 6 Configuration
    	// Configures a start-of-conversion (SOC) in the ADC and its interrupt SOC trigger.
    	// 	  	SOC number		: 6
    	//	  	Trigger			: ADC_TRIGGER_SW_ONLY
    	//	  	Channel			: ADC_CH_ADCIN6
    	//	 	Sample Window	: 20 SYSCLK cycles
    	//		Interrupt Trigger: ADC_INT_SOC_TRIGGER_NONE
    	ADC_setupSOC(ADC_Low_Speed_BASE, ADC_SOC_NUMBER6, ADC_TRIGGER_SW_ONLY, ADC_CH_ADCIN6, 20U);
    	ADC_setInterruptSOCTrigger(ADC_Low_Speed_BASE, ADC_SOC_NUMBER6, ADC_INT_SOC_TRIGGER_NONE);
    	// Start of Conversion 7 Configuration
    	// Configures a start-of-conversion (SOC) in the ADC and its interrupt SOC trigger.
    	// 	  	SOC number		: 7
    	//	  	Trigger			: ADC_TRIGGER_SW_ONLY
    	//	  	Channel			: ADC_CH_ADCIN7
    	//	 	Sample Window	: 20 SYSCLK cycles
    	//		Interrupt Trigger: ADC_INT_SOC_TRIGGER_NONE
    	ADC_setupSOC(ADC_Low_Speed_BASE, ADC_SOC_NUMBER7, ADC_TRIGGER_SW_ONLY, ADC_CH_ADCIN7, 20U);
    	ADC_setInterruptSOCTrigger(ADC_Low_Speed_BASE, ADC_SOC_NUMBER7, ADC_INT_SOC_TRIGGER_NONE);
    	// ADC Interrupt 1 Configuration
    	// 		SOC/EOC number	: 7
    	// 		Interrupt Source: enabled
    	//		Continuous Mode	: enabled
    	ADC_setInterruptSource(ADC_Low_Speed_BASE, ADC_INT_NUMBER1, ADC_SOC_NUMBER7);
    	ADC_enableInterrupt(ADC_Low_Speed_BASE, ADC_INT_NUMBER1);
    	ADC_clearInterruptStatus(ADC_Low_Speed_BASE, ADC_INT_NUMBER1);
    	ADC_enableContinuousMode(ADC_Low_Speed_BASE, ADC_INT_NUMBER1);
    
    }

    Here is the code of the DMA manager

    // Dual Buffers for reading the ADCs
    
    #pragma DATA_SECTION(Dual_Adc_Buffer, "ramgs0");
    high_speed_buffers_t  Dual_Adc_Buffer[H_BUFFERS_QTY];
    
    #pragma DATA_SECTION(Low_Speed_Channels, "CpuToCla1MsgRAM");
    uint16_t Low_Speed_Channels[QTY_LOW_SPEED_ADC];
    
    
    // Buffers for a copy of the readings to be processed by the CLA.
    // As there is no room in this memory for having the Dual Buffers
    // In this buffer goes a copy of the last readings. When the DMA,
    // finishes the copy, it will trigger the CLA
    
    #pragma DATA_SECTION(Dma_Cla_Buffer, "Dma_To_Cla");
    high_speed_buffers_t  Dma_Cla_Buffer;
    
    
    
    
    /******************************************************************************/
    /* Local Functions                                                            */
    /******************************************************************************/
    
    // This DMA ISR channel is triggered at the start of the transfer.
    // As the DMA has shadow registers, it will complete the transfer
    // and after it ends, will load the new values in the active registers
    // In this ISR, we change the destination buffer of the DMA for ADC_A and ADC_B
    // The PWM runs at 48Khz and we sample at 960Ks/s, we have 20 samples per cycle
    // After 20 sample we will trigger the CLA that will calculate the DC current
    // with 4 sampled cycles. The Control Loop runs at 12Khz from the CLA
    
    __interrupt void DMA_CH2_ISR(void)
    {
    
        if( here.DMA_CH1_CH2_buff_dest == BUFFER_0 )
        {
            // Remember that we are at the beginning of the new transfer and with
            // shadow registers. When is updating this registers, the CH1 & CH2 is
            // Writing on the buffers 0
    
            here.DMA_CH1_CH2_buff_dest = BUFFER_1;
        }
        else
        {
            // Remember that we are at the beginning of the new transfer and with
            // shadow registers. When is updating this registers, the CH1 & CH2 is
            // writing on the buffers 1
    
            here.DMA_CH1_CH2_buff_dest = BUFFER_0;
        }
    
        // Triggers the copy to the CLA, changing the source to the newer buffer
        // As the current buffer with the new data is the same that it will be loaded
        // the nex time that the active registers are loaded from the shadows, I can
        // use the same variable
        DMA_configSourceAddress(DMA_CH3_BASE, &Dual_Adc_Buffer[here.DMA_CH1_CH2_buff_dest]);
        DMA_forceTrigger(DMA_CH3_BASE);
    
        // Change the destination of the buffers for the next time that the shadow registers
        // are loaded
        DMA_configDestAddress(DMA_CH1_BASE, (uint16_t *)&Dual_Adc_Buffer[here.DMA_CH1_CH2_buff_dest].ADC_VOLTAGES);
        DMA_configDestAddress(DMA_CH2_BASE,  (int16_t *)&Dual_Adc_Buffer[here.DMA_CH1_CH2_buff_dest].ADC_CURRENTS);
    
        // When the ISR of DMA of the second channel is triggered, is because
        // both channels of both converters have finished ( We are using 20
        // cycles of window sampling and it takes 11 more cycles of processing
        // total 31 cycles each channel. Total 62 cycles). We are sampling at 960Ksamples
        // at 120Mhz, that is 125 CPU cycles, thus we have a window of 63 samples
        // to sample the low speed channels. Forcing a sample by software
        // here ( this ISR enters at 960.000KHz/20samples of the buffer = 48Khz ) of one of the 8 low speed channels
        // each time, we have 48000/8channels = 6000 samples/second
    
        ADC_forceSOC(ADC_Low_Speed_BASE, here.current_low_speed_socNumber);
    
        // Change to the next SOC
        here.current_low_speed_socNumber++;
    
        // Load the results into the Msg Ram To the Cla
        if( here.current_low_speed_socNumber >= ADC_C_SOCS_QTY )
        {
            Low_Speed_Channels[NTC_XFMR]    = ADC_readResult(ADCCRESULT_BASE, ADC_SOC_NUMBER0);
            Low_Speed_Channels[NTC_A]       = ADC_readResult(ADCCRESULT_BASE, ADC_SOC_NUMBER1);
            Low_Speed_Channels[NTC_B]       = ADC_readResult(ADCCRESULT_BASE, ADC_SOC_NUMBER2);
            Low_Speed_Channels[NTC_C]       = ADC_readResult(ADCCRESULT_BASE, ADC_SOC_NUMBER3);
            Low_Speed_Channels[NTC_D]       = ADC_readResult(ADCCRESULT_BASE, ADC_SOC_NUMBER4);
            Low_Speed_Channels[RAIL_5V_A]   = ADC_readResult(ADCCRESULT_BASE, ADC_SOC_NUMBER5);
            Low_Speed_Channels[RAIL_5V_D]   = ADC_readResult(ADCCRESULT_BASE, ADC_SOC_NUMBER6);
            Low_Speed_Channels[RAIL_12V_D]  = ADC_readResult(ADCCRESULT_BASE, ADC_SOC_NUMBER7);
    
            here.current_low_speed_socNumber = ADC_SOC_NUMBER0;
        }
    
        //
        // Acknowledge interrupt
        //
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP7);
    }
    
    
    //
    // initializeDMA - Initialize DMA through hard reset
    static void DMA_Init(void)
    {
        //
        // Perform a hard reset on DMA
        //
        DMA_initController();
    
        //
        // Allow DMA to run free on emulation suspend
        //
        DMA_setEmulationMode(DMA_EMULATION_STOP);
    }
    
    //
    // configureDMAChannels - Initialize DMA ch 1 to transfer ADCA results
    //                        and DMA ch 2 to transfer ADCB results
    static void DMA_Configure_Channels(void)
    {
        here.DMA_CH1_CH2_buff_dest = BUFFER_0;
    
        //
        // DMA channel 1 set up for ADCA Voltages
        //
    
        DMA_configAddresses(DMA_CH1_BASE, (uint16_t *)&Dual_Adc_Buffer[0].ADC_VOLTAGES,
                            (uint16_t *)ADCARESULT_BASE);
    
        // 2 is the qty of bytes, 1 is the step of the source after each word transfer
        // BUFFER_SIZE is the step of the destination after each word transfer,
        // leaving the data in the corresponding array of the second channel
        DMA_configBurst(DMA_CH1_BASE, 2, 1, BUFFER_SIZE);
    
        //BUFFER_SIZE is the qty of transfers
        //-1 is the step of the soruce after the transfer, it returns to the
        // first ADC register
        // (- BUFFER_SIZE + 1 ) is the step of the destination after the
        // transfer, it returns to the first array but in the next free position
        DMA_configTransfer(DMA_CH1_BASE, BUFFER_SIZE, -1, (- BUFFER_SIZE + 1 ));
    
        DMA_configMode(DMA_CH1_BASE, DMA_TRIGGER_ADCA1,
                           (DMA_CFG_ONESHOT_DISABLE | DMA_CFG_CONTINUOUS_ENABLE |
                            DMA_CFG_SIZE_16BIT));
    
    
        //
        // DMA channel 2 set up for ADCB Currents
        //
        DMA_configAddresses(DMA_CH2_BASE, (int16_t *)&Dual_Adc_Buffer[0].ADC_CURRENTS,
                            (int32_t *)( ADCBRESULT_BASE + 0x10));
    
        // The only difference with the CH1is that the source resiters are 32bits
        // but as I am taking only 16bits, I use the 16bits format and I Jump
        // 2 words in each transfer
        DMA_configBurst(DMA_CH2_BASE, 2, 2, (BUFFER_SIZE) );
    
    
        DMA_configTransfer(DMA_CH2_BASE, BUFFER_SIZE, -2, (-BUFFER_SIZE) + 1);
    
    
        DMA_configMode(DMA_CH2_BASE, DMA_TRIGGER_ADCB1,
                               (DMA_CFG_ONESHOT_DISABLE | DMA_CFG_CONTINUOUS_ENABLE |
                                DMA_CFG_SIZE_16BIT));
    
    
        DMA_disableOverrunInterrupt(DMA_CH2_BASE);
        DMA_setInterruptMode(DMA_CH2_BASE, DMA_INT_AT_BEGINNING);
        DMA_enableInterrupt(DMA_CH2_BASE);
    
    
        // DMA Channel 3, we use it to copy the full buffer to the CLA memory
        // We copy Voltage and currents at once, thus we need ONE shot enable
        // to do that. As we are transferring the whole consuctive array and we need to do
        // that in less time than the sampling, we use 32bit mode that is faster
        // It takes 2 bursts of 20 (32 bits) words 2 * [ 3 cycles/word * 20 words/burst) + 1]
        // = 122 cycles that is less than the 125 cycles betweens samples
    
        DMA_configAddresses(DMA_CH3_BASE, (uint16_t *)&Dma_Cla_Buffer,
                            (uint16_t *)&Dual_Adc_Buffer[0]);
    
        // 20 words +2 src +2 step each burst
        DMA_configBurst(DMA_CH3_BASE, 20, 1, 1);
    
        // 2 bursts +2 src +2 stp
        DMA_configTransfer(DMA_CH3_BASE, 8, 2, 2);
    
        DMA_configMode(DMA_CH3_BASE, DMA_TRIGGER_SOFTWARE,
                           (DMA_CFG_ONESHOT_ENABLE | DMA_CFG_CONTINUOUS_ENABLE |
                            DMA_CFG_SIZE_32BIT));
    
        // Interrupt that will be used to start the CLA
        DMA_disableOverrunInterrupt(DMA_CH3_BASE);
        DMA_setInterruptMode(DMA_CH3_BASE, DMA_INT_AT_END);
        DMA_enableInterrupt(DMA_CH3_BASE);
    
    
    }
    
    // configureTrigger - Set up the epwmBase module so that the A output has a
    //                    sampling frequency of 960Khz
    //                    ( 120.000.000Mhz / 960.000Khz ) - 1 = 124
    static void DMA_Configure_Trigger_ADC(uint32_t epwmBase)
    {
        //
        // Make the timer count up with a period of 40us
        //
        HWREGH(epwmBase + EPWM_O_TBCTL) = 0x0000U;
        EPWM_setTimeBasePeriod(epwmBase, SAMPLING_PRD);
    
        //
        // Set the A output on zero and reset on CMPA
        //
        EPWM_setActionQualifierAction(epwmBase, EPWM_AQ_OUTPUT_A,
                                      EPWM_AQ_OUTPUT_HIGH,
                                      EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
        EPWM_setActionQualifierAction(epwmBase, EPWM_AQ_OUTPUT_A,
                                      EPWM_AQ_OUTPUT_LOW,
                                      EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
    
        //
        // Set CMPA to get a 50% duty, 124/2
        //
        EPWM_setCounterCompareValue(epwmBase, EPWM_COUNTER_COMPARE_A, 60U);
    
        // epwmBase uses the ePWM 1 SYNCO as its SYNCIN.
        EPWM_setSyncInPulseSource(epwmBase, EPWM_SYNC_IN_PULSE_SRC_SYNCOUT_EPWM1);
    
        EPWM_setPhaseShift(epwmBase, 1);
    
        // Enable phase shifts.
        EPWM_enablePhaseShiftLoad(epwmBase);
    
        //
        // Start ADC when timer equals zero (note: don't enable yet)
        //
        EPWM_setADCTriggerSource(epwmBase, EPWM_SOC_A, EPWM_SOC_TBCTR_ZERO);
        EPWM_setADCTriggerEventPrescale(epwmBase, EPWM_SOC_A, 1U);
    
        //
        // Enable initialization of the SOCA event counter. Since we are
        // disabling the ETSEL.SOCAEN bit, we need a way to reset the SOCACNT.
        // Hence, enable the counter initialize control.
        //
        EPWM_enableADCTriggerEventCountInit(epwmBase, EPWM_SOC_A);
    }
    
    /******************************************************************************/
    /* Public Functions                                                           */
    /******************************************************************************/
    
    void DMA_ADC_Init( void )
    {
    
        // Set up ISRs used by this task
    
        // ISR for DMA ch2 - occurs when DMA transfer is complete for ADC_A and ADC_B
        Interrupt_register(INT_DMA_CH2, &DMA_CH2_ISR);
    
    
        // Enable specific PIE & CPU interrupts:
        // DMA interrupt - Group 7, interrupt 1
        Interrupt_enable(INT_DMA_CH2);
    
    
        // Stop the ePWM clock
        SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
    
        // Set up the ePWM for triggering the ADC
        DMA_Configure_Trigger_ADC(EPWM_ADC_TRIG_BASE);
    
        // Setup the CLA
        initCLA();
    
        // Start the ePWM clock
        SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
    
        //
        // Initialize the DMA & configure DMA channels 1 & 2
        //
        DMA_Init();
        DMA_Configure_Channels();
    
        //
        // Clearing all pending interrupt flags
        //
        DMA_clearTriggerFlag(DMA_CH1_BASE);   // DMA channel 1
        DMA_clearTriggerFlag(DMA_CH2_BASE);   // DMA channel 2
        DMA_clearTriggerFlag(DMA_CH3_BASE);   // DMA channel 2
        HWREGH(ADC_Voltages_BASE + ADC_O_INTFLGCLR) = 0x3U; // ADCA
        HWREGH(ADC_Currents_BASE + ADC_O_INTFLGCLR) = 0x3U; // ADCB
        HWREGH(ADC_Low_Speed_BASE + ADC_O_INTFLGCLR) = 0x3U; // ADCC
        EPWM_forceADCTriggerEventCountInit(EPWM_ADC_TRIG_BASE, EPWM_SOC_A); // EPWM5 SOCA
        EPWM_clearADCTriggerFlag(EPWM_ADC_TRIG_BASE, EPWM_SOC_A);           // EPWM5 SOCA
    
    
        // Configure the SOC for the Low Speed ADC
        here.current_low_speed_socNumber = ADC_SOC_NUMBER0;
    }
    
    void DMA_ADC_Start( void )
    {
        //
        // Start DMA for reading the ADCs into the buffers
        DMA_startChannel(DMA_CH1_BASE);
        DMA_startChannel(DMA_CH2_BASE);
        DMA_startChannel(DMA_CH3_BASE);
    
    
        DMA_enableTrigger(DMA_CH1_BASE);
        DMA_enableTrigger(DMA_CH2_BASE);
        DMA_enableTrigger(DMA_CH3_BASE);
    
        //
        // Start ePWM5 for, enabling SOCA and putting the counter in up-count mode
        // this starts the ADC
        EPWM_enableADCTrigger(EPWM_ADC_TRIG_BASE, EPWM_SOC_A);
    }

    And this is the code of the PWM channels @ 48 Khz

    /******************************************************************************/
    /* Local Typedefs                                                             */
    /******************************************************************************/
    
    typedef struct
    {
    
        power_pwm_states_t          power_pwm_state[POWER_PWM_OUT_MAX];
        uint32_t                    pwm_base_reg   [POWER_PWM_OUT_MAX];
    
    }file_scope_t;
    
    /******************************************************************************/
    /* Local Variables                                                            */
    /******************************************************************************/
    
    #pragma DATA_ALIGN(here, 2)
    static volatile file_scope_t here;
    
    /******************************************************************************/
    /* Local Functions                                                            */
    /******************************************************************************/
    
    
    void EPWM_Common_configs(uint32_t base_reg)
    {
        // Set-up TBCLK
        EPWM_setTimeBasePeriod (base_reg, EPWM_TIMER_TBPRD);
        EPWM_setPhaseShift     (base_reg, 0U);
        EPWM_setTimeBaseCounter(base_reg, 0U);
    
        // Set Compare values (start with PWM in Off state).
        EPWM_setCounterCompareValue(base_reg,
                                    EPWM_COUNTER_COMPARE_A,
                                    EPWM_TIMER_TBPRD+1);
        EPWM_setCounterCompareValue(base_reg,
                                    EPWM_COUNTER_COMPARE_B,
                                    EPWM_TIMER_TBPRD+1);
    
        // Set up counter mode
        EPWM_setTimeBaseCounterMode(base_reg, EPWM_COUNTER_MODE_UP);
        EPWM_disablePhaseShiftLoad (base_reg);
        EPWM_setClockPrescaler     (base_reg,
                                    EPWM_CLOCK_DIVIDER_1,
                                    EPWM_HSCLOCK_DIVIDER_1);
    
        // Set up shadowing
        EPWM_setCounterCompareShadowLoadMode(base_reg,
                                             EPWM_COUNTER_COMPARE_A,
                                             EPWM_COMP_LOAD_ON_CNTR_ZERO);
        EPWM_setCounterCompareShadowLoadMode(base_reg,
                                             EPWM_COUNTER_COMPARE_B,
                                             EPWM_COMP_LOAD_ON_CNTR_ZERO);
    
        // Set actions
        EPWM_setActionQualifierAction(base_reg,
                                      EPWM_AQ_OUTPUT_A,
                                      EPWM_AQ_OUTPUT_LOW,
                                      EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
        EPWM_setActionQualifierAction(base_reg,
                                      EPWM_AQ_OUTPUT_B,
                                      EPWM_AQ_OUTPUT_HIGH,
                                      EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
        EPWM_setActionQualifierAction(base_reg,
                                      EPWM_AQ_OUTPUT_A,
                                      EPWM_AQ_OUTPUT_HIGH,
                                      EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
        EPWM_setActionQualifierAction(base_reg,
                                      EPWM_AQ_OUTPUT_B,
                                      EPWM_AQ_OUTPUT_LOW,
                                      EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB);
    
        //Dead bands
        //FED: Falling Edge Delay
        //RED: Rising Edge Delay
    
        // Use EPWMA as the input for both RED and FED
        EPWM_setRisingEdgeDeadBandDelayInput (base_reg, EPWM_DB_INPUT_EPWMA);
        EPWM_setFallingEdgeDeadBandDelayInput(base_reg, EPWM_DB_INPUT_EPWMA);
    
        // Set the RED and FED values
        EPWM_setFallingEdgeDelayCount(base_reg, EPWM_RISING_EDGE_DELAY_CNTS);
        EPWM_setRisingEdgeDelayCount (base_reg, EPWM_RISING_EDGE_DELAY_CNTS);
    
        // Do not invert the delayed outputs (AH)
        EPWM_setDeadBandDelayPolarity(base_reg, EPWM_DB_RED, EPWM_DB_POLARITY_ACTIVE_HIGH);
        EPWM_setDeadBandDelayPolarity(base_reg, EPWM_DB_FED, EPWM_DB_POLARITY_ACTIVE_LOW);
    
        // Use the delayed signals instead of the original signals
        EPWM_setDeadBandDelayMode(base_reg, EPWM_DB_RED, true);
        EPWM_setDeadBandDelayMode(base_reg, EPWM_DB_FED, true);
    
        // DO NOT Switch Output A with Output B
        EPWM_setDeadBandOutputSwapMode(base_reg, EPWM_DB_OUTPUT_A, false);
        EPWM_setDeadBandOutputSwapMode(base_reg, EPWM_DB_OUTPUT_B, false);
    }
    
    /******************************************************************************/
    /* Public Functions                                                           */
    /******************************************************************************/
    
    void PWM_setPhase_Discharging(int32_t Phase_Pri, int32_t Phase_Pri_Sec, int32_t Phase_Sec)
    {
    
        int32_t phase_B_to_A;
        int32_t phase_C_to_A;
        int32_t phase_D_to_A;
    
        phase_B_to_A = -Phase_Pri;
    
        phase_C_to_A = -Phase_Pri_Sec;
    
        phase_D_to_A = -( Phase_Pri_Sec + Phase_Sec );
    
    
        PWM_Set_Phase_Referred_to_OutA_degreesx100(POWER_PWM_OUT_B_BAT,phase_B_to_A);
        PWM_Set_Phase_Referred_to_OutA_degreesx100(POWER_PWM_OUT_C_UPS,phase_C_to_A);
        PWM_Set_Phase_Referred_to_OutA_degreesx100(POWER_PWM_OUT_D_UPS,phase_D_to_A);
    }
    
    
    void PWM_setPhase_Charging(int32_t Phase_Pri, int32_t Phase_Pri_Sec, int32_t Phase_Sec)
    {
    
        int32_t phase_B_to_A;
        int32_t phase_C_to_A;
        int32_t phase_D_to_A;
    
        phase_B_to_A = -Phase_Sec;
    
        phase_C_to_A = Phase_Pri_Sec;
    
        phase_D_to_A = Phase_Pri_Sec - Phase_Pri;
    
    
    
        PWM_Set_Phase_Referred_to_OutA_degreesx100(POWER_PWM_OUT_B_BAT,phase_B_to_A);
        PWM_Set_Phase_Referred_to_OutA_degreesx100(POWER_PWM_OUT_C_UPS,phase_C_to_A);
        PWM_Set_Phase_Referred_to_OutA_degreesx100(POWER_PWM_OUT_D_UPS,phase_D_to_A);
    }
    
    
    //-------------------------------------------------------------------------------------------------
    void PWM_Config(void)
    {
        uint32_t  i;
    
        here.pwm_base_reg[POWER_PWM_OUT_A_BAT]=EPWM_BAT_AH_AL_BASE;
        here.pwm_base_reg[POWER_PWM_OUT_B_BAT]=EPWM_BAT_BH_BL_BASE;
        here.pwm_base_reg[POWER_PWM_OUT_C_UPS]=EPWM_UPS_CH_CL_BASE;
        here.pwm_base_reg[POWER_PWM_OUT_D_UPS]=EPWM_UPS_DH_DL_BASE;
    
        // Disable sync(Freeze clock to PWM as well). GTBCLKSYNC is applicable
        // only for multiple core devices. Uncomment the below statement if
        // applicable.
        //
        // SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_GTBCLKSYNC);
        SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
    
    
        for(i=0;i<POWER_PWM_OUT_MAX;i++)
        {
            EPWM_Common_configs(here.pwm_base_reg[i]);
        }
    
    
        /****ePWM1 SOCA event to trigger ADC conversions ****/
        // Disable SOCA
        EPWM_disableADCTrigger(here.pwm_base_reg[POWER_PWM_OUT_A_BAT], EPWM_SOC_A);
    
        // Configure the SOC to occur when Time-base counter equal to zero
        EPWM_setADCTriggerSource(here.pwm_base_reg[POWER_PWM_OUT_A_BAT], EPWM_SOC_A, EPWM_SOC_TBCTR_U_CMPA/*EPWM_SOC_TBCTR_ZERO*/);
        EPWM_setADCTriggerEventPrescale(here.pwm_base_reg[POWER_PWM_OUT_A_BAT], EPWM_SOC_A, 1);
        // Enable SOCA
        EPWM_enableADCTrigger(here.pwm_base_reg[POWER_PWM_OUT_A_BAT], EPWM_SOC_A);
    
    
        EPWM_selectPeriodLoadEvent(EPWM_BAT_BH_BL_BASE, EPWM_SHADOW_LOAD_MODE_SYNC);
        EPWM_selectPeriodLoadEvent(EPWM_UPS_CH_CL_BASE, EPWM_SHADOW_LOAD_MODE_SYNC);
        EPWM_selectPeriodLoadEvent(EPWM_UPS_DH_DL_BASE, EPWM_SHADOW_LOAD_MODE_SYNC);
    
    
        // ePWM1 SYNCO is generated on CTR=0
        EPWM_enableSyncOutPulseSource(EPWM_BAT_AH_AL_BASE, EPWM_SYNC_OUT_PULSE_ON_CNTR_ZERO);
    
        // ePWM2 uses the ePWM 1 SYNCO as its SYNCIN.
        EPWM_setSyncInPulseSource(EPWM_BAT_BH_BL_BASE, EPWM_SYNC_IN_PULSE_SRC_SYNCOUT_EPWM1);
    
        // ePWM3 uses the ePWM 1 SYNCO as its SYNCIN.
        EPWM_setSyncInPulseSource(EPWM_UPS_CH_CL_BASE, EPWM_SYNC_IN_PULSE_SRC_SYNCOUT_EPWM1);
    
        // ePWM4 uses the ePWM 1 SYNCO as its SYNCIN.
        EPWM_setSyncInPulseSource(EPWM_UPS_DH_DL_BASE, EPWM_SYNC_IN_PULSE_SRC_SYNCOUT_EPWM1);
    
        // Enable all phase shifts.
        EPWM_enablePhaseShiftLoad(EPWM_BAT_BH_BL_BASE);
        EPWM_enablePhaseShiftLoad(EPWM_UPS_CH_CL_BASE);
        EPWM_enablePhaseShiftLoad(EPWM_UPS_DH_DL_BASE);
    
    
        // Enable sync and clock to PWM
        SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
    }
    
    //-------------------------------------------------------------------------------------------------
    bool PWM_Set_On (power_pwm_outs_t power_pwm_sel)
    {
        if(power_pwm_sel>=POWER_PWM_OUT_MAX)
            return false;
    
        // Set Compare values
        EPWM_setCounterCompareValue(here.pwm_base_reg[power_pwm_sel],
                                    EPWM_COUNTER_COMPARE_A,
                                    EPWM_TIMER_TBPRD/2);
        EPWM_setCounterCompareValue(here.pwm_base_reg[power_pwm_sel],
                                    EPWM_COUNTER_COMPARE_B,
                                    EPWM_TIMER_TBPRD/2);
    
        here.power_pwm_state[power_pwm_sel] = POWER_PWM_ENABLED;
    
        return true;
    }
    
    //-------------------------------------------------------------------------------------------------
    bool PWM_Set_Off (power_pwm_outs_t power_pwm_sel)
    {
        if(power_pwm_sel>=POWER_PWM_OUT_MAX)
            return false;
        // Set Compare values
        EPWM_setCounterCompareValue(here.pwm_base_reg[power_pwm_sel],
                                    EPWM_COUNTER_COMPARE_A,
                                    EPWM_TIMER_TBPRD+1);
        EPWM_setCounterCompareValue(here.pwm_base_reg[power_pwm_sel],
                                    EPWM_COUNTER_COMPARE_B,
                                    EPWM_TIMER_TBPRD+1);
    
        here.power_pwm_state[power_pwm_sel] = POWER_PWM_DISABLED;
        return true;
    }
    
    
    power_pwm_states_t PWM_Get_State (power_pwm_outs_t power_pwm_sel)
    {
        if(power_pwm_sel>=POWER_PWM_OUT_MAX)
            return POWER_PWM_MAX;
    
        return here.power_pwm_state[power_pwm_sel];
    
    }
    
    
    //-------------------------------------------------------------------------------------------------
    bool PWM_Set_Phase_Referred_to_OutA_degreesx100 (power_pwm_outs_t power_pwm_sel, int32_t degreesx100)
    {
    
        bool is_negative;
        uint32_t shift_deg;
        uint32_t shift_cnts;
    
        if(power_pwm_sel>=POWER_PWM_OUT_MAX || power_pwm_sel==POWER_PWM_OUT_A_BAT)
            return false;
    
        if(degreesx100<0)
        {
            is_negative=true;
            shift_deg = degreesx100^=0xFFFFFFFF;
            shift_deg++;
        }
        else
        {
            is_negative = false;
            shift_deg = degreesx100;
        }
    
        while(shift_deg>=36000)
            shift_deg-=36000;
    
    
        //if the period is 2500 counts, representing 360 degrees. Then we have to divide degreesx100 x10 by 144
        shift_deg *= 10;
        shift_cnts = shift_deg/144;
    
        if(is_negative)
        {
            EPWM_setPhaseShift(here.pwm_base_reg[power_pwm_sel], EPWM_TIMER_TBPRD-shift_cnts);
            EPWM_setTimeBaseCounter(here.pwm_base_reg[power_pwm_sel], EPWM_TIMER_TBPRD-shift_cnts);
        }
        else
        {
            EPWM_setPhaseShift(here.pwm_base_reg[power_pwm_sel], shift_cnts);
            EPWM_setTimeBaseCounter(here.pwm_base_reg[power_pwm_sel], shift_cnts);
        }
        return true;
    }
    

    To sum up, I need that the DMA transfers to the buffers are in synchro with the 

    PWM channel 1. In order words, when the cycle of this PWM starts I want that 

    the first sample of the channels goes to the first position of the buffer.

    Another thing that I didn't mention is that once the DMA finish filling one of

    the Dual Buffers, it is transferred with another DMA channel to a CLA memory for further processing,

    but this thing works perfectly.

    Regards and thank you in advance

  • Hi Fernando,

    Sorry, I did not have a chance to look through the code today.  Will hopefully get to this tomorrow.

    Best regards,

    Joseph

  • Hi Fernando,

    One suggestion is to use DMA to trigger the transfer using DMASRCSELx register, however only SOCA and SOCB events are allowed to trigger the transfer.  You can set SOCA/B of the EPWM to be generated at the start of EPWM cycle at CTR=0.  You would have to ensure that the ADC results are ready though before CTR=0.  You would have to use both SOCA and SOCB, one SOC to start the conversions and the other to set CTR=0 when all results are ready.

    Regards,

    Joseph   

  • Hi Joseph, 

                      Thanks for your time. I can't clearly understand your suggestion.

    The current firmware triggers the DMA at the end of conversion.

    Are you suggesting using the same EPWM channel that is used for generating the Output signal for triggering the ADC and the DMA?

    In that case, I will need to trigger 20 times the ADC and DMA on each cycle of the output, how I could do that?

    Thanks in advance

  • Hi Fernando,

    Yes, that is what i was suggesting, but it may not work for you if you specifically need 20 conversions.  Will your application work with 16 conversions?  It will be feasible if your application is flexible to take 16 conversions.  How this will work is that for the Voltage conversions using ch0 and ch1, have the SOC channel setup such that even SOCs (SOC0,SOC2,SOC4...SOC14) will be assigned to ch0 and odd SOCs (SOC1,SOC3...SOC15) will be assigned to ch1.  You can then configure EPWM such that CMPA will occur when CTR=0 so that ADCSOCA event will occur and trigger the conversions for all 15 SOCs.  You can even use INT1SEL in register ADCINTSEL1N2 to trigger ADCINT1 when end of conversion for SOC15 (EOC15) happens.

    Using the ADC timing diagram in the datasheet, you can calculate exactly the number of cycles it would take for a single conversion which is tSH + tLAT (values will be dependent on ADC prescaler).  Multiply this by 16 and that will be the total cycles for 16 conversions and you can use this number to set CMPB. This will cause ADCSOCB event and you can use this event to trigger DMA transfer of the 16 ADC conversions.  Alternatively, if you choose to trigger INT1SEL at end of SOC15 conversion, you can also use ADCINT1 to trigger the DMA transfer.

    Not sure if the above alternatives work for your application, especially if it requires 20 conversions.

    Regards,

    Joseph

  • Hi Joseph:

                     Thanks for your time. Probably the application could work with 16 samples, but that implies going backward and validating all the simulations again and we don't have time for that. I think that a mash-up of ideas could work.

    Your idea of enabling multiple SOCs with my idea of using DMA  in the DMA_CFG_CONTINUOUS_DISABLE mode should work. The fact of adding SOCs gives me enough time to be sure that the interruption of the start of conversion needed to enable the DMA channel will be attended to before the DMA should start transferring results. Obviously, I have to adjust the ADC conversion time in order to ensure the sampling rate. I will tell you how it results

     

    Regards.

    Fernando

  • Hi Fernando,

    Understood the time factor.  Hope you can make the combination of conversions and DMA trigger work.

    Regards,

    Joseph 

  • Hi Joseph.

    Finally, I managed to get every synchronized doing one-shot synch between the faster EPWM ( the one that drives the ADC ) to the slower EPWM ( the one that drives the Output PWM). Before that synchro occurs, I reset and start the ADC and DMA. 

    Regards and thanks in advance