DMA destination data & ptr increment

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

DMA destination data & ptr increment

1,333 Views
claudiobrunelli
Contributor II

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

}

Labels (1)
0 Kudos
5 Replies

1,041 Views
mjbcswitzerland
Specialist V

Hi

Which processor and board are you working with?
Have you check the errata since some KL parts have PIT trigger erratas?

Regards

Mark

0 Kudos

1,041 Views
claudiobrunelli
Contributor II

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

 

0 Kudos

1,042 Views
mjbcswitzerland
Specialist V

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

1,042 Views
claudiobrunelli
Contributor II

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

0 Kudos

1,042 Views
claudiobrunelli
Contributor II

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

0 Kudos