//###########################################################################
//
// FILE:   Example_2833xEPwm_DMA.c
//
// TITLE:   DSP2833x Device DMA interface with ePWM example.
//
// ASSUMPTIONS:
//
//    This program requires the DSP2833x header files.
//
//    As supplied, this project is configured for "boot to SARAM"
//    operation.  The 2833x Boot Mode table is shown below.
//    For information on configuring the boot mode of an eZdsp,
//    please refer to the documentation included with the eZdsp,
//
//       $Boot_Table:
//
//         GPIO87   GPIO86     GPIO85   GPIO84
//          XA15     XA14       XA13     XA12
//           PU       PU         PU       PU
//        ==========================================
//            1        1          1        1    Jump to Flash
//            1        1          1        0    SCI-A boot
//            1        1          0        1    SPI-A boot
//            1        1          0        0    I2C-A boot
//            1        0          1        1    eCAN-A boot
//            1        0          1        0    McBSP-A boot
//            1        0          0        1    Jump to XINTF x16
//            1        0          0        0    Jump to XINTF x32
//            0        1          1        1    Jump to OTP
//            0        1          1        0    Parallel GPIO I/O boot
//            0        1          0        1    Parallel XINTF boot
//            0        1          0        0    Jump to SARAM	    <- "boot to SARAM"
//            0        0          1        1    Branch to check boot mode
//            0        0          1        0    Boot to flash, bypass ADC cal
//            0        0          0        1    Boot to SARAM, bypass ADC cal
//            0        0          0        0    Boot to SCI-A, bypass ADC cal
//                                              Boot_Table_End$
//
// DESCRIPTION:
//
// This example demonstrates several cases where the DMA is triggered from
// SOC signals generated by ePWM modules.
//
// DMA CH1 setup:
//   Trigger  = ADCSOCA from ePWM1
//   Datasize = 16 bits
//   Source   = VarA
//   Dest     = EPwm1Regs.TBPRD
//   Burst    = One word / burst
//   Transfer = One burst / transfer
//   CPU int  = every transfer
//
// DMA CH2 setup:
//   Trigger  = ADCSOCB from ePWM2
//   Datasize = 32 bits
//   Source   = VarB
//   Dest     = EPwm1Regs.CMPA.all
//   Burst    = One 32-bit word / burst
//   Transfer = One burst / transfer
//   CPU int  = none
//
// DMA CH3 setup:
//   Trigger  = ADC SEQ1INT
//   Datasize = 32 bits
//   Source   = AdcMirror.ADCRESULT[0-5]
//   Dest     = ADCbuffer
//   Burst    = Three 32-bit words / burst
//   Transfer = One burst / transfer
//   CPU int  = none
//
// Watch Variables:
//
//    EPwm1Regs.TBPRD
//    EPwm1Regs.CMPA.all
//    ADCbuffer
//    InterruptCount
//
//###########################################################################

#include "DSP28x_Project.h"     // Device Headerfile and Examples Include File


// Prototype statements for functions found within this file.
void delay_loop(void);
void DMAInitialize(void);
void DMACH1Config(void);
void DMACH2Config(void);
void DMACH3Config(void);
void ConfigAdc(void);
void config_ePWM1_to_generate_ADCSOCA(void);
void config_ePWM2_to_generate_ADCSOCB(void);
interrupt void local_DINTCH1_ISR(void);


// Global Variables
#pragma DATA_SECTION(ADCbuffer,"DMARAML4");
volatile Uint32 ADCbuffer[3];

Uint16 VarA;
Uint32 VarB;

volatile Uint16 *MAPCNF = (Uint16 *)0x00702E;

Uint16 InterruptCount;

void main(void)
{
   Uint16 i;

// Step 1. Initialize System Control:
// PLL, WatchDog, enable Peripheral Clocks
// This example function is found in the DSP2833x_SysCtrl.c file.
   InitSysCtrl();

// Step 2. Initalize GPIO:
// This example function is found in the DSP2833x_Gpio.c file and
// illustrates how to set the GPIO to it's default state.
// InitGpio();  // Skipped for this example

// For this example use the following configuration:

// Step 3. Clear all interrupts and initialize PIE vector table:
// Disable CPU interrupts
   DINT;

// Initialize 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 DSP2833x_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 DSP2833x_DefaultIsr.c.
// This function is found in DSP2833x_PieVect.c.
   InitPieVectTable();

   EALLOW;
   // Initialize PIE vector for CPU interrupt:
   PieVectTable.DINTCH1 = &local_DINTCH1_ISR;		// Point to DMA CH1 ISR
   PieCtrlRegs.PIEIER7.bit.INTx1 = 1;              // Enable DMA CH1 interrupt in PIE
   EDIS;

// Step 4. Initialize all the Device Peripherals:
// This function is found in DSP2833x_InitPeripherals.c
// InitPeripherals(); // Not required for this example

// Step 5. User specific code:

   InterruptCount = 0;

   EALLOW;
   GpioCtrlRegs.GPADIR.all = 0xFFFFFFFF;    // All outputs
   SysCtrlRegs.MAPCNF.bit.MAPEPWM = 1;      // Remap ePWMs for DMA access
   EDIS;

   GpioDataRegs.GPASET.all = 0xFFFFFFFF;
   delay_loop();
   GpioDataRegs.GPACLEAR.all = 0x00000002;

   for(i=0; i<3; i++)
   {
      ADCbuffer[i] = ((Uint32)i*0x00011000) + 0x00044000;
   }

   VarA = 75;
   VarB = 0x652000;

   // Enable and configure clocks to peripherals:
   EALLOW;
   SysCtrlRegs.PCLKCR3.bit.DMAENCLK = 1;  // Enable SYSCLK to DMA
   EDIS;

   DMAInitialize();
   DMACH1Config();
   DMACH2Config();
   DMACH3Config();

   // Enable all interrupts:
   IER = M_INT7;							// Enable INT7 (7.1 DMA Ch1)
   EINT;

   InitAdc();
   ConfigAdc();

   config_ePWM1_to_generate_ADCSOCA();
   config_ePWM2_to_generate_ADCSOCB();


   EALLOW;
   DmaRegs.CH1.CONTROL.bit.RUN = 1;
   DmaRegs.CH2.CONTROL.bit.RUN = 1;
   DmaRegs.CH3.CONTROL.bit.RUN = 1;
   asm("   NOP");
   EPwm1Regs.TBCTL.bit.CTRMODE = 0;						// Up count mode
   EPwm2Regs.TBCTL.bit.CTRMODE = 0;						// Up count mode
   EDIS;

   for(;;) {}

}


//===========================================================================
// DMA Functions
//===========================================================================

void DMAInitialize(void)
{
	EALLOW;

	// Perform a hard reset on DMA
	DmaRegs.DMACTRL.bit.HARDRESET = 1;

	// always perform one NOP after a HARDRESET
	asm("     NOP");

	// Stop DMA on emulation suspend
	DmaRegs.DEBUGCTRL.bit.FREE = 0;

	EDIS;
}


void DMACH1Config(void)
{
	EALLOW;
	// Configure CH1:
	//
	// Reset selected channel via CONTROL Register:
//	DmaRegs.CH1.CONTROL.bit.SOFTRESET = 1; 			// Perform SOFT reset on channel (clears all counters)

	// Set up MODE Register:
	DmaRegs.CH1.MODE.bit.PERINTSEL = 18;			// ePWM1 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 = 1;        		// 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 = 0;					// Bursts (N-1) per transfer
	DmaRegs.CH1.SRC_TRANSFER_STEP = 0;				// 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 = 0xFFFF;				// No source wrap-around
	DmaRegs.CH1.DST_WRAP_SIZE = 0xFFFF;				// 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) &VarA;	// Point to variable in RAM

	// Set up DESTINATION address:
	DmaRegs.CH1.DST_ADDR_SHADOW = (Uint32) &EPwm1Regs.TBPRD;	// Point to ePWM1 TBPRD register remapped for DMA
																//   need to make sure .cmd file has ePWMs remapped
	// 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;
}

void DMACH2Config(void)
{
	EALLOW;
	// Configure CH2:
	//
	// Reset selected channel via CONTROL Register:
//	DmaRegs.CH2.CONTROL.bit.SOFTRESET = 1; 			// Perform SOFT reset on channel (clears all counters)

	// Set up MODE Register:
	DmaRegs.CH2.MODE.bit.PERINTSEL = 21;			// ePWM2 SOCB as peripheral interrupt source
	DmaRegs.CH2.MODE.bit.PERINTE = 1;       		// Peripheral interrupt enabled
	DmaRegs.CH2.MODE.bit.ONESHOT = 0;       		// 1 burst per SW interrupt
	DmaRegs.CH2.MODE.bit.CONTINUOUS = 1;    		// Do not stop after each transfer
	DmaRegs.CH2.MODE.bit.SYNCE = 0;         		// No sync signal
	DmaRegs.CH2.MODE.bit.SYNCSEL = 0;       		// No sync signal
	DmaRegs.CH2.MODE.bit.DATASIZE = 1;				// 32-bit data size transfers
	DmaRegs.CH2.MODE.bit.CHINTMODE = 0;
	DmaRegs.CH2.MODE.bit.CHINTE = 0;        		// Channel Interrupt to CPU disabled

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

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

	// Set up WRAP registers:
	DmaRegs.CH2.SRC_WRAP_SIZE = 0xFFFF;				// No source wrap-around
	DmaRegs.CH2.DST_WRAP_SIZE = 0xFFFF;				// No destination wrap-around
	DmaRegs.CH2.SRC_WRAP_STEP = 0;
	DmaRegs.CH2.DST_WRAP_STEP = 0;

	// Set up SOURCE address:
	DmaRegs.CH2.SRC_ADDR_SHADOW = (Uint32) &VarB;	// Point to variable in RAM

	// Set up DESTINATION address:
	DmaRegs.CH2.DST_ADDR_SHADOW = (Uint32) &EPwm1Regs.CMPA.all;	// Point to ePWM1 CMPAHR/CMPA registers

	// Clear any spurious flags:
	DmaRegs.CH2.CONTROL.bit.PERINTCLR = 1;  		// Clear any spurious interrupt flags
	DmaRegs.CH2.CONTROL.bit.SYNCCLR = 1;    		// Clear any spurious sync flags
	DmaRegs.CH2.CONTROL.bit.ERRCLR = 1; 			// Clear any spurious sync error flags

	EDIS;
}

void DMACH3Config(void)
{
	EALLOW;
	// Configure CH3:
	//

	// Set up MODE Register:
	DmaRegs.CH3.MODE.bit.PERINTSEL = 1;				// ADC SEQ1INT as peripheral interrupt source
	DmaRegs.CH3.MODE.bit.PERINTE = 1;       		// Peripheral interrupt enabled
	DmaRegs.CH3.MODE.bit.ONESHOT = 0;       		// 1 burst per SW interrupt
	DmaRegs.CH3.MODE.bit.CONTINUOUS = 1;    		// Do not stop after each transfer
	DmaRegs.CH3.MODE.bit.SYNCE = 0;         		// No sync signal
	DmaRegs.CH3.MODE.bit.SYNCSEL = 0;       		// No sync signal
	DmaRegs.CH3.MODE.bit.DATASIZE = 1;				// 32-bit data size transfers
	DmaRegs.CH3.MODE.bit.CHINTMODE = 0;
	DmaRegs.CH3.MODE.bit.CHINTE = 0;        		// Channel Interrupt to CPU disabled

	// Set up BURST registers:
	DmaRegs.CH3.BURST_SIZE.all = 5;					// Number (N-1) of 16-bit words transferred in a burst
	DmaRegs.CH3.SRC_BURST_STEP = 2;					// Increment source burst address by 2 (32-bit)
	DmaRegs.CH3.DST_BURST_STEP = 2;					// Increment destination burst address by 2 (32-bit)

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

	// Set up WRAP registers:
	DmaRegs.CH3.SRC_WRAP_SIZE = 0xFFFF;				// No source wrap-around
	DmaRegs.CH3.DST_WRAP_SIZE = 0xFFFF;				// No destination wrap-around
	DmaRegs.CH3.SRC_WRAP_STEP = 0;
	DmaRegs.CH3.DST_WRAP_STEP = 0;

	// Set up SOURCE address:
	DmaRegs.CH3.SRC_ADDR_SHADOW = (Uint32) &AdcMirror.ADCRESULT0;		// Point to first RESULT reg

	// Set up DESTINATION address:
	DmaRegs.CH3.DST_ADDR_SHADOW = (Uint32) &ADCbuffer[0];	// Point to beginning of ADCbuffer

	// Clear any spurious flags:
	DmaRegs.CH3.CONTROL.bit.PERINTCLR = 1;  		// Clear any spurious interrupt flags
	DmaRegs.CH3.CONTROL.bit.SYNCCLR = 1;    		// Clear any spurious sync flags
	DmaRegs.CH3.CONTROL.bit.ERRCLR = 1; 			// Clear any spurious sync error flags

	EDIS;
}



interrupt void local_DINTCH1_ISR(void)	// DMA INT7.1
{
   GpioDataRegs.GPATOGGLE.all = 0x00000001;		// Toggle GPIOA0

   InterruptCount++;


   if((DmaRegs.CH1.CONTROL.bit.OVRFLG == 1) || (DmaRegs.CH2.CONTROL.bit.OVRFLG == 1) ||
      (DmaRegs.CH3.CONTROL.bit.OVRFLG == 1))
   {
      asm("     ESTOP0");
   }

   PieCtrlRegs.PIEACK.bit.ACK7 = 1;				// Clear PIEIFR bit
}


void ConfigAdc(void)
{
   AdcRegs.ADCMAXCONV.bit.MAX_CONV1 = 7;
   AdcRegs.ADCCHSELSEQ1.bit.CONV00 = 0;			// ADCINA0
   AdcRegs.ADCCHSELSEQ1.bit.CONV01 = 1;			// ADCINA1
   AdcRegs.ADCCHSELSEQ1.bit.CONV02 = 2;			// ADCINA2
   AdcRegs.ADCCHSELSEQ1.bit.CONV03 = 3;			// ADCINA3
   AdcRegs.ADCCHSELSEQ2.bit.CONV04 = 4;			// ADCINA4
   AdcRegs.ADCCHSELSEQ2.bit.CONV05 = 5;			// ADCINA5
   AdcRegs.ADCTRL2.bit.EPWM_SOCA_SEQ1 = 1;		// Enable ADC to accept ePWM_SOCA trigger
   AdcRegs.ADCTRL1.bit.SEQ_CASC = 1;
   AdcRegs.ADCTRL2.bit.RST_SEQ1 = 1;
   AdcRegs.ADCST.bit.INT_SEQ1_CLR = 1;			// Clear interrupt flag
   AdcRegs.ADCTRL2.bit.INT_ENA_SEQ1 = 1;		// Enable SEQ1 interrupt
}


void config_ePWM1_to_generate_ADCSOCA(void)
{
	// Configure ePWM1 Timer
	// Interrupt triggers ADCSOCA

	EALLOW;
	EPwm1Regs.TBPRD = 74;						// Setup period (one off so DMA transfer will be obvious)
	EPwm1Regs.CMPA.all = 0x501000;
	EPwm1Regs.ETSEL.bit.SOCASEL = 2;			// ADCSOCA on TBCTR=TBPRD
	EPwm1Regs.ETPS.bit.SOCAPRD = 1;				// Generate SOCA on 1st event
	EPwm1Regs.ETSEL.bit.SOCAEN = 1;				// Enable SOCA generation
	EPwm1Regs.TBCTL.bit.HSPCLKDIV = 0;			// /1 clock mode
	EDIS;
}


void config_ePWM2_to_generate_ADCSOCB(void)
{
	// Configure ePWM2 Timer
	// Interrupt triggers ADCSOCB

	EALLOW;
	EPwm2Regs.TBPRD = 150;						// Setup periodSetup period
	EPwm2Regs.CMPA.all = 0x200000;
	EPwm2Regs.ETSEL.bit.SOCBSEL = 2;			// ADCSOCB on TBCTR=TBPRD
	EPwm2Regs.ETPS.bit.SOCBPRD = 1;				// Generate SOCB on 1st event
	EPwm2Regs.ETSEL.bit.SOCBEN = 1;				// Enable SOCB generation
	EPwm2Regs.TBCTL.bit.HSPCLKDIV = 0;			// /1 clock mode
	EDIS;
}


void delay_loop()
{
    short      i;
    for (i = 0; i < 1000; i++) {}
}


//===========================================================================
// No more.
//===========================================================================

