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.

F28377D, Can DMA read ADC result registers?

Hi anyone can do help:

Currently I am working on the F28377D (development tools). I tried to use DMA to read the ADC. Now I have two problems:

1, DMA can be triggered by ADC's interrupt, but each time the ADC's interrupt function will be run with the DMA.

  That means the CPU will response each ADC interruption, and the DMA becomes no sense at all.

2, DMA can not read the ADC result registers correctly. In other words, the DMA's registers' value are changing with the ADC interruption, and I can see that the values in source/destination address registers are correct; however, there is no output to the destination variable. --- it may not read the ADC result register, or it may not write the result to the destination variable address.

From the datasheet(TMS320F2837xD Delfino Microcontrollers, Technical Reference Manual), at the DMA part(page591), 'DMA Block Diagram' shows that CPU1/2 Bus can access the ADC result registers, but CPU1/2DMA bus looks like can not.

Thanks for your reading; and if you can answer them, I appreciate it.

-----------------------------------

#include "F28x_Project.h"     // Device Headerfile and Examples Include File
#include "F2837xD_struct.h"
#include "F2837xD_Dma_defines.h"

// function prototypes
void ConfigureADC(void);
void ConfigureEPWM(void);
void ConfigureDAC(void);
void SetupADCEpwm(void);
interrupt void adca1_isr(void);

// variables
#define RESULTS_BUFFER_SIZE 256
#define MAX_SAMPLES  1024

#define ONE_WORD_BURST  0  // 16-bit word per burst
#define TWO_WORD_BURST  1  // 32-bit word per burst

#define SOURCE_NO_ADDRESS_CHANGE  0
#define DESTINATION_INCREMENT_ONE_ADDRESS 1

#define TRANSFER_SIZE_256  255

#define TRANSFER_STEP_SOURCE_NO_CHANGE  0
#define TRANSFER_STEP_DEST_INCREMENT_ONE_ADDRESS 1

volatile uint16_t *DMA1Source, *DMA1Dest;
volatile Uint16 DMABuf1[RESULTS_BUFFER_SIZE]; //DMA buffer store ADC results
__interrupt void local_DMACH1_ISR(void);

void DMA_configure(void);
volatile uint16_t DMA_Done = 0;

Uint16 AdcaResults[RESULTS_BUFFER_SIZE];
Uint16 AdcbResults[RESULTS_BUFFER_SIZE];
Uint16 resultsIndex;
Uint16 ToggleCount = 0;
Uint16 dacOffset;
Uint16 dacOutput;
Uint16 sineEnable = 0;
extern int QuadratureTable[40];
Uint16 i;


void main(void)
{
    // Initialize System Control: PLL, WatchDog, enable Peripheral Clocks
    InitSysCtrl();
    EALLOW;
    ClkCfgRegs.PERCLKDIVSEL.bit.EPWMCLKDIV = 0;
    EDIS;

    // Initialize GPIO:
    InitGpio();                 // configure default GPIO
    EALLOW;
    GpioCtrlRegs.GPADIR.bit.GPIO8 = 1;  // used as input to ADC
    GpioCtrlRegs.GPADIR.bit.GPIO31 = 1; // drives LED LD2 on controlCARD
    EDIS;
    GpioDataRegs.GPADAT.bit.GPIO8 = 0; // force GPIO8 output LOW
    GpioDataRegs.GPADAT.bit.GPIO31 = 1;// turn off LED

    // Clear all interrupts and initialize PIE vector table:
    DINT;
    InitPieCtrl();
    IER = 0x0000;
    IFR = 0x0000;
    InitPieVectTable();

    // Map ISR functions
    EALLOW;
    PieVectTable.DMA_CH1_INT = &local_DMACH1_ISR; //function for DMA interrupt 1
    PieVectTable.ADCA1_INT = &adca1_isr;
    EDIS;

    // Enable global Interrupts and higher priority real-time debug events:
//    IER = M_INT7 ;                                //Enable INT7 (7.1 DMA Ch1)
    EnableInterrupts();

   // Configure the ADC and power it up
    ConfigureADC();

    // Configure the ePWM
    ConfigureEPWM();

    // Setup the ADC for ePWM triggered conversions on channel 0
    SetupADCEpwm();
    //--- Enable the ADC interrupt
    EALLOW;
    PieCtrlRegs.PIEIER1.bit.INTx1 = 1;  // Enable ADCINT in PIE group 1
    IER |= 0x0001;                      // Enable INT1 in IER to enable PIE group
    EDIS;

    DMA_configure();


    // Initialize results buffer
    for(resultsIndex = 0; resultsIndex < RESULTS_BUFFER_SIZE; resultsIndex++)
    {
        AdcaResults[resultsIndex] = 0;
        AdcbResults[resultsIndex] = 0;
        DMABuf1[i] = 0;
    }
    resultsIndex = 0;

    EALLOW;
    // Sync ePWM
    CpuSysRegs.PCLKCR0.bit.TBCLKSYNC = 1;
    EDIS;
    // Start ePWM
    EPwm2Regs.TBCTL.bit.CTRMODE = 0;            // un-freeze and enter up-count mode

    do {

        GpioDataRegs.GPADAT.bit.GPIO31 = 0;     // Turn on LED
        DELAY_US(1000 * 500);                   // ON delay
        GpioDataRegs.GPADAT.bit.GPIO31 = 1;     // Turn off LED
        DELAY_US(1000 * 500);                   // OFF delay

    } while(1);
}




void DMA_configure(void)
{
    EALLOW;
    CpuSysRegs.SECMSEL.bit.VBUS32_1 = 1;
    EDIS;
    DMAInitialize();
    DMA1Source = &AdcaResultRegs.ADCRESULT0;
    DMA1Dest = &DMABuf1[0]; //DMA destination;
    DMACH1AddrConfig(DMA1Dest,DMA1Source);
    // BURST size = 1 | Source step size = 0 | Dest step size += 1
    DMACH1BurstConfig(ONE_WORD_BURST,SOURCE_NO_ADDRESS_CHANGE,DESTINATION_INCREMENT_ONE_ADDRESS);
    // Transfer size = 0x1000 | Source step size = 0 | Dest step size += 1
    DMACH1TransferConfig(TRANSFER_SIZE_256,TRANSFER_STEP_SOURCE_NO_CHANGE,
                                TRANSFER_STEP_DEST_INCREMENT_ONE_ADDRESS);
    DMACH1WrapConfig(0,0,256,256);
    DMACH1ModeConfig(DMA_ADCAINT1,PERINT_ENABLE,ONESHOT_DISABLE,CONT_DISABLE,SYNC_DISABLE,SYNC_SRC,
                     OVRFLOW_DISABLE,SIXTEEN_BIT,CHINT_END,CHINT_ENABLE);
    StartDMACH1();
}



__interrupt void local_DMACH1_ISR(void)
{
    DMA_Done = 0x0001;
    EALLOW;
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP7;
    DmaRegs.CH1.CONTROL.bit.TRANSFERSTS = 1;
    DmaRegs.CH1.CONTROL.bit.RUN = 1;
    EDIS;
//    ESTOP0;
}



//Write ADC configurations and power up the ADC for both ADC A and ADC B
void ConfigureADC(void)
{
    //Device_cal();
    EALLOW;
    AdcaRegs.ADCCTL2.bit.PRESCALE = 6;          // set ADCCLK divider to /4
    AdcaRegs.ADCCTL2.bit.RESOLUTION = 0;        // 12-bit resolution
    AdcaRegs.ADCCTL2.bit.SIGNALMODE = 0;        // single-ended channel conversions (12-bit mode only)
    AdcaRegs.ADCCTL1.bit.INTPULSEPOS = 1;       // Set pulse positions to late
    AdcaRegs.ADCCTL1.bit.ADCPWDNZ = 1;          // power up the ADC

    DELAY_US(1000);                             // delay for 1ms to allow ADC time to power up
    EDIS;

}

void ConfigureEPWM(void)
{
    EALLOW;
    // Assumes ePWM clock is already enabled
    EPwm2Regs.TBCTL.bit.CTRMODE = 3;            // freeze counter
    EPwm2Regs.TBCTL.bit.HSPCLKDIV = 0;          // TBCLK pre-scaler = /1
    EPwm2Regs.TBPRD = 0x0FA0;                   // Set period to 4000 counts (50kHz)
    EPwm2Regs.CMPA.half.CMPA = 0x0800;          // Set compare A value to 2048 counts
    EPwm2Regs.ETSEL.bit.SOCAEN  = 0;            // Disable SOC on A group
    EPwm2Regs.ETSEL.bit.SOCASEL = 4;            // Select SOC on up-count
    EPwm2Regs.ETSEL.bit.SOCAEN = 1;             // enable SOCA
    EPwm2Regs.ETPS.bit.SOCAPRD = 1;             // Generate pulse on 1st event
    EDIS;
}

void SetupADCEpwm(void)
{
    EALLOW;
    AdcaRegs.ADCSOC0CTL.bit.CHSEL = 0;          // SOC0 will convert pin A0
    AdcaRegs.ADCSOC0CTL.bit.ACQPS = 14;         // sample window is 15 SYSCLK cycles
    AdcaRegs.ADCSOC0CTL.bit.TRIGSEL = 7;        // trigger on ePWM2 SOCA/C
    AdcaRegs.ADCINTSEL1N2.bit.INT1SEL = 0;      // end of SOC0 will set INT1 flag
    AdcaRegs.ADCINTSEL1N2.bit.INT1E = 1;        // enable INT1 flag
    AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1;      // make sure INT1 flag is cleared

    EDIS;
}

interrupt void adca1_isr(void)
{
    // Read the ADC result and store in circular buffer
    AdcaResults[resultsIndex++] = AdcaResultRegs.ADCRESULT0;
    if(RESULTS_BUFFER_SIZE <= resultsIndex)
    {
        resultsIndex = 0;
    }

    // Return from interrupt
    AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1;      // Clear INT1 flag
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;     // acknowledge PIE group 1 to enable further interrupts
}

 // end of file

  • Hi King Kong,

    DMA doesn't have access to every memory location. One safe location to use for DMA is the global shared memory (GS). This means in your code, you have to link the DMA buffer into one of the GSM eg: RAMGS0. 

    I added this line->

    #pragma

    DATA_SECTION(DMABuf1,"SecureRam0");

    Uint16 DMABuf1[RESULTS_BUFFER_SIZE];

    I have attached the code with the changes. This should work. You also have to add a line like this to your linker file in the "SECTIONS" section

    8306.Test.c
    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #include "F28x_Project.h" // Device Headerfile and Examples Include File
    //#include "F2837xD_struct.h"
    //#include "F2837xD_Dma_defines.h"
    // function prototypes
    void ConfigureADC(void);
    void ConfigureEPWM(void);
    void ConfigureDAC(void);
    void SetupADCEpwm(void);
    interrupt void adca1_isr(void);
    // variables
    #define RESULTS_BUFFER_SIZE 256
    #define MAX_SAMPLES 1024
    #define ONE_WORD_BURST 0 // 16-bit word per burst
    #define TWO_WORD_BURST 1 // 32-bit word per burst
    #define SOURCE_NO_ADDRESS_CHANGE 0
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    ->

    SecureRam0 : > RAMGS0 PAGE = 1

    Regards,

    Frank

  • Thank you so much Frank, I will try it tomorrow. Have a good day.

  • Hi Frank,

    Thanks again, your advice is working very well.

    Now I'm  moving to seek a way to avoid the calling of ADC's interruption function with every EOC.

    Bests,

    King

  • Hi King Kong,

    Glad i could help. About the ADC, i'm not exactly sure what you are trying to achieve with it but looking through your code, it looks like you want to oversample one channel. To avoid calling the ADC interrupt after every EOC, you could setup SOC1-SOC15 to sample the same channel (this is effectively oversampling) and setup the ADC interrupt to trigger after EOC15. Keep in mind that if you do it this way, you would have to reconfigure the DMA to transfer 16 words after every trigger instead of just 1.  

    Regards,

    Frank

  • Dear Frank,

    I got the same result by myself, and it is similar you suggested.

    Basically I am using EPwm2.SOCA to trigger the ADC, and at the same time, use the same SOCA to trigger the DMA. Since the ADC result will have one trigger delay, the first value read by DMA has no meaning (trigger1->DMA read0 and ADC convert1; trigger2->DMA read1 and ADC convert2, and so on). In this case I disabled the interrupt of ADC(from EOC), so the ADC interrupt function will not be called anymore.

    Thanks a lot for your help, I appreciate. Have a good day :)

    Sincerely,

    King