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.

SPI_Open()

Other Parts Discussed in Thread: ENERGIA, CC2650

Hello, 

I'm using the SPI loopback example provided with the TI-RTOS , it works well.
but when I tried to use the same SPI " Board_SPI1 " in other task with the same priorirty , this error happened !!
Error 2222 initializing SPI" 
and the program is aborted !!


I thought that the SPI is gated with a mutex , isn't it ?

thanks in advance.






/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
Void slaveTaskFxn (UArg arg0, UArg arg1)
{
SPI_Handle slaveSpi;
SPI_Params slaveSpiParams;
SPI_Transaction slaveTransaction;
UInt transferOK;

/* Initialize SPI handle with slave mode */
SPI_Params_init(&slaveSpiParams);
slaveSpiParams.mode = SPI_SLAVE;
slaveSpi = SPI_open(Board_SPI1, &slaveSpiParams);
if (slaveSpi == NULL) {
System_abort("Error1 initializing SPI\n");
}
else {
System_printf("SPI1 initialized\n");
}

/* Initialize slave SPI transaction structure */
slaveTransaction.count = SPI_MSG_LENGTH;
slaveTransaction.txBuf = (Ptr)slaveTxBuffer;
slaveTransaction.rxBuf = (Ptr)slaveRxBuffer;

/* Initiate SPI transfer */
transferOK = SPI_transfer(slaveSpi, &slaveTransaction);

if(transferOK) {
/* Print contents of slave receive buffer */
System_printf("Slave1: %s\n", slaveRxBuffer);
}
else {
System_printf("Unsuccessful slave1 SPI transfer");
}

/* Deinitialize SPI */
SPI_close(slaveSpi);
}


Void slave2TaskFxn (UArg arg0, UArg arg1)
{
SPI_Handle slaveSpi;
SPI_Params slaveSpiParams;
SPI_Transaction slaveTransaction;
UInt transferOK;

/* Initialize SPI handle with slave mode */
SPI_Params_init(&slaveSpiParams);
slaveSpiParams.mode = SPI_SLAVE;
slaveSpi = SPI_open(Board_SPI1, &slaveSpiParams);
if (slaveSpi == NULL) {

System_abort("Error 2222 initializing SPI\n");
}
else {
System_printf("SPI 222 initialized\n");
}

/* Initialize slave SPI transaction structure */
slaveTransaction.count = SPI_MSG_LENGTH;
slaveTransaction.txBuf = (Ptr)slaveTxBuffer;
slaveTransaction.rxBuf = (Ptr)slaveRxBuffer;

/* Initiate SPI transfer */
transferOK = SPI_transfer(slaveSpi, &slaveTransaction);

if(transferOK) {
/* Print contents of slave receive buffer */
System_printf("Slave2: %s\n", slaveRxBuffer);
}
else {
System_printf("Unsuccessful slave 222 SPI transfer");
}

/* Deinitialize SPI */
SPI_close(slaveSpi);
}


/*
* ======== masterTaskFxn ========
* Task function for master task.
*
* This task runs at a lower priority after the slave
* task to ensure it is ready for a transaction.
* Master SPI sends a message to slave and also
* receives message from slave. Task for this function
* is created statically. See the project's .cfg
* file.
*/
Void masterTaskFxn (UArg arg0, UArg arg1)
{
SPI_Handle masterSpi;
SPI_Transaction masterTransaction;
UInt transferOK;

/* Initialize SPI handle as default master */
masterSpi = SPI_open(Board_SPI0, NULL);
if (masterSpi == NULL) {
System_abort("Error initializing SPI\n");
}
else {
System_printf("SPI initialized\n");
}

/* Initialize master SPI transaction structure */
masterTransaction.count = SPI_MSG_LENGTH;
masterTransaction.txBuf = (Ptr)masterTxBuffer;
masterTransaction.rxBuf = (Ptr)masterRxBuffer;

/* Initiate SPI transfer */
transferOK = SPI_transfer(masterSpi, &masterTransaction);

if(transferOK) {
/* Print contents of master receive buffer */
System_printf("Master: %s\n", masterRxBuffer);
}
else {
System_printf("Unsuccessful master SPI transfer");
}

/* Deinitialize SPI */
SPI_close(masterSpi);

System_printf("Done\n");

System_flush();

/*
* Spin to avoid SDOCM00105002 "TI-RTOS examples with no heap get an error
* if they call BIOS_exit"
*/
while(true);
}

  • What board are you using? Also, which version of TI-RTOS are you using?

    Todd

  • I'm using TI-RTOS version 1_21_00_09

    and DK-TM4C129X.

  • There are a couple things you need to keep in mind:

    1. the slave must open the channel and initiate communication before the master starts.

    2. Multiple tasks can initiate a transfer, but they should only be one SPI_open.

    It looks like #2 is the problem (I'm assuming slave2 has the same Task priority as slave1...correct me if I am wrong). I expect slave1 runs first, calls SPI_open then calls SPI_transfer. Then before SPI_transfer returns, slave2 calls SPI_open on the same channel. This is wrong. It should just call the SPI_transfer. You need to figure out how to share the SPI_Handle returned from SPI_open().

    Todd

  • Mostafa,

    to add to Todd's reply.

    SPI_open() can be only called once. If it returns NULL, it was probably already opened. You can pass an opened SPI handle to your tasks if you wish.

    SPI_transfer doesn't have a mutex to protect itself between tasks; however, if an SPI_transfer is currently in progress, it will return FALSE. As SPI_transfer() calls don't handle any chip select pin (de)assertion, its up to the task to assert that pin before and after a SPI_transfer call.

    gate = GateMutex_enter()
    Assert_GPIO_low() //Pseudo code function call
    done = SPI_transfer(handle, &spiTransaction);
    Assert_GPIO_high() //Pseudo code function call
    GateMutex_leave(gate);
    if (!done) {
      System_printf("Something is wrong");
    }

    If this is to be done between task, you must use some sort of RTOS lock around the gpio calls and the SPI_transfer so that another task wouldn't interfere with the CS pin states. Because of this, having another mutex in SPI_transfer isn't really useful.

    From my understanding some SPI controllers may have some hardware chip select feature, but as it currently stands the SPI driver doesn't know about those features. If this still presents a problem in your application, perhaps you can elaborate on your setup and we can find a elegant solution.

  • Hi Tom, Todd,

    Thanks for your replies.

    I have a situation in which I want to have SPI communications with two different slaves, and each one has a different frame format (one uses SPI_MODE3 and the other SPI_MODE0; one uses LSB_FIRST and the other MSB_FIRST)

    Using Energia, one can setDataMode and setBitOrder before doing the transfer, but in TI-RTOS, I only see the SPI_open interface which takes in the SPI_Params - I don't see any option to change the params associated with an already open handle, so I can communicate with both devices using the same handle.

    What are my options in this scenario?

    Thanks,
    Sridhar
  • Sridhar Rajagopal92 said:
    I have a situation in which I want to have SPI communications with two different slaves, and each one has a different frame format (one uses SPI_MODE3 and the other SPI_MODE0; one uses LSB_FIRST and the other MSB_FIRST)

    Using Energia, one can setDataMode and setBitOrder before doing the transfer, but in TI-RTOS, I only see the SPI_open interface which takes in the SPI_Params - I don't see any option to change the params associated with an already open handle, so I can communicate with both devices using the same handle.

    As far as I understand the current SPI driver, you need to close and the reopen it if you want to change any SPI_Param options.

  • Hi Sridhar,

    Did you figure out how to set MSB first in SPI_Transfer() function? for TI-RTOS? I couldn't find any documentation regarding that.

  • Hi,

    Since this is an old thread and there is no response from Sridhar, I recommend you open a new thread. Please include the device and version of software you are using.

    Keeping the threads shorter helps our search engine.

    Todd
  • Hi, 

    I just saw this. I will need to dig up how I resolved it. I will update the thread either way. 

    Thanks,
    Sridhar

  • Hi Vijay,

    I did what Tom had suggested. I had mutex protection, and implemented a getHandle call, and closed/reopened SPI handles based on what device I wanted to talk to, specifying the requisite params in SPI_Param to the SPI init call.

    In particular, I used
    spiParams.frameFormat = SPI_POL1_PHA1;
    or
    spiParams.frameFormat = SPI_POL0_PHA0;

    for my two cases (I don't remember which was which at the top of my head). Did you check the spiParams.frameFormat documentation?

    Best,
    Sridhar
  • Hello Todd and Sridhar,

    Thanks for your replies. I am currently using CC2650 Launchpad to control the LED Matrix using MAX7219. So I needed 16 bit data transfer with MSP first and the frameFormat needed to be SPI_POL0_PHA1. 

    Initially I used MSP432 Launchpad (and CC2650 as Simple Network processor) to test the SPI protocol. In particular I used MSP432 driverlib. It had option to set the phase, polarity and MSB/LSB. This was my SPI driverlib config:

    /* SPI Master Configuration Parameter */ 
    const eUSCI_SPI_MasterConfig spiMasterConfig = 
    { 
            EUSCI_B_SPI_CLOCKSOURCE_SMCLK,             // SMCLK Clock Source 
            32000,                                  // SMCLK = DCO = 32khz // Initially I kept it in 3Mhz. Didn't work 
            32000,                                     // SPICLK = 32khz   // Initially I kept it in 500Khz. Didn't work 
            EUSCI_B_SPI_MSB_FIRST,                     // MSB First 
            EUSCI_B_SPI_PHASE_DATA_CHANGED_ONFIRST_CAPTURED_ON_NEXT,    // Phase 
        EUSCI_B_SPI_CLOCKPOLARITY_INACTIVITY_LOW, // Low polarity  - check datasheet pg. 82 and max7219 datasheet - timing diagram 
            EUSCI_B_SPI_3PIN                           // 3Wire SPI Mode 
    //EUSCI_B_SPI_4PIN_UCxSTE_ACTIVE_LOW 
    };

    Then I planned to use CC2650 to control the MAX7219. Initially I was searching for the option to set MSB first. (That is why I posted in the forum). Later checking the CC2650 technical reference manual, I realized that CC2650 performs SPI with MSB first default. 

    But still, it would be a good option to provide MSB/LSB first option under SPI_Param :)

    Also, one other thing I noticed that MAX7219 doesn't respond if I set the frameFormat  SPI_POL0_PHA1 (but the same thing worked with MSP432). It worked for all other three combos (SPI_POL0_PHA0, SPI_POL1_PHA1, SPI_POL1_PHA0). I don't have a oscilloscope or logic analyzer to confirm whether it is a bug in TI-RTOS for CC2650.

    Thanks.