What is the most efficient way to perform bulk DMA transfers from the ADC on the K64?

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

What is the most efficient way to perform bulk DMA transfers from the ADC on the K64?

Jump to solution
1,534 Views
alistair_lowe
Contributor I

Hi guys,

I'm wishing to sample audio at 20KHz on a single 16-bit ADC channel. I would like to gather, in RAM, 64 to 128 samples (128B to 256B) before raising an interrupt from the DMA to trigger an FFT. What's the most efficient/effective way (energy and least CPU interruption) to configure the DMA to achieve this?

i.e. Is this a 128 minor loop iteration or 2 minor and 64 major loops scenario etc?

Many thanks

Labels (1)
Tags (4)
0 Kudos
1 Solution
1,049 Views
EarlOrlando
Senior Contributor II

Hello,

I agree with Mark. Just to translate it into register terms, you need to configure the (ping pong) buffer with a major loop of 256 iterations and enable the DMA_TCDn_CSR[INTHALF] and the DMA_TCDn_CSR[INTMAJOR] flags to get an interrupt every 128 samples.

Best regards,

Earl Ramírez.

View solution in original post

0 Kudos
4 Replies
1,049 Views
alistair_lowe
Contributor I

Thank you very much guys, working a charm.

Will post my code example once I've tidied it up a little.

0 Kudos
1,048 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Alistair,

As Mark said you have to use a timer for example PDB, FTM, PIT to generate triggering signal to ADC converter with 20KHz frequency by setting the SIM_SOPT7 for K64 processor. You have to  configure the ADC in hardware trigger mode, and set the DMAEN bit in ADCx_SC2 so that the ADC can trigger DMA after the conversion is over. For the DMA setting, the DMA channel only transfer one data per DMA triggering signal, so you do not need use minor loop(minor loop is disabled),  the DMA_TCDn_NBYTES_MLNO register can be 2 so that the DMA will transfer 16 bits sample from ADC_Ra each times. If you want to get 128 samples, you can set the BITER bits in DMA_TCDn_BITER_ELINKYES as 128, and enable interrupt by setting the INTMAJOR bit in DMA_TCDn_CSR so that an interrupt from DMA can be triggered after 128 samples have been transferred.

Regard FFT, we provide CMSIS library in SDK, which provide the FFT code as the following code.

Hope it can help you.

BR

Xiangjun Rong

/* Including needed modules to compile this module/procedure */

#include "Cpu.h"

#include "Events.h"

#include "clockMan1.h"

#include "pin_init.h"

#include "osa1.h"

#if CPU_INIT_CONFIG

  #include "Init_Config.h"

#endif

/* User includes (#include below this line is not maintained by Processor Expert) */

#include "arm_math.h"

#include "arm_const_structs.h"

#define PI 3.141592

#define TEST_LENGTH_SAMPLES 32

#define COSGENERATED

/* -------------------------------------------------------------------

* External Input and Output buffer Declarations for FFT Bin Example

* ------------------------------------------------------------------- */

arm_rfft_fast_instance_f32 fS;

extern float32_t testInput[TEST_LENGTH_SAMPLES];

static float32_t testOutput[TEST_LENGTH_SAMPLES];

static float32_t magtestOutput[TEST_LENGTH_SAMPLES/2];

/* ------------------------------------------------------------------

* Global variables for FFT Bin Example

* ------------------------------------------------------------------- */

uint32_t fftSize = 32;

uint32_t ifftFlag = 0;

uint32_t doBitReverse = 1;

/* Reference index at which max energy of bin ocuurs */

uint32_t refIndex = 213, testIndex = 0;

arm_status status;

float32_t maxValue;

/* ----------------------------------------------------------------------

* Max magnitude FFT Bin test

* ------------------------------------------------------------------- */

/*lint -save  -e970 Disable MISRA rule (6.3) checking. */

int main(void)

/*lint -restore Enable MISRA rule (6.3) checking. */

{

        unsigned int i,harmonic_index;

  /* Write your local variable definition here */

    float32_t maxValue,temp,sum_cos15,sum_sin15;

    status = ARM_MATH_SUCCESS;

  /*** Processor Expert internal initialization. DON'T REMOVE THIS CODE!!! ***/

  PE_low_level_init();

  /*** End of Processor Expert internal initialization.                    ***/

  /* Write your code here */

  /* For example: for(;;) { } */

  sum_cos15=0;

  sum_sin15=0;

    status = ARM_MATH_SUCCESS;

#ifndef COSGENERATED

    for(i=0; i<32; i++)

    {

        testInput[i]=testInput[i]-0.25;

    }

#else

    for(i=0; i<32; i++)

    {

        temp=((float)i)*(2.0*PI/32.0);

        __asm("nop");

        testInput[i]=arm_cos_f32(temp);

    }

    //get harmonic sin/cos component,

    //compute foundmental and 15th harmonic

    harmonic_index=1;

//   harmonic_index=15;

    for(i=0; i<32; i++)

    {

        temp=((float)(harmonic_index*i))*(2.0*PI/32.0);

        sum_cos15=sum_cos15+testInput[i]*arm_cos_f32(temp);

        sum_sin15=sum_sin15+testInput[i]*arm_sin_f32(temp);

    }

    __asm("nop");

#endif

    status= arm_rfft_fast_init_f32(&fS,32);

    if(status!=ARM_MATH_SUCCESS)

    {

        __asm("nop"); //error occured

    }

    arm_rfft_fast_f32(&fS,&testInput[0], &testOutput[0],0);

    __asm("nop");

    /* Process the data through the Complex Magnitude Module for

    calculating the magnitude at each bin */

    arm_cmplx_mag_f32(&testOutput[0], &magtestOutput[0], 16);

    __asm("nop");

    /* Calculates maxValue and returns corresponding BIN value */

    arm_max_f32(&magtestOutput[0], fftSize/2, &maxValue, &testIndex);

    __asm("nop");

    if(testIndex !=  refIndex)

    {

      status = ARM_MATH_TEST_FAILURE;

    }

    /* ----------------------------------------------------------------------

    ** Loop here if the signals fail the PASS check.

    ** This denotes a test failure

    ** ------------------------------------------------------------------- */

    if( status != ARM_MATH_SUCCESS)

    {

      while(1);

    }

    while(1);                             /* main function does not return */

  /*** Don't write any code pass this line, or it will be deleted during code generation. ***/

  /*** RTOS startup code. Macro PEX_RTOS_START is defined by the RTOS component. DON'T MODIFY THIS CODE!!! ***/

  #ifdef PEX_RTOS_START

    PEX_RTOS_START();                  /* Startup of the selected RTOS. Macro is defined by the RTOS component. */

  #endif

  /*** End of RTOS startup code.  ***/

  /*** Processor Expert end of main routine. DON'T MODIFY THIS CODE!!! ***/

  for(;;){}

  /*** Processor Expert end of main routine. DON'T WRITE CODE BELOW!!! ***/

} /*** End of main routine. DO NOT MODIFY THIS TEXT!!! ***/

0 Kudos
1,049 Views
mjbcswitzerland
Specialist V

Alistair

You need to configure for 128 itterations since you can only have a minor loop count of 1 due to the fact that you only have 1 sample ready at each trigger.

For such applications is is generally best to have a DMA ping-pong buffer so that the second buffer continues collecting data while the first one is being processed (eg. by your FFT).That means having a circular buffer of 2 x 128 and two interrupts - one after the first 128 have been collected and one after the complete buffer is full.

This is described in chapter 3 of http://www.utasker.com/docs/uTasker/uTaskerADC.pdf

The processor can "sleep" between the two interrupts when it hasn't anything else to do and the DMA configuration (minor / major loops) will not have any impact on the overall processor power consumption.

Regards

Mark

0 Kudos
1,050 Views
EarlOrlando
Senior Contributor II

Hello,

I agree with Mark. Just to translate it into register terms, you need to configure the (ping pong) buffer with a major loop of 256 iterations and enable the DMA_TCDn_CSR[INTHALF] and the DMA_TCDn_CSR[INTMAJOR] flags to get an interrupt every 128 samples.

Best regards,

Earl Ramírez.

0 Kudos