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.

CC1310: Strange behaviour of SPI when calling SPI_transfer() from the SPI tranfer complete callback

Part Number: CC1310


Hello,

I am trying to build and SPI slave application on the CC1310 that should behave in the followng manner:

  1. Master will assert the chip select
  2. Master transmits 3 bytes
  3. Delay
  4. Master transmits rest of the data or clocks to read data from CC1310

The first byte is command, the next to depend on the context.

The idea is that when the master send GET command, followed by two bytes for identifying what data is wants to get, the CC1310 will load that particular data mid transaction (during the delay).

To achieve this I did the following on the slave side:

#define SPI_MSG_LENGTH  0x100
SPI_Handle      spiHandle;
SPI_Transaction spiTransaction;
uint8_t         spiRxBuffer[SPI_MSG_LENGTH];
uint8_t         spiTxBuffer[SPI_MSG_LENGTH];

static void spiInit(void)
{
    SPI_Params      spiParams;

    SPI_init();
    SPI_Params_init(&spiParams);
    spiParams.frameFormat         = SPI_POL1_PHA1;
    spiParams.mode                = SPI_SLAVE;
    spiParams.transferCallbackFxn = spiTransferCallback;
    spiParams.transferMode        = SPI_MODE_CALLBACK;
    spiParams.bitRate             = 2000000;

    memset(spiTxBuffer, 0, sizeof(spiTxBuffer));
    memset(spiRxBuffer, 0, sizeof(spiRxBuffer));

    spiHandle = SPI_open(SPI0, &spiParams);

    if (spiHandle == NULL)
    {
        while (1);
    }

    SPI_control(spiHandle, SPICC26XXDMA_RETURN_PARTIAL_ENABLE, NULL);

    memcpy(spiTxBuffer, "123456789ABCDEF", sizeof("123456789ABCDEF"));
    spiTransaction.count = 3;
    spiTransaction.txBuf = spiTxBuffer;
    spiTransaction.rxBuf = spiRxBuffer;

    SPI_transfer(spiHandle, &spiTransaction);
}


static void spiTransferCallback(SPI_Handle handle, SPI_Transaction* transaction)
{
    bool status;

    /* Cancel transfer just in case */
    SPI_transferCancel(spiHandle);

    if (transaction->status == SPI_TRANSFER_COMPLETED)
    {
        /* Prepare for second part of transfer */
        transaction->txBuf = spiTxBuffer + 3;
        transaction->rxBuf = spiRxBuffer + 3;
        transaction->count = SPI_MSG_LENGTH - 3;

    }
    else
    {
        /* Chip select deasserted. Prepare for new transfer */
        transaction->txBuf = spiTxBuffer;
        transaction->rxBuf = spiRxBuffer;
        transaction->count = 3;

    }

    status = SPI_transfer(handle, transaction);
}

On the master side I do the following:

  1. Assert CS
  2. Transmit 3 bytes
  3. Delay 1 ms
  4. Transmit 7 bytes
  5. Deassert CS

Everything works mostly as intended, with the exception that the 4th bytes I receive on the master side is always corrupted, while there is never a problem with the data received on the slave side.

The first transaction after restarting CC1310 the RX buffer on the master side looks like this:

Index

Data

[0]

‘1’

[1]

‘2’

[2]

‘3’

[3]

‘1’

[4]

‘2’

[5]

‘3’

[6]

‘4’

[7]

‘5’

[8]

‘6’

[9]

‘7’

After the second transaction, the master RX buffer looks like:

Index

Data

[0]

‘1’

[1]

‘2’

[2]

‘3’

[3]

‘B’

[4]

‘5’

[5]

‘6’

[6]

‘7’

[7]

‘8’

[8]

‘9’

[9]

‘A’

For all other transactions, the master RX buffer looks like:

Index

Data

[0]

‘1’

[1]

‘2’

[2]

‘3’

[3]

‘E’

[4]

‘5’

[5]

‘6’

[6]

‘7’

[7]

‘8’

[8]

‘9’

[9]

‘A’

I am using simplelink_cc13x0_sdk_1_60_00_21 and CCS Version: 10.1.0.00010.

I would appreciate your help with the issue. Thank you,

Borislav

  • Hi Borislav

    You are using a VERY old SDK. I would strongly recommend that download the latest SDK and implement the same code there, to see if you still see the same problem. If you do, it would be appreciated if you could send us some complete code that we can test to try to reproduce the problem.

    You do not have to port the complete application at first. Use the spi examples available in the SDK and modify them to your need, and see if you can re-create the problem.

    BR

    Siri

  • Hi Siri,

    I did as you suggested and got the same result with simplelink_cc13x0_sdk_4_10_02_04.

    I used the "uartecho" as base for my test project, because it is without RTOS, whereas the SPI example project have only TI RTOS option.

    This is my uartecho.c file:

    /*
     * Copyright (c) 2015-2019, Texas Instruments Incorporated
     * All rights reserved.
     *
     * 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.
     */
    
    /*
     *  ======== uartecho.c ========
     */
    #include <stdint.h>
    #include <stddef.h>
    #include <string.h>
    
    /* Driver Header files */
    #include <ti/drivers/GPIO.h>
    #include <ti/drivers/SPI.h>
    #include <ti/drivers/spi/SPICC26XXDMA.h>
    
    /* Example/Board Header files */
    #include "Board.h"
    
    #define SPI_MSG_LENGTH  256
    SPI_Handle      spiHandle;
    SPI_Transaction spiTransaction;
    uint8_t         spiRxBuffer[SPI_MSG_LENGTH];
    uint8_t         spiTxBuffer[SPI_MSG_LENGTH];
    
    static void spiInit(void);
    static void spiTransferCallback(SPI_Handle handle, SPI_Transaction* transaction);
    
    
    /*
     *  ======== mainThread ========
     */
    void *mainThread(void *arg0)
    {
        /* Call driver init functions */
        GPIO_init();
    
        spiInit();
    
        /* Loop forever */
        while (1);
    }
    
    
    /*
     *  ======== spiInit ========
     */
    static void spiInit(void)
    {
        SPI_Params      spiParams;
    
        SPI_init();
        SPI_Params_init(&spiParams);
        spiParams.frameFormat         = SPI_POL1_PHA1;
        spiParams.mode                = SPI_SLAVE;
        spiParams.transferCallbackFxn = spiTransferCallback;
        spiParams.transferMode        = SPI_MODE_CALLBACK;
        spiParams.bitRate             = 2000000;
    
        memset(spiTxBuffer, 0, sizeof(spiTxBuffer));
        memset(spiRxBuffer, 0, sizeof(spiRxBuffer));
    
        spiHandle = SPI_open(CC1310_LAUNCHXL_SPI0, &spiParams);
    
        if (spiHandle == NULL)
        {
            while (1);
        }
    
        SPI_control(spiHandle, SPICC26XXDMA_RETURN_PARTIAL_ENABLE, NULL);
    
        /* Start transfer */
        memcpy(spiTxBuffer, "123456789ABCDEF", sizeof("123456789ABCDEF"));
        spiTransaction.count = 3;
        spiTransaction.txBuf = spiTxBuffer;
        spiTransaction.rxBuf = spiRxBuffer;
    
        SPI_transfer(spiHandle, &spiTransaction);
    }
    
    
    /*
     *  ======== spiTransferCallback ========
     */
    static void spiTransferCallback(SPI_Handle handle, SPI_Transaction* transaction)
    {
        bool status;
    
        if (transaction->status == SPI_TRANSFER_COMPLETED)
        {
            /* Prepare for second part of transfer */
            transaction->txBuf = spiTxBuffer + 3;
            transaction->rxBuf = spiRxBuffer + 3;
            transaction->count = SPI_MSG_LENGTH - 3;
    
        }
        else
        {
            /* Chip select deasserted. Prepare for new transfer */
            transaction->txBuf = spiTxBuffer;
            transaction->rxBuf = spiRxBuffer;
            transaction->count = 3;
    
        }
    
        status = SPI_transfer(handle, transaction);
    }

    I made the followng changes in to CC1310_LAUNCHXL.c:

    const PIN_Config BoardGpioInitTable[] = {
    
        CC1310_LAUNCHXL_SPI0_MOSI | PIN_INPUT_EN | PIN_PULLDOWN,                                            /* SPI master out - slave in */
        CC1310_LAUNCHXL_SPI0_MISO | PIN_INPUT_EN | PIN_PULLDOWN,                                            /* SPI master in - slave out */
        CC1310_LAUNCHXL_SPI0_CLK | PIN_INPUT_EN | PIN_PULLDOWN,                                             /* SPI clock */
    
        PIN_TERMINATE
    };
    
    
    void CC1310_LAUNCHXL_initGeneral(void)
    {
        Power_init();
    
        if (PIN_init(BoardGpioInitTable) != PIN_SUCCESS) {
            /* Error with PIN_init */
            while (1);
        }
    
        /* Perform board-specific initialization */
        //Board_initHook();
    }

    And finally I changed the following in CC1310_LAUNCHXL.h to match my board:

    #define CC1310_LAUNCHXL_SPI0_MISO             IOID_13
    #define CC1310_LAUNCHXL_SPI0_MOSI             IOID_14
    #define CC1310_LAUNCHXL_SPI0_CLK              IOID_12
    #define CC1310_LAUNCHXL_SPI0_CSN              IOID_11

    The application on the master side looks like this:

    spiCSactivate(handle);
    spiWrite(handle, testTxBuffer, testRxBuffer, 3);
    uSecDelay(1000);
    spiWrite(handle, testTxBuffer + 3, testRxBuffer + 3, 7);
    mSecDelay(1000);

    With all the above, the behaviour is the same as in my original post.

    I've ruled out problem on the master side, because when I make the following change to the slave, everything works flawlessly:

    static void spiInit(void)
    {
        SPI_Params      spiParams;
    
        SPI_init();
        SPI_Params_init(&spiParams);
        spiParams.frameFormat         = SPI_POL1_PHA1;
        spiParams.mode                = SPI_SLAVE;
        spiParams.transferCallbackFxn = spiTransferCallback;
        spiParams.transferMode        = SPI_MODE_CALLBACK;
        spiParams.bitRate             = 2000000;
    
        memset(spiTxBuffer, 0, sizeof(spiTxBuffer));
        memset(spiRxBuffer, 0, sizeof(spiRxBuffer));
    
        spiHandle = SPI_open(CC1310_LAUNCHXL_SPI0, &spiParams);
    
        if (spiHandle == NULL)
        {
            while (1);
        }
    
        SPI_control(spiHandle, SPICC26XXDMA_RETURN_PARTIAL_ENABLE, NULL);
    
        /* Start transfer */
        memcpy(spiTxBuffer, "123456789ABCDEF", sizeof("123456789ABCDEF"));
        spiTransaction.count = 10;
        spiTransaction.txBuf = spiTxBuffer;
        spiTransaction.rxBuf = spiRxBuffer;
    
        SPI_transfer(spiHandle, &spiTransaction);
    }
    
    
    /*
     *  ======== spiTransferCallback ========
     */
    static void spiTransferCallback(SPI_Handle handle, SPI_Transaction* transaction)
    {
        bool status;
    
        spiTransaction.count = 10;
        status = SPI_transfer(handle, transaction);
    }

    Please let me know if you need more information.

    Best regards,

    Borislav

  • Hi Borislav

    Please attach the complete uartecho.c file (both for master and for slave). as I cannot find the definition for the following.

    I still do not know what spiCSactivate(handle);
    spiWrite(handle, testTxBuffer, testRxBuffer, 3);

    If you have one slave file that works, andone that does not work, please send both.

    BR

    Siri

  • Hi Siri,

    I am running the SPI master on a different MCU (not TI). This is why I've just outlined what the code does. I don't have a boards that I can easily rewire to connect CC1310 with CC1310.

    I am attaching the source for the slave,

    Best regards,

    Borislav

    /*
     * Copyright (c) 2015-2019, Texas Instruments Incorporated
     * All rights reserved.
     *
     * 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.
     */
    
    /*
     *  ======== s.c ========
     */
    #include <stdint.h>
    #include <stddef.h>
    #include <string.h>
    
    /* Driver Header files */
    #include <ti/drivers/GPIO.h>
    #include <ti/drivers/SPI.h>
    #include <ti/drivers/spi/SPICC26XXDMA.h>
    
    /* Example/Board Header files */
    #include "Board.h"
    
    #define SPI_MSG_LENGTH  256
    SPI_Handle      spiHandle;
    SPI_Transaction spiTransaction;
    uint8_t         spiRxBuffer[SPI_MSG_LENGTH];
    uint8_t         spiTxBuffer[SPI_MSG_LENGTH];
    
    static void spiInit(void);
    static void spiTransferCallback(SPI_Handle handle, SPI_Transaction* transaction);
    
    
    /*
     *  ======== mainThread ========
     */
    void *mainThread(void *arg0)
    {
        /* Call driver init functions */
        GPIO_init();
    
        spiInit();
    
        /* Loop forever */
        while (1);
    }
    
    
    /*
     *  ======== spiInit ========
     */
    static void spiInit(void)
    {
        SPI_Params      spiParams;
    
        SPI_init();
        SPI_Params_init(&spiParams);
        spiParams.frameFormat         = SPI_POL1_PHA1;
        spiParams.mode                = SPI_SLAVE;
        spiParams.transferCallbackFxn = spiTransferCallback;
        spiParams.transferMode        = SPI_MODE_CALLBACK;
        spiParams.bitRate             = 2000000;
    
        memset(spiTxBuffer, 0, sizeof(spiTxBuffer));
        memset(spiRxBuffer, 0, sizeof(spiRxBuffer));
    
        spiHandle = SPI_open(CC1310_LAUNCHXL_SPI0, &spiParams);
    
        if (spiHandle == NULL)
        {
            while (1);
        }
    
        SPI_control(spiHandle, SPICC26XXDMA_RETURN_PARTIAL_ENABLE, NULL);
    
        /* Start transfer */
        memcpy(spiTxBuffer, "123456789ABCDEF", sizeof("123456789ABCDEF"));
        spiTransaction.count = 10;
        spiTransaction.txBuf = spiTxBuffer;
        spiTransaction.rxBuf = spiRxBuffer;
    
        SPI_transfer(spiHandle, &spiTransaction);
    }
    
    
    /*
     *  ======== spiTransferCallback ========
     */
    static void spiTransferCallback(SPI_Handle handle, SPI_Transaction* transaction)
    {
        bool status;
    
    //    if (transaction->status == SPI_TRANSFER_COMPLETED)
    //    {
    //        /* Prepare for second part of transfer */
    //        transaction->txBuf = spiTxBuffer + 3;
    //        transaction->rxBuf = spiRxBuffer + 3;
    //        transaction->count = SPI_MSG_LENGTH - 3;
    //
    //    }
    //    else
    //    {
    //        /* Chip select deasserted. Prepare for new transfer */
    //        transaction->txBuf = spiTxBuffer;
    //        transaction->rxBuf = spiRxBuffer;
    //        transaction->count = 3;
    //
    //    }
    
        //SPI_control(spiHandle, SPICC26XXDMA_RETURN_PARTIAL_ENABLE, NULL);
        spiTransaction.count = 10;
        status = SPI_transfer(handle, transaction);
    }
    

  • Hi Borislav

    I am afraid that I am not able to reproduce your problem. I tested your code below:

    static void spiInit(void)
    {
        SPI_Params      spiParams;
    
        SPI_init();
        SPI_Params_init(&spiParams);
        spiParams.frameFormat         = SPI_POL1_PHA1;
        spiParams.mode                = SPI_SLAVE;
        spiParams.transferCallbackFxn = spiTransferCallback;
        spiParams.transferMode        = SPI_MODE_CALLBACK;
        spiParams.bitRate             = 2000000;
    
        memset(spiTxBuffer, 0, sizeof(spiTxBuffer));
        memset(spiRxBuffer, 0, sizeof(spiRxBuffer));
    
        spiHandle = SPI_open(CC1310_LAUNCHXL_SPI0, &spiParams);
    
        if (spiHandle == NULL)
        {
            while (1);
        }
    
        SPI_control(spiHandle, SPICC26XXDMA_RETURN_PARTIAL_ENABLE, NULL);
    
        /* Start transfer */
        memcpy(spiTxBuffer, "123456789ABCDEF", sizeof("123456789ABCDEF"));
        spiTransaction.count = 3;
        spiTransaction.txBuf = spiTxBuffer;
        spiTransaction.rxBuf = spiRxBuffer;
    
        SPI_transfer(spiHandle, &spiTransaction);
    }
    
    static void spiTransferCallback(SPI_Handle handle, SPI_Transaction* transaction)
    {
        bool status;
    
        if (transaction->status == SPI_TRANSFER_COMPLETED)
        {
            /* Prepare for second part of transfer */
            transaction->txBuf = spiTxBuffer + 3;
            transaction->rxBuf = spiRxBuffer + 3;
            transaction->count = SPI_MSG_LENGTH - 3;
    
        }
        else
        {
            /* Chip select deasserted. Prepare for new transfer */
            transaction->txBuf = spiTxBuffer;
            transaction->rxBuf = spiRxBuffer;
            transaction->count = 3;
    
        }
        status = SPI_transfer(handle, transaction);
    }

    and were not able to see any problems. I made simple master code to test it. The slave returned the correct results all the time:

    Have you tried to monitor the SPI bus with a logic analyzer to try to figure out what is going on on the bus?

    Siri

  • Hi Siri,

    I've check the bus and see the exact same thing (I changed the delay between the two parts of the transaction to 60 microseconds, but I get the same result when the delay is 1ms):

    uartecho_CC1310_LAUNCHXL_nortos_ccs.zip

    I've attached the whole uartecho project folder. It also contains the output hex of my last build. Perhaps you could flash that and check again with the analyser. 

    Best regards,
    Borislav

  • Before I look into this once more, I noticed something. In your code, and the code I tested,

    spiParams.frameFormat = SPI_POL1_PHA1;

    Which means that SCLK is high between transfers (as shown in my plot), while in your plot above, SCLK is low between transfers.

    Could it be that you are using the wrong SPI configuration compared to what your master is using?

    Siri

  • Hi Siri,

    I've double checked the configuration and even tested with the other 3 combinations. I believe the setup on both sides is correct.

    Another inetersting thing is that if I change the contents of the slave TX buffer from "123456789ABCDEF" to "123456789ABCDZF", then the 4th byte in the master RX buffer changes from 'E' to 'Z'. Furthermore, by increasing the total transaction length, then the erronous 4th byte also changes value. For example, by changing the length from 10 to 11 bytes, the value of the 4th symbol changes to 'F'.

    Best regards,
    Borislav

  • I cannot understand that the configuration is correct.

    You should not set SPI_POL1_PHA1 if your SCLK is low when IDLE.

    Can you please send a plot of the SPI from the master when it is not connected to the slave? Also provide information regarding which data you tell your master to transmit. Please Zoom in properly on the plot so that I can see all edges

    BR

    Siri

  • Hello Siri,

    Here are plots of the first byte and the full transaction when the slave is connected:

    And here are the same plots when the slave is disconnected:

    The signals in the plots are as follows:

    D0: CS

    D1: CLK

    D2: MISO

    D3: MOSI

    The data being transmitted is the same on both ends and is "12346789A".

    Best regards,

    Borislav

  • Hi Borislav

    I tried the .hex file and the .out file from your zip file, but was not able to see any communication on the MISO line.

    Instead I copied the uart.c file into my project and was running it.

    I was not able to see any problems:

    In the above plots, when everything works, I am running your slave code.

    This code is settings spiParams.frameFormat = SPI_POL1_PHA1;

    However, when you compare my plots and your plots, you will see that in my plots SCLK is 1 when IDLE, but in your plots, it is 0.

    Since the difference between these tests are the master code, I changed my master code to use

    spiParams.frameFormat = SPI_POL0_PHA1; The slave code is kept the same:

    In this case, my SCLK line behave the same way as in your plots, but I get an error in the 4th byte (like you do). This is because the slave code is using the wrong configuration compared to what the master is doing.

    I now modified your slave code to use spiParams.frameFormat = SPI_POL0_PHA1;

    BR

    Siri

  • Hi Siri,

    Thanks for your help. The error was indeed in the master as it was only able to "work" when the slave was configured to POL1, PHA1.

    Best regards,
    Borislav