TI E2E Community (Beta)
Welcome to the TI E2E (Engineer-to-Engineer) Community! We invite you to freely and openly interact with your peer Engineers, TI Engineers, and other experts in order to ask questions, share knowledge, explore ideas, and help solve problems.
More Search Options

DMA - SPI issue

rated by 0 users
Answered (Not Verified) This post has 0 verified answers | 2 Replies | 2 Followers

Not Ranked
3 Posts
Community Member
MostlyHarmless posted on 7 Jul 2009 4:05 AM

Hey, all-

Been struggling with using DMA to write to an SD card with SPI. It's my first try at using DMA so please excuse any silly mistakes.

The facts:

1) MSP430F1611

2) Using SLAA281b appnote code

3) ***Can read/write fine without DMA***

4) Modified appnote code to use USART0 rather than the "default" USART1

5) Can't read or write.

6) Tried many modifications of this to troubleshoot the poroblem and I'm stumped.

7) I don't have an oscope to probe the SPI connection.

8) mmcInit() from SLAA281b appears to work

9) I note that comments say "UART send" is the trigger but the original code used USART1 receive. Tried both ways...

Let's start with writing for now. Here's my modified code from the appnote:

#define withDMA

//Send a frame of bytes via SPI
unsigned char spiSendFrame(unsigned char* pBuffer, unsigned int size)
{
#ifndef withDMA
  unsigned long i = 0;
  // clock the actual data transfer and receive the bytes; spi_read automatically finds the Data Block
  for (i = 0; i < size; i++){
    while (halSPITXREADY ==0);   // wait while not ready for TX
    halSPI_SEND(pBuffer[i]);     // write
    while (halSPIRXREADY ==0);   // wait for RX buffer (full)
    pBuffer[i] = halSPIRXBUF;
  }
#else

    /* Get the block */
    /* DMA trigger is UART send */
    DMACTL0 &= ~(DMA0TSEL_15);
    DMACTL0 |= (DMA0TSEL_3);      //USART0 Rx trigger
    /* Source DMA address: the data buffer.  */
    DMA0SA = (unsigned short)pBuffer;
    /* Destination DMA address: the UART send register. */
    DMA0DA = U0TXBUF_;
    /* The size of the block to be transferred */
    DMA0SZ = size;
    /* Configure the DMA transfer*/
    DMA0CTL =
        DMADT_0 |                           /* Single transfer mode */
        DMASBDB |                           /* Byte mode */
        DMAEN |                             /* Enable DMA */
        DMASRCINCR1 | DMASRCINCR0;          /* Increment the source address */
    DMA0CTL |= DMAREQ;

#endif
  return(0);
}

Thanks for any help or suggestions!

Cheers, MH

 

 

 

All Replies

Top 150 Contributor
50 Posts
Community Member
Suggested by Harman

Hello!

I did it on a 5438 and I don't have the code right now, but here is how to do it (sorry I don't have the code right now).

Let's assume you want to transmit buf, the size of which is "size".

- You set the trigger for your DMA. Select TX, not RX. Therefore, everytime one byte is transmitted,

you receive a TX interrupt which triggers the next byte.

- You set the start address; DMAxSA = buf; increment = 1;

- You set the target address to SPI.

- You set the transmission to size-1, not size (see next line)

- You send the first byte manually TXBUF1 = buf[0];

What happens: everytime one byte has been sent, you get a tx flag which sends the next one.

Sending the first byte "manually" triggers the DMA transfer which transmits the  size -1 remaining

bytes.

 

That's about it. Have fun!

Pascal

 

 

Not Ranked
3 Posts
Community Member

Pascal-

Thanks! Your outline really helped. I got it working (sort of) with a couple things I added and changed:

1) Start address is pBuffer + 1 (because the first byte is sent manually)

2) Enter LPM0 during transfer and leave LPM0 in the DMA isr.

Tested and debugged with 100 sequential block writes. Some findings while testing:

1) While writing 100 sequential blocks 2 BAD situations occur on occasion: a) bad blocks are written to SD. Bad. b) SD enters an unrecoverable state! Really bad!

2) Adding some NOPs between writes stopped the SD from locking up but did not stop the bad block writes. Not a very elegant solution.

3) Power consumption reduced a little (~5%) when using DMA in LPM0 AND DMA w/o LPM0 compared to no DMA but my baseline power is ~6mA. Entering LPM0 didn't seem to help. Still need to play with other LPM modes.

4) Speed improved by about 6% when using DMA.

5) Looking at the bad blocks on the SD, it appears dummy characters (0xff) and commands are being written to the block.

6) Using LPM0 seemd to reduce bad blocks. Weird.

Conclusion: I haven't really figured out DMA yet! Any help is welcome!

Here's my updated spiSendFrame function. Again, this is modified from the SLAA281B appnote code.

//Send a frame of bytes via SPI
unsigned char spiSendFrame(unsigned char* pBuffer, unsigned int size)
{
#ifndef withDMA
  unsigned long i = 0;
  // clock the actual data transfer and receive the bytes; spi_read automatically finds the Data Block
  for (i = 0; i < size; i++){
    while (halSPITXREADY ==0);   // wait while not ready for TX
    halSPI_SEND(pBuffer[i]);     // write
    while (halSPIRXREADY ==0);   // wait for RX buffer (full)
    pBuffer[i] = halSPIRXBUF;
  }
#else

    /* Get the block */
    /* DMA trigger is UART send */
    DMACTL0 &= ~(DMA0TSEL_15);
    DMACTL0 |= (DMA0TSEL_4);
    /* Wait for last CPU instruction to finish */
    //DMACTL1 |= DMAONFETCH;
    /* Source DMA address: the data buffer.  */
    DMA0SA = (unsigned short)(pBuffer+1);
    /* Destination DMA address: the UART send register. */
    DMA0DA = U0TXBUF_;
    /* The size of the block to be transferred */
    DMA0SZ = size - 1;
    /* Configure the DMA transfer*/
    DMA0CTL =
        DMAIE |                             /* Enable interrupt to leave LPM0 */
        DMADT_0 |                           /* Single transfer mode */
        DMASBDB |                           /* Byte mode */
        DMAEN |                             /* Enable DMA */
        DMASRCINCR1 | DMASRCINCR0;         /* Increment the source address, dest address constant*/


    halSPI_SEND(pBuffer[0]);                /* Send manually to kickoff */
    LPM0;                                   /* Enter LPM0 */

#endif
  return(0);
}

 

Some other stuff: DMA between RAM works fine. An application to look at the mmc card directly really helps. I use WinHex.

Cheers,

MH

 

 

Page 1 of 1 (3 items) |

ALL CONTENT AND MATERIALS ON THIS SITE ARE PROVIDED "AS IS". TI AND ITS RESPECTIVE SUPPLIERS MAKE NO REPRESENTATIONS ABOUT THE SUITABILITY OF THESE MATERIALS FOR ANY PURPOSE AND DISCLAIM ALL WARRANTIES AND CONDITIONS WITH REGARD TO THESE MATERIALS, INCLUDING BUT NOT LIMITED TO, ALL IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT OF ANY THIRD PARTY INTELLECTUAL PROPERTY RIGHT. NO LICENSE, EITHER EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, IS GRANTED BY TI. USE OF THE INFORMATION ON THIS SITE MAY REQUIRE A LICENSE FROM A THIRD PARTY, OR A LICENSE FROM TI.

Content on this site may contain or be subject to specific guidelines or limitations on use. All postings and use of the content on this site are subject to the Terms of Use of the site; third parties using this content agree to abide by any limitations or guidelines and to comply with the Terms of Use of this site. TI and its suppliers reserve the right to make corrections, deletions, modifications, enhancements, improvements and other changes to the content and materials, its products, programs and services at any time or to move or discontinue any content, products, programs, or services without notice.