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 - SPI issue

Other Parts Discussed in Thread: MSP430F1611

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

 

 

 

  • 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

     

     

  • 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

     

     

  • Hi ,

    I'm trying to W\R numerous data to SD card via SPI(5438), if the MCU transmitts the data solely, works well. But, there're many other modules doing at the same time, SPI plus DMA seems urgent. I've not tried any DMA sort of things before, TI's code example helps a little. Would U give me some detailed advice. Thank U in advance!

    Regards,

    Jenny Tan

**Attention** This is a public forum