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: CC1310 SPI slave callback mode without RTOS

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

Hi all.

I try to combine SPI Slave and RF Tx module.

I attached to SPI slave blocking mode in my code. It run but not correctly.

I want to work synchronize with SPI Master.

I want to set read position that no overlap. 

So i think SPI slave callback mode can use like interrupt. But it doesn't work.

I have some question.

1. How can i use SPI slave callback in non-RTOS? if it can't, How can i synchronize SPI master?

2. Do you have SPI Slave Timing diagram?

Below is apart of my code.

------------------------------------------------------------------------------------------------------------------------------------------------

void *mainThread(void *arg0)
{
// RF Setting
RF_Params rfParams;
RF_Params_init(&rfParams);

RF_cmdPropTx.pktLen = SPI_MSG_LENGTH;
RF_cmdPropTx.pPkt = RFTxBuffer;//packet;
RF_cmdPropTx.startTrigger.triggerType = TRIG_NOW;

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

GPIO_init();
SPI_init();
UART_init();

static UART_Handle uart;
static UART_Params uartParams;

/* Create a UART with data processing off. */
UART_Params_init(&uartParams);
uartParams.writeDataMode = UART_DATA_BINARY;
uartParams.readDataMode = UART_DATA_BINARY;
uartParams.readReturnMode = UART_RETURN_FULL;
uartParams.readEcho = UART_ECHO_OFF;
uartParams.baudRate = 115200;

uart = UART_open(Board_UART0, &uartParams);

if (uart == NULL) {
/* UART_open() failed */
while (1);
}

SPI_Params_init(&spiParams);
spiParams.dataSize = 8;
spiParams.bitRate = 4000000;
spiParams.frameFormat = SPI_POL0_PHA0;
spiParams.mode = SPI_SLAVE;
spiParams.transferCallbackFxn = Callback;
spiParams.transferMode = SPI_MODE_CALLBACK;
slaveSpi = SPI_open(Board_SPI_SLAVE, &spiParams);
if (slaveSpi == NULL) {
while (1);
}

/* Open LED pins */
ledPinHandle1 = PIN_open(&ledPinState1, pinTable1);
ledPinHandle2 = PIN_open(&ledPinState2, pinTable2);
if (ledPinHandle1 == NULL || ledPinHandle2 == NULL)
{
while(1);
}

/* Request access to the radio */
rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, &rfParams);

/* Set the frequency */
RF_postCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0);

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

while(1)
{
// SPI_transfer(slaveSpi, &transaction);

// if(packetRxCb){
// RF_postCmd(rfHandle, (RF_Op*)&RF_cmdPropTx,RF_PriorityNormal, NULL, 0);
// packetRxCb = false;
// }
SPI_transfer(slaveSpi, &transaction);
if (transferOK) {
memcpy(RFTxBuffer, slaveRxBuffer, SPI_MSG_LENGTH);
UART_write(uart, (&RFTxBuffer), SPI_MSG_LENGTH);
UART_write(uart, "\n\r", 2);
transferOK = false;

PIN_setOutputValue(ledPinHandle1, Board_PIN_LED1,!PIN_getOutputValue(Board_PIN_LED1));
}
else {
PIN_setOutputValue(ledPinHandle2, Board_PIN_LED2,!PIN_getOutputValue(Board_PIN_LED2));
}


}
}

void Callback(SPI_Handle handle, SPI_Transaction *transaction)
{
if(transaction->status == SPI_TRANSFER_COMPLETED){
transferOK = true;
}
}

  • Hi Chanbin,

    The spimaster and spislave examples are not supported in nortos. But if you take a look at the RTOS version of the examples, you will see, typically there is an additional Ready GPIO pin that is used to syncronize between the master and slave. please use the same logic in the nortos example you have implemented. 

    dev.ti.com/.../node

    Regards,

    Sid

  • Hi, Sid.

    Thank you for reply.

    I understood. I will try to use 'Ready GPIO'.

    By the way, Does it have any spislave interrupt that is related with CS Pin? If it doesn't, I will use 4-pin spi.

    One more thing, Does spislave have timing diagram such as WDEL? or is it same with spimaster diagram?

  • Hi Chanbin,

    The timing diagrams for SPI is found in section 20.4.4 of the technical reference manual: https://www.ti.com/lit/ug/swcu117i/swcu117i.pdf

    The spimaster and spislave have the same timing diagram. 

    If you are asking about waking up the spi slave because of activity on the CS line, please refer to the driver file. Please refer to the section named

    "Wake Up On Chip Select Deassertion In Slave Mode Using SPI_MODE_CALLBACK"

    https://dev.ti.com/tirex/content/simplelink_cc13x0_sdk_4_20_02_07/docs/tidrivers/doxygen/html/_s_p_i_c_c26_x_x_d_m_a_8h.html

    If you are looking for a solution where the slave controls the CS line, it is not possible.

    I also want to point out there is an errata for the spislave mode, please look into it. 

    www.ti.com/.../swrz062f.pdf

    Regards,

    Sid

  • Hi Sid,

    "Wake Up On Chip Select Deassertion In Slave Mode Using SPI_MODE_CALLBACK" is solution that i want.

    but it has pretty much latency until run into callback function.

    In my situation, SPI receive 4Mbps speed and random position, about 200 bytes. and received data transmit through RF.

    So i want to process quickly. 

    Below is my code. and picture is SPI and callback position waveform.

    How can i process quickly ?

    /***** Function definitions *****/
    // Chip select callback
    static void chipSelectCallback(PIN_Handle handle, PIN_Id pinId)
    {
        PIN_setOutputValue(ledPinHandle, Board_PIN_LED1, 1);
    
        PIN_setOutputValue(slaveRdyHandle, Board_DIO21, 0);
    
        // Release the chip select pin
        PIN_remove(handle, pinId);
    
        // Open SPI driver
        slaveSpi = SPI_open(Board_SPI_SLAVE, &spiParams);
    
        // Issue echo transfer
        SPI_transfer(slaveSpi, &transaction);
    
        PIN_setOutputValue(ledPinHandle, Board_PIN_LED1, 0);
    
    }
    
    // SPI transfer callback
    static void transferCallback(SPI_Handle handle, SPI_Transaction *transaction)
    {
        PIN_setOutputValue(ledPinHandle, Board_PIN_LED0, 1);
    
        uint32_t cmdStatus = transaction->status;
        //if(cmdStatus != SPI_TRANSFER_COMPLETED){
        //   while(1);
        //}
    
        // Close the SPI driver
        SPI_close(handle);
    
        memcpy(RFTxBuffer, slaveRxBuffer, SPI_MSG_LENGTH);
    
        RF_EventMask terminationReason = RF_postCmd(rfHandle, (RF_Op*)&RF_cmdPropTx,RF_PriorityNormal, NULL, 0);
    
        PIN_add(slaveCsnHandle, slaveCsnTable[0]);
    
        PIN_registerIntCb(slaveCsnHandle, &chipSelectCallback);
    
        //transferOK = true;
        PIN_setOutputValue(slaveRdyHandle, Board_DIO21, 1);
    
        PIN_setOutputValue(ledPinHandle, Board_PIN_LED0, 0);
    }
    
    void *mainThread(void *arg0)
    {
        // RF Setting
        RF_Params rfParams;
        RF_Params_init(&rfParams);
    
        GPIO_init();
        SPI_init();
    
        RF_cmdPropTx.pktLen = SPI_MSG_LENGTH;
        RF_cmdPropTx.pPkt = RFTxBuffer;//packet;
        RF_cmdPropTx.startTrigger.triggerType = TRIG_NOW;
    
        SPI_Params_init(&spiParams);
        spiParams.dataSize = 8;
        spiParams.bitRate = 4000000;
        spiParams.frameFormat = SPI_POL0_PHA0;
        spiParams.mode = SPI_SLAVE;
        spiParams.transferCallbackFxn = transferCallback;
        spiParams.transferMode = SPI_MODE_CALLBACK;
        //slaveSpi = SPI_open(Board_SPI_SLAVE, &spiParams);
        //if (slaveSpi == NULL) {
        //    while (1);
        //}
    
        /* Request access to the radio */
        rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, &rfParams);
    
        /* Set the frequency */
        RF_postCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0);
    
        /* Initialize slave SPI transaction structure */
        transaction.count = SPI_MSG_LENGTH;
        transaction.txBuf = NULL;
        transaction.rxBuf = (void *) slaveRxBuffer;
    
        /* 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);
        }
    
        /* slave CSN pin */
        slaveCsnHandle = PIN_open(&slaveCsnState, slaveCsnTable);
        if(!slaveCsnHandle) {
            /* Error initializing button pins */
            while(1);
        }
    
        /* Setup callback for Csn pins */
        if (PIN_registerIntCb(slaveCsnHandle, &chipSelectCallback) != 0) {
            /* Error registering button callback function */
            while(1);
        }
    
        PIN_setOutputValue(slaveRdyHandle, Board_DIO21, 1);
        while(1)
        {
            //GPIO_write(Board_SPI_SLAVE_READY, 1);
            //transferOK = SPI_transfer(slaveSpi, &transaction);
    
    //        PIN_setOutputValue(ledPinHandle, Board_PIN_LED1, !PIN_getOutputValue(Board_PIN_LED1));
    
            HwiP_Params_init
            if (0) {
                memcpy(RFTxBuffer, slaveRxBuffer, SPI_MSG_LENGTH);
    
                PIN_setOutputValue(ledPinHandle, Board_PIN_LED1, 1);
    
                RF_EventMask terminationReason = RF_postCmd(rfHandle, (RF_Op*)&RF_cmdPropTx,RF_PriorityNormal, NULL, 0);
    
                transferOK = 0;
    
                PIN_add(slaveCsnHandle, slaveCsnTable[0]);
    
                PIN_registerIntCb(slaveCsnHandle, &chipSelectCallback);
    
                PIN_setOutputValue(slaveRdyHandle, Board_DIO21, 1);
    
                PIN_setOutputValue(ledPinHandle, Board_PIN_LED1, 0);
    
            }
            else {
                /*
                GPIO_write(Board_SPI_SLAVE_READY, 0);
                GPIO_toggle(Board_GPIO_LED0);
                */
            }
        }
    }

    Green : MOSI / Blue : SCK / Yellow : CSN / Red : To inform that callbackfunction running.

    G : MOSI / B : SCK / Y : CSN / R : Signal to inform callbackfunction

  • Hi Changim,

    Just to clarify, do you want the chip select callback to trigger quicker?

    Regards,
    Sid

  • Hi sid,

    Yes, i need the chip select callback quicker.

    And i have one more question.

    Below is SPI Master waveform in my condition.

    Last SPI clock in 8bit and continuous transmission mode is little bit longer than other clocks.

    Is it Ok ? or can be problem? Blue is clock

  • Hi Chanbin, 

    In the solution Wake Up On Chip Select Deassertion In Slave Mode Using SPI_MODE_CALLBACK, what you are effectively doing is sharing the pin between pin driver and the SPI driver. 

    1. You are setting up a pin callback function called chipSelectCallback which gets triggered when the pin is deasserted. In this callback function, you are now handing over the pin to the SPI driver and now the slave device is ready to receive the data on the SPI lines. 

    2. Then the SPI Transfer callback function is triggered when the SPI transaction happens. In this callback, you have done a memcpy which is time consuming and also posted a radio command before handing over the pin back to the pin driver. Once you hand over the pin to the pin driver, then it is again waiting for the CSN pin to be deasserted by the master. If it is deasserted , then the chipSelectCallback is triggered.

    In my situation, SPI receive 4Mbps speed and random position, about 200 bytes. and received data transmit through RF.

    So i want to process quickly. 

    What do you mean by process quickly? If you are talking about the radio TX happening quicker, then maybe you should reduce the packet length to have lesser data to copy in the callback.

    If you are talking about the Chip select callback itself, then after the SPI transfer, you should de-assert the CSN line quicker in the master, you can find the time which actually works through some iterations.

    Last SPI clock in 8bit and continuous transmission mode is little bit longer than other clocks.

    Please take a look at the timing diagrams of some frames formats in the Technical reference manual I have linked in my previous answer. 

    The timing diagrams for SPI is found in section 20.4.4 of the technical reference manual: https://www.ti.com/lit/ug/swcu117i/swcu117i.pdf

    Please check 20.4.4.5 section of the TRM.

    Regards,

    Sid

  • Hi Sid,

    I thought that Chip select callback call as soon as CSN de-asserted.

    I understood what you mean about callback function.

    I will try to insert callback function properly and control timing.

    By the way, i've already seen the timing diagrams for SPI in TRM.

    there is 3 figure SPI timing diagrams.

    All of them can get only up to 16bits. ( I think that should control CSN after get 16bits. )

    Does SPI of CC1310 have method that get more 16bits without control CSN?

    Thank you for your assistance.

  • Hi Chanbin,

    It seems you are right, the max frame size is maximum 16 bits long. The FSS signal does toggle between each 16 bit frame. 

    Regards,

    Sid

  • Thank you sid,

    I solved problem about SPI.