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.

MibSpi DMA

Other Parts Discussed in Thread: HALCOGEN

Hi,

I am strugging a little with the example_mibspiDma.c example included in HalCoGen. I had to modify it to MibSpi3 because I am using a custumized bord, SPI1 is in use. DMA-Transfer seems to work, but not for the first three words in an transaction. Hope someone can help, here the lines I modified:

dmaReqAssign(DMA_CH2, 14); // request line for MibSPI is 14

damSetCtrlPacket(DMA_CH2 ,g_dmaCTRLPKT); //dma control packet 
dmaSetChEnable(DMA_CH2, DMA_HW);

 mibspiDmaConfig(mibspiREG3,DMA_CH,0,1); // not too sure what this does, specially this part: mibspi->DMACTRL[channel] |= (((rxchannel<<4)|txchannel) << 16);

It's actually just the beginning of something bigger, here's, what I actually want to do

 -Send large arrays of 8-Bit-data (each >1k)

- delay after each packet; I am guessing HW-Trigger, for example HET would be applicable

Example:

uint8 TxBuf[50[1000];

send TxBuf[0][0]->DELAY-10ms->send TxBuf[1][0]->DELAY_10ms ........send TxBuf[49][0]->DELAY_10ms->sendTxBuf[0][0] ....

But right now I am stuck on the simple DMA example.

Regards,

Juergen

                                                                            

  • Hi Juergen,

    Sorry for a late response. Each MibSPI generates multiple requests which are connected to the DMA controller as described in the datasheet. MibSPI1 uses DMA requests 0 and 1 for transmit and receive conditions when in standard SPI mode. It has several other DMA requests that it can generate based on the MibSPI module configuration in multi-buffered mode.

    Similarly MibSPI3 generates TX and RX DMA requests in standard SPI mode on DMA requests number 14 and 15. There are other DMA requests available only in multi-buffered mode.

    mibspiDmaConfig configures the DMACTRL register for you. When you change the example to use MibSPI3 instead of MibSPI1, you need to change the TX and RX DMA channels being used for this (the last two arguments to this function can not be 0 and 1 as these are dedicated for MibSPI1).

    Regards,
    Sunil
  • Hi Jürgen,

    I'm currently writing on a Application Note about transmitting and receiving large chunks of data with the MIBSPI and DMA controller.
    The MIBSPI has a rather large buffer to store SPI frames, this buffer can trigger the DMA controller to efficiently fill this buffer for even larger chunk of data.

    For now I can provide you the following preliminary code on how to transmit data. But please keep in mind, that this is still work in progress and I honestly didn't spend too much time on the transmitter side yet, my primary focus was on the receiver side till now. However, this code should be stable enough to serve you as a starting point.

    /*
     * main.c
     */
    
    #include <stdio.h>
    
    #include "sys_common.h"
    #include "sys_dma.h"
    #include "mibspi.h"
    
    typedef struct {
    	struct {
    #if ((__little_endian__ == 1) || (__LITTLE_ENDIAN__ == 1))
    		uint16_t u16Data;
    		uint16_t u16Control;
    #else
    		uint16_t u16Control;
    		uint16_t u16Data;
    #endif
    	} sTXBuffer[128];
    
    	struct {
    #if ((__little_endian__ == 1) || (__LITTLE_ENDIAN__ == 1))
    		uint16_t u16Data;
    		uint16_t u16Status;
    #else
    		uint16_t u16Status;
    		uint16_t u16Data;
    #endif
    	} sRXBuffer[128];
    } tMibSpiRam;
    
    #pragma LOCATION(sMibSpi5Ram, 0xFF0A0000);
    tMibSpiRam sMibSpi5Ram;
    
    #pragma DATA_ALIGN(source, 8);
    uint16_t source[64] = {0u};
    uint16_t dest[64]   = {0u};
    
    int main(void)
    {
    	int32_t  i32Index   = 0l;
    	uint16_t ui16Index2 = 0u;
    	uint16_t ui16Check  = 0u;
    
    	g_dmaCTRL g_dmaCTRLPKT;
    
    	mibspiInit();
    
    	mibspiREG5->DMACNTLEN  =   1ul; /* Enable Large Count */
    	mibspiREG5->DMACTRL[0] =  (1ul << 31)   /* Auto-disable of DMA channel (in MibSPIP) after ICOUNT+1 transfers. */
    							| (63ul << 24)  /* Buffer utilized to trigger DMA transfer. */
    							| (0ul << 20)   /* RXDMA_MAPx */
    							| (2ul << 16)   /* TXDMA_MAPx */
    							| (0ul << 15)   /* Receive data DMA channel enable. */
    							| (0ul << 14)   /* Transmit data DMA channel enable. */
    							| (0ul << 13)   /* Non-interleaved DMA block transfer. This bit is available in master mode only. */
    							| (0ul <<  8);  /* ICOUNTx */
    	mibspiREG5->DMACOUNT[0] = (64ul - 1ul) << 16;   /* Large ICOUNT */
    
    	/* Enable DMA module : this brings DMA out of reset */
    	dmaEnable();
    
    	/* Setup DMA Control Packed (structure is part of dma.c) */
    	g_dmaCTRLPKT.SADD      = (uint32_t)(&source[0]);  /* initial source address */
    	g_dmaCTRLPKT.DADD      = (uint32_t)(&sMibSpi5Ram.sTXBuffer[0].u16Data); /* initial destination address */
    	g_dmaCTRLPKT.CHCTRL    = 0ul; /* channel control */
    	g_dmaCTRLPKT.RDSIZE    = ACCESS_64_BIT; /* read size */
    	g_dmaCTRLPKT.WRSIZE    = ACCESS_16_BIT; /* write size */
    	g_dmaCTRLPKT.FRCNT     = 1; /* frame count */
    	g_dmaCTRLPKT.ELCNT     = (sizeof(source) / sizeof(source[0])) / 4;   /* element count */
    	g_dmaCTRLPKT.ELSOFFSET = 1ul << g_dmaCTRLPKT.RDSIZE; /* element source offset */
    	g_dmaCTRLPKT.FRSOFFSET = 0ul << g_dmaCTRLPKT.RDSIZE; /* frame source offset */
    	g_dmaCTRLPKT.ELDOFFSET = 2ul << g_dmaCTRLPKT.WRSIZE; /* element destination offset */
    	g_dmaCTRLPKT.FRDOFFSET = 0ul << g_dmaCTRLPKT.WRSIZE; /* frame destination offset */
    	g_dmaCTRLPKT.PORTASGN  = 4ul; /* port b */
    	g_dmaCTRLPKT.TTYPE     = FRAME_TRANSFER ; /* transfer type */
    	g_dmaCTRLPKT.ADDMODERD = ADDR_OFFSET;     /* address mode read */
    	g_dmaCTRLPKT.ADDMODEWR = ADDR_OFFSET;     /* address mode write */
    	g_dmaCTRLPKT.AUTOINIT  = AUTOINIT_ON;     /* autoinit */
    
    	/* Assign DMA Control Packet to Channel 0 */
    	dmaSetCtrlPacket(DMA_CH0, g_dmaCTRLPKT);
    
    	/* Assign DMA request: channel-0 with request line - 8 */
    	dmaReqAssign(DMA_CH0, 6ul); /* Request Line 6 is MIBSPI5[2] */
    
    	/* Set the DMA Channel 0 to trigger on h/w request */
    	dmaSetChEnable(DMA_CH0, DMA_HW);
    
    	mibspiPmodeSet(mibspiREG5, PMODE_4_DATALINE, DATA_FORMAT0);
    
    	for (i32Index = 0l ; i32Index < ((sizeof(source) / sizeof(source[0])) - 1); i32Index++)
    	{
    		ui16Check       += ui16Index2;
    		source[i32Index] = ui16Index2++;
    	}
    
    	source[(sizeof(source) / sizeof(source[0])) - 1] = ui16Check;
    
    	mibspiREG5->DMACTRL[0] |= (1ul << 14); /* Transmit data DMA channel enable. */
    	mibspiSetData(mibspiREG5, 0ul, source);
    
    	do
    	{
    		ui16Check = 0u;
    
    		mibspiTransfer(mibspiREG5, 0ul);
    
    		for (i32Index = 0l ; i32Index < ((sizeof(source) / sizeof(source[0])) - 1); i32Index++)
    		{
    			ui16Check       += ui16Index2;
    			source[i32Index] = ui16Index2++;
    		}
    
    		source[(sizeof(source) / sizeof(source[0])) - 1] = ui16Check;
    
    		mibspiREG5->DMACTRL[0] |= (1ul << 14); /* Transmit data DMA channel enable. */
    
    		while (!mibspiIsTransferComplete(mibspiREG5, 0ul));
    
    		//mibspiGetData(mibspiREG5, 0ul, dest);
    		//mibspiREG5->DMACOUNT[0] = (64ul - 1ul) << 16;   /* Large ICOUNT */
    
    		if (ui16Index2 >= 256u)
    		{
    			asm("test: NOP");
    		}
    	}
    	while(1);
    	
    	return 0;
    }

    The program above transmits 128 byte packets (64 x 16 bit SPI transfers), the MIBSPI RAM is loaded via the DMA in chunks of 4 x 16bit (8 byte), till the whole 128 byte buffer was transmitted (64 SPI transfers, 16 DMA elements).

    Please also notice, that the MIBSPI is able to introduce adjustable delays between consecutive transactions and that is has an optional handshake feature (ENA pin).

    Best Regards,
    Christian

  • , it would be great if you could post a link to the AN once it's written.
  • Hi Sunil,

    it's totally fine, I still consider this quick. What you say was my intial understanding, I sum up what I think I know:

    dmaReqAssign(DMA_CH2, 14); //datasheet tells me that request line 14 is a MIPSPI3 request line; I wire it up to DMA-channel 2

    mibspiDmaConfig(mibspiREG3,DMA_CH_2,14,15); // connect request line 14 to MIBSPI3 transmit path and line 15 to rx path (should matter, no RX DMA)

    That's what I initally tried, I didn't receive anything through digital loopback.

    When I modify it to mibspiDmaConfig(mibspiREG3,DMA_CH,0,1) I don't get the first 3 half-words looped back on the first time I inititate mibspiTransfer(), If I initiate it once more (loop) I receive everything, including the first 3 half-words.

    I attach my example for reference.

    Regards,

    Juergen

    4061.mibspi3_dma_example.c

  • Hi Christian,

    thanks a lot, I'll lock into it after I solved my beginners problem with Sunil's help.

    Regards,
    Juergen
  • Juergen,

    The configuration inside MibSPI is only aware of the request number being output from MibSPI, and not the physical request number on the DMA module being used. That said, the DMA request numbers 14 and 15 are still wired to MibSPI3 request outputs number 0 and 1, so your initial configuration was correct for the TXDMAMAP and RXDMAMAP.

    MibSPI also supports up to 8 pairs of requests, each controlled by one DMAxCTRL register inside the MibSPI module. This does not have any relationship to the actual DMA channel being used (DMA_CH2 in your case). Still the entire configuration done using MibSPI request pair # 2 is fine.

    I will have to check into why you are not getting the first three half-words looped back.

    Regards,
    Sunil
  • Juergen,


    If this can help, I've attached an example of MIBSPI using DMA to communicate to a regular SPI (on the same chip)
    This code requires external connection between MIBSPI1 and SPI4 (SOMI to SOMI, SIMO to SIMO, CLK to CLK and CS_0 to CS_0)

    The Halcogen project is included.

    Modifying this code to run on MIBSPI3 will be very easy.

    Please have a look and let me know if it helps.

    8713.TMS570LS1224_MIPSPI1_SPI4_DMA.zip

  • Jean-Marc,

    this for sure helps. RX-DMA is no problem. I tried modify the TX side of the example. I tested RX-DMA by sending out data on the same SPI in analog/digital loopback mode, works fine. Then I tried to feed the DAT0/DAT1-Register trough DMA, but I can't get a DMA transfer to DAT0/DAT1 going.TRM says that setting DMA_REQ_EN to 1 should generate a request, TXINTFLAG is set, which means DAT0/DAT1 are ready to receive data.

    dmaEnable();      /* enable DMA now to make sure it's ready to take requests   */      
                                /* enable dma requests, should send request to DMA             */
    spiREG3->INT0 = (spiREG3->INT0 & 0x0000FFFFU) | 0x00010000;

    Would appreciate it if you could take a look at it, I'lll attach the code.4214.spi3_dma.c

  • Hi all,

    I still require some help DMA on MibSpi. I got DMA TX/RX in compatibility mode to work, I'll post that with a few comments later, I think the post should end with all problems solved :)

    My MibSpi example is quite simple (code attached). Sending out 16 words and looping it back in on the same MibSpi. TX-DMA works just fine, data is looped back, I can see that in the mibspiRAM3->rx[] locations. But DMA only transfers the first word to the data buffer in RAM. If I stop the debugger at the line mibspiTransfer(mibspiREG3,0 ); and single step from there a few times I get all data transfered to my rx-buffer in RAM. I can't explain myself that behavior nor can I get the transfer done in free running mode.

    1667.mibspi3Dma.c

    Hope someone can help me here.

    Regards,

    Juergen

  • Juergen,

    Your code was almost perfect. What is missing is in the mibspiDmaConfig routine the definition of bufid.

    Bufid is used as trigger for the DMA request. In your case, it was set to 0, so on the first received data in the MIBSPI_RX, the DMA was fired and was transferring the correct first data and all other were 0s. To validate this, try filling the RX_DATA with non 0x0000_0000 and see the result.
    After the transfer, the first location will be 0x1111_0000 and all other 0x0000_0000 showing that the DMA was working, but only 1 data was received.

    Change in mibspiDmaConfig

        uint32 bufid  = D_SIZE - 1;

    With this initialization, all 16 received data are transferred.

    For information, check the TRM page:

    Also in the configuration of the MIBSPI transfer group0, I'm not sure why you are using Buffer_Mode = 7. (It is working)
    I usually use Buffer_Mode = 4 (Always)

    Please have a try and let me know.

  • Jean-Marc,

    very interesting, it works. But I have no idea what's happening :) I want to understand what's going to be able to tailor MibSPI and DMA to all kind of applications.

    I filled the RAM RX-Buffer with none zeros as you suggested. And just like you said, I ended up with the first word being transferred correctly and the following locations filled with zeros. That tells me that the MibSPI actually fired the correct amount of DMA requests but only the first word matches the content of the MibSPI RX-Buffers (all words sent are looped back correctly into MibSPI RX buffer). Two Questions:

    1) Where do the zeros come from?

    2) I don't understand what BUFID actually does, this is the TRM description BUFIDx:

    Buffer utilized for DMA transfer. BUFIDx defines the buffer that is utilized for the DMA

    transfer. In order to synchronize the transfer with the DMA controller with the NOBRK

    condition the "suspend to wait until..." modes must be used.


    I use TG0 zero. That's why I set it to zero. Obviously it doesn't have anything to do with the transfer group in use. But reading it I'd never think of setting it to DSIZE-1, can you help? Should I read it like "BUFID is the Bufffer size utilized for DMA transfer....."?

    I can't answer why I use Buffer_Mode 7, I just tried out a couple of things :)

    Regards,
    Juergen

     

  • Juergen,

    It is necessary to specify for the MIBSPI Receive DMA request, when to fire the request.
    The amount of data to be transferred by DNA is defined in the DMA control packet used for MIBSPI Receive.

    In case BUFID = 0, when the first data (0x1111) is send and received, the MIBSPI will fire the DMA request for receive.
    The DMA will then read the MIBSPI RX RAM according to the definition in the corresponding control packet and transfer 16 data.
    At that point, only the first received buffer contains a valid data (0x1111) all others are still 0x0000. That the reason why you see in your receive array the first data as 0x1111 and all others as 0x0000.

    Now when you stop execution, the MIBSPI was still transferring the other 15 data and when you look at the receive buffer they are all correct.

    I think the mibspiDmaConfig is not defined correctly. The BUFID should be an argument that is passed to the function.
    I your case, BUFID=DSIZE - 1 because you are only using 1 Transfer Group and the buffer in used are 0 to 15.
    I will check the RTL to double check this statement.

    Please let me know if I've clarified your question. 

  • Jean-Marc,

    let me put it in my own words and we'll see if I fully understand what is going on:

    TX:
    TG0 is configured to a size of 16, so is the DMA control package. MibSPI fires one DMA request at the beginning and DMA transfers 16 Words to MibSPI's TX RAM

    RX:
    After reception of a certain amount of data-packets (16 Words in my case) MibSPI fires one DMA request and DMA reads from 16 locations in MibSPI's RX RAM. BUFID tells MibSPI when it's time to fire this request?

    Of course BUFID should be a parameter to mibspiDmaConfig(), for an example code it's fine that it's not though. I am not sure if the TRM describes BUFID very well. Either way, DMA is not the easiest module to work with since there is usually DMA/Peripheral. There is a great deal of flexibility in the systems which sometimes makes it hard to get it all together.

    This is why you guys are great, would be very time consuming otherwise, thanks a lot.

    Regards,
    Juergen
  • Jurgen,


    Yes your understanding is correct. Anyway on the RX description I will change:

    After reception of a certain amount of data-packets

    by

    After reception of a specific buffer (defined by BUFID)