I'd like to use the ad converter with a dma support.
In the specific case the ad converter is triggered by a PIT's channel every 2 ms.
Then the ad converter must trigger the dma channel.
It works but, as you can see, in the code, I was expecting to see the ad converter data in a buffer previously set in the dma DAR register. I can see the data only in the first 2 buffer position. In the first two. Seem that the destination increment doesn't work correctly or something continue to clear the counter. Ther's something wrong in the firmware.
For more detail I can post the ad converter init in the case.
Thanks.
Claudio
/*!
*********************************************************************************************************************************************************************************
*** @fn : void Init_Dma(void)
*** @brief : dma initialization
***
*** @param : channel to be initialized
*** @ return: none
***
*** @details: initialize dma module
***
*********************************************************************************************************************************************************************************
*/
void Init_Dma(UINT8 channel)
{
DMA_Type *dma;
DMAMUX_Type *dma_mux;
UINT32 *destination;
UINT8 dma_int[] =
{
DMA0_IRQn,
DMA1_IRQn,
DMA2_IRQn,
DMA3_IRQn
};
if(channel > 0x00) // just for debug is 0. Then will be 3
return;
// clock gating on dmux & dma modules
SIM->SCGC6 |= SIM_SCGC6_DMAMUX_MASK; // dma mux clock gating
SIM->SCGC7 |= SIM_SCGC7_DMA_MASK; // dma clock gating
dma_mux = DMAMUX0;
dma = DMA0;
switch(channel)
{
case 0: destination = (UINT32*)&Buffer_A; break;
case 1: destination = (UINT32*)&Buffer_B; break;
case 2: destination = NULL; break;
case 3: destination = NULL; break;
default:
return;
}
// dma mux
dma_mux->CHCFG[channel] = 0x00; // clear register
// dma
dma->DMA[channel].SAR = (UINT32)&ADC0[0].R; // dma source register (where dma takes data)
dma->DMA[channel].DAR = (UINT32)destination; // dma destination register (where dma write data)
dma->DMA[channel].DSR_BCR |= DMA_DSR_BCR_DONE_MASK; // clear BCR reg
dma->DMA[channel].DSR_BCR = DMA_DSR_BCR_BCR(16); // bcr = 16
dma->DMA[channel].DCR |= DMA_DCR_EINT_MASK + // enable interrupt
DMA_DCR_ERQ_MASK + // Enable peripheral requestDMA_DCR_SSIZE(2)
0 + // CS
0 + // AA
0 + // EADREQ
0 + // SINC
DMA_DCR_SSIZE(0x02) + // source size = 16 bit
DMA_DCR_DINC_MASK + // set increments to destination address
0 + // DINC
DMA_DCR_DSIZE(0x02) + // destination size = 16 bit
0 + // START
0 + // SMOD
DMA_DCR_DMOD(0x01) + // destination circular buffer = 16 bytes
0 + // D_REQ
0 + // LINKCC
0 + // LCH1
0; // LCH2
DMAMUX0->CHCFG[channel] |= kDmaRequestMux0ADC0 + // dma source pheripheral
DMAMUX_CHCFG_ENBL_MASK; // no trigg, then dma is in normal mode
ConnectInterruptToCortex(dma_int[channel]); // set dma channel 0 interrupts
}
void DMA0_IRQHandler(void)
{
DMA_Type *dma;
dma = DMA0;
dma->DMA[0].DSR_BCR |= DMA_DSR_BCR_DONE_MASK; // Clear Done Flag
dma->DMA[0].DSR_BCR |= DMA_DSR_BCR_BCR(16); // Set byte count register
}
Hi
Which processor and board are you working with?
Have you check the errata since some KL parts have PIT trigger erratas?
Regards
Mark
Hi Mark.
I'm using the freedom board FRDM KL27 with MKL27Z64VLH4 on board.
Honestly I didn't check the errata about the PIT.
But the timer seem to work right.
Before to use the DMA, the timer was used to trig the converter and everything it worked properly. Then I disabled the adc interrupt handler and enabled the corresponding bit to trig the DMA.
And the timer, trig the adc.
But the data written from Dma aren't in the order that I'm expecting.
I can post the rest of the code to help you.
Thanks in advance.
Claudio
Hi Claudio
For the FRDM-KL27Z see the following:
http://www.utasker.com/kinetis/FRDM-KL27Z.html#PIT_ADC_DMA_PWM
It is a reference for PIT driven ADC sampling to RAM via DMA (plus a second SRAM to PWM output via DMA from the same buffer) with more details at http://www.utasker.com/docs/uTasker/uTaskerADC.pdf
The code is included in the open source uTasker Kinetis project at the link below, which also allows saving DMA filled swap buffers as a .WAV file to an SD card or to send it via USB audio to a PC host in real-time.
If you load the binary file you could use the debugger to check its DMA setup (it uses DMA channel 2 for ADC to RAM and channel 0 for RAM to PWM output) or you can run the project at the source code link in the uTasker simulator to see the internal operation (it simulates the Kinetis and complete DMA operation in visual studio to remove the need for HW debugging and informs of DMA setup issues).
This is the (lower level) DMA configuration sequence it uses for the ADC->SRAM direction, which may also give a hint (the project code is intensively commented for clarity):
KINETIS_DMA *ptrDMA = (KINETIS_DMA *)DMA_BLOCK;
ptrDMA += ucDMA_channel; // move to the DMA channel to be used (0, 1, 2 or 3)
ptrDMA->DMA_DSR_BCR = DMA_DSR_BCR_DONE; // clear the DONE flag and clear errors etc.
ptrDMA->DMA_DCR = (DMA_DCR_DSIZE_16 | DMA_DCR_SSIZE_16 | DMA_DCR_DMOD_OFF | DMA_DCR_SMOD_OFF); // transfer size half-words
ptrDMA->DMA_DCR |= (DMA_DCR_DINC); // transfers with increment only on destination
ptrDMA->DMA_SAR = (unsigned long)ptrBufSource; // set source buffer (ADC address)
ptrDMA->DMA_DAR = (unsigned long)ptrBufDest; // set destination buffer (SRAM buffer)
ptrDMA->DMA_DSR_BCR = ulBufLength; // set transfer count (don't set DMA_DSR_BCR_DONE at the same time otherwise BCR is reset)
fnEnterInterrupt((irq_DMA0_ID + ucDMA_channel), int_priority, (void (*)(void))_DMA_Interrupt[ucDMA_channel]); // enter DMA interrupt handler on buffer completion
ptrDMA->DMA_DCR |= (DMA_DCR_EINT | DMA_DCR_D_REQ); // interrupt when the transmit buffer is empty and stop operation after full buffer has been transferred
POWER_UP_ATOMIC(6, DMAMUX0); // enable DMA multiplexer 0
*(unsigned char *)(DMAMUX0_BLOCK + ucDMA_channel) = (unsigned char)(DMAMUX0_CHCFG_SOURCE_ADC0 | DMAMUX_CHCFG_ENBL); // connect trigger to DMA channel
ptrDMA->DMA_DCR |= (DMA_DCR_CS | DMA_DCR_EADREQ); // enable peripheral request - single cycle for each request (asynchronous requests enabled in stop mode)
ptrDMA->DMA_DCR |= (DMA_DCR_ERQ); // enable DMA operation
Regards
Mark
Complete Kinetis solutions for faster/more efficient professional needs, training and support: http://www.utasker.com/kinetis.html
i.MX RT project compatibility (move projects between Kinetis and i.MX RT parts with almost zero effort or learning curve): http://www.utasker.com/iMX.html
Including FreeRTOS integration for all Kinetis parts
Kinetis KL25, KL26, KL27, KL28, KL43, KL46, KL82
- http://http://www.utasker.com/kinetis/FRDM-KL25Z.html
- http://www.utasker.com/kinetis/TWR-KL25Z48M.html
- http://www.utasker.com/kinetis/FRDM-KL26Z.html
- http://www.utasker.com/kinetis/TEENSY_LC.html
- http://www.utasker.com/kinetis/FRDM-KL27Z.html
- http://www.utasker.com/kinetis/Capuccino-KL27.html
- http://www.utasker.com/kinetis/FRDM-KL28Z.html
- http://www.utasker.com/kinetis/FRDM-KL43Z.html
- http://www.utasker.com/kinetis/TWR-KL43Z48M.html
- http://www.utasker.com/kinetis/FRDM-KL46Z.html
- http://www.utasker.com/kinetis/TWR-KL46Z48M.html
- http://www.utasker.com/kinetis/FRDM-KL82Z.html
uTasker: supporting >1'000 registered Kinetis users get products faster and cheaper to market
Request Free emergency remote desk-top consulting at http://www.utasker.com/services.html
Open Source version at https://github.com/uTasker/uTasker-Kinetis
https://community.nxp.com/thread/512558
https://community.nxp.com/thread/352862
https://community.nxp.com/thread/498809
Hi Mark.
I thank you for your explanations and documents.
I solved my problem.
Essentially I did a mistake between a dma hardware trigger and software trigger.
I didn't set the right adc hardware trigger. It was the tpm counter (as default) and not pit timer how I wanted.
Again I left active the adc interrupt handle where the adc was triggered too by software.
Just a little bit of miss match ! ! !
Thank you for your assistance.
Claudio
Thank you very much Mark, for your more than exaustive reply.
In the next days I will tell you the results.
Have a good time.
Claudio