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
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!
-----------------------------------------------------------------------------------------------------------------------
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 sourceRegards
Mark