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.

LAUNCHXL-CC1310: How can exit SPI_transfer in callback mode.

Part Number: LAUNCHXL-CC1310
Other Parts Discussed in Thread: CC1310

Hi,

I wonder that how do i exit SPI_transfer in callback mode.

CC1310 launchpad operate as SPI slave.

when get SPI data, SPI slave doesn't call callback every now and then.

At this moment, how do i exit SPI_transfer. or how can i call callback funcition.

below is my CC1310 Code. 

when SPI slave operate correctly,  'transferOK2' variable set '0'. and then rest of code operate.

#define SPI_MSG_LENGTH  (200) + 3

#define DATA_ENTRY_HEADER_SIZE  8   // Constant header size of a Generic Data Entry
#define MAX_LENGTH              SPI_MSG_LENGTH // Set the length of the data entry
#define NUM_DATA_ENTRIES        1
#define NUM_APPENDED_BYTES      0

/* TX queue or RF Core to read data from */
static dataQueue_t dataQueue;
static rfc_dataEntryGeneral_t* currentDataEntry;
static uint8_t *pPacket;

static uint8_t txDataEntryBuffer[RF_QUEUE_DATA_ENTRY_BUFFER_SIZE(NUM_DATA_ENTRIES,
                                                                 MAX_LENGTH,
                                                                 NUM_APPENDED_BYTES)];

/***** Variable declarations *****/
static bool            transferOK;
static bool            transferOK2;

uint8_t slaveRxBuffer[SPI_MSG_LENGTH];

/* Pin driver handle */
static PIN_Handle ledPinHandle;
static PIN_State ledPinState;
PIN_Config ledPinTable[] = {
    Board_PIN_LED0 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
    Board_PIN_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
    PIN_TERMINATE
};

static PIN_Handle slaveRdyHandle;
static PIN_State slaveRdyState;
PIN_Config slaveRdyTable[] = {
    Board_DIO21 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_DRVSTR_MAX,
    PIN_TERMINATE
};

static PIN_Handle masterRdyHandle;
static PIN_State masterRdyState;
PIN_Config masterRdyTable[] = {
    Board_DIO15 | PIN_INPUT_EN,
    PIN_TERMINATE
};

static void SPIRxCallback(SPI_Handle handle, SPI_Transaction *transaction)
{
    transferOK2 = 0;

    if(transaction->status == SPI_TRANSFER_COMPLETED){ // Green
        PIN_setOutputValue(ledPinHandle, Board_PIN_LED1,  !PIN_getOutputValue(Board_PIN_LED1));
    }

    else{
        PIN_setOutputValue(ledPinHandle, Board_PIN_LED0,  !PIN_getOutputValue(Board_PIN_LED0));
    }
}

void tx_callback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e)
{
    if(e & RF_EventLastCmdDone)
    {

        //PIN_setOutputValue(ledPinHandle, Board_PIN_LED0,  !PIN_getOutputValue(Board_PIN_LED0));

    }

}

void *mainThread(void *arg0)
{
    // RF Setting
    RF_Object rfObject;
    RF_Handle rfHandle;

    RF_Params rfParams;
    RF_Params_init(&rfParams);

    // SPI Rx Setting
    SPI_Handle      slaveSpi;
    SPI_Params      spiParams;
    SPI_Transaction transaction;

    SPI_init();

    if( RFQueue_defineQueue(&dataQueue,
                            txDataEntryBuffer,
                            sizeof(txDataEntryBuffer),
                            NUM_DATA_ENTRIES,
                            MAX_LENGTH + NUM_APPENDED_BYTES))
    {
        /* Failed to allocate space for all data entries */
        while(true);
    }

    RF_cmdTxHS.pQueue = &dataQueue;
    RF_cmdTxHS.startTrigger.triggerType  = TRIG_NOW;
    RF_cmdTxHS.startTrigger.pastTrig = 1;
    RF_cmdTxHS.startTime = 0;

    currentDataEntry = (rfc_dataEntryGeneral_t*)&txDataEntryBuffer;
    currentDataEntry->length = SPI_MSG_LENGTH;
    pPacket = &currentDataEntry->data;

    SPI_Params_init(&spiParams);
    spiParams.frameFormat = SPI_POL0_PHA1;
    spiParams.mode = SPI_SLAVE;
    spiParams.transferCallbackFxn = SPIRxCallback;
    spiParams.transferMode = SPI_MODE_CALLBACK;
    spiParams.bitRate = 4000000;
    slaveSpi = SPI_open(Board_SPI_SLAVE, &spiParams);
    if (slaveSpi == NULL) {
       while (1);
    }
    /* Request access to the radio */
    rfHandle = RF_open(&rfObject, &RF_prop_hsm, (RF_RadioSetup*)&RF_cmdRadioSetup_hsm, &rfParams);

    /* Set the frequency */
    //{ "868.0  ", 0x0364, 0x0000, 0x0 },
    //{ "915.0  ", 0x0393, 0x0000, 0x0 },
    RF_cmdFs_preDef.frequency = 0x0393;
    RF_cmdFs_preDef.fractFreq = 0x0000;
    RF_postCmd(rfHandle, (RF_Op*)&RF_cmdFs_preDef, RF_PriorityNormal, NULL, 0);

    /* Open LED pins */
    ledPinHandle = PIN_open(&ledPinState, ledPinTable);
    if(!ledPinHandle) {
        /* Error initializing board LED pins */
        while(1);
    }

    /* slave Ready pin */
    slaveRdyHandle = PIN_open(&slaveRdyState, slaveRdyTable);
    if(!slaveRdyHandle) {
        /* Error initializing button pins */
        while(1);
    }

    /* master Ready pin */
    masterRdyHandle = PIN_open(&masterRdyState, masterRdyTable);
    if(!masterRdyHandle) {
        /* Error initializing button pins */
        while(1);
    }

    /* Initialize slave SPI transaction structure */
    transaction.count = SPI_MSG_LENGTH;
    transaction.txBuf = NULL;
    transaction.rxBuf = (void *) slaveRxBuffer;

    while(1)
    {
        transferOK2 = 1;

        memset(slaveRxBuffer, 0, SPI_MSG_LENGTH + 1);

        transferOK = SPI_transfer(slaveSpi, &transaction);

        if (transferOK) {
            while(!PIN_getInputValue(Board_DIO15));

            PIN_setOutputValue(slaveRdyHandle, Board_DIO21, 1);

            while(transferOK2);

            PIN_setOutputValue(slaveRdyHandle, Board_DIO21, 0);

            memcpy(pPacket, slaveRxBuffer, SPI_MSG_LENGTH + 1);

            RF_postCmd(rfHandle, (RF_Op*)&RF_cmdTxHS, RF_PriorityNormal, NULL, 0);

        }
        else {

        }
    }
}

  • I have another question.

    How much length can get SPI data withou CSN handling?

    I refered 'spislave' & 'spimaster' example.

    it doesn't control CSN pin during 30bytes sending in example.

  • Please refer to the documentation of the SPI driver here: SPI.h File Reference (ti.com)

    I am afraid I do not fully understand exactly what you are trying to do and how it fails.

    I recommend that you start with the SPI master and slave example in the SDK, and get it to operate as wanted (correct, number of bytes, correct use of CSn etc.) before you start including the RF driver into the application.

    If you are not able to get the master/slave communication up and running, you can share the code with me, so that I can test it.

    It needs to be able to run on the CC1310 LP and I would need both master and slave code.

    A figure of the SPI data you want to transmit (or that your master transmits if it is not the CC1310) would be needed to be able to guide you on how the slave needs to be configured to be able to receive those data.

    Siri

  • Hi Siri,

    As i understood SPI slave callback mode, SPI slave get data from master until specified count. ( In code, "transaction.count = SPI_MSG_LENGTH" )

    So i expected that SPI callback always call after SPI transfer end even though SPI_transfer is fail.

    But callback sometimes doesn't work. So i need to exit SPI transfer. 

    in my code, if doesn't work callback, can't work after "while(transferOK2)".

    i need function like "SPI_Params.transferTimeout". but it can use only SPI blocking mode. right?

    So i asked function like "transfertimeout" in callback mode.

    Other question is about SPI frame format.

    In TRM, SPI need to control CSN like below mentioned.

    But in SDK example "spislave_CC1310_LAUNCHXL_tirtos_ccs" and "spimaster_CC1310_LAUNCHXL_tirtos_ccs", 

    CSN doesn't de-assertion during send 30-Bytes data.

    So what is correct information? can i use SPI slave send about 200-bytes data without CSN de-assertion from master ?

    below is master SPI waveform ( Y : CSN, B : SPI clock, G : SPI MOSI )

  • There are no timeout in SPI_MODE_CALLBACK. This is stated in the documentation I sent you.

    If you are using SPI_MODE_CALLBACK, and set the transaction.count = 20; on the slave device, you will get a callback after you have received 20 bytes.

    That means that if you only transmit 10 bytes from you master in one transaction (transaction.count = 10), you will not get a callback on the slave before you have done two transfers from the master.

    That means that if you want to cancel the SPI transfer BEFORE 20 bytes are received, you need to use the SPI_transferCancel().

    I have simplified the Master and Slave examples for you, so that you can use these examples and monitor the SPI lines together with the two LEDs, so that you better can understand how this works.

    Slave:

    #define THREADSTACKSIZE (1024)
    
    #define SPI_MSG_LENGTH  (20)
    
    unsigned char slaveRxBuffer[SPI_MSG_LENGTH];
    unsigned char slaveTxBuffer[SPI_MSG_LENGTH];
    
    sem_t slaveSem;
    
    void transferCompleteFxn(SPI_Handle handle, SPI_Transaction *transaction)
    {
        sem_post(&slaveSem);
    }
    
    void *slaveThread(void *arg0)
    {
        SPI_Handle      slaveSpi;
        SPI_Params      spiParams;
        SPI_Transaction transaction;
        uint32_t        i;
        bool            transferOK;
        int32_t         status;
    
        status = sem_init(&slaveSem, 0, 0);
        if (status != 0)
        {
            while(1);
        }
    
        GPIO_init();
        SPI_init();
    
        SPI_Params_init(&spiParams);
        spiParams.frameFormat = SPI_POL0_PHA1;
        spiParams.mode = SPI_SLAVE;
        spiParams.transferCallbackFxn = transferCompleteFxn;
        spiParams.transferMode = SPI_MODE_CALLBACK;
        slaveSpi = SPI_open(Board_SPI_SLAVE, &spiParams);
    
        if (slaveSpi == NULL)
        {
            while (1);
        }
    
        for(i = 0; i < SPI_MSG_LENGTH; i++)
            slaveTxBuffer[i] = SPI_MSG_LENGTH - i;
    
        while(1)
        {
            GPIO_write(Board_GPIO_LED1, 1);
            transaction.count = SPI_MSG_LENGTH;
            transaction.txBuf = (void *) slaveTxBuffer;
            transaction.rxBuf = (void *) slaveRxBuffer;
    
            transferOK = SPI_transfer(slaveSpi, &transaction);
    
            if (transferOK)
            {
                // Wait until transfer has completed
                sem_wait(&slaveSem);
                GPIO_toggle(Board_GPIO_LED0);
            }
            GPIO_write(Board_GPIO_LED1, 0);
        }
    }

    Master:

    #define THREADSTACKSIZE (1024)
    
    #define SPI_MSG_LENGTH  (20)
    
    unsigned char masterRxBuffer[SPI_MSG_LENGTH];
    unsigned char masterTxBuffer[SPI_MSG_LENGTH];
    
    sem_t transactionSem;
    
    void TransmitReceiveFxn(uint_least8_t index)
    {
        sem_post(&transactionSem);
    }
    
    uint8_t i = 0;
    
    void *masterThread(void *arg0)
    {
        SPI_Handle      masterSpi;
        SPI_Params      spiParams;
        SPI_Transaction transaction;
        bool            transferOK;
        int32_t         status;
    
        GPIO_init();
        SPI_init();
    
        GPIO_setConfig(Board_GPIO_BUTTON1, GPIO_CFG_IN_PU | GPIO_CFG_IN_INT_FALLING);
        GPIO_setCallback(Board_GPIO_BUTTON1, TransmitReceiveFxn);
        GPIO_enableInt(Board_GPIO_BUTTON1);
    
        status = sem_init(&transactionSem, 0, 0);
        if (status != 0)
        {
            while(1);
        }
    
        // Open SPI as master (default)
        SPI_Params_init(&spiParams);
        spiParams.frameFormat = SPI_POL0_PHA1;
        spiParams.bitRate = 2000000;
        masterSpi = SPI_open(Board_SPI_MASTER, &spiParams);
        if (masterSpi == NULL)
        {
            while (1);
        }
    
        for(i = 0; i < SPI_MSG_LENGTH; i++)
            masterTxBuffer[i] = i + 1;
    
        while(1)
        {
            // Press a button to start a transaction
            sem_wait(&transactionSem);
    
            GPIO_write(Board_GPIO_LED1, 1);
    
            transaction.count = (SPI_MSG_LENGTH / 2); // Set different length to see how this affects the slave
            transaction.txBuf = (void *) masterTxBuffer;
            transaction.rxBuf = (void *) masterRxBuffer;
    
            transferOK = SPI_transfer(masterSpi, &transaction);
            if (transferOK)
            {
                GPIO_toggle(Board_GPIO_LED0);
            }
            GPIO_write(Board_GPIO_LED1, 0);
        }
    }

    Siri

  • Hi Siri,

    I already knew this example. it is that i mentioned.

    As far as i understand, CC1310 can't work SPI callback if doesn't get data that number of transaction.count. right?

    I need to find other method to progress code regardless number of SPI data.

    By the way, could you tell me about frame format?

    Other question is about SPI frame format.

    In TRM, SPI need to control CSN like below mentioned.

    But in SDK example "spislave_CC1310_LAUNCHXL_tirtos_ccs" and "spimaster_CC1310_LAUNCHXL_tirtos_ccs", 

    CSN doesn't de-assertion during send 30-Bytes data.

    So what is correct information? can i use SPI slave send about 200-bytes data without CSN de-assertion from master ?

    Thank you.

  • The example I posted is not the example from the SDK. If you lock at the code I posted you will see that this is much simpler.

    It is not correct that it cannot work in in callback mode if you do not know the count.

    What is true is that you will not get a callback BEFORE you reach transaction.count. If this is acceptable for your application or not, I cannot answer.

    If you want to cancel the transaction BEFORE you have reached number of bytes set in  transaction.count, you need to use SPI_transferCancel().

    For the example I posted, CSn is held low during the complete transaction. This is the same if transaction.count is 30 or 200. If you had tested the code I sent you, you could easily change the SPI_MSG_LENGTH to 200 and see that it still works

    If you want CSn to go low and high for every byte sent, you simply set the transaction.count to 1, and do SPI_MSG_LENGTH numbers of SPI_transfer’s

  • I got it what you mean.

    I wanted to insert exception handling in my code. such as unstable connection or something like that.

    Thank you.