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.

TMS570LC4357: How to configure SPI with DMA?

Part Number: TMS570LC4357
Other Parts Discussed in Thread: HALCOGEN

Hello everyone,

I’m working on transmitting and receiving data by SPI with DMA. After trying to send a message once, clock will be constantly active but MOSI and MISO remain completely disabled.

Can you please check my config, maybe I’m doing something wrong?

P.S. I'm wondering that there are some code examples for MIBSPI working with DMA, but literally nothing similar for the SPI, although they have some difference in their base registers.

Thanks in advance!

Here is my config:

/* Include Files */
#include "HL_sys_common.h"
#include "HL_sys_dma.h"
#include "HL_spi.h"
#include "main.h"
#include "spi.h"
#include "dma.h"

/* Defines */
#define D_SIZE                  8
#define SPI_REGISTER            spiREG3
#define BIT_SHIFTING_24         24
#define BIT_SHIFTING_16         16
#define HEX_ONE                 0x1
#define HEX_ZERO                0x0
#define DMA_REQ_LINE_SPI3_TX    15
#define DMA_REQ_LINE_SPI3_RX    14

/* Variables */
uint16_t TXDATA[D_SIZE] = {0x03, 0x88, 0xFF, 0xFF, 0x00, 0xFF, 0x88, 0xF0};     /* transmit buffer */
uint16_t RXDATA[D_SIZE] = {0};                                                  /* receive  buffer */

g_dmaCTRL g_dmaCTRLPKT_TX, g_dmaCTRLPKT_RX;                                     /* dma control packet configuration stack */

/* Function declarations */
void spi_test(void);

/* Function definitions */
int main(void) {
    spi_test();
    return 0;
}

void spi_test(void) {

    /* Initialize SPI interface */
    spiInit();

    // assigning dma request: channel - 0 with request line - 15 (SPI3 Transmit DMA Request) (TRM p710)
    dmaReqAssign((uint32_t)DMA_CH0, DMA_REQ_LINE_SPI3_TX);
    // assigning dma request: channel - 1 with request line - 14 (SPI3 Receive DMA Request)
    dmaReqAssign((uint32_t)DMA_CH1, DMA_REQ_LINE_SPI3_RX);

    // Enable Interrupt after reception of data
    // Group A - Interrupts (FTC, LFS, HBC, and BTC) are routed to the ARM CPU
    // User software should configure only Group A interrupts
    dmaEnableInterrupt((uint32_t)DMA_CH0, (dmaInterrupt_t)BTC, DMA_INTA);
    dmaEnableInterrupt((uint32_t)DMA_CH1, (dmaInterrupt_t)BTC, DMA_INTA);

    /* - configuring dma control packets   */
    g_dmaCTRLPKT_TX.SADD      = (uint32_t)TXDATA;                       /* source address             */
    g_dmaCTRLPKT_TX.DADD      = (uint32_t)(&SPI_REGISTER->DAT1) + 3U;   /* destination  address       */
    g_dmaCTRLPKT_TX.CHCTRL    = 0;                                      /* channel control            */
    g_dmaCTRLPKT_TX.FRCNT	  = 1U;                                     /* frame count                */
    g_dmaCTRLPKT_TX.ELCNT     = D_SIZE;                                 /* element count              */
    g_dmaCTRLPKT_TX.ELDOFFSET = 0U;/*D_SIZE;*/                          /* element destination offset */
    g_dmaCTRLPKT_TX.ELSOFFSET = 0U;		                                /* element destination offset */
    g_dmaCTRLPKT_TX.FRDOFFSET = 0U;		                                /* frame destination offset   */
    g_dmaCTRLPKT_TX.FRSOFFSET = 0U;                                     /* frame destination offset   */
    g_dmaCTRLPKT_TX.PORTASGN  = PORTA_READ_PORTB_WRITE;                 /* port assignment            */
    g_dmaCTRLPKT_TX.RDSIZE    = ACCESS_8_BIT;	                        /* read size                  */
    g_dmaCTRLPKT_TX.WRSIZE    = ACCESS_8_BIT; 	                        /* write size                 */
    g_dmaCTRLPKT_TX.TTYPE     = FRAME_TRANSFER;/*BLOCK_TRANSFER;*/      /* transfer type              */
    g_dmaCTRLPKT_TX.ADDMODERD = ADDR_INC1;                              /* address mode read          */
    g_dmaCTRLPKT_TX.ADDMODEWR = ADDR_FIXED;                             /* address mode write         */
    g_dmaCTRLPKT_TX.AUTOINIT  = AUTOINIT_ON;                            /* autoinit                   */

    g_dmaCTRLPKT_RX.SADD      = (uint32_t)(&SPI_REGISTER->BUF);         /* source address             */
    g_dmaCTRLPKT_RX.DADD      = (uint32_t)RXDATA;                       /* destination  address       */
    g_dmaCTRLPKT_RX.CHCTRL    = 0U;                                     /* channel control            */
    g_dmaCTRLPKT_RX.FRCNT	  = 1U;                                     /* frame count                */
    g_dmaCTRLPKT_RX.ELCNT     = D_SIZE;                                 /* element count              */
    g_dmaCTRLPKT_RX.ELDOFFSET = 0U;                                     /* element destination offset */
    g_dmaCTRLPKT_RX.ELSOFFSET = 0;/*D_SIZE;*/        		            /* element destination offset */
    g_dmaCTRLPKT_RX.FRDOFFSET = 0U;		                                /* frame destination offset   */
    g_dmaCTRLPKT_RX.FRSOFFSET = 0U;                                     /* frame destination offset   */
    g_dmaCTRLPKT_RX.PORTASGN  = PORTB_READ_PORTA_WRITE;                 /* port assignment            */
    g_dmaCTRLPKT_RX.RDSIZE    = ACCESS_8_BIT;	                        /* read size                  */
    g_dmaCTRLPKT_RX.WRSIZE    = ACCESS_8_BIT; 	                        /* write size                 */
    g_dmaCTRLPKT_RX.TTYPE     = FRAME_TRANSFER;/*BLOCK_TRANSFER;*/      /* transfer type              */
    g_dmaCTRLPKT_RX.ADDMODERD = ADDR_FIXED;                             /* address mode read          */
    g_dmaCTRLPKT_RX.ADDMODEWR = ADDR_INC1;                              /* address mode write         */
    g_dmaCTRLPKT_RX.AUTOINIT  = AUTOINIT_ON;                            /* autoinit                   */

    /* - setting dma control packets */
    dmaSetCtrlPacket((uint32_t)DMA_CH0, g_dmaCTRLPKT_TX);               // channel - 0 for transmit
    dmaSetCtrlPacket((uint32_t)DMA_CH1, g_dmaCTRLPKT_RX);               // channel - 1 for receive

    /* - setting the dma channels 0 and 1 to trigger on h/w request */
    dmaSetChEnable((uint32_t)DMA_CH0, (uint32_t)DMA_HW);
    dmaSetChEnable((uint32_t)DMA_CH1, (uint32_t)DMA_HW);

    // enabling dma module : this brings DMA out of reset
    dmaEnable();

    /* spi port config */
    spiDAT1_t dataconfig1_t;
    dataconfig1_t.CS_HOLD = TRUE;                                       // The chip select signal is activated
    dataconfig1_t.WDEL = TRUE;                                          // No delay will be inserted
    dataconfig1_t.DFSEL = SPI_FMT_0;                                    // Data word format select
    dataconfig1_t.CSNR = 0xFE;                                          // Chip select (CS) number; 0x01h for CS[0]

    /* Check whether SPIEN bit = 1 */
    if ((SPI_REGISTER->GCR1>>BIT_SHIFTING_24)&(HEX_ONE) == HEX_ONE) {
        /* DMA_REQ_Enable */
        SPI_REGISTER->INT0^=(-HEX_ONE^SPI_REGISTER->INT0)&(HEX_ONE<<BIT_SHIFTING_16);
    }
    else {
        /* Set SPIEN bit = 1 */
        SPI_REGISTER->GCR1^=(-HEX_ONE^SPI_REGISTER->GCR1)&(HEX_ONE<<BIT_SHIFTING_24);
        /* DMA_REQ_Enable */
        SPI_REGISTER->INT0^=(-HEX_ONE^SPI_REGISTER->INT0)&(HEX_ONE<<BIT_SHIFTING_16);
    }

    /* SPI transmit and receive */
    // Function spiSendAndGetData sets bits 8 & 9 in INT0 to 1.
    // Bit 8 -> RXINTENA causes an interrupt to be generated when the RXINTFLAG bit
    // (SPI Flag Register (SPIFLG)[8]) is set by hardware.
    // Bit 9 -> TXINTENA causes an interrupt to be generated every time data is written
    // to the shift register, so that the next word can be written to TXBUF. Setting this
    // bit will generate an interrupt if the TXINTFLG bit (SPI Flag Register (SPIFLG)[9])
    // is set to 1.
    /* Transmit and Receive Data using Interrupt mode */
    spiSendAndGetData(SPI_REGISTER, &dataconfig1_t, D_SIZE, TXDATA, RXDATA);

    /* Transmit and Receive Data using Polling method */
    // spiTransmitAndReceiveData(SPI_REGISTER, &dataconfig1_t, D_SIZE, TXDATA, RXDATA);

    int64_t count = 0;
    while(dmaREG->BTCFLAG != 0x00000003) {				// Wait for Block Transfer Complete
		count++;
	}
    dmaREG->BTCFLAG = 0x00000003;						// Clear BTC Flag
	  	  	  	  	  	  	  	  	  	  	  	  	  	// Because Channel 0 and 1 are configured with AutoInit
	  	  	  	  	  	  	  	  	  	  	  	  	  	// DMA is ready to transmit / receive the next Block
	count = 0;

}

  • Hello Ivan,

    1. Please check your pinmux to make sure the SOMI and SIMO pins are configured as SPI signals

    2. Make sure the MibSPI3 is used as compatibility mode rather than the multi-buffered mode

    3. In SPI configuration, make sure the SOMI and SIMO pins are used as functional signals.

  • Hello QJ Wang,

    thanks for your responce!

    QJ Wang said:
    1. Please check your pinmux to make sure the SOMI and SIMO pins are configured as SPI signals

    MIBSPI3 in Pin Muxing tab in HalCoGen is now enabled.

    QJ Wang said:
    2. Make sure the MibSPI3 is used as compatibility mode rather than the multi-buffered mode

    Only SPI3 driver is enabled in Driver Enable tab.

    QJ Wang said:
    3. In SPI configuration, make sure the SOMI and SIMO pins are used as functional signals.

    All SPI3 pins are set to SPI Functional.

    Do you think it's on the HAL drivers setup? Does my config have some critical errors?

  • Hi Ivan,

    You code looks fine. I have similar code which works for LS12x device.

    /* example data Pattern configuration */

    #define SPI4_RXBUF 0xFFF7FA42

    #define SPI4_TXBUF 0xFFF7FA3E

     

    {

    /* - creating a data chunk in system ram to start with ... */

    loadDataPattern(BlockSize, &TX_DATA[0]);

    /* - initializing mibspi - enabling tg 0 , length 127 (halcogen file)*/

    spiInit();

    // _enable_interrupt_();

    /* - enabling internal loopback ( this is to emulate data transfer without external wires */

    spiREG4->GCR1 = (spiREG4->GCR1 & 0xFEFFFFFFU) | 0x00010000U;

    /* - enabling dma module */

    dmaEnable();

    /* Enable Interrupt after reception of data */

    //dmaEnableInterrupt(DMA_CH0, FTC); //Frame transfer complete

    dmaEnableInterrupt(DMA_CH0, BTC); //Block transfer complete

    dmaEnableInterrupt(DMA_CH0, HBC); //Half block transfer complete

    /* - assigning dma request: channel-0 with request line - 24/25 */

    /* Request line 24: SPI4 Receive */

    /* Request line 25: SPI4 Transmit */

    /* Request line 0: SPI1 Receive */

    /* Request line 1: SPI1 Transmit */

    dmaReqAssign(DMA_CH0, 24); //SPI4 RX

    dmaReqAssign(DMA_CH1, 25); //SPI4 TX

    /* - configuring dma TX control packets */

    dmaConfigCtrlTxPacket((unsigned int)&TX_DATA, SPI4_TXBUF, 1, BlockSize);

    dmaSetCtrlPacket(DMA_CH1, g_dmaCTRLPKT_TX);

    /* - configuring dma RX control packets */

    /* dmaConfigCtrlRxPacket(uint32 sadd, uint32 dadd, uint32 dsize) */

    dmaConfigCtrlRxPacket(SPI4_RXBUF, (unsigned int)&RX_DATA, 1, BlockSize);

    dmaSetCtrlPacket(DMA_CH0, g_dmaCTRLPKT_RX);

    /* - setting the dma channel to trigger on h/w request */

    dmaSetChEnable(DMA_CH0, DMA_HW); //SPI4 RX, hardware triggering

    dmaSetChEnable(DMA_CH1, DMA_HW); //SPI4 TX, hardware triggering

    //For efficient behavior during DMA operations, the transmitter empty and receive-buffer full interrupts can be disabled

    spiREG4->GCR1 = (spiREG4->GCR1 & 0xFFFFFFFFU) | 0x01000000U; //Enable SPI

    spiREG4->INT0 = (0x1 << 16); //SPI_DMAREQ; Enable DMA REQ only after setting the SPIEN bit to 1.

    /* - start the mibspi transfer */

    // spiREG4->DAT1 = (0x00FE<<16) | (unsigned short) TX_DATA[1];

    }

    while( SPI4_BTCFlag == 0 ) {

    }

    if (SPI4_BTCFlag == 1)

    txrx_error = SPI_TestVerify();

     

  • The DMA packet configuration:

    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 = 0; /* element destination 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_FIXED; /* address mode read */

    g_dmaCTRLPKT_RX.ADDMODEWR = ADDR_INC1; /* address mode write */

    g_dmaCTRLPKT_RX.AUTOINIT = AUTOINIT_ON; /* autoinit */

    }

    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 = 0; /* element destination offset */

    g_dmaCTRLPKT_TX.ELSOFFSET = 0; /* element destination 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_FIXED; /* address mode write */

    g_dmaCTRLPKT_TX.AUTOINIT = AUTOINIT_ON; /* autoinit */

    }

  • Hello QJ Wang,

    thanks for your reply. Sorry for the long waiting time. Let me check your code today. I'll give some feedback here later.

    Regards,

    Ivan

  • Hello QJ Wang,

    after debugging we figuted out that variable TXDATA was reseted before transmit for some reason. After using it as a constant we could transfer and receive data.

    Regards,

    Ivan