ADC-DMA Trigger

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

ADC-DMA Trigger

1,930 Views
schw_gld
Contributor II

Hello,

I am trying to implement an ADC driver on a Kinetis MK22FN512M12.
The ADC is configured once and should be hardware triggered by the PIT. The ADC should then send a DMA request on conversion complete to readout the result.


The PIT triggering and ADC conversion seems to run properly. Also the DMA executes one minor loop correctly when I write a '1' to the DMA channel start register:

 DMA0->TCD[SYSTEM_AUDIOADC_DMA_CHANNEL].CSR |= DMA_CSR_START(1);

Unfortunately, the ADC DMA request does not seem to work. The DMA Multiplexer is configured as

DMAMUX->CHCFG[SYSTEM_AUDIOADC_DMA_CHANNEL] = 0;

DMAMUX->CHCFG[SYSTEM_AUDIOADC_DMA_CHANNEL] |= 28; // for ADC0

DMAMUX->CHCFG[SYSTEM_AUDIOADC_DMA_CHANNEL] |= DMAMUX_CHCFG_ENBL_MASK;

and the ADC is configured to send a DMA request on COCO:

ADC0->SC2 = ADC_SC2_ADTRG_MASK | ADC_SC2_DMAEN_MASK;

The clocks are ungated. The COCO flag is asserted all the time because the result register is never read out. I really don't want to fall back to interrupts (which would work fine btw) for efficiency reasons.

If you need further information about my code, feel free to ask!

Can anyone help me with my

Thank you in advance!

Labels (1)
Tags (3)
5 Replies

1,117 Views
schw_gld
Contributor II

Okay, I solved the problem... It was a pretty obvious thing since the question already hinted to the answer...

I forgot to enable the DMA request using

DMA0->REQ |= (1 << SYSTEM_AUDIOADC_DMACHANNEL);

Well fortunately you mostly run into those mistakes once and never again...

Thank you guys!

0 Kudos

1,117 Views
mjbcswitzerland
Specialist V

Hi

See http://www.utasker.com/docs/uTasker/uTaskerADC.pdf and get any code needed from the uTasker project, containing PIT/DMA driven ADC and also K22 simulation to allow its operation (including interrupts and DMA) to be analysed and any problems in your code to be suitably solved.

Note also that PDB is usually used for this on the K22.

Regards

Mark

0 Kudos

1,117 Views
schw_gld
Contributor II

Is there an example for this scenario I could use to find the problem on my own?

0 Kudos

1,117 Views
michael_galda
NXP Employee
NXP Employee

Hi Eike,

In your SW I can see the line (with number mistake):

DMAMUX->CHCFG[SYSTEM_AUDIOADC_DMA_CHANNEL] |= 28; // for ADC0

But in the Table in the Reference Manual I can see the ADC0 request source is 40.

Which is nuber 40 (decimal) or 0x28 (hexa). So maybe this is the typo mistake.

- If not, send me the complete DMA register configuration. If there is anything wrong, it won't work at all.

Thanks,

Michael

1,117 Views
schw_gld
Contributor II

Oh, I should have copied the code direcly, it is actually already 0x28 in my firmware. I only made the mistake in the Question so this should work fine.

Here comes the DMA and DMAMUX configuration:

// Enable DMA requests from ADC

ADC0->SC2 = ADC_SC2_ADTRG_MASK | ADC_SC2_DMAEN_MASK;

// Clear DMAMUX configuration register

DMAMUX->CHCFG[SYSTEM_AUDIOADC_DMA_CHANNEL] = 0;

// Configure DMAMUX for ADC0

DMAMUX->CHCFG[SYSTEM_AUDIOADC_DMA_CHANNEL] = 0x28;

DMA0->CR = DMA_CR_HOE_MASK;

// Set DMA source address to ADC0 Data Result Register

DMA0->TCD[SYSTEM_AUDIOADC_DMA_CHANNEL].SADDR = (int)(&ADC0->R[0]);

// Set offset for each pointer increase to zero to always read from the same register

DMA0->TCD[SYSTEM_AUDIOADC_DMA_CHANNEL].SOFF = 0;

// 16 bit operations (buffer has 16 bit words)

DMA0->TCD[SYSTEM_AUDIOADC_DMA_CHANNEL].ATTR = DMA_ATTR_SSIZE(1) | DMA_ATTR_DSIZE(1);

// Number of bytes per dma request (minor loop)

DMA0->TCD[SYSTEM_AUDIOADC_DMA_CHANNEL].NBYTES_MLNO = 2;

// Number of bytes per dma request (minor loop)

DMA0->TCD[SYSTEM_AUDIOADC_DMA_CHANNEL].SLAST = 0;

// Destination address is the start of the current writing buffer

DMA0->TCD[SYSTEM_AUDIOADC_DMA_CHANNEL].DADDR = (int)WritingBuffer;

// Destination address increases by 2 after each request (minor loop)

DMA0->TCD[SYSTEM_AUDIOADC_DMA_CHANNEL].DOFF = 2;

// Number of iterations (major loop) until an interrupt is thrown

DMA0->TCD[SYSTEM_AUDIOADC_DMA_CHANNEL].CITER_ELINKNO = SYSTEM_AUDIOADC_BUFFERLENGTH;

// Address after major loop finished

DMA0->TCD[SYSTEM_AUDIOADC_DMA_CHANNEL].DLAST_SGA = 0;

// Enable interrupt at the end of major loop and automatically disable requests when major loop ends

DMA0->TCD[SYSTEM_AUDIOADC_DMA_CHANNEL].CSR = DMA_CSR_INTMAJOR_MASK | DMA_CSR_DREQ_MASK;

// Number of iterations (major loop) until an interrupt is thrown

DMA0->TCD[SYSTEM_AUDIOADC_DMA_CHANNEL].BITER_ELINKNO = SYSTEM_AUDIOADC_BUFFERLENGTH;

// Enable major loop interrupt

DMA0->TCD[SYSTEM_AUDIOADC_DMA_CHANNEL].CSR |= DMA_CSR_INTMAJOR_MASK;

// Enable DMA requests

DMAMUX->CHCFG[SYSTEM_AUDIOADC_DMA_CHANNEL] |= DMAMUX_CHCFG_ENBL_MASK;

0 Kudos