KINETIS MK12DN512VMC5 - ADC WITH DMA

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

KINETIS MK12DN512VMC5 - ADC WITH DMA

1,159 Views
avivagam
Contributor I

Hi all,

My project based on MK12DN512VMC5 MCU and I want to change the ADC method from interrupt (via internal timer) to DMA due to

the need to increase the sampling rate to 10 KHz to 7 ADC channels serially (it’s mean 70KHz sampling rate…).

I am trying to implement sampling with DMA that will bring me interrupt after the sampling buffer is full ( 7 channels, 4 samples each)

I am trying to use software trigger for ADC, following my ADC code:

  Master_Adc_Config.CONFIG1  = ADLPC_NORMAL | ADC_CFG1_ADIV(ADIV_1) | /* ADLSMP_SHORT*/ ADLSMP_LONG| ADC_CFG1_MODE(MODE_16) | ADC_CFG1_ADICLK(ADICLK_BUS);

  Master_Adc_Config.CONFIG2  = MUXSEL_ADCA | ADACKEN_DISABLED | ADHSC_HISPEED | ADC_CFG2_ADLSTS(ADLSTS_2) ;

  Master_Adc_Config.COMPARE1 = 0x1234u ;

  Master_Adc_Config.COMPARE2 = 0x5678u ;

  Master_Adc_Config.STATUS2  = ADTRG_SW | ACFE_DISABLED | ACFGT_GREATER | ACREN_DISABLED | DMAEN_ENABLED | ADC_SC2_REFSEL(REFSEL_EXT);

  Master_Adc_Config.STATUS3  = CAL_OFF | ADCO_SINGLE | /*AVGE_ENABLED*/AVGE_DISABLED | ADC_SC3_AVGS(AVGS_4);

  Master_Adc_Config.STATUS1A = AIEN_ON | DIFF_SINGLE | ADC_SC1_ADCH(SNSR_1);

  Master_Adc_Config.STATUS1B = AIEN_ON | DIFF_SINGLE | ADC_SC1_ADCH(SNSR_1);

 

In addition i am trying to use 2 DMA channels in order to get continuous scan mode, following my DMA initialization code:

(void DMACH0_CH1_Init(void
}
  //****************************************************************************
  //**** DMA channel 0, use for Write ADC mux channel, form SRAM to ADC ********
  //****************************************************************************
  DMAMUX_CHCFG0           = DMAMUX_CHCFG_ENBL_MASK|DMAMUX_CHCFG_SOURCE(0x36);   //DMA source DMA Mux
  DMA_TCD0_SADDR          = (uint32) &uc_adc_mux[0];                            //New mux setiing
  DMA_TCD0_SOFF           = 0x01;                                               //Source address increment, adding "1"
  DMA_TCD0_SLAST          = (uint32) -7;                                        //Source address decrement after major loop complete
  DMA_TCD0_DADDR          = (uint32) &ADC0_SC1A;                                //Destination address ADC0 mux selector
  DMA_TCD0_DOFF           = 0x00;                                               //Destination address increment, adding "0"
  DMA_TCD0_DLASTSGA       = 0x00;                                               //Destination address shift, go to back to [0]
  DMA_TCD0_NBYTES_MLNO    = 0x02;                                               //No of bytes minor loop
  DMA_TCD0_BITER_ELINKNO  = 0x07;                                               //Major loop step, 7 ADC channel are scaning
  DMA_TCD0_CITER_ELINKNO  = 0x07;                                               //Major loop step, 7 ADC channel are scaning
  DMA_TCD0_ATTR           = DMA_ATTR_SSIZE(1)|DMA_ATTR_DSIZE(1);                //Source a destination size, 16bit
  DMA_TCD0_CSR            = 0x0000;                                             //
 
  //****************************************************************************
  //**** DMA channel 1, use for Read ADC result data, form ADC to SRAM *********
  //****************************************************************************
  NVIC_SetIsr(INT_DMA1,2);                                                      //17


  DMAMUX_CHCFG1           = DMAMUX_CHCFG_ENBL_MASK|DMAMUX_CHCFG_SOURCE(0x28);   //DMA source ADC0
  DMA_TCD1_SADDR          = (uint32) &ADC0_RA;                                  //Source address ADC0 result register
  DMA_TCD1_SOFF           = 0x00;                                               //Source address increment, adding "0"
  DMA_TCD1_SLAST          = 0x00;                                               //Source address decrement 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) -24;                                       //Destination address decrement after major loop complete
  DMA_TCD1_NBYTES_MLNO    = 0x02;                                               //No of bytes minor loop, 16bit ADC result
  DMA_TCD1_BITER_ELINKNO  = (DMA_BITER_ELINKNO_ELINK_MASK|0x0000|0x1C);         //Channel 0 Link, Channel 0, Major loop step 7 x 4 = 28
  DMA_TCD1_CITER_ELINKNO  = (DMA_CITER_ELINKNO_ELINK_MASK|0x1C);                //Channel 0 Link, Major loop step 7 x 4 = 28
  DMA_TCD1_ATTR           = DMA_ATTR_SSIZE(1)|DMA_ATTR_DSIZE(1);                //Source a destination size, 16bit
  DMA_TCD1_CSR            = (DMA_CSR_MAJORLINKCH(0)|DMA_CSR_MAJORELINK_MASK)|   //Major loop finished start request for Channel 0
                            DMA_CSR_INTMAJOR_MASK; //|DMA_CSR_INTHALF_MASK;     //Irq. enable, full transfer, half complet transfer
  DMA_ERQ                |= DMA_ERQ_ERQ1_MASK;                                  //HW request enable
{

for some reason I am not getting interrupt via the DMA isr:

(void dma_ch1_isr(void

}

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

{

...What is not Ok with my initialization code? I tried to refer AN4590

0 Kudos
Reply
2 Replies

786 Views
jeremyzhou
NXP Employee
NXP Employee

Hi Aviv,

I'd highly recommend you to check the end up value of the DMA registers versus the beginning.

As Mark pointed out, you also should check out the configuration of the DMA interrupt.

Hope it helps.
Have a great day,
Ping

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos
Reply

786 Views
mjbcswitzerland
Specialist V

Hi

I didn't notice any error but you should check the DMA status register when it operates to be sure that the DMA is not failing and thus the end of the buffer not being reached. Aso it is not possible to confirm whether you have configured the DMA interrupts correcty in the NVIC.

Below is the generic Peripheral<-> Circular Buffer DMA configuration for K parts from the uTasker project which you can compare to and possibly find a discrepancy in your code.

    KINETIS_DMA_TDC *ptrDMA_TCD = (KINETIS_DMA_TDC *)eDMA_DESCRIPTORS;
    ptrDMA_TCD += ucDMA_channel;
    if (iOutput != 0) {                                                  // buffer to fixed output
        ptrDMA_TCD->DMA_TCD_SOFF = 2;                                    // source increment one word (buffer)
        ptrDMA_TCD->DMA_TCD_DOFF = 0;                                    // destination not incremented
    }
    else {                                                               // fixed input to buffer
        ptrDMA_TCD->DMA_TCD_SOFF = 0;                                    // source not incremented
        ptrDMA_TCD->DMA_TCD_DOFF = 2;                                    // destination increment one word (buffer)
    }
    ptrDMA_TCD->DMA_TCD_ATTR = (DMA_TCD_ATTR_DSIZE_16 | DMA_TCD_ATTR_SSIZE_16); // transfer sizes always words
    ptrDMA_TCD->DMA_TCD_SADDR = (unsigned long)ptrBufSource;             // source buffer
    ptrDMA_TCD->DMA_TCD_NBYTES_ML = 2;                                   // each request starts a single transfer of a word
    _DMA_handler[ucDMA_channel] = int_handler;                           // user interrupt callback
    if (int_handler != 0) {                                              // if there is a buffer interrupt handler at the end of DMA buffer operation
        if (iHalfBufferInterrupt != 0) {
            ptrDMA_TCD->DMA_TCD_CSR = (DMA_TCD_CSR_INTMAJOR | DMA_TCD_CSR_INTHALF); // interrupt when the transmit buffer is half full (and when full)
        }
        else {
            ptrDMA_TCD->DMA_TCD_CSR = (DMA_TCD_CSR_INTMAJOR);            // interrupt when the transmit buffer is full
        }
        fnEnterInterrupt((irq_DMA0_ID + ucDMA_channel), int_priority, (void (*)(void))_DMA_Interrupt[ucDMA_channel]); // enter DMA interrupt handler on ful/half buffer completion
    }
    else {
        ptrDMA_TCD->DMA_TCD_CSR = 0;                                     // free-running mode without any interrupt
    }
    ptrDMA_TCD->DMA_TCD_DADDR = (unsigned long)ptrBufDest;               // destination
    ptrDMA_TCD->DMA_TCD_DLASTSGA = 0;                                    // no destination displacement on transmit buffer completion
    ptrDMA_TCD->DMA_TCD_SLAST = (-(signed long)(ulBufLength));           // when the buffer has been transmitted set the destination back to the start of it
    ptrDMA_TCD->DMA_TCD_BITER_ELINK = ptrDMA_TCD->DMA_TCD_CITER_ELINK = (signed short)(ulBufLength/sizeof(signed short)); // the number of service requests
    POWER_UP(6, SIM_SCGC6_DMAMUX0);                                      // enable DMA multiplexer 0
    *(unsigned char *)(DMAMUX0_BLOCK + ucDMA_channel) = (ucDmaTriggerSource | DMAMUX_CHCFG_ENBL); // connect trigger source to DMA channel
    DMA_ERQ |= (DMA_ERQ_ERQ0 << ucDMA_channel);                          // enable request source

Regards

Mark

0 Kudos
Reply