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!
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!
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
Is there an example for this scenario I could use to find the problem on my own?
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
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;