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.

Using SPI for MSP430

Other Parts Discussed in Thread: MSP430F5437A, MSP430F5529, MSP430F5259, MSP430DRIVERLIB

I am using the MSP430F5437A, TI-RTOS v2.00.01.23, CCS v6.

I am trying to get the SPI drivers to work for my project. I believe have most of the settings setup correctly except for the HWI. The user guide states that for MSP430's, an HWI needs to be created statically in order to handle interrupts for the drivers. I got this to successfully work for the I2C bus by setting the HWI ISR function to that stated in the user guide (I2CUSCIB_hwiIntFxn). However, for SPI, the user guide doesn't give a specific function to use, but instead states:

"A DMA interrupt function defined by the user must call the SPI driver's SPI_serviceISR function."

I'm not completely sure how to do that. I tried just using the SPI_serviceISR function as the ISR function for my statically created HWI, but that caused an error.

If anyone has any insight they can give me, I'd appreciate it.

  • Robert,

    This example is from the MSP430F5529

    CFG file changes:
    var hwi1Params = new Hwi.Params();
    hwi1Params.instance.name = "dmaISR";
    Program.global.dmaISR = Hwi.create(50, "&MSP_EXP430F5529LP_isrDMA", hwi1Params);

    Board file changes:
    /*
    *  ======== MSP_EXP430F5529_isrDMA ========
    *  This is a application defined DMA ISR. This ISR must map and call the
    *  appropriate Driver_event(handle) API to indicate completed DMA transfers.
    */
    Void MSP_EXP430F5529_isrDMA(UArg arg)
    {
    #if TI_DRIVERS_WIFI_INCLUDED
        /* Call the SPI DMA function, passing the SPI handle used for WiFi */
        SPI_serviceISR((SPI_Handle) &(SPI_config[1]));
    #elif TI_DRIVERS_SPI_INCLUDED
        /* Use the SPI_Handle that operates the SPI driver */
        SPI_serviceISR((SPI_Handle) &(SPI_config[0]));
    #endif
    }

    Explanation:
    *  ## DMA Interrupts #
    *  The MSP430 DMA controller uses a single interrupt vector to handle all DMA
    *  related IRQ. Because of the "shared" nature, of the DMA's ISR, this driver
    *  implementation provides a simple ISR function SPIEUSCIADMA_hwiIntFxn() which
    *  needs to be called from within the DMA's ISR.
    *  SPIEUSCIADMA_hwiIntFxn() will only service DMA channel interrupts that are
    *  associated with the SPI_Handle. Each SPIEUSCIADMA instance will require a
    *  call from within the DMA's ISR.
    *
    *  @code
    *  SPI_Handle spi0uscidma;
    *  SPI_Handle spi1uscidma;
    *
    *  // As this DMA controller uses a single interrupt vector for all DMA
    *  // channels (regardless of the triggering source), its left up to the user
    *  // to call SPI_serviceISR() to service its associated DMA channels.
    *  Void myDMAISR(UArg arg)
    *  {
    *      // Services and clears its assigned DMA channel interrupts
    *      SPI_serviceISR(spi0uscidma);
    *
    *      // Services and clears its assigned DMA channel interrupts
    *      SPI_serviceISR(spi1uscidma);
    *
    *      // some other user application code that's not related to the SPI driver,
    *      // but is used to service remaining DMA channels
    *  }

     Judah

     

  • Thanks Judah,

    I apologize for not responding sooner, I have been out of the office for the past week. This information was really helpful, so far, I think it is what I needed to get things going. I will continue testing with and see how it goes.

  • Judah,

    Do you have a full code example for the MSP430F5529? I can't seem to find an example project that uses SPI for the TI-RTOS.

    I'm not sure if I am doing an SPI Transaction correctly, here is a snippet of what I am trying to do:

            uint8_t             rxBuffer[1];
    	uint8_t				tempRxBuffer[2];
    	uint8_t				txBuffer[1];
    	SPI_Transaction 	spiTransaction;
    
    	tempRxBuffer[0] = 0;
    	tempRxBuffer[1] = 0;
    
    	/* Clear error flag command */
    	/* Set Slave Select line Active (low) */
    	GPIO_setOutputLowOnPin(GPIO_PORT_P5, GPIO_PIN5);
    
    	txBuffer[0] = 0xE7;
    	spiTransaction.count = 1;
    	spiTransaction.rxBuf = NULL;
    	spiTransaction.txBuf = txBuffer;
    	if ( !SPI_transfer(*handle, &spiTransaction) )
    	{
    		//GPIO_write(Board_LED1, Board_LED_ON);
    		//System_abort("Bad I2C transfer!");
    		while(1);
    	}
    	/* Receive response from previous cmd */
    	spiTransaction.count = 1;
    	spiTransaction.rxBuf = rxBuffer;
    	spiTransaction.txBuf = NULL;
    	if ( !SPI_transfer(*handle, &spiTransaction) )
    	{
    		//GPIO_write(Board_LED1, Board_LED_ON);
    		//System_abort("Bad I2C transfer!");
    		while(1);
    	}
    	tempRxBuffer[0] = rxBuffer[0];

    I'm a little suspicious that the transmit operation has not finished by the time the receive operation occurs. 

    Again, if there is any example project using SPI for TI-RTOS, I would really like to take a look at it.

    Thanks.

  • Just some additional information. As per the info sent earlier in this post, I have created an interrupt function for the DMA ISR. It is pretty simple, let me know if I left anything out with it:

    void DMAISR(void)
    {
    	// Service and clear its assigned DMA channel interrupts
    	SPI_serviceISR(spi);
    }
    var hwi3Params = new Hwi.Params();
    hwi3Params.instance.name = "SPIDMAHwi";
    Program.global.SPIDMAHwi = Hwi.create(50, "&DMAISR", hwi3Params);

  • Hi Robert,

    One thing I've seen in your code is that you're trying to perform a 'one-way' SPI transaction by setting either rx or tx buffer to NULL. If you're using any version of TI-RTOS older than the most recent v2.00.02.36, you have to supply a dummy buffer to rx/tx. The dummyBuffer should be the size of the transaction count. 

    uint8_t             rxBuffer[1];
    uint8_t             tempRxBuffer[2];
    uint8_t             txBuffer[1];
    uint8_t             dummyBuffer[1];
    SPI_Transaction     spiTransaction;
    
     
    tempRxBuffer[0] = 0;
    tempRxBuffer[1] = 0;
    
     
    /* Clear error flag command */
    /* Set Slave Select line Active (low) */
    GPIO_setOutputLowOnPin(GPIO_PORT_P5, GPIO_PIN5);
    
     
    txBuffer[0] = 0xE7;
    spiTransaction.count = 1;
    spiTransaction.rxBuf = dummyBuffer;
    spiTransaction.txBuf = txBuffer;
    if ( !SPI_transfer(*handle, &spiTransaction) )
    {
        //GPIO_write(Board_LED1, Board_LED_ON);
        //System_abort("Bad I2C transfer!");
        while(1);
    }
    /* Receive response from previous cmd */
    spiTransaction.count = 1;
    spiTransaction.rxBuf = rxBuffer;
    spiTransaction.txBuf = dummyBuffer;
    if ( !SPI_transfer(*handle, &spiTransaction) )
    {
        //GPIO_write(Board_LED1, Board_LED_ON);
        //System_abort("Bad I2C transfer!");
        while(1);
    }
    tempRxBuffer[0] = rxBuffer

    I've modified your code to do this. Give it a try and let me know how it goes.

    Thanks

    Moses

  • Hi Moses,

    I updated my version of TI-RTOS and am now using version: 2.00.02.36

    Since that update, I am running into a different problem. This issue occurs when I use a dummyBuffer like you suggested and if I use a NULL buffer instead.

    When I attempt my first SPI_transfer, the system gets stuck waiting for the transferComplete semaphore to post. Since the SPI driver is configured as blocking, nothing else works. 

    Before I made the update to the newer version of TI-RTOS, I was able to break when the DMA interrupt occurred. However, now, that interrupt never happens, which, I presume, is why the transferComplete semaphore never gets posted.

    Here is a copy of my printf Logs:

    3265380,MSP430,SPI:(@600)  DMA transfer enabled
    3326416,MSP430,"SPI:(@600) DMA transaction: @4646, rxBuf: @4640; txBuf: @4644; Count: 1"
    3356933,MSP430,SPI:(@600)  transfer pending on transferComplete semaphore

    Any clue why this is happening? Also, are there any SPI project examples for the MSP430 I can reference?

  • I think with the update to TI-RTOS, the SPI hardware attributes struct elements also changed. This is how it is defined in the latest version of TI-RTOS:

    typedef struct SPIUSCIADMA_HWAttrs {
        /*!< USCI_A_SPI Peripheral's base address */
        uint32_t   baseAddr;
        /*!< USCI_A_SPI Clock source */
        uint8_t   clockSource;
        /*!< USCI_A_SPI Bit order */
        uint8_t   bitOrder;
        /*! Address of a scratch buffer of size uint32_t */
        uint8_t *scratchBufPtr;
        /*! Default TX value if txBuf == NULL */
        uint8_t  defaultTxBufValue;
    
        /*!< DMA Peripheral's base address */
        uint32_t  dmaBaseAddr;
        /*!< DMA rxDMAChannel for Rx data */
        uint8_t   rxDMAChannelIndex;
        /*!< DMA trigger source for Rx data */
        uint8_t   rxDMASourceTrigger;
        /*!< DMA txDMAChannel for Tx data */
        uint8_t   txDMAChannelIndex;
        /*!< DMA trigger source for Tx data */
        uint8_t   txDMASourceTrigger;
    } SPIUSCIADMA_HWAttrs;

    In the board files for the MSP-EXP430F5539, this struct is populated like this:

    /* SPI configuration structure, describing which pins are to be used */
    const SPIUSCIADMA_HWAttrs spiUSCIADMAHWAttrs[MAGELLAN_MSP430F5437A_SPICOUNT] = {
        {
            USCI_A1_BASE,
            USCI_A_SPI_CLOCKSOURCE_SMCLK,
            USCI_A_SPI_MSB_FIRST,
    
            /* DMA */
            DMA_BASE,
            /* Rx Channel */
            DMA_CHANNEL_1,
            DMA_TRIGGERSOURCE_20,
            /* Tx Channel */
            DMA_CHANNEL_0,
            DMA_TRIGGERSOURCE_21
        }
    };

    This does populate the elements of this struct correctly, it does not provide values for the scratchBufPtr and defaultTxBufValue elements. 

    Any idea what I should use to populate this elements? This is starting to get fairly frustrating, has no one ever used these SPI drivers for the MSP430 before??

  • Robert,

    I'm working on sending you a working SPI project to help you. One thing I've seen is that you need to look at the updated MSP-430F5529 board file in the new TI-RTOS. It should match the hardware attributes of the updated SPI driver.

    So are you saying that in the new TI-RTOS you have the issue where the SPI_transfer blocks forever when you use a dummyBuffer or when you pass in NULL?

    Moses

  • I'm not sure if my problem is related or not, but it does seem to be.  Maybe my solution will help.

    I'm using a Tiva C mcu with TI-RTOS.  When I downloaded the new TI-RTOS 2.0.2.36, my SPI driver broke, i.e. it would go to the exception handler when I tried to send data.  After some digging, I discovered (as was suggested by Robert) that the board file (in my case, EK_TM4C123GXL.c) had been modified in the new TI-RTOS.  After I updated my old board file to match the new board file (obtained by importing one of the new sample projects), then my program runs fine.  Because the expected structure format had changed, the TI-RTOS driver was interpreting ints as pointers, etc.

    Below are the changes I had to make.  Any line with // after it, I had to add.  Maybe the idea will help, even though you're running on a different platform.  

    #if TI_DRIVERS_SPI_INCLUDED
    #include <ti/drivers/SPI.h>
    #include <ti/drivers/spi/SPITivaDMA.h>

    /* SPI objects */
    SPITivaDMA_Object spiTivaDMAobjects[EK_TM4C123GXL_SPICOUNT];
    #if defined(ccs) //
    #pragma DATA_ALIGN(spiTivaDMAscratchBuf, 32) //
    #elif defined(ewarm) //
    #pragma data_alignment=32 // All of this code added/updated with TI-RTOS 2.00.02.36
    #elif defined(gcc) //
    __attribute__ ((aligned (32))) //
    #endif //
    uint32_t spiTivaDMAscratchBuf[EK_TM4C123GXL_SPICOUNT]; //

    /* SPI configuration structure, describing which pins are to be used */
    const SPITivaDMA_HWAttrs spiTivaDMAHWAttrs[EK_TM4C123GXL_SPICOUNT] = {
    {
    SSI0_BASE,
    INT_SSI0,
    &spiTivaDMAscratchBuf[0], // All of this code added/updated with TI-RTOS 2.00.02.36
    0, //
    UDMA_CHANNEL_SSI0RX,
    UDMA_CHANNEL_SSI0TX,
    uDMAChannelAssign,
    UDMA_CH10_SSI0RX,
    UDMA_CH11_SSI0TX
    },
    {
    SSI2_BASE,
    INT_SSI2,
    &spiTivaDMAscratchBuf[1], // All of this code added/updated with TI-RTOS 2.00.02.36
    0, //
    UDMA_SEC_CHANNEL_UART2RX_12,
    UDMA_SEC_CHANNEL_UART2TX_13,
    uDMAChannelAssign,
    UDMA_CH12_SSI2RX,
    UDMA_CH13_SSI2TX
    },
    {
    SSI3_BASE,
    INT_SSI3,
    &spiTivaDMAscratchBuf[2], // All of this code added/updated with TI-RTOS 2.00.02.36
    0, //
    UDMA_SEC_CHANNEL_TMR2A_14,
    UDMA_SEC_CHANNEL_TMR2B_15,
    uDMAChannelAssign,
    UDMA_CH14_SSI3RX,
    UDMA_CH15_SSI3TX
    }
    };

    -snellr314

  • Moses,

    Thank you for putting together that example project, I appreciate that. 

    As for the blocking issue, once I realized that I did not have all of the hardware attributes defined correctly, I went ahead and put in some values that seemed appropriate and that would make the compiler happy. After doing that, the DMA ISR was once again operating and the SPI_transfer no longer blocked forever.

    A little bit of background information. I have a loop that runs at 50Hz. I use this loop to read some sensors including one that is on an SPI bus. So, after the blocking issue was resolved I found that the first time through that loop the SPI driver would partially work, meaning, it wouldn't give any errors, but it wouldn't give the correct data from the sensor. However, on the second time through the sampling loop, the SPI_transfer would fail. This was very repeatable.

    I had code from an older project where I had wrote a driver for SPI for this processor. When I removed all of the TI-RTOS SPI driver code and replaced it with my low level code, everything worked just fine. So it seems that I am still not correctly using the SPI driver correctly.

  • Robert, 

    Here's a base SPI loopback project that I created for the MSP430F5529 experimenter board. You can compare it with yours to make sure you have same setup.

    6011.gpiointerrupt_MSP430F5529.zip

    For the issue you are seeing in your project, it will help if I can see snippets of code of how you're using the SPI driver.

    Thanks,
    Moses

  • Moses,

    Thank you for creating this. I noticed a few differences between your project and mine, so I will start by testing those changes.

    In the mean time, I have a few questions after looking through your project:

    It looks like this example does not use a Slave Select (SS) line, is that correct? That is not something that the TI-RTOS SPI driver handles is it?

    In the .cfg file the "Memory" module is used even though there is no memory allocated for the heap. Is there a reason for using this module, does it allow other necessary functions to perform? Currently, I do not use it in my project.

    the taskFxn has two arguments passed to it, but they don't seem to be used and I can't find what would even pass them. Is there a reason why they are there?

    Thanks again for your help!

  • Moses,

    I still can't seem to get it to work. Here are some code snippets to help your diagnosis. Let me know if you need to see anything else:

    This the main function I am testing with. The first half of the function is set to use the TI-RTOS SPI driver functions and the second half uses some old code I had written awhile ago. I use the #if to select which I want to use.
    If I run it using the my old driver code, everything works as expected. If I run it using the TI-RTOS driver functions instead, I don't get the correct responses back from the SPI slave. Obviously, I am doing something wrong with the TI-RTOS implementation.

    void initAngleSensor(SPI_Handle *handle)
    {
    #if 1
    	uint8_t             rxBuffer[1];
    	volatile uint8_t	tempRxBuffer[2];
    	uint8_t				txBuffer[1];
    	SPI_Transaction 	spiTransaction;
    
    	tempRxBuffer[0] = 0;
    	tempRxBuffer[1] = 0;
    
    	/* Clear error flag command */
    	/* Set Slave Select line Active (low) */
    	GPIO_setOutputLowOnPin(GPIO_PORT_P5, GPIO_PIN5);
    
    	txBuffer[0] = 0xE7;
    	spiTransaction.count = 1;
    	spiTransaction.rxBuf = rxBuffer;
    	spiTransaction.txBuf = txBuffer;
    	if ( !SPI_transfer(*handle, &spiTransaction) )
    	{
    		//GPIO_write(Board_LED1, Board_LED_ON);
    		//System_abort("Bad I2C transfer!");
    		while(1);
    	}
    	tempRxBuffer[1] = rxBuffer[0];
    
    	txBuffer[0] = 0x00;
    	spiTransaction.count = 1;
    	spiTransaction.rxBuf = rxBuffer;
    	spiTransaction.txBuf = txBuffer;
    	if ( !SPI_transfer(*handle, &spiTransaction) )
    	{
    		//GPIO_write(Board_LED1, Board_LED_ON);
    		//System_abort("Bad I2C transfer!");
    		while(1);
    	}
    	tempRxBuffer[0] = rxBuffer[0];
    
    	/* Set Slave Select line Inactive (high) */
    	GPIO_setOutputHighOnPin(GPIO_PORT_P5, GPIO_PIN5);
    
    	__delay_cycles(5);
    
    	/* Read system config register */
    	/* Set Slave Select line Active (low) */
    	GPIO_setOutputLowOnPin(GPIO_PORT_P5, GPIO_PIN5);
    
    	txBuffer[0] = SPI_SYSCONF_BYTE1;
    	spiTransaction.count = 1;
    	spiTransaction.rxBuf = rxBuffer;
    	spiTransaction.txBuf = txBuffer;
    	if ( !SPI_transfer(*handle, &spiTransaction) )
    	{
    		//GPIO_write(Board_LED1, Board_LED_ON);
    		//System_abort("Bad I2C transfer!");
    		while(1);
    	}
    	tempRxBuffer[1] = rxBuffer[0];
    
    	txBuffer[0] = SPI_SYSCONF_BYTE2;
    	spiTransaction.count = 1;
    	spiTransaction.rxBuf = rxBuffer;
    	spiTransaction.txBuf = txBuffer;
    	if ( !SPI_transfer(*handle, &spiTransaction) )
    	{
    		//GPIO_write(Board_LED1, Board_LED_ON);
    		//System_abort("Bad I2C transfer!");
    		while(1);
    	}
    	tempRxBuffer[0] = rxBuffer[0];
    
    	/* Set Slave Select line Inactive (high) */
    	GPIO_setOutputHighOnPin(GPIO_PORT_P5, GPIO_PIN5);
    
    	__delay_cycles(5);
    
    	/* Set Slave Select line Active (low) */
    	GPIO_setOutputLowOnPin(GPIO_PORT_P5, GPIO_PIN5);
    
    	/* Send NOP command to read data from sys config command */
    	txBuffer[0] = SPI_NOP_BYTE;
    	spiTransaction.count = 1;
    	spiTransaction.rxBuf = rxBuffer;
    	spiTransaction.txBuf = txBuffer;
    	if ( !SPI_transfer(*handle, &spiTransaction) )
    	{
    		//GPIO_write(Board_LED1, Board_LED_ON);
    		//System_abort("Bad I2C transfer!");
    		while(1);
    	}
    	tempRxBuffer[1] = rxBuffer[0];
    
    	txBuffer[0] = SPI_NOP_BYTE;
    	spiTransaction.count = 1;
    	spiTransaction.rxBuf = rxBuffer;
    	spiTransaction.txBuf = txBuffer;
    	if ( !SPI_transfer(*handle, &spiTransaction) )
    	{
    		//GPIO_write(Board_LED1, Board_LED_ON);
    		//System_abort("Bad I2C transfer!");
    		while(1);
    	}
    	tempRxBuffer[0] = rxBuffer[0];
    
    	/* Set Slave Select line Inactive (high) */
    	GPIO_setOutputHighOnPin(GPIO_PORT_P5, GPIO_PIN5);
    #endif
    
    #if 0
    	uint16_t n = SPI_WAIT;
    	volatile uint8_t dontcare[2];
    
    	UCA1CTL1 |= UCSWRST;                      // **Put state machine in reset**
    	UCA1CTL0 |= UCMST+UCSYNC+UCMSB;    		// 3-pin, 8-bit SPI master
    											// Clock polarity high, MSB
    	UCA1CTL1 |= UCSSEL_2;                     // SMCLK
    	UCA1BR0 = 0x02;                           // /3R0
    	UCA1BR1 = 0;                              //
    	UCA1MCTL = 0;                             // No modulation
    	P5OUT |= 0x20;	                       	// raise nSS (make inactive)
    	UCA1CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
    
    
    	__delay_cycles(5);                      // delay
    
    	P5OUT &= ~0x20;
    
    	// prepare read command as two separate bytes
    
    	//Clear error flag
    	while (!(UCA1IFG&UCTXIFG) && --n);               // USCI_A0 TX buffer ready? wait for register to empty
    	UCA1TXBUF = 0xE7;            // Load shift register for first byte
    	while (!(UCA1IFG&UCRXIFG) && --n);               // USCI_A0 TX buffer ready? wait for register to empty
    	dontcare[1] = UCA1RXBUF;                    // Receive System Config response
    	while (!(UCA1IFG&UCTXIFG) && --n);               // USCI_A0 TX buffer ready? wait for register to empty
    	UCA1TXBUF=0x00;                      //2nd byte
    	while (!(UCA1IFG&UCRXIFG) && --n);               // USCI_A0 TX buffer ready? wait for register to empty
    	dontcare[0] = UCA1RXBUF;                    // Receive System Config response
    
    	P5OUT |= 0x20;	                       // raise nSS (make inactive)
    	__disable_interrupt();
    	__delay_cycles(5);                      // delay
    	__enable_interrupt();
    	P5OUT &= ~0x20;
    
    	// prepare read command as two separate bytes
    	if(n==0)	// if time out
    	{
    		//error occurred
    	}
    	n = SPI_WAIT;
    
    	//Request sys config
    	//Receive response from previous clear error flag
    	while (!(UCA1IFG&UCTXIFG) && --n);               // USCI_A0 TX buffer ready? wait for register to empty
    	UCA1TXBUF = SPI_SYSCONF_BYTE1;            // Load shift register for first byte
    	while (!(UCA1IFG&UCRXIFG) && --n);               // USCI_A0 TX buffer ready? wait for register to empty
    	dontcare[1] = UCA1RXBUF;                    // Receive System Config response
    	while (!(UCA1IFG&UCTXIFG) && --n);               // USCI_A0 TX buffer ready? wait for register to empty
    	UCA1TXBUF = SPI_SYSCONF_BYTE2;                      //2nd byte
    	while (!(UCA1IFG&UCRXIFG) && --n);               // USCI_A0 TX buffer ready? wait for register to empty
    	dontcare[0] = UCA1RXBUF;                    // Receive System Config response
    
    	P5OUT |= 0x20;	                       // raise nSS (make inactive)
    
    	__delay_cycles(5);                      // delay
    
    	P5OUT &= ~0x20;
    
    	// prepare read command as two separate bytes
    	if(n==0)	// if time out
    	{
    		//error occurred
    	}
    	n = SPI_WAIT;
    
    	//Send NOP
    	//Receive response from previous sys config request
    	while (!(UCA1IFG&UCTXIFG) && --n);               // USCI_A0 TX buffer ready? wait for register to empty
    	UCA1TXBUF = SPI_NOP_BYTE;            // Load shift register for first byte
    	while (!(UCA1IFG&UCRXIFG) && --n);               // USCI_A0 TX buffer ready? wait for register to empty
    	dontcare[1] = UCA1RXBUF;                    // Receive System Config response
    	while (!(UCA1IFG&UCTXIFG) && --n);               // USCI_A0 TX buffer ready? wait for register to empty
    	UCA1TXBUF = SPI_NOP_BYTE;                      //2nd byte
    	while (!(UCA1IFG&UCRXIFG) && --n);               // USCI_A0 TX buffer ready? wait for register to empty
    	dontcare[0] = UCA1RXBUF;                    // Receive System Config response
    
    	P5OUT |= 0x20;	                       // raise nSS (make inactive)
    
    #endif
    }

    Here is my initialization of the TI-RTOS spi driver:

    	/* Init and Create SPI bus for usage */
    	SPI_Params_init(&spiParams);
    	spiParams.bitRate = 8000000;
    	spi = SPI_open(Board_SPI0, &spiParams);
    	if (spi == NULL)
    	{
    		while(1);
    	}

    Let me know what you think!

  • Robert,

    To answer your questions:

    The SPI driver doesn't drive the chip select line. It's left to your application to handle that and I see you're doing it the right way. My example was a loop back (MOSI and MISO connected together) so I didn't need the CS line.

    The memory module isn't used. We usually just include it our cfg files. It's just part of the base modules we like to pull in for our examples.

    The task arguments aren't being used in this example either. It's just part of the defined function type that the Task module requires. If your application needs to pass in any argument to a created task then it can make use of it or else ignore it.

    Nothing stands out in your code as being wrong. So are you having any successful transfer or it hangs on the first one. Also are you creating the Hwi for the DMA in your cfg file? The example I sent you has that in its cfg file. Check the datasheet of your device for the DMAs interrupt number. To verify that you set up interrupts correctly, set breakpoints on the MSP_EXP430FXXXX_isrDMA function in your boardName.c file. You can also set breakpoints in the SPIUSCIBDMA_hwiIntFxn in the SPI driver and verify the interrupt status from the DMA. If you setup interrupts correctly it should hit those break points during the SPI transfer.

    Let me know if this helps

    Moses

  • Hi Moses,

    Thank you so much for your help with this, I think I found the issue.

    Originally, I was using my own function for the DMA ISR:

    void DMAISR(void)
    {
    	// Service and clear its assigned DMA channel interrupts
    	SPI_serviceISR(spi);
    }

    Then, after looking at your example project, I realized that there was already a function for this in the F5529 example project board files. So, now my HWI uses this function:

    Void MAGELLAN_MSP430F5437A_isrDMA(UArg arg)
    {
    #if TI_DRIVERS_WIFI_INCLUDED
        /* Call the SPI DMA function, passing the SPI handle used for WiFi */
        SPI_serviceISR((SPI_Handle) &(SPI_config[1]));
    #elif TI_DRIVERS_SPI_INCLUDED
        /* Use the SPI_Handle that operates the SPI driver */
        SPI_serviceISR((SPI_Handle) &(SPI_config[0]));
    #endif
    }

    The difference between the two is the parameters used in the SPI_serviceISR() function. After I used the latter, everything has seemed to start working.

    Thanks again for your help, I think I should be good to go now.

  • Hello,

    I've came across this thread when investigating the use of multiple SPI links DMA transfer.

    My App using SPI_A0, SPI_A1 & SPI_A2 on MSP430F5259 device (Note its different than the 5529 used in the examples..)

    My questions are:

    1.  I have 3 SPI links and only 3 DMA channels. Can I use a single DMA channel for each SPI link only for the RX (there is an ADC constantly 'spitting out' data over SPI), or does the whole DMA concept fails in this case (since the CPU concurrently is working on the TX ?

      If its possible should I substitute the TX DMA fields (BASE, CHANNEL & TRIGGER) with NULL ?

    2. In the first post of the thread (by judahvang) SPI_serviceISR() is called twice (within myDMAISR) passing each of the elements of SPI_Config[] array
      *  // As this DMA controller uses a single interrupt vector for all DMA
      *  // channels (regardless of the triggering source), its left up to the user
      *  // to call SPI_serviceISR() to service its associated DMA channels.
      *  Void myDMAISR(UArg arg)
      *  {
      *      // Services and clears its assigned DMA channel interrupts
      *      SPI_serviceISR(spi0uscidma);
      *
      *      // Services and clears its assigned DMA channel interrupts
      *      SPI_serviceISR(spi1uscidma);
      *
      *      // some other user application code that's not related to the SPI driver,
      *      // but is used to service remaining DMA channels
      *  }

      However I don't see how myDMAISR() is hooked to DMA Hwi, I notice that *.cfg file hooks the DMA Hwi to MSP_EXP430F5529_isrDMA() which calls SPI_ServiceISR() with a only the first element of SPI_Config[].
      This also repeats in the example posted sent later in the thread by Moses - only a single call to SPI_ServiceISR().

      CFG file changes:
      var hwi1Params = new Hwi.Params();
      hwi1Params.instance.name = "dmaISR";
      Program.global.dmaISR = Hwi.create(50, "&MSP_EXP430F5529LP_isrDMA", hwi1Params);
      
      Board file changes:
      /*
      *  ======== MSP_EXP430F5529_isrDMA ========
      *  This is a application defined DMA ISR. This ISR must map and call the
      *  appropriate Driver_event(handle) API to indicate completed DMA transfers.
      */
      void MSP_EXP430F5529_isrDMA(UArg arg)
      {
      #if TI_DRIVERS_WIFI_INCLUDED
          /* Call the SPI DMA function, passing the SPI handle used for WiFi */
          SPI_serviceISR((SPI_Handle) &(SPI_config[1]));
      #elif TI_DRIVERS_SPI_INCLUDED
          /* Use the SPI_Handle that operates the SPI driver */
          SPI_serviceISR((SPI_Handle) &(SPI_config[0]));
      #endif
      }

      So, Which one is right :

      SPI_ServiceISR((SPI_Handle) &(SPI_config[0]));
      
       OR
      
      SPI_ServiceISR((SPI_Handle) &(SPI_config[0])); // SPI_A2
      SPI_ServiceISR((SPI_Handle) &(SPI_config[1])); // SPI_A1
      SPI_ServiceISR((SPI_Handle) &(SPI_config[2])); // SPI_A0
      

      I will greatly appreciate if you could shed some light on this issue.

      Thanks in advance

  • Hi,
    Can you make a fresh post on your issue?

    Thanks,
    Moses
  • Hi Moses,

    SPI demo is missing in msp430driverlib examples found in CCSv6. Please do add SPI demo project to msp430driverlib demo projects list.

    Thanks!

    --Rahul

  • Moses,

    I am using SPI based external ADC. Need some help in receiving the data from ADC. How to write receive driver?
    ADC after start conversion gives the DRDY interrupt, how to read the data?
    Even while configuring i want to send multiple bytes to ADC. How to send mulitple data? You gpiointerrupt example code sends only one data .


    Nitesh
  • Moses,

    I am using SPI based external ADC. Need some help in receiving the data from ADC. How to write receive driver?
    ADC after start conversion gives the DRDY interrupt, how to read the data?
    Even while configuring i want to send multiple bytes to ADC. How to send mulitple data? You gpiointerrupt example code sends only one data .

    Even apart from ADC read i have diagnostic and USB transmit task running , so my question is whether i need DMA based SPI or normal SPI do well?
    Please suggest

    Nitesh
  • Nitesh,

    This is an old thread. Please start a new thread with your question and specify which device and software versions you are using.

    In general, we provide advice on how to use our low-level drivers, such as SPI. But we do not provide drivers for external peripherals. You need to write a driver for the ADC peripheral you are using. Your driver would use the TI-RTOS SPI driver to perform the low-level bus transactions.

    ~Ramsey