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.

SPI - DMA Reading Configuration of TMS570LS3137

Other Parts Discussed in Thread: HALCOGEN

Dear tech supporters,

How should I configure SPI-DMA reading. I have made SPI-DMA writing work fine. However for reading, I configured 2 DMAs, one for writing and the other one for reading as the code below. I got correct scope curves of both writing(MOSI) and reading(MISO) to and from NVRAM chip. But the reading DMA did not work. Therefore, I cannot get the reading data DMAed to addrRdDest. I have following conceptual questions:

  1. RD_8_BIT_SOURCE_ADDR should be 0xff0e0203 Rx[0], or 0xff0e0207 Rx[1]? We send out using Tx[1] fine.

  2. SS_DMA_ReqAssign(CHANNEL_WR_NO, LINE_WR_NO);

    SS_DMA_ReqAssign(CHANNEL_RD_NO, LINE_RD_NO);

    we use lines and channels above. Can we map lines and channels as below? What is the correct way to map for the followings?

    spiREG1->DMACTRL[CHANNEL_WR_NO].TXDMA_MAP = LINE_WR_NO;

    spiREG1->DMACTRL[CHANNEL_WR_NO].RXDMA_MAP = LINE_RD_NO;

    spiREG1->DMACTRL[CHANNEL_RD_NO].TXDMA_MAP = LINE_WR_NO;

    spiREG1->DMACTRL[CHANNEL_RD_NO].RXDMA_MAP = LINE_RD_NO;

  3. In order to make the reading DMA working, can we chain the reading DMA as below?

    dmaCtrlPktRd.CHCTRL = CHANNEL_WR_NO; //CHANNEL+1, 0 for not chaining.

Thank you and best regards,

Long Wan

 

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#define WR_8_BIT_DESTINATION_ADDR 0xff0e0007 // 0xff0e0007 Tx[1]

#define RD_8_BIT_SOURCE_ADDR 0xff0e0203 // 0xff0e0203 Rx[0], 0xff0e0207 Rx[1]

#define LARGE_COUNT

#define CHANNEL_WR_NO 7

#define CHANNEL_RD_NO 6

#define LINE_WR_NO 0

#define LINE_RD_NO 1

void StartSpiDmaRead( U8*addrWrSrc, U8*addrRdDest, U32 numBytes)

{

SS_DMA_CONTROL_PACKET_ST dmaCtrlPktWr, dmaCtrlPktRd;

SS_SPI_DMA_Init1(9U);

dmaREG->GCTRL = 0x00000001U; /* reset dma */

while(dmaREG->GCTRL);

spiREG1->ENA = 0; // SPIENA hold low for configuration

#ifdef LARGE_COUNT

spiREG1->DMACNTLEN = 1U; // select large count for SPI DMA

spiREG1->RAMACCESS = 0; // not to use Multi-buffer mode by set bit MSPIENA

#else

spiREG1->DMACNTLEN = 0; // select large count for SPI DMA

spiREG1->RAMACCESS |= 1U; // to use Multi-buffer mode by set bit MSPIENA

#endif

//============= SPI-DMA FOR WRITE=================================

dmaCtrlPktWr.SADD = (U32)addrWrSrc; //source address of DMA, Post-incremented

dmaCtrlPktWr.DADD = WR_8_BIT_DESTINATION_ADDR; //Fixed address needed here

dmaCtrlPktWr.FRCNT = (numBytes); //Frame count

dmaCtrlPktWr.ELCNT = 1; //element count

dmaCtrlPktWr.PORTASGN = 4U; //Port B

dmaCtrlPktWr.ADDMODERD = ADDR_INC1; //post-incremented

dmaCtrlPktWr.ADDMODEWR = ADDR_FIXED; //ADDR_FIXED; //constant

dmaCtrlPktWr.RDSIZE = SS_DMA_ACCESS_8_BIT; //8 or 16-bit

dmaCtrlPktWr.WRSIZE = SS_DMA_ACCESS_8_BIT; //8 or 16-bit

dmaCtrlPktWr.TTYPE = FRAME_TRANSFER; //FRAME_TRANSFER is required for SPI-DMA

dmaCtrlPktWr.AUTOINIT = AUTOINIT_ON; //AUTOINIT_OFF AUTOINIT_ON auto-init

dmaCtrlPktWr.CHCTRL = 0; //0 for not chaining. n+1 for channel n,

dmaCtrlPktWr.ELDOFFSET = 0; //element destination offset

dmaCtrlPktWr.ELSOFFSET = 0; //element source offset

dmaCtrlPktWr.FRDOFFSET = 0; //frame destination offset

dmaCtrlPktWr.FRSOFFSET = 0; //frame source offset

SS_DMA_ReqAssign(CHANNEL_WR_NO, LINE_WR_NO); // (SS_U32 channel, SS_U32 reqline)

SS_DMA_SetCtrlPacket(CHANNEL_WR_NO, &dmaCtrlPktWr);

SS_DMA_SetChEnable(CHANNEL_WR_NO, SS_DMA_REQ_TYPE_HW); // SS_DMA_REQ_TYPE_HW is spiREG1->DMACTRL[CHANNEL_WR_NO].ONESHOT = 1; // set, not clear ONESHOT

spiREG1->DMACTRL[CHANNEL_WR_NO].NOBRK = 1U; // set NOBRK

spiREG1->DMACTRL[CHANNEL_WR_NO].BUFID = 1; // a 7-bit BUFID. Start from No. 0 buffer RAM: 0 ~ 127, total 128 buffer RAMs. My set-up is using buffer1 that is verified by scope

spiREG1->DMACTRL[CHANNEL_WR_NO].TXDMA_MAP = LINE_WR_NO; // DMA TX channel line number?

spiREG1->DMACTRL[CHANNEL_WR_NO].RXDMA_MAP = LINE_RD_NO; // DMA RX channel line number?

#ifdef LARGE_COUNT

spiREG1->DMACOUNT[CHANNEL_WR_NO] = ( numBytes << 16 );

#else

spiREG1->DMACTRL[CHANNEL_WR_NO].ICOUNT = numBytes;

#endif

spiREG1->DMACTRL[CHANNEL_WR_NO].TXDMA_ENA = 1U;

spiREG1->DMACTRL[CHANNEL_WR_NO].RXDMA_ENA = 1U;

spiREG1->TGCTRL[CHANNEL_WR_NO] &= 0xffff00ff; // let PSTART = 0;

spiREG1->TGCTRL[CHANNEL_WR_NO] |= 0x80000000; // set TGENA bit

//============= SPI-DMA FOR READ =================================

dmaCtrlPktRd.SADD = RD_8_BIT_SOURCE_ADDR;

dmaCtrlPktRd.DADD = (U32)addrRdDest;

dmaCtrlPktRd.FRCNT = (numBytes); //Frame count

dmaCtrlPktRd.ELCNT = 1; //element count

dmaCtrlPktRd.PORTASGN = 4U; //Port B

dmaCtrlPktRd.ADDMODERD = ADDR_FIXED; //ADDR_FIXED; //constant

dmaCtrlPktRd.ADDMODEWR = ADDR_INC1; //post-incremented

dmaCtrlPktRd.RDSIZE = SS_DMA_ACCESS_8_BIT; //8-bit

dmaCtrlPktRd.WRSIZE = SS_DMA_ACCESS_8_BIT; //8-bit

dmaCtrlPktRd.TTYPE = FRAME_TRANSFER; //FRAME_TRANSFER is required for SPI-DMA

dmaCtrlPktRd.AUTOINIT = AUTOINIT_ON; //AUTOINIT_OFF AUTOINIT_ON auto-init

dmaCtrlPktRd.CHCTRL = CHANNEL_WR_NO; //CHANNEL_NO +1; // 0 for not chaining.

dmaCtrlPktRd.ELDOFFSET = 0; //element destination offset

dmaCtrlPktRd.ELSOFFSET = 0; //element source offset

dmaCtrlPktRd.FRDOFFSET = 0; //frame destination offset

dmaCtrlPktRd.FRSOFFSET = 0; //frame source offset

SS_DMA_ReqAssign(CHANNEL_RD_NO, LINE_RD_NO); // (SS_U32 channel, SS_U32 reqline). SS_DMA_SetCtrlPacket(CHANNEL_RD_NO, &dmaCtrlPktRd);

SS_DMA_SetChEnable(CHANNEL_RD_NO, SS_DMA_REQ_TYPE_HW); // SS_DMA_REQ_TYPE_HW is required for SPI-DMA

spiREG1->DMACTRL[CHANNEL_RD_NO].ONESHOT = 1; // set, not clear ONESHOT

spiREG1->DMACTRL[CHANNEL_RD_NO].NOBRK = 1U; // set NOBRK

spiREG1->DMACTRL[CHANNEL_RD_NO].BUFID = 1; // a 7-bit BUFID. Start from No. 0 buffer RAM: 0 ~ 127, total 128 buffer RAMs. My set-up is using buffer1 that is verified by scope

spiREG1->DMACTRL[CHANNEL_RD_NO].TXDMA_MAP = LINE_WR_NO; // DMA TX channel line number?

spiREG1->DMACTRL[CHANNEL_RD_NO].RXDMA_MAP = LINE_RD_NO; // DMA RX channel line number? RXDMA_MAP should be different from TXDMA_MAP, see page 698 of data sheet

#ifdef LARGE_COUNT

spiREG1->DMACOUNT[CHANNEL_RD_NO] = ( numBytes << 16 );

#else

spiREG1->DMACTRL[CHANNEL_RD_NO].ICOUNT = numBytes;

#endif

spiREG1->DMACTRL[CHANNEL_RD_NO].TXDMA_ENA = 1U;

spiREG1->DMACTRL[CHANNEL_RD_NO].RXDMA_ENA = 1U;

spiREG1->TGCTRL[CHANNEL_RD_NO] &= 0xffff00ff; // let PSTART = 0;

spiREG1->TGCTRL[CHANNEL_RD_NO] |= 0x80000000; // set TGENA bit

////////////////////////////////////////////////////////////////////////

dmaREG->GCTRL |= 0x00010000U; /* enable dma */

spiREG1->DMAREQEN = 1;// condition 1 to start for normal SPI DMA

spiREG1->ENA = 1U; // SPIENA condition 2 to start for normal SPI DMA

}

  • Hi,

      It looks like you don't use HalCoGen and any API provided by HalCoGen. This will make the debug more difficult. Is there any reason you will not use the HalCoGen?

      When you said the writing is working, are you sure it is 100% working. Do you have any skipped data?

      When you said the reading is not working, is it that no data at all is read by the DMA or you at least see one data?

      I see the below code from you. Here you have the source address mode being fixed and the destination address being post-increment. So this is already a problem. You are always reading from the same location. Is this what you want?  I assume you want to use the MibSPI mode, right? Not the compatibility SPI mode. If this is the case, then the source addressing mode needs to be the indexing mode. The reason you need indexing mode is because your read transfer size is 8-bit. The first 8-bit data is located at 0xff0e0203 for Rx[0] but the next 8-bit data will be at 0xff0e0207 for RX[1] and so on so forth. You can't use post-increment for your source addressing mode because with it the DMA will only automatically increment the source address by 8-bit for each element. After the 0xff0e0203 is read it will increment the address to 0xff0e0204 and then onto 0xff0e0205 and so on so forth. What is at 0xff0e0204 and 0xff0e0205 will the upper 8-bit of a 16-bit data if you were to transmit/receive in 16-bit length and 0xff0e0205 is just some status information. Check the DMA userguide for details on the indexing mode. What you most likely need is a element offset of 0 and frame offset of 4. You might need to do the same for the writing channel too. I just don't understand why it is working for you the way it is. Perhaps I'm missing something. This is why I asked if your writing is 100% working with your current setup.

    dmaCtrlPktRd.DDMODERD = ADDR_FIXED; //ADDR_FIXED; //constant

    dmaCtrlPktRd.ADDMODEWR = ADDR_INC1; //post-incremented

    dmaCtrlPktRd.RDSIZE = SS_DMA_ACCESS_8_BIT; //8-bit

    dmaCtrlPktRd.WRSIZE = SS_DMA_ACCESS_8_BIT; //8-bit

      

  • Hi Charles,

    I am new and the first time to use CCS and TMS570. I did not know HalCoGen until my reading your reply mentioned here. Therefore I just dig into the data sheet and start coding from scratch. 

    I intended to send data out from Tx[1] and receive data from Rx[1] both in fixed location. Currently it is 100% working for SPI-DMA writing from memory pool  to NVRAM without data lost. From oscilloscope point of view, the recorded 4 curves of CS, CLK, SO and SI of reading from NVRAM is also 100% correct without data lost. However the SPI did not generate RX_DMA_REQ to LINE_RD_NO for reading DMA at channel of CHANNEL_RD_NO as configured. I found all the 0x00s at the memory location from 0xff0e0208 and up. Now I am not sure the way of my understand in configuration methods in my three previous questions, especially the read channel and writing channel mapping lines of question 2).

     

    Best Regards,

    Long Wan

  • Hi Long,
    I will suggest that you reference the HalcoGen example. Please go to HalCoGen->Help->Help Topics->Examples and you will find the example_mibspiDma.c with instructions on how to configure the HalCoGen for MibSPI+DMA operation.

    There are two more things that I see in your code.

    1. You seem to configure the MibSPI with just one buffer for DMA operation. If one buffer is what you want then you should use the SPI (which is the MibSPI in compatibility mode) instead. Normally, if you use MibSPI you will have multiple buffers setup to transfer.

    2. I see below code. First, the write channel and read channel are generating the same request line. For example, spiREG1->DMACTRL[CHANNEL_WR_NO].TXDMA_MAP = LINE_WR_NO; and spiREG1->DMACTRL[CHANNEL_RD_NO].TXDMA_MAP = LINE_WR_NO are generating request to the same request which is LINE_WR_NO. Secondly, you enable both TXDMA and RXDMA for each write and read channel. I think this can cause problem too.

    For writes:
    spiREG1->DMACTRL[CHANNEL_WR_NO].TXDMA_MAP = LINE_WR_NO; // DMA TX channel line number?
    spiREG1->DMACTRL[CHANNEL_WR_NO].RXDMA_MAP = LINE_RD_NO; // DMA RX channel line number?
    spiREG1->DMACTRL[CHANNEL_WR_NO].TXDMA_ENA = 1U;
    spiREG1->DMACTRL[CHANNEL_WR_NO].RXDMA_ENA = 1U;

    For reads:
    spiREG1->DMACTRL[CHANNEL_RD_NO].TXDMA_MAP = LINE_WR_NO; // DMA TX channel line number?
    spiREG1->DMACTRL[CHANNEL_RD_NO].RXDMA_MAP = LINE_RD_NO; // DMA RX channel line number? RXDMA_MAP should be different
    spiREG1->DMACTRL[CHANNEL_RD_NO].TXDMA_ENA = 1U;
    spiREG1->DMACTRL[CHANNEL_RD_NO].RXDMA_ENA = 1U;


    You might want to try:

    1. for the write channel only enable the TXDMA but not the RXDMA and do the same for the read channel in opposite. See below.

    For writes:
    spiREG1->DMACTRL[CHANNEL_WR_NO].TXDMA_MAP = LINE_WR_NO; // DMA TX channel line number?
    spiREG1->DMACTRL[CHANNEL_WR_NO].TXDMA_ENA = 1U;

    For reads:
    spiREG1->DMACTRL[CHANNEL_RD_NO].RXDMA_MAP = LINE_RD_NO; // DMA RX channel line number? RXDMA_MAP should be different
    spiREG1->DMACTRL[CHANNEL_RD_NO].RXDMA_ENA = 1U;

    2. Simply leave out the the read channel because in your write channel you enable both the TX and RXDMA already. Like below.

    For writes:
    spiREG1->DMACTRL[CHANNEL_WR_NO].TXDMA_MAP = LINE_WR_NO; // DMA TX channel line number?
    spiREG1->DMACTRL[CHANNEL_WR_NO].RXDMA_MAP = LINE_RD_NO; // DMA RX channel line number?
    spiREG1->DMACTRL[CHANNEL_WR_NO].TXDMA_ENA = 1U;
    spiREG1->DMACTRL[CHANNEL_WR_NO].RXDMA_ENA = 1U;

    For reads:
    Do configure the read channel because the write will trigger both the TX and RX.


    I strongly suggest you look at the HalCoGen and use the HalCoGen example. If SPI mode can fit your application, you should consider SPI rather than MibSPI if the number of buffers you want to transfer is only 1.