K20 having issues linking ADC channels with eDMA

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

K20 having issues linking ADC channels with eDMA

Jump to solution
1,152 Views
brentwilliams
Contributor II

Hi, I am using a K20.

I want to set up the ADC so that I can use DMA to load TCD as well as for  writing the ADC results to SRAM (i.e. utilizing linking of channels).

Specifically I have a array of 3 DMA TCDs = used to load ADC0_SC1A, with  an array of 3 16 bit words for the ADC results.

I have tried following the "Using DMA to Emulate ADC Flexible Scan Mode on Kinetis K Series" app note without success.

What I am seeing is that I get two ADC interrupts (used only for debug) before I get the DMA interrupt signifying the end of my major loop.

I have 3 ADC result values in my SRAM buffer.  I would assume I would get 3 ADC interrupts.  One for each of the TCD mux values loaded into the ADC0_SC1A register.

  DMA0_TCD0_CSR - 0x00 indicating that it is NOT done

  DMA0_TCD1_CSR - 0x82 indicating that the major loop is done

  DMA0_TCD0_CITER_ELINKYES = 0x0001 indicating I have one more TCD to load.

Looking at ADC0_SC1A = 65 (the second element in my MUX array)

My code is below.  Any insight would be welcomed.

volatile unsigned short ui_adc_result[NUM_CHANNELS] = {0};

volatile unsigned char uc_adc_mux[NUM_CHANNELS] = {

  64,

  65,

  66

};

void ADCSetup_InitADC(void)

{

    // ADC 0:

    // enable clock gate control for ADC 0

    SIM_SCGC6 |= SIM_SCGC6_ADC0_MASK;          

    NVICISER1 |= (1<<25);   // Set Enable Register

    NVICICPR1 |= (1<<25);   // Clear Pending Register

    NVICIP57   = 0x10;

               

    // Normal Power

    // Divide by one

    // Short Sample Time

    // 12 bit conversion

    // Bus clock divided by 2--12.5 MHz

    ADC0_CFG1 = 0x0005;

    // Select ADC Mux A*

    // Asynchronous Clock Output disabled

    // Normal conversion

    // shortest sample time selected*

    ADC0_CFG2 = 0x0003;

               

    // Software Trigger selected

    // Compare fx disabled

    // DMA enabled

    // Voltage reference section is default*

    ADC0_SC2 = 0x0004;

               

    // Continuous Conversion disabled--i.e. do single conversion

    // Hardware average disabled

    ADC0_SC3 = 0;

    // select channel--0x1F disables

    // enable in timer interrupt

    ADC0_SC1A = 0x1F;                                                        

    // select channel--0x1F disables

    // enable in timer interrupt

    ADC0_SC1B = 0x1F;                                                        

    // Programmable Gain Amplifier is disabled

    ADC0_PGA = 0;

    // enable clock gate control for DMA Mux

    SIM_SCGC6 |= SIM_SCGC6_DMAMUX_MASK;

               

    // enable clock gate control for DMA Module

    SIM_SCGC7 |= SIM_SCGC7_DMA_MASK;           

    // Clear All Enable Error Interrupts

    DMA_CEEI |= 0x40;

    DMA_CERR |= 0x40;

               

    //****************************************************************************

    //**** DMA channel 0, use for Write ADC mux channel, from SRAM to ADC ********

    //****************************************************************************

    DMAMUX_CHCFG0 = 0x00;

               

    // DMA source DMA Mux (54)

    DMAMUX_CHCFG0 = DMAMUX_CHCFG_ENBL_MASK|DMAMUX_CHCFG_SOURCE(0x36);  

                               

    // SADDR is a 32 bit number

    // New mux setting

    DMA_TCD0_SADDR          = (Uint32) &uc_adc_mux[0];                           

    // SOFF is a signed 16 bit number

    // Source address increment, adding "1"

    DMA_TCD0_SOFF           = 0x01;                                              

    // SLAST is signed 32 bit number

    // Source address decrement after major loop complete

    DMA_TCD0_SLAST          = (Uint32)-3;                                        

    // DADDR is a 32 bit number

    // SC1A is a 32 bit number with only the meaning only in the LSbyte

    DMA_TCD0_DADDR             = (Uint32) &ADC0_SC1A;                                       // Destination address ADC0 mux selector

    DMA_TCD0_DOFF               = 0x00; // always the same destination--SC1A          // Destination address increment, adding "0"

    DMA_TCD0_DLASTSGA       = 0x00; // always the same destination--SC1A          // Destination address shift, go to back to [0]

    DMA_TCD0_NBYTES_MLNO    = 0x01; // No of bytes minor loop

    DMA_TCD0_BITER_ELINKNO  = 0x03; // Major loop step, 3 ADC channel are scanning

    DMA_TCD0_CITER_ELINKNO  = 0x03; // Major loop step, 3 ADC channel are scanning

               

    // 0 = 8 bit

    // 1 = 16 bit

    // 2 = 32 bit

    DMA_TCD0_ATTR           = DMA_ATTR_SSIZE(0)|DMA_ATTR_DSIZE(0);  // Source a destination size, 8bit

    DMA_TCD0_CSR            = 0x0000;                              

               

    //****************************************************************************

    //**** DMA channel 1, use for Read ADC result data, form ADC to SRAM *********

    //****************************************************************************

    NVICISER0 |= (1<<1); // Set Enable Register

    NVICICPR0 |= (1<<1); // Clear Pending Register

    NVICIP1 = 0x20;      // Interrupt Priority--priority 0 is the highest, 15 is the lowest (Most Significant Nibble is priority)

    DMAMUX_CHCFG1                  = 0x00;

    DMAMUX_CHCFG1                  = DMAMUX_CHCFG_ENBL_MASK|DMAMUX_CHCFG_SOURCE(0x28); // DMA source ADC0  (40)

    DMA_TCD1_SADDR                 = (Uint32) &ADC0_RA;                                                                        // Source address ADC0 result register

    DMA_TCD1_SOFF                    = 0x00;  // always the same source--ADC0_RA                                    // Source address increment, adding "0"

    DMA_TCD1_SLAST                  = 0x00;  // always the same source--ADC0_RA                                     // Source address decrements after major loop complete

    DMA_TCD1_DADDR                 = (Uint32) &ui_adc_result[0];                                                               // Destination address, ADC0 result buffer

    DMA_TCD1_DOFF                    = 0x02;                                                                                             // Destination address increment, adding "+2"

    DMA_TCD1_DLASTSGA           = (Uint32) -6;                                                                                     // Destination address decrements after major loop complete

    DMA_TCD1_NBYTES_MLNO    = 0x02;                                                                                             // No of bytes minor loop, 16 bit ADC result

    DMA_TCD1_BITER_ELINKNO   = (DMA_BITER_ELINKNO_ELINK_MASK|0x0000|0x03);                       // Channel 0 Link, Channel 0, Major loop step 3

    DMA_TCD1_CITER_ELINKNO   = (DMA_CITER_ELINKNO_ELINK_MASK|0x03);                                  // Channel 0 Link, Major loop step 3

    DMA_TCD1_ATTR                    = DMA_ATTR_SSIZE(0)|DMA_ATTR_DSIZE(0);                                    // Source a destination size, 16 bit

    DMA_TCD1_CSR                     = DMA_CSR_INTMAJOR_MASK;

    DMA_ERQ                              |= DMA_ERQ_ERQ1_MASK;                                                             // HW request enable

    DMA_CINT                               = DMA_CINT_CINT(1);                                                                     // Clear the interrupt flag for channel 1

}

__ramfunc void dma_ch1_isr( void )

{

  DMA_CINT = DMA_CINT_CINT(1);  // clear the interrupt flag for channel 1      

}

volatile int adcIntCount = 0;

__ramfunc void adc0_isr( void )

{

  adcIntCount++;

}

__ramfunc void Timers_isr( void )

{

  if( DMA_INT == 0 )         

      DMA_SSRT = 0x01; // start DMA channel 0, which triggers another round of ADC readings

}

_

1 Solution
541 Views
alejandrolozan1
NXP Employee
NXP Employee

Hi Brent,

How are you starting the first DMA transfer?

As far as I see, you want to perform the next:

DMA channel 0 transfer value of ADC channel to ADC_SC1A then the ADC will trigger the DMA channel 1 to store the results.

This configuration seems to be correct. But I see that you are using a timer ISR to write in the SSRT to trigger a DMA transfer by software.

But I believe you are starting channel 1, not 0.

Maybe you can try with:

  DMA_SSRT = 0x00;

View solution in original post

0 Kudos
3 Replies
541 Views
brentwilliams
Contributor II

Hi Alejandro,

I am seeing something unexpected.  I am trying to configure ADC1 to use DMA channels 6 and 7 along with DMA_MUX 6.  DMA channel 6 points to a mux of ADC 1 channels.  The MUX has 12 channels for ADC1.  DMA channel 7 points to ADC1_RA. 

What I am seeing when I get my DMA channel 7 interrupt is the following (see inserted screen shot of DMA registers below):

             DMA_TCD7_CSR = 0x82 => GOOD – MAJOR COMPLETE AND GET INTERRUPT

DMA_TCD6_CSR = 0x00 => BAD, DID NOT INDICATE MAJOR WAS COMPLETE, EXPECTING 0x80

DMA_TCD0_CSR = 0x80 => WHY IS THIS UPDATED???  THIS IS SAYING DMA channel 0 completed a MAJOR LOOP I DID NOT CONFIGURE THIS

I am not sure why anything is happening on DMA channel 0??  I am not configuring it at all.  My configuration of ADC1 and DMA channels/MUX is below:

//*************************************************************************
// configure ADC1
//*************************************************************************
// enable clock gate control for ADC1
SIM_SCGC3 |= SIM_SCGC3_ADC1_MASK;

// set up the ADC1 interrupt
// BAW only used for debug
NVICISER1 |= (1<<26);// Set Enable Register
NVICICPR1 |= (1<<26);// Clear Pending Register
NVICIP58   = 0x10;
// Normal Power
// Divide by one
// Short Sample Time
// 12 bit conversion
// Bus clock divided by 2--12.0 MHz
ADC1_CFG1 = 0x0005;

// Select ADC Mux A*
// Asynchronous Clock Output disabled
// Normal conversion
// shortest sample time selected*

ADC1_CFG2 = 0x0003;

// Software Trigger selected
// Compare fx disabled
// DMA enabled
// Voltage reference section is default*

ADC1_SC2 = 0x0004;

// Continuous Conversion disabled--i.e. do single conversion
// Hardware average disabled
ADC1_SC3 = 0;

// select channel--0x1F disables (Chapter 3 in RM: 3.7.1.3.1.1 for 64 pin package)
ADC1_SC1A = 0x1F;

// select channel--0x1F disables (Chapter 3 in RM: 3.7.1.3.1.1 for 64 pin package)
ADC1_SC1B = 0x1F;

// Programmable Gain Amplifier is disabled
ADC1_PGA = 0;

// enable clock gate control for DMA Mux
SIM_SCGC6 |= SIM_SCGC6_DMAMUX_MASK;
// enable clock gate control for DMA Module
SIM_SCGC7 |= SIM_SCGC7_DMA_MASK;

DMA_CEEI |= 0x40;
DMA_CERR |= 0x40;

//*************************************************************************
//**** DMA channel 6, use for Write ADC mux channel, from SRAM to ADC *****
//*************************************************************************
DMAMUX_CHCFG6 = 0x00;

// DMA source DMA Mux (60)

DMAMUX_CHCFG6 = DMAMUX_CHCFG_ENBL_MASK|DMAMUX_CHCFG_SOURCE(0x3C);  

// SADDR is a 32 bit number

// New mux setting
DMA_TCD6_SADDR          = (Uint32) &uc_adc_mux2[1];                           

// SOFF is a signed 16 bit number
// Source address increment, adding "1"
DMA_TCD6_SOFF           = 0x01;                                              

// SLAST is signed 32 bit number
// Source address decrement after major loop complete
DMA_TCD6_SLAST          = (Uint32) (-NUM_CHANNELS+1);                                       

// DADDR is a 32 bit number
// SC1A is a 32 bit number with only the meaning only in the LSbyte
DMA_TCD6_DADDR          = (Uint32) &ADC1_SC1A;                           // Destination address ADC1 mux selector
DMA_TCD6_DOFF           = 0x00;// always the same destination--SC1A     // Destination address increment, adding "0"
DMA_TCD6_DLASTSGA       = 0x00; // always the same destination--SC1A     // Destination address shift, go to back to [0]

DMA_TCD6_NBYTES_MLNO    = 0x01;             // No of bytes minor loop
DMA_TCD6_BITER_ELINKNO  = (NUM_CHANNELS-1); // Major loop step, 3 ADC channel are scanning
DMA_TCD6_CITER_ELINKNO  = (NUM_CHANNELS-1); // Major loop step, 3 ADC channel are scanning
// 0 = 8 bit
// 1 = 16 bit
// 2 = 32 bit
DMA_TCD6_ATTR           = DMA_ATTR_SSIZE(0)|DMA_ATTR_DSIZE(0);  // Source a destination size, 8bit
DMA_TCD6_CSR            = 0x0000;                              
//*************************************************************************
//**** DMA channel 7, use for Read ADC result data, form ADC to SRAM ******
//*************************************************************************
NVICISER0 |= (1<<7);// Set Enable Register
NVICICPR0 |= (1<<7);// Clear Pending Register
NVICIP7 = 0x20;    // Interrupt Priority--priority 0 is the highest, 15 is the lowest (Most Significant Nibble is priority)

DMAMUX_CHCFG7           = 0x00;
DMAMUX_CHCFG7           = DMAMUX_CHCFG_ENBL_MASK|DMAMUX_CHCFG_SOURCE(0x29);   // DMA source ADC1  (41)
DMA_TCD7_SADDR          = (Uint32) &ADC1_RA;                                  // Source address ADC1 result register
DMA_TCD7_SOFF           = 0x00;// always the same source--ADC1_RA            // Source address increment, adding "0"
DMA_TCD7_SLAST          = 0x00;// always the same source--ADC1_RA            // Source address decrement after major loop complete

DMA_TCD7_DADDR          = (Uint32) &ui_adc_result2[0];                         // Destination address, ADC1 result buffer
DMA_TCD7_DOFF           = 0x02;                                               // Destination address increment, adding "+2"

DMA_TCD7_DLASTSGA       = (Uint32) -(NUM_CHANNELS*2);                         // Destination address decrement after major loop complete

DMA_TCD7_NBYTES_MLNO    = 0x02;                                               // No of bytes minor loop, 16 bit ADC result

DMA_TCD7_BITER_ELINKNO  = (DMA_BITER_ELINKNO_ELINK_MASK|0x0000|NUM_CHANNELS); // Channel 0 Link, Channel 0, Major loop step NUM_CHANNELS
DMA_TCD7_CITER_ELINKNO  = (DMA_CITER_ELINKNO_ELINK_MASK|NUM_CHANNELS);        // Channel 0 Link, Major loop step NUM_CHANNELS
DMA_TCD7_ATTR           = DMA_ATTR_SSIZE(1)|DMA_ATTR_DSIZE(1);                // Source a destination size, 16 bit

DMA_TCD7_CSR            = DMA_CSR_INTMAJOR_MASK;  

DMA_ERQ                |= DMA_ERQ_ERQ7_MASK;                                  // HW request enable
DMA_CINT                = DMA_CINT_CINT(7);                                  // Clear the interrupt flag for channel 7
DMA_CINT                = DMA_CINT_CINT(7);                                  // Clear the interrupt flag for channel 7

}

DMA7.png

0 Kudos
542 Views
alejandrolozan1
NXP Employee
NXP Employee

Hi Brent,

How are you starting the first DMA transfer?

As far as I see, you want to perform the next:

DMA channel 0 transfer value of ADC channel to ADC_SC1A then the ADC will trigger the DMA channel 1 to store the results.

This configuration seems to be correct. But I see that you are using a timer ISR to write in the SSRT to trigger a DMA transfer by software.

But I believe you are starting channel 1, not 0.

Maybe you can try with:

  DMA_SSRT = 0x00;

0 Kudos
541 Views
brentwilliams
Contributor II

Thank you Alejandro.