This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

DMA purpose?

Hi guys,

I'm just a beginner in Direct Memory Access and now want to study a bit more but I just don't understand a few things.

I know that the purpose of DMA is to transfer a byte or word from one memory location to another location without using CPU. Like for example in the application in ADC12. I saw a lot of sample coding using DMA to transfer the ADC conversion in ADC12MEM0 to another memory location.

But what I don't understand is, why use DMA? Can't I just declare the below to transfer my ADC conversion in the main routine?

ADCresult0 = ADC12MEM0;

This line shows that I transfer the ADC result from ADC12MEM0 to ADCresult0 without using DMA right? Then why use DMA?

  • Hi,

     

    The true power of DMA is to do these memory transfers without the CPU being involved.

    Once DMA configured it works like a stand alone unit.

    As a quick example you can think of system on chip with ADC, SPI interface and a DMA,

    you can configure the DMA to transfer converted ADC data directly to SPI, where the SPI

    transmits it to another device. So basically you transferred data without involving the CPU,

    while the CPU is busy with some other task.

  • Also imagine events with a very high frequency, e.g. AD conversion, emulation of a serial link and so on.

    While the DMA requires after proper setup only a few clock cycles per event, an interrupt procedure would require context save/restore operation which need some magnitudes more time.

    There are also some features of the DMA which cannot be done by the CPU even with interrupts, e.g. UART character reception/transmission while flash programming is active (to be honest: not tested).

    Hardy

  • But there is one fact about MSP DMA. While DMA is busy, CPU stops.

  • Igor Sherer said:

    Hi,

     

    The true power of DMA is to do these memory transfers without the CPU being involved.

    Once DMA configured it works like a stand alone unit.

    As a quick example you can think of system on chip with ADC, SPI interface and a DMA,

    you can configure the DMA to transfer converted ADC data directly to SPI, where the SPI

    transmits it to another device. So basically you transferred data without involving the CPU,

    while the CPU is busy with some other task.

    I still don't understand. You mean if i write one variable equals to the ADC12 memory location like what I give above (ADCresult0 = ADC12MEM0) to do transferring of data, it will still involve CPU?

  • Hi,

     

    If you write ADCresult0 = ADC12MEM0, yes this will involve CPU.

    I meant something else:

    In case you've configured DMA to transfer one byte of memory form one location

    to another, you do not have to write this line in your code.

    But, apparently it is not useful in MSP since according to BasePointer's statement

    MSP core won't be able to perform tasks while DMA busy (sounds very odd to me).

  • Igor Sherer said:

    But, apparently it is not useful in MSP since according to BasePointer's statement

    MSP core won't be able to perform tasks while DMA busy (sounds very odd to me).

    Is this true? Is there any official documentation about this?

  • Yes, during DMA operation the CPU is not active.

    Impact depends on DMA mode, see 6.2.2. in slau144 for MSP430x2xx family.

    Hardy

  • HardyGriech said:

    Yes, during DMA operation the CPU is not active.

    Impact depends on DMA mode, see 6.2.2. in slau144 for MSP430x2xx family.

    Hardy

    I see. Then do you recommend us to use the DMA during transferring of ADC12 conversion to another location?

  • There seems to be a bit of misunderstandign about this 'CPU is stopped while DMA is active'.

    It is true, yes, but in a different sense.

    While a DMA transfer takes place, the CPU cannot run. This is becaus eonly one, DMA controller or CPU, can access the address and data bus at the same time. This also applies to the PC. Whiel DMA is reading from or writing to ram, the CPU cannot access ram. However, on a PC, there is the cache, and the ram has waitstates anyway, so a DMA access is fo rthe CPU judt some additional ram waitstates.

    However, this applies only if there is an active DMA transfer. If the DMA controller is jus twaiting for its trigger event, the CPU can do whatever it wants. At full speed.
    If a DMA transfer applies on a block of data at once (e.g. a memory->memory move without individual triggers for each transfer), there are two modes. Either the DMA will transfer a byte/word every two MCLK ticks and the CPU is paused. This is much faster than a CPU program loop, as no program code needs to be fetched, no counter to be incremented in software, no loop end condition to be checked etc.
    Or there is a mode where the DMA will pause for a frew MCLK cycles after each transfer, to let the CPU continue at a limited pace.

    One thing to keep in mind is when using DMA with low power modes. DMA requires MCLK. So when LPM1 or higher is entered, each DMA trigger will cause teh LPM to be reverted to LPM0 (CPU stopped, but DOC etc. running), with all the required DCO startup time etc. (but not the IRQ latency time, since the CPU remains dormant and no IRQ is triggered) Then the DMA transfer takes place and then LPM goes back to previous level.

  • I've seen a sample coding that uses just two lines to do the DMA transfer (of course the DMA initialization have all configured):

    __data16_write_addr((unsigned short) &DMA0SA,(unsigned long) &ADC12MEM0); // Source block address                                        

    __data16_write_addr((unsigned short) &DMA0DA,(unsigned long) &DMA_DST); // Destination single address   

    Is it just by this two lines we can do a DMA transfer?

    From the comment of the sample coding above ,why is it ADC12MEM0 has a block address? Or it's just a typing error?

    Do we change to destination block address if we want to transfer from ADC12MEM0 to ADC12MEM15? How do we configure in terms of coding?

  • Steven Gan Teck Yik said:
    Is it just by this two lines we can do a DMA transfer?

    No. These two lines only define the source and destination (start) address.

    You'll also need to define the trigger that triggers the DMA, the amoutn of data to be moved, and whether source and/or destination address shall be incremented between transfers.

    So while &ADCMEM0 is the source start address, depending on DAM config, the second DMA transfer may be taken from ADC12MEM1, which is 2 bytes apart (word increment)

    In the above example, it seems that the DMA has been configured to increment the source address by a word but keep the destination address constant. So after each conversion, one word is moved from the next ADC12MEMx to the common DMA_DST-Variable (overwriting the last). That's assumed by the comments.

    Configuring the DMA has taken place with all the assignments to the other DMAxxx registers. The writes to DMA0SA and DMA0DA are just the final information.
    However, if the setup is always the same and just the addresses change, then those two lines may be enough. Or perhaps the count value to define the new number of transfers.

    Steven Gan Teck Yik said:
    Do we change to destination block address if we want to transfer from ADC12MEM0 to ADC12MEM15? How do we configure in terms of coding?

    If you want to copy ADC12MEM0 to ADC12MEM15 into an an array like "unsigned int RESULTS[16]", tehn you'll need to configure the DMA to use destination address increment, and pass the start address (which is the plain name of the array, "RESULTS", without a '&') of the array to DMA0DA.

    I don't know why the intrinsic '__data_write_addr' is used here. Sure, therewill be a type conflic if you just do an assignment, but

    DMA0DA = (unsinged int)(void *)(&DMA_DST)

    should do fine. (&DMA_DST is likely an unsigned int *, which must be cast to a void * first, and then can be cast to an unsigned int, giving you the address as a value) Perhaps the (void*) is not necessary. It depends on the compiler.

  • Jens-Michael Gross said:

    So while &ADCMEM0 is the source start address, depending on DAM config, the second DMA transfer may be taken from ADC12MEM1, which is 2 bytes apart (word increment)

    In the above example, it seems that the DMA has been configured to increment the source address by a word but keep the destination address constant. So after each conversion, one word is moved from the next ADC12MEMx to the common DMA_DST-Variable (overwriting the last). That's assumed by the comments.

     

    The initialization for the DMA from the sample coding is as below:

      DMACTL0 = DMA0TSEL_24;                    // ADC12IFGx triggered
      DMACTL4 = DMARMWDIS;                      // Read-modify-write disable
      DMA0CTL &= ~DMAIFG;
      DMA0CTL = DMADT_4+DMAEN+DMADSTINCR_3+DMAIE; // Rpt single tranfer, inc dst, Int
      DMA0SZ = 1;                               // DMA0 size = 1

    It is not a source address increment but a destination address increment. So, iI think it mean that one word is always moved from ADC12MEM0 to DMA_DST variable. But DMA_DST is just a single variable, how to increment it's address which is the destination address? Or it mean there is many address for a single DMS_DST variable?

    Again to the below coding:

    __data16_write_addr((unsigned short) &DMA0SA,(unsigned long) &ADC12MEM0); // Source block address                                        

    __data16_write_addr((unsigned short) &DMA0DA,(unsigned long) &DMA_DST); // Destination single address 

    Why is it stated that ADC12MEM0 is source block address? How do we determine each address whether is a block address or single address?

  • DMA0TSEL is the trigger than triggers an DMA transfer. It's the ADC12IFG signal which is set when the ADC has finished a signlke conversion (in single or repeated single converison mode) or completed a sequence. It has nothing to do with the individual IFG bits set when a particular channel got a new conversion result.

    DMARWMDIS ensures that the CPU won't be interrupted when it is executing a comamnd that reads, modifies and writes a value (such an an x |=y operation). Important for some hardware register accesses, or if the CPU works on the data that is altered by the DMA transfer.

    DMA0SZ = 1 means one byte/word to transfer on  atrigger, then DMA0DA and DMA0SA are restored to initial value. So it is a don't care whether source or destination address are pointong to a block or a single storage location.
    DMADT_4 means that once DMA0SZ transfers have been finished, DMA0DA, DMA0SZ and DMA0DA are restored to the originally written value and the system is 'armed' again.
    DMADSTINCR_3 would increment DMA0DA afte reach transfer. However, since DMA0DA is restored after a complete cycle, and the cycle length is 1, it is a don't care.

    After all, the 'block' info in the DMA0SA comment is wrong, and the DMADSTINCR_3 is superfluous, since the incremented valeu won't be used.
    To write ADC12MEM0 into a destination array, DMA0SZ mus tbe set to the number of bytes written in successive locations (array), or if ADC12MEM0..15 shall be written, DMASRCINCR_3 needs to be set.

    If this code is taken 1:1 from a TI example, then I'd say it is more confusing than helpful. :(

**Attention** This is a public forum