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.

TMS570LS3137: MibSpi DMA Clock and MOSI line

Part Number: TMS570LS3137
Other Parts Discussed in Thread: HALCOGEN

Hi, I tried to implement a data exchange on MIBSPI1 by connecting the board's SIMO[0] MIBSPI1 line with the SOMI[0] MIBSPI1 port.
In Halcogen I selected these settings:

I want to transfer 10 FRAME of 61 ELEMENT each.

This is the implemented DMA and MIBSPI configuration: 

void dmaConfigCtrlTxPacket(uint32 sadd,uint32 dadd,uint16 ElmntCnt, uint16 FrameCnt)
{
g_dmaCTRLPKT_TX.SADD = sadd; /* source address */
g_dmaCTRLPKT_TX.DADD = dadd; /* destination address */
g_dmaCTRLPKT_TX.CHCTRL = 0; /* channel control */
g_dmaCTRLPKT_TX.FRCNT = FrameCnt; /* frame count */
g_dmaCTRLPKT_TX.ELCNT = ElmntCnt; /* element count */
g_dmaCTRLPKT_TX.ELDOFFSET = 4; /* element destination offset */
g_dmaCTRLPKT_TX.ELSOFFSET = 0; /* element source offset */
g_dmaCTRLPKT_TX.FRDOFFSET = 0; /* frame destination offset */
g_dmaCTRLPKT_TX.FRSOFFSET = 0; /* frame destination offset */
g_dmaCTRLPKT_TX.PORTASGN = 4; /* port b */
g_dmaCTRLPKT_TX.RDSIZE = ACCESS_16_BIT; /* read size */
g_dmaCTRLPKT_TX.WRSIZE = ACCESS_16_BIT; /* write size */
g_dmaCTRLPKT_TX.TTYPE = FRAME_TRANSFER ; /* transfer type */
g_dmaCTRLPKT_TX.ADDMODERD = ADDR_INC1; /* address mode read */
g_dmaCTRLPKT_TX.ADDMODEWR = ADDR_OFFSET; /* address mode write */
g_dmaCTRLPKT_TX.AUTOINIT = AUTOINIT_ON; /* autoinit */
}

void dmaConfigCtrlRxPacket(uint32 sadd,uint32 dadd,uint16 ElmntCnt, uint16 FrameCnt)
{
g_dmaCTRLPKT_RX.SADD = sadd; /* source address */
g_dmaCTRLPKT_RX.DADD = dadd; /* destination address */
g_dmaCTRLPKT_RX.CHCTRL = 0; /* channel control */
g_dmaCTRLPKT_RX.FRCNT = FrameCnt; /* frame count */
g_dmaCTRLPKT_RX.ELCNT = ElmntCnt; /* element count */
g_dmaCTRLPKT_RX.ELDOFFSET = 0; /* element destination offset */
g_dmaCTRLPKT_RX.ELSOFFSET = 4; /* element source offset */
g_dmaCTRLPKT_RX.FRDOFFSET = 0; /* frame destination offset */
g_dmaCTRLPKT_RX.FRSOFFSET = 0; /* frame destination offset */
g_dmaCTRLPKT_RX.PORTASGN = 4; /* port b */
g_dmaCTRLPKT_RX.RDSIZE = ACCESS_16_BIT; /* read size */
g_dmaCTRLPKT_RX.WRSIZE = ACCESS_16_BIT; /* write size */
g_dmaCTRLPKT_RX.TTYPE = FRAME_TRANSFER ; /* transfer type */
g_dmaCTRLPKT_RX.ADDMODERD = ADDR_OFFSET; /* address mode read */
g_dmaCTRLPKT_RX.ADDMODEWR = ADDR_INC1; /* address mode write */
g_dmaCTRLPKT_RX.AUTOINIT = AUTOINIT_ON; /* autoinit */
}

void mibspiDmaConfig(mibspiBASE_t *mibspi,uint32 channel, uint32 txchannel, uint32 rxchannel)
{
uint32 bufid = E_COUNT - 1; //number of buffers in TG0

/* setting transmit and receive channels */
mibspi->DMACTRL[channel] |= (rxchannel << 20) | (txchannel << 16);

if (F_COUNT > 1) {
mibspi->TGCTRL[channel] &= 0xBFFFFFFF; // Disable ONESHOT
} else {
mibspi->TGCTRL[channel] |= 0x40000000; // Enable ONESHOT
}

/* enabling transmit and receive dma */
mibspi->DMACTRL[channel] |= 0x8000C000;

/* setting Initial Count of DMA transfers and the buffer utilized for DMA transfer */
mibspi->DMACTRL[channel] |= (bufid<<24);

/* setting Initial Count of DMA transfers and the buffer utilized for DMA transfer */
mibspi->DMACTRL[channel] |= ((F_COUNT - 1)<<8);

// /* setting Initial Count of DMA transfers and the buffer utilized for DMA transfer */
// mibspi->DMACTRL[channel] |= (0<<31);
//
// mibspi->DMACNTLEN = 0x1;
// mibspi->DMACOUNT[channel] = (F_COUNT - 1) << 16;
}

If I start the program the transfer occurs correctly, but with the oscilloscope, I see that the clock and MOSI lines continue to send data despite the fact that the transmission should be finished since I receive the block transfer complete interrupt. Is this behavior normal or is there something wrong with the configuration or implementation?


Attached is the complete sys_main.c for further analysis.

/** @file sys_main.c 
*   @brief Application main file
*   @date 11-Dec-2018
*   @version 04.07.01
*
*   This file contains an empty main function,
*   which can be used for the application.
*/

/* 
* Copyright (C) 2009-2018 Texas Instruments Incorporated - www.ti.com 
* 
* 
*  Redistribution and use in source and binary forms, with or without 
*  modification, are permitted provided that the following conditions 
*  are met:
*
*    Redistributions of source code must retain the above copyright 
*    notice, this list of conditions and the following disclaimer.
*
*    Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the 
*    documentation and/or other materials provided with the   
*    distribution.
*
*    Neither the name of Texas Instruments Incorporated nor the names of
*    its contributors may be used to endorse or promote products derived
*    from this software without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
*  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
*  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
*  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
*  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
*  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
*  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
*  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/


/* USER CODE BEGIN (0) */
/* USER CODE END */

/* Include Files */

#include "sys_common.h"

/* USER CODE BEGIN (1) */
#include "mibspi.h"
#include "sys_dma.h"
#include "stdio.h"
#include "sys_core.h"
/* USER CODE END */

/** @fn void main(void)
*   @brief Application main function
*   @note This function is empty by default.
*
*   This function is called after startup.
*   The user can use this function to implement the application.
*/

/* USER CODE BEGIN (2) */
void mibspiDmaConfig(mibspiBASE_t *mibspi,uint32 channel, uint32 txchannel, uint32 rxchannel);
void dmaConfigCtrlRxPacket(uint32 sadd,uint32 dadd,uint16 ElmntCnt, uint16 FrameCnt);
void dmaConfigCtrlTxPacket(uint32 sadd,uint32 dadd,uint16 ElmntCnt, uint16 FrameCnt);
void loadDataPattern1(uint32 psize, uint16* pptr);
void loadDataPattern2(uint32 psize, uint16* pptr);
#define E_COUNT      61  //4   /*Element count*/
#define F_COUNT      10   //2   /*Frame count*/
#define D_SIZE      E_COUNT * F_COUNT

/* SPI1 transmit buffer in sys ram */
uint16 mibSPI1_TX_Data[D_SIZE];//= "$GPZDA,hhmmss.ss,dd,mm,yyyy,aa,bb*CS<CR><LF>$GPGLL,llll.lllll,a,yyyyy.yyyyy,b,hhmmss.ss,c,a*CS<CR><LF>$GPGSV,t,n,xx,aa,ee,zzz,cc,aa,ee,zzz,cc,aa,ee,zzz,cc,aa,ee,zzz,cc*CS<CR><LF>$GPRMC,hhmmss.ss,A,llll.lllll,A,yyyyy.yyyyy,B,ssss.ss,hhh.hh,ddmmyy,mm.m,D,B*CS<CR><LF>$GPGGA,hhmmss.ss,llll.lllll,A,yyyyy.yyyyy,B,q,nn,hh.h,aaaaa.a,M,sss.s,M,a.a,aaaa*CS<CR><LF>$GPGSA,a,m,s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,pp.p,hh.h,vv.v*CS<CR><LF>$GPVTG,ddd.dd,T,ddd.dd,M,ssss.ss,N,ssss.ss,K,a*CS<CR><LF>";
/* SPI2 transmit  buffer in sys ram */
/* SPI1 receive buffer in sys ram */
uint16 mibSPI1_RX_Data[D_SIZE]= {0};
/* SPI2 receive  buffer in sys ram */

g_dmaCTRL g_dmaCTRLPKT_RX;  /* dma control packet configuration stack for receive */
g_dmaCTRL g_dmaCTRLPKT_TX;  /* dma control packet configuration stack for transmit */

typedef enum dmaRequest
{
    DMA_REQ0 = 0U,  DMA_REQ1,   DMA_REQ2,   DMA_REQ3,
    DMA_REQ4,       DMA_REQ5,   DMA_REQ6,   DMA_REQ7,
    DMA_REQ8,       DMA_REQ9,   DMA_REQ10,  DMA_REQ11,
    DMA_REQ12,      DMA_REQ13,  DMA_REQ14,  DMA_REQ15,
    DMA_REQ16,      DMA_REQ17,  DMA_REQ18,  DMA_REQ19,
    DMA_REQ20,      DMA_REQ21,  DMA_REQ22,  DMA_REQ23,
    DMA_REQ24,      DMA_REQ25,  DMA_REQ26,  DMA_REQ27,
    DMA_REQ28,      DMA_REQ29,  DMA_REQ30,  DMA_REQ31,
    DMA_REQ32,      DMA_REQ33,  DMA_REQ34,  DMA_REQ35,
    DMA_REQ36,      DMA_REQ37,  DMA_REQ38,  DMA_REQ39,
    DMA_REQ40,      DMA_REQ41,  DMA_REQ42,  DMA_REQ43,
    DMA_REQ44,      DMA_REQ45,  DMA_REQ46,  DMA_REQ47
}dmaRequest_t;

unsigned MIBSPI_DMA_FLG;
/* USER CODE END */

int main(void)
{
/* USER CODE BEGIN (3) */
    uint32 i;

    _enable_interrupt_();

    /* - initializing mibspi - enabling Transfer Group 0 , length 128 (halcogen file)*/
    mibspiInit();
    dmaDisable();

    loadDataPattern1(D_SIZE, &mibSPI1_TX_Data[0]);

/*****************************************************************/
    /* - configuring dma control packet for sending data to mibSPI3 tx buffer*/
    dmaConfigCtrlRxPacket((uint32)&(mibspiRAM1->rx[0].data),(uint32)&(mibSPI1_RX_Data), E_COUNT, F_COUNT);
    /* - configuring dma control packet for receiving data from mibSPI3 rx buffer*/
    dmaConfigCtrlTxPacket((uint32)&(mibSPI1_TX_Data),(uint32)&(mibspiRAM1->tx[0].data), E_COUNT, F_COUNT);

    /* - setting dma control packets for transmit */
    dmaSetCtrlPacket(DMA_CH1, g_dmaCTRLPKT_TX);
    /* - setting dma control packets for Receive */
    dmaSetCtrlPacket(DMA_CH0, g_dmaCTRLPKT_RX);

    /* DMA Request Sources: MIBSPI1[0] -> DMA request 1 */
    dmaReqAssign(DMA_CH1, DMA_REQ9 );    /* Transmit data DMA channel enable. Request line=0*/
    /* DMA Request Sources: MIBSPI1[1] -> DMA request 0 */
    dmaReqAssign(DMA_CH0, DMA_REQ8 );    /* Receive data DMA channel enable. Request Line=1. */

    /* - setting the dma channel to trigger on h/w request */
    dmaSetChEnable(DMA_CH1, DMA_HW);
    dmaSetChEnable(DMA_CH0, DMA_HW);

    /* - configuring the mibspi dma , channel 0 , tx line -0 , rxline -1     */
    /* - refer to the device data sheet dma request source for mibspi tx/rx  */
    mibspiDmaConfig(mibspiREG1, 0, 5, 4);

    /* Enable Block Transfer Complete interrupt for the receive after transfer complete */
    dmaEnableInterrupt(DMA_CH0, BTC);  //MibSPI1 RX

/****************************************************************/


/****************************************/

    /* enable DMA now to make sure it's ready to take requests   */
    dmaEnable();

//    mibspiSetData(mibspiREG1, 0, &mibSPI1_TX_Data[0]);
//    mibspiSetData(mibspiREG3, 0, &mibSPI3_TX_Data[0]);

    for(i=0;i<=20;i++){printf("\n%dA",i);}
    mibspiTransfer(mibspiREG1, 0);
    while(MIBSPI_DMA_FLG == 0);

    for(i=0;i<=D_SIZE;i++)
    {
        printf("\r\n%d mibSPI1_TX_Data: 0x%04x mibSPI1_RX_Data: 0x%04x  ",i, mibSPI1_TX_Data[i], mibSPI1_RX_Data[i]);
    }
    while(1);
/* USER CODE END */

    return 0;
}


/* USER CODE BEGIN (4) */
void dmaGroupANotification(dmaInterrupt_t inttype, uint32 channel)
{
   MIBSPI_DMA_FLG = 1;
}

void dmaConfigCtrlTxPacket(uint32 sadd,uint32 dadd,uint16 ElmntCnt, uint16 FrameCnt)
{
    g_dmaCTRLPKT_TX.SADD      = sadd;              /* source address             */
    g_dmaCTRLPKT_TX.DADD      = dadd;              /* destination  address       */
    g_dmaCTRLPKT_TX.CHCTRL    = 0;                 /* channel control            */
    g_dmaCTRLPKT_TX.FRCNT     = FrameCnt;                 /* frame count                */
    g_dmaCTRLPKT_TX.ELCNT     = ElmntCnt;             /* element count              */
    g_dmaCTRLPKT_TX.ELDOFFSET = 4;                 /* element destination offset */
    g_dmaCTRLPKT_TX.ELSOFFSET = 0;                 /* element source offset */
    g_dmaCTRLPKT_TX.FRDOFFSET = 0;                 /* frame destination offset   */
    g_dmaCTRLPKT_TX.FRSOFFSET = 0;                 /* frame destination offset   */
    g_dmaCTRLPKT_TX.PORTASGN  = 4;                 /* port b                     */
    g_dmaCTRLPKT_TX.RDSIZE    = ACCESS_16_BIT;     /* read size                  */
    g_dmaCTRLPKT_TX.WRSIZE    = ACCESS_16_BIT;     /* write size                 */
    g_dmaCTRLPKT_TX.TTYPE     = FRAME_TRANSFER ;   /* transfer type              */
    g_dmaCTRLPKT_TX.ADDMODERD = ADDR_INC1;         /* address mode read          */
    g_dmaCTRLPKT_TX.ADDMODEWR = ADDR_OFFSET;       /* address mode write         */
    g_dmaCTRLPKT_TX.AUTOINIT  = AUTOINIT_ON;       /* autoinit                   */
}

void dmaConfigCtrlRxPacket(uint32 sadd,uint32 dadd,uint16 ElmntCnt, uint16 FrameCnt)
{
    g_dmaCTRLPKT_RX.SADD      = sadd;              /* source address             */
    g_dmaCTRLPKT_RX.DADD      = dadd;              /* destination  address       */
    g_dmaCTRLPKT_RX.CHCTRL    = 0;                 /* channel control            */
    g_dmaCTRLPKT_RX.FRCNT     = FrameCnt;                 /* frame count                */
    g_dmaCTRLPKT_RX.ELCNT     = ElmntCnt;             /* element count              */
    g_dmaCTRLPKT_RX.ELDOFFSET = 0;                 /* element destination offset */
    g_dmaCTRLPKT_RX.ELSOFFSET = 4;                 /* element source offset */
    g_dmaCTRLPKT_RX.FRDOFFSET = 0;                 /* frame destination offset   */
    g_dmaCTRLPKT_RX.FRSOFFSET = 0;                 /* frame destination offset   */
    g_dmaCTRLPKT_RX.PORTASGN  = 4;                 /* port b                     */
    g_dmaCTRLPKT_RX.RDSIZE    = ACCESS_16_BIT;     /* read size                  */
    g_dmaCTRLPKT_RX.WRSIZE    = ACCESS_16_BIT;     /* write size                 */
    g_dmaCTRLPKT_RX.TTYPE     = FRAME_TRANSFER ;   /* transfer type              */
    g_dmaCTRLPKT_RX.ADDMODERD = ADDR_OFFSET;       /* address mode read          */
    g_dmaCTRLPKT_RX.ADDMODEWR = ADDR_INC1;         /* address mode write         */
    g_dmaCTRLPKT_RX.AUTOINIT  = AUTOINIT_ON;       /* autoinit                   */
}

void mibspiDmaConfig(mibspiBASE_t *mibspi,uint32 channel, uint32 txchannel, uint32 rxchannel)
{
    uint32 bufid  = E_COUNT - 1;  //number of buffers in TG0

    /* setting transmit and receive channels */
    mibspi->DMACTRL[channel] |= (rxchannel << 20) | (txchannel << 16);

    if (F_COUNT > 1) {
         mibspi->TGCTRL[channel] &= 0xBFFFFFFF; // Disable ONESHOT
    } else {
         mibspi->TGCTRL[channel] |= 0x40000000; // Enable ONESHOT
    }

    /* enabling transmit and receive dma */
    mibspi->DMACTRL[channel] |=  0x8000C000;

    /* setting Initial Count of DMA transfers and the buffer utilized for DMA transfer */
    mibspi->DMACTRL[channel] |=  (bufid<<24);

    /* setting Initial Count of DMA transfers and the buffer utilized for DMA transfer */
    mibspi->DMACTRL[channel] |=  ((F_COUNT - 1)<<8);

//    /* setting Initial Count of DMA transfers and the buffer utilized for DMA transfer */
//    mibspi->DMACTRL[channel] |=  (0<<31);
//
//    mibspi->DMACNTLEN = 0x1;
//    mibspi->DMACOUNT[channel] = (F_COUNT - 1) << 16;
}

void loadDataPattern1(uint32 psize, uint16* pptr)
{
    int i;
    for(i=0;i<psize;i++)
    {
        pptr[i] = i;
    }
 }

void loadDataPattern2(uint32 psize, uint16* pptr)
{
    int i;
    int j = 0;
    for(i=psize;i>0;i--)
    {
        pptr[j] = i;
        j++;
    }
 }

/* USER CODE END */


Thank you in advance for your help.

  • Hi,

    I would like to know one thing that are you verifying after receiving complete data to the receive buffer( mibSPI1_RX_Data)? I mean in your example we are sending 610 halfwords(61*10), did you verifying with oscilloscope after you receiving entire data of 610 bytes or not?

    --

    Thanks,

    Jagadish.

  • Hi Jagadish,
    I don't quite understand your question.

    With the oscilloscope from the time of the first send onwards, on the MOSI line, I keep seeing data sent infinitely.
    In the receive buffer, I can see the same values present in the transmit buffer, as I expect.

  • Hi,

    I found the root cause for the problem, it was due to buffer mode you configured 

    As we are disabling one shot transfer(we are disabling when frame count greater than 1) in our code right so the transfer group trigger will always present and we are configuring buffer mode as "continuous mode" so the behavior is as below

    The sequencer will transmit the data whenever it checks the transfer group buffer, so configure buffer mode as 3 i.e."skip single tranfer overwrite-protect mode" so that the data will transfer only when TX_FULL flag set i.e. new data coming from DMA and receives only when RX_EMPTY flag clears.

    So please use above mode and let me know the result. I tested at my end and it worked fine for me.

    --

    Thanks,

    Jagadish.

  • Hi Jagardish,
    the solution you proposed seems to work well! Thank you!


    Now I would like to implement master-slave communication with two different boards, one acting as master and one as slave, and communicating through MIBSPI1.


    On the master side, I would leave the same settings I showed you.


    On the Slave side I need to (HALCOGEN):
    - MIBSPI1 Global: Disable Master Mode and Internal Clock.
    - MIBSPI1 Data formats: leave everything unchanged from the master?
    - MIBSPI1 Delays: leave everything unchanged from the master?
    - MIBSPI1 Transfer Group: leave everything unchanged from the master?
    - MIBSPI1 Port: enable Output direction for SOMI, disable it for SIMO and CLOCK.


    Are these assumptions correct?
    Also, how does the slave-side code change from the master?


    Sorry for so many questions, but this topic is a bit difficult for me.
    Thank you.

    Guglielmo

  • Hi Guglielmo,

    Are these assumptions correct?

    Yes your assumptions are correct.

    You can also refer below thread for reference

    (+) RM46L852: SPI Slave with DMA - Arm-based microcontrollers forum - Arm-based microcontrollers - TI E2E support forums

    --

    Thanks,

    Jagadish.