RM48L952: Understanding Mibspi dma data size

Hi!

I'm planning on using dma on mibspi and currently testing the module, but I'm having hard time understanding how exactly it works.

Mibspi will have to handle data size ranging from 2 bytes at least to 823 bytes at most, and it can vary. The problem is passing 823 bytes packet with dma and I came up with 2 options.

1. Using all 128 word buffer of mibspi, pass it as 128 elements, 7 frame data. In this case, (128*7)-823 = 73 bytes will be redundant. I don't know if I'm being correct, but if DMAxCOUNT is actually number of elements that dma transfers, then I'd be able to stop mibspi and dma when it transmitted(and recieved) 823 bytes of data.

2. Using only 1 word buffer of mibspi, pass it as 1 element, 823 frame data or vise versa. Write to single buffer of tx and read from single buffer of rx.

I tried both options to achieve the goal. Unfortunately, it didn't go very well. Actually I'm not even sure if those are possible. I've tried altering many control values and the most frequent problem is that received data by mibspi rx dma becoming same data(ex: receiving "abcdefgh" becomes "cccccccc"). I wonder if using digital loopback has to do anything with this.

I'll look into it more but I'd like to know if any of those options is possible.

It might be better to use compatible spi for this kind of communication, but spi5 tx/rx and sci tx/rx share same dma request line and since I have to use them both, I'd like to use mibspi5 and use other dma request line for mibspi5. 

Thanks for help!

  • Hello,

    1. DMAxCOUNT is used only if the LARGE COUNT bit in the DMACNTLEN register is set. ICOUNT in DMAxCOUNT is the number of DMA transfer rather than the number of elements. If frame transfer is used in DMA configuration, ICOUNT defines the frame number. In your example, ICOUNT=7-1=6. The number of elements transferred are 128*7=896. 

    2. It is easy to transfer 1 element per DMA transfer. 

    Attached is my working example of MibSPI+DMA:

        

  • Hi Wang,

    I think your example is not attached? I checked and referred your other example of RM48L952: MibSpi Tx and Rx using DMA - Other microcontrollers forum - Other microcontrollers - TI E2E support forums, but still couldn't get it done correctly.

    My current design for testing is this:

    txBuffer and rxBuffer are both 128 byte size, though data is 66 bytes total.

    static uint8_t txBuffer[128] = "abcdefghijklmnopqrstuvwxyz\r\n0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n";
    static uint8_t rxBuffer[128] = {0};

    Data format is same as default except charlen is 8bit. Transfer group buffer mode is 7(suspend read/write) so that dma can be synchronized and group buffer size is 1 so that mibspi and dma can be used to transfer data of any size.

    In dma control packet, element count is 1 and frame count is 66 to send and get 66 bytes total. Also length of data can be changed easily by changing frame count. Size of element is 8bit and ttype is BLOCK_TRANSFER so that data communication can be done by single activation.

    void setDmaMibspiPacketCommon(g_dmaCTRL *packet)
    {
        packet->CHCTRL = 0;
        packet->ELCNT = 1;
        packet->FRCNT = 66;
        packet->PORTASGN = 4;
        packet->RDSIZE = ACCESS_8_BIT;
        packet->WRSIZE = ACCESS_8_BIT;
        packet->TTYPE = BLOCK_TRANSFER;
        packet->ADDMODERD = ADDR_OFFSET;
        packet->ADDMODEWR = ADDR_OFFSET;
        packet->AUTOINIT = AUTOINIT_OFF;
    }

    For transmission, source is txBuffer and frame offset is 1, while destination is tx[0].data and both offsets are 0. For receiving, source is rx[0].data and both offsets are 0, while destination is rxBuffer and frame offset is 1.

    mibspiRAM_t* ram = ((mibspiRAM_t *)0xFF0A0000U);
    void setDmaMibspiPacketTransmit(g_dmaCTRL *packet)
    {
        packet->ELSOFFSET = 0;
        packet->FRSOFFSET = 1;
        packet->SADD = (uint32_t)txBuffer;
    
        packet->ELDOFFSET = 0;
        packet->FRDOFFSET = 0;
        packet->DADD = (uint32_t)(&(ram->tx[0].data));
    }
    
    void setDmaMibspiPacketReceive(g_dmaCTRL *packet)
    {
        packet->ELSOFFSET = 0;
        packet->FRSOFFSET = 0;
        packet->SADD = (uint32_t)(&(ram->rx[0].data));
    
        packet->ELDOFFSET = 0;
        packet->FRDOFFSET = 1;
        packet->DADD = (uint32_t)rxBuffer;
    }

    Below code is main routine. Before going into loop, program sets dma control packet, enable dma, set request line, enable BTC interrupt for dma rx.

    In each iteration in main loop, program clears buffer, set dma channel enable, set dma request and start transfer, then wait until done.

    void mibspiMasterDmaTest(){
        g_dmaCTRL dmaRxPacket = {0};
        g_dmaCTRL dmaTxPacket = {0};
        uint32_t dmaReqlineMibspiRx = 28; /* mibspi5[14] */
        uint32_t dmaReqlineMibspiTx = 29; /* mibspi5[15] */
        uint32_t dmaChannelRx = DMA_CH0;
        uint32_t dmaChannelTx = DMA_CH1;
        int i;
    
        /* Digital loopback test mode */
        mibspiEnableLoopback(mibspiREG5, Digital_Lbk);
    
        setDmaMibspiPacketCommon(&dmaTxPacket);
        setDmaMibspiPacketCommon(&dmaRxPacket);
    
        setDmaMibspiPacketTransmit(&dmaTxPacket);
        setDmaMibspiPacketReceive(&dmaRxPacket);
    
        /* Dma request line channel for mibspi5 */
        mibspiREG5->DMACTRL[0] |= (14 << 20) | (15 << 16);
    
        /* Using oneshot mode at mibspi dma. Using it does not change behaviour */
    //    mibspiREG5->DMACTRL[0] |= (1 << 31);
    //    mibspiREG5->DMACNTLEN = 1;
    //    mibspiREG5->DMACOUNT[0] |= (65 << 16);
    
        dmaEnable();
    
        dmaReqAssign(dmaChannelRx, dmaReqlineMibspiRx);
        dmaReqAssign(dmaChannelTx, dmaReqlineMibspiTx);
    
        dmaSetCtrlPacket(dmaChannelRx, dmaRxPacket);
        dmaSetCtrlPacket(dmaChannelTx, dmaTxPacket);
    
        /* Tx complete interrupt is not needed */
        dmaEnableInterrupt(dmaChannelRx, BTC);
    
        /* Keep transfering */
        while(1){
    
            /* Wait between spi communications */
            for(i = 0; i < 10000000; i++){
            }
    
            /* Clear buffers to check if mibspi and dma are working correctly */
            for(i = 0; i < 128; i++){
                rxBuffer[i] = 0;
                ram->tx[i].data = 0;
            }
    
            /* Set dma ready */
            dmaSetChEnable(dmaChannelRx, DMA_HW);
            dmaSetChEnable(dmaChannelTx, DMA_HW);
            mibspiREG5->DMACTRL[0] |= (1 << 15) | (1 << 14);
    
            /* Start transfering */
            mibspiTransfer(mibspiREG5, 0);
    
            /* Wait until communication is done */
            while(mibspiIsTransferComplete(mibspiREG5, 0) != true)
            {
            }
        }
    }

    In dma notification, program prints out rxBuffer to pc via uart(sci).

    void dmaGroupANotification(dmaInterrupt_t inttype, uint32 channel)
    {
        /* Send data to console */
        sciSend(sciREG, 128, rxBuffer);
    }

    Expected behaviour is printing

    abcdefghijklmnopqrstuvwxyz
    0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ

    to pc terminal repeatedly. But instead it prints same random character 66 times, mostly c, g or h. When I peeked mibspiRAM5 memory right after transfer is over, tx had 10(\n) which is correct but rx had 104(h) which is incorrect.

    I think I've done correctly but it seems not. What could be the problem?

  • Please use Frame Transfer for TTYPE.  

  • Hi Wang,

    Changing TType to Frame transfer and disabling Oneshot for Transfer Group made it work.

    Now I tried to use dma oneshot and DMAxCOUNT value to transfer data, so uncommented below part.

    void mibspiMasterDmaTest(){
        ...
        
        mibspiREG5->DMACTRL[0] |= (1 << 31);
        mibspiREG5->DMACNTLEN = 1;
        mibspiREG5->DMACOUNT[0] |= (65 << 16);
        
        ...
        while(1){
            ...
        }
    }

    It does transfer data but only one time. I looked into register values and it showed RxBuf was full. Also both completed and suspended interrupt of TG0 was set. While dma btc notification was called for rx, TG enabled and TG triggered in TG control register was 1.

    Do I need to change some other value to make it work?

  • If bit 31 (oneshot) of DMACTRL register is set, the DMA only transfer (ICOUNT+1) frames. 

    If oneshot of TGxCTRL register is set, the MibSPI only transfers 1 time for each trigger event (if TG size is 1 buffer, only 1 buffer is transferred).