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: CC1310 WOR TX and RX. How to switch from TX to RX mode and back?

Expert 1595 points
Part Number: CC1310


Hi all,

I have already implemented a transmitter and receiver application on the CC1310 using WOR. However, I now want to have the function of verifying that the transmitted packet has indeed been received. I have a push button on the transmitter which when pressed, sends out a packet. The receiver can receive the packet successfully and re-transmit the pack out. I am able to verify that the packet is re-transmitted out properly and correctly.

What I want to do now is to have the transmitter switch to RX mode for 2 seconds after it has transmitted the packet out (so that is can get the reply back from the receiver to confirm the packet is received) and go back to transmit mode (sleep) again. May I know how can this be implemented? The RX software seems to be doing some scheduling for WOR and it looks complicated to integrate into the transmitter code. Is  there a simpler way to just switch to RX mode for 2 seconds and go back to TX?

Thanks in advance.

  • Hey Kian,

    Please see this related post: e2e.ti.com/.../653233

    BR,
    Seong
  • Hi Seong,

    I saw the link you provided. Does it work with Wake On Radio?
  • Kian,

    For CC1310, it would in many cases be the best to use a time sync'ed system:

    dev.ti.com/.../time-synchronization.html

    dev.ti.com/.../README.html

    "Unlike the wake-on-radio example, the transmitter does not need to send a very long preamble and the receiver does not need to wait and check for a signal on air. This leads to the lowest possible power consumption on both sides. It also fits very well to the SimpleLink Long-range mode."

    BR,
    Seong
  • Hi Seong,

    Unfortunately the current product already implements the wake on radio function and it is impossible to change to a time sync'ed system.

    The current setup which uses wake on radio is already working well. I can transmit out a packet. The receiver successfully receives the packet and re-transmits (original packet with long preamble) out immediately after receiving the packet. Now I just want to make a slight modification to my transmitter side to go into RX mode after sending out the packet so it can receive this acknowledgement. My transmitter runs on a small battery and needs to go to sleep when there is no activity. It cannot be constantly in RX mode. So the only thing I can do is to go into RX mode for a short time (eg. 1-2 seconds) to wait for the acknowledgement.

    My main tx loop is written like this now:

       /* Enter main TX loop */
        while(1)
        {
            if(txTimeout)
            {
                txTimeout = FALSE;
                RF_yield(rfHandle); //Added to force radio into standby while waiting for button press
    
                /* Wait for a button press */
                Semaphore_pend(txSemaphoreHandle, BIOS_WAIT_FOREVER);
            }
            if(btnPress)
            {
                btnPress = 0;
    
                /* Send packet */
                RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropTxAdv, RF_PriorityNormal, NULL, 0);
                
                // Short delay
                CPUdelay((uint32_t)((48000000/3)*0.050f));
                
                RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropRx,
                                                               RF_PriorityNormal, &callback,
                                                               RF_EventRxEntryDone);
    
                
                // set a 1 second timeout. Sets txTimeout Flag after 1 second
                Clock_setTimeout(clockHandle1,  milli_to_ticks(TX_Delay));
                Clock_start(clockHandle1);
            }
        }


    How should I setup the RX parameters?

  • /***** Includes *****/
    #include <stdlib.h>
    
    /* XDCtools Header files */
    #include <xdc/std.h>
    #include <xdc/runtime/Assert.h>
    #include <xdc/cfg/global.h>
    #include <xdc/runtime/System.h>
    
    /* BIOS Header files */
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Semaphore.h>
    #include <ti/sysbios/knl/Task.h>
    #include <ti/sysbios/knl/Clock.h>
    
    /* TI-RTOS Header files */
    #include <ti/drivers/rf/RF.h>
    #include <ti/drivers/PIN.h>
    #include <ti/drivers/I2C.h>
    
    /* Board Header files */
    #include "Board.h"
    
    /* RF settings */
    #include "RFQueue.h"
    #include "smartrf_settings/smartrf_settings.h"
    
    #include DeviceFamily_constructPath(inc/hw_fcfg1.h)
    
    #include <ti/devices/DeviceFamily.h>
    #include DeviceFamily_constructPath(driverlib/rf_prop_mailbox.h)
    
    
    /***** Defines *****/
    /* Wake-on-Radio configuration */
    #define WOR_WAKEUPS_PER_SECOND 2
    
    /* TX number of random payload bytes */
    #define PAYLOAD_LENGTH 8
    
    /* WOR Example configuration defines */
    #define WOR_PREAMBLE_TIME_RAT_TICKS(x) \
        ((uint32_t)(4000000*(1.0f/(x))))
    
    /* TX task stack size and priority */
    #define TX_TASK_STACK_SIZE 1024
    #define TX_TASK_PRIORITY   2
    
    /* TI-RTOS Task configuration */
    #define RX_TASK_STACK_SIZE 1024
    #define RX_TASK_PRIORITY   2
    
    #define RXEVENT_TASK_STACK_SIZE 256
    #define RXEVENT_TASK_PRIORITY   1
    
    #define TX_Delay    1000
    
    /* Packet RX Configuration */
    #define DATA_ENTRY_HEADER_SIZE 8  /* Constant header size of a Generic Data Entry */
    #define MAX_LENGTH             30 /* Max length byte the radio will accept */
    #define NUM_DATA_ENTRIES       2  /* NOTE: Only two data entries supported at the moment */
    #define NUM_APPENDED_BYTES     2  /* The Data Entries data field will contain:
                                       * 1 Header byte (RF_cmdPropRx.rxConf.bIncludeHdr = 0x1)
                                       * Max 30 payload bytes
                                       * 1 status byte (RF_cmdPropRx.rxConf.bAppendStatus = 0x1) */
    
    /***** Prototypes *****/
    static void txTaskFunction(UArg arg0, UArg arg1);
    static void initializeTxAdvCmdFromTxCmd(rfc_CMD_PROP_TX_ADV_t* RF_cmdPropTxAdv, rfc_CMD_PROP_TX_t* RF_cmdPropTx);
    static void callback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e);
    
    /***** Variable declarations *****/
    static uint8_t btnPress = 0;
    
    /* TX task objects and task stack */
    static Task_Params txTaskParams;
    Task_Struct txTask;    /* not static so you can see in ROV */
    static uint8_t txTaskStack[TX_TASK_STACK_SIZE];
    
    /* TX packet payload (length +1 to fit length byte) and sequence number */
    static uint8_t packet[PAYLOAD_LENGTH +1];
    
    /* RF driver objects and handles */
    static RF_Object rfObject;
    static RF_Handle rfHandle;
    
    /* Pin driver objects and handles */
    static PIN_Handle ledPinHandle;
    static PIN_Handle buttonPinHandle;
    static PIN_State ledPinState;
    static PIN_State buttonPinState;
    
    // Initialize and create/construct clock module
    static Clock_Struct clockStruct1;
    static Clock_Handle clockHandle1;
    
    /* TX Semaphore */
    static Semaphore_Struct txSemaphore;
    static Semaphore_Handle txSemaphoreHandle;
    
    /* RX Semaphore */
    static Semaphore_Struct rxSemaphore;
    static Semaphore_Handle rxSemaphoreHandle;
    
    /* Advanced TX command for sending long preamble */
    static rfc_CMD_PROP_TX_ADV_t RF_cmdPropTxAdv;
    
    /* MAC Address */
    static uint64_t macAddrLsb;
    static uint64_t macAddrMsb;
    static uint64_t macAddress;
    
    static bool txTimeout = TRUE;
    static bool sentMsg = FALSE;
    
    /*
     * Application LED pin configuration table:
     *   - All LEDs board LEDs are off.
     */
    PIN_Config pinTable[] =
    {
        Board_PIN_LED0 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
        PIN_TERMINATE
    };
    
    /*
     * Application button pin configuration table:
     *   - Buttons interrupts are configured to trigger on falling edge.
     */
    PIN_Config buttonPinTable[] = {
        Board_PIN_BUTTON0 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_BOTHEDGES,
        BMA250_INT1 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE,
        //BMA250_INT2 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_POSEDGE,
        PIN_TERMINATE
    };
    
    
    /* Buffer which contains all Data Entries for receiving data.
     * Pragmas are needed to make sure this buffer is 4 byte aligned (requirement from the RF Core) */
    #if defined(__TI_COMPILER_VERSION__)
        #pragma DATA_ALIGN (rxDataEntryBuffer, 4);
            static uint8_t rxDataEntryBuffer[RF_QUEUE_DATA_ENTRY_BUFFER_SIZE(NUM_DATA_ENTRIES,
                                                                     MAX_LENGTH,
                                                                     NUM_APPENDED_BYTES)];
    #endif
    
    /* RX Data Queue and Data Entry pointer to read out received packets */
    static dataQueue_t dataQueue;
    static rfc_dataEntryGeneral_t* currentDataEntry;
    
    /* Received packet's length and pointer to the payload */
    static uint8_t packetLength;
    static uint8_t* packetDataPointer;
    
    
    /***** Function definitions *****/
    static void clockCallback1(UArg u0)
    {
        Clock_stop(clockHandle1);
        txTimeout = TRUE;
    
        /* Post RX semaphore to TX task */
        Semaphore_post(rxSemaphoreHandle);
    }
    
    uint32_t milli_to_ticks(uint32_t milli)
    {
        return((milli * 1000) / Clock_tickPeriod);
    }
    
    /* Pin interrupt Callback function board buttons configured in the pinTable. */
    void buttonCallbackFunction(PIN_Handle handle, PIN_Id pinId) {
        if(pinId == Board_PIN_BUTTON0)
        {
            /* Simple debounce logic, only toggle if the button is still pushed (low) */
            CPUdelay((uint32_t)((48000000/3)*0.050f));
    
            if(PIN_getInputValue(pinId) == 0)    // Press
            {
    
            }
            else    // Release
            {
                    btnPress = 1;
    
                    /* Post TX semaphore to TX task */
                    Semaphore_post(txSemaphoreHandle);
            }
        }
    }
    
    /* TX task initialization function. Runs once from main() */
    void txTaskInit()
    {
        /* Initialize TX semaphore */
        Semaphore_construct(&txSemaphore, 0, NULL);
        txSemaphoreHandle = Semaphore_handle(&txSemaphore);
    
        /* Initialize RX semaphore */
        Semaphore_construct(&rxSemaphore, 0, NULL);
        rxSemaphoreHandle = Semaphore_handle(&rxSemaphore);
    
        /* Initialize and create TX task */
        Task_Params_init(&txTaskParams);
        txTaskParams.stackSize = TX_TASK_STACK_SIZE;
        txTaskParams.priority = TX_TASK_PRIORITY;
        txTaskParams.stack = &txTaskStack;
        Task_construct(&txTask, txTaskFunction, &txTaskParams, NULL);
    }
    
    /* TX task function. Executed in Task context by TI-RTOS when the scheduler starts. */
    static void txTaskFunction(UArg arg0, UArg arg1)
    {
        /* Setup callback for button pins */
        PIN_Status status = PIN_registerIntCb(buttonPinHandle, &buttonCallbackFunction);
        Assert_isTrue((status == PIN_SUCCESS), NULL);
    
        /* Initialize the radio */
        RF_Params rfParams;
        RF_Params_init(&rfParams);
    
        /* Initialize TX_ADV command from TX command */
        initializeTxAdvCmdFromTxCmd(&RF_cmdPropTxAdv, &RF_cmdPropTx);
    
        /* Set application specific fields */
        RF_cmdPropTxAdv.pktLen = PAYLOAD_LENGTH +1; /* +1 for length byte */
        RF_cmdPropTxAdv.pPkt = packet;
        RF_cmdPropTxAdv.preTrigger.triggerType = TRIG_REL_START;
        RF_cmdPropTxAdv.preTime = WOR_PREAMBLE_TIME_RAT_TICKS(WOR_WAKEUPS_PER_SECOND);
    
        if( RFQueue_defineQueue(&dataQueue,
                                rxDataEntryBuffer,
                                sizeof(rxDataEntryBuffer),
                                NUM_DATA_ENTRIES,
                                MAX_LENGTH + NUM_APPENDED_BYTES))
        {
            /* Failed to allocate space for all data entries */
            while(1);
        }
    
        /* Modify CMD_PROP_RX command for application needs */
        /* Set the Data Entity queue for received data */
        RF_cmdPropRx.pQueue = &dataQueue;
        /* Discard ignored packets from Rx queue */
        RF_cmdPropRx.rxConf.bAutoFlushIgnored = 1;
        /* Discard packets with CRC error from Rx queue */
        RF_cmdPropRx.rxConf.bAutoFlushCrcErr = 1;
        /* Implement packet length filtering to avoid PROP_ERROR_RXBUF */
        RF_cmdPropRx.maxPktLen = MAX_LENGTH;
        RF_cmdPropRx.pktConf.bRepeatOk = 1;
        RF_cmdPropRx.pktConf.bRepeatNok = 1;
    
        /* Request access to the radio */
        rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, &rfParams);
    
        /* Set the frequency */
        RF_runCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0);
    
        /* Enter main TX loop */
        while(1)
        {
            if(sentMsg)
            {
                sentMsg = FALSE;
                Semaphore_pend(rxSemaphoreHandle, BIOS_WAIT_FOREVER);
            }
            if(txTimeout)
            {
                PIN_setOutputValue(ledPinHandle, Board_PIN_LED0, 0);
    
                txTimeout = FALSE;
                RF_yield(rfHandle); //Added to force radio into standby while waiting for button press
    
                /* Wait for a button press */
                Semaphore_pend(txSemaphoreHandle, BIOS_WAIT_FOREVER);
            }
            if(btnPress)
            {
                btnPress = 0;
                sentMsg = TRUE;
    
                /* Send packet */
                RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropTxAdv, RF_PriorityNormal, NULL, 0);
    
                Clock_setTimeout(clockHandle1,  milli_to_ticks(TX_Delay));
                Clock_start(clockHandle1);
    
                RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropRx,
                                                               RF_PriorityNormal, &callback,
                                                               RF_EventRxEntryDone);
            }
        }
    }
    
    
    static void initializeTxAdvCmdFromTxCmd(rfc_CMD_PROP_TX_ADV_t* RF_cmdPropTxAdv, rfc_CMD_PROP_TX_t* RF_cmdPropTx)
    {
        #define RADIO_OP_HEADER_SIZE 14
    
        /* Copy general radio operation header from TX commmand to TX_ADV */
        memcpy(RF_cmdPropTxAdv, RF_cmdPropTx, RADIO_OP_HEADER_SIZE);
    
        /* Set command to CMD_PROP_TX_ADV */
        RF_cmdPropTxAdv->commandNo = CMD_PROP_TX_ADV;
    
        /* Copy over relevant parameters */
        RF_cmdPropTxAdv->pktConf.bFsOff = RF_cmdPropTx->pktConf.bFsOff;
        RF_cmdPropTxAdv->pktConf.bUseCrc = RF_cmdPropTx->pktConf.bUseCrc;
        RF_cmdPropTxAdv->syncWord = RF_cmdPropTx->syncWord;
    }
    
    void callback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e)
    {
        if (e & RF_EventRxEntryDone)
        {
            /* Get current unhandled data entry */
            currentDataEntry = RFQueue_getDataEntry();
    
            /* Handle the packet data, located at &currentDataEntry->data:
             * - Length is the first byte with the current configuration
             * - Data starts from the second byte */
            packetLength      = *(uint8_t*)(&currentDataEntry->data);
            packetDataPointer = (uint8_t*)(&currentDataEntry->data + 1);
    
            /* Copy the payload + the status byte to the packet variable */
            memcpy(packet, packetDataPointer, (packetLength + 1));
    
            RFQueue_nextEntry();
    
            /* Toggle LED */
            PIN_setOutputValue(ledPinHandle, Board_PIN_LED0, 1);
            //Task_sleep(milli_to_ticks(500));
            //PIN_setOutputValue(ledPinHandle, Board_PIN_LED0, 0);
    
        }
    }
    
    /*
     *  ======== main ========
     */
    int main(void)
    {
        /* Call driver init functions. */
        Board_initGeneral();
    
        /* Open LED pins */
        ledPinHandle = PIN_open(&ledPinState, pinTable);
        Assert_isTrue(ledPinHandle != NULL, NULL);
    
        /* Open Button pins */
        buttonPinHandle = PIN_open(&buttonPinState, buttonPinTable);
        Assert_isTrue(buttonPinHandle != NULL, NULL);
    
        /* Read MAC Address */
        macAddrLsb = HWREG(FCFG1_BASE + FCFG1_O_MAC_15_4_0);
        macAddrMsb  =HWREG(FCFG1_BASE + FCFG1_O_MAC_15_4_1);
        macAddress = (uint64_t)(macAddrMsb << 32) + macAddrLsb;
    
        /* Create packet containing MAC Address  */
        packet[0] = PAYLOAD_LENGTH;
        packet[1] = (uint8_t)((macAddress & 0xFF00000000000000UL) >> 56);
        packet[2] = (uint8_t)((macAddress & 0x00FF000000000000UL) >> 48);
        packet[3] = (uint8_t)((macAddress & 0x0000FF0000000000UL) >> 40);
        packet[4] = (uint8_t)((macAddress & 0x000000FF00000000UL) >> 32);
        packet[5] = (uint8_t)((macAddress & 0x00000000FF000000UL) >> 24);
        packet[6] = (uint8_t)((macAddress & 0x0000000000FF0000UL) >> 16);
        packet[7] = (uint8_t)((macAddress & 0x000000000000FF00UL) >> 8);
        packet[8] = (uint8_t)((macAddress & 0x00000000000000FFUL));
    
        Clock_Params clockParams;
        Clock_Params_init(&clockParams);
        clockParams.arg = (UArg)buttonPinHandle;
        clockParams.period = 0; // this will make it one-shot (the timeout period is set in the construct or create function parameters)
        clockParams.startFlag = false;
        Clock_construct(&clockStruct1, clockCallback1, milli_to_ticks(50), &clockParams);
        clockHandle1 = Clock_handle(&clockStruct1);
    
        /* Initialize task */
        txTaskInit();
    
        /* Start BIOS */
        BIOS_start();
    
        return (0);
    }
    

    Hi all,

    I tried to merge the WOR TX example  with the rfPacketRX example.  It seems like my transmitter is able to go into rx mode after transmitting and it can successfully receive the acknowledgement.

    How my code works is when a button is pressed and released, it  sends out a packet. Then immediately it starts a 1 second timer and switches to RX mode to wait for acknowledgement. When a packet is received, it turns on the LED. When the 1 second timer is up, it will turn off the LED and  put the radio to sleep using RF_yield and waits for button press again.

    I have the programming running and it can successfully receive the acknowledgement packet and also turn on the LED. The timer callback is also successfully called after 1 second. However, it seems like the program gets stuck after that. The LED is not turning off and my program doesn't go into the  main TX loop.

    Anyone can help?

  • Kian,

    Have you tried using the ROV tool's Task Module view to debug this? What does your task's stack size look like? If you get a stack overflow, then the OS will usually get stuck in that same task.

    BR,
    Seong
  • Hi Seong,

    I don't know what how to use the ROV tool task module view. How can I check my task stack size?


    Thanks.
  • Hi all,

    Anyone can give some advise of the problem? I need to get this function working for a client. Hoping to solve it.

    Thanks in advance!
  • Hey Kian,

    You can get started with the ROV tool from here: processors.wiki.ti.com/.../Runtime_Object_View_(ROV)

    There is also an overview on the ROV tool from our TI-RTOS lab here: dev.ti.com/.../tirtos_basics.html

    BR,
    Seong
  • Hi Seong,

    I tried to use ROV tool to check and it seems like there isn't any stack overflow.

    I figured out that by setting this to 0 (previously was 1):

    RF_cmdPropRx.pktConf.bRepeatOk = 0;
    RF_cmdPropRx.pktConf.bRepeatNok = 0;

    My program can send, receive the acknowledgement and return back to the txTaskFunction. However, now there is a different problem. I can press the push button a second time. It triggers the button interrupt, sets a flag in the main tx loop and calls:

    /* Send packet */
    RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropTxAdv, RF_PriorityNormal, NULL, 0);

    But nothing is sent out and the program hangs.

    What else could be wrong? Thanks.
  • Hi Seong,

    I am still having problems. Can you advise what can be wrong and how can i troubleshoot?
  • Hi,
    You can use command chaining to put the radio in RX immediately after TX.
    Please see the rfEchoTx and rfEchoRx examples in the SDK.

    The following line of code (copied from the rfEchoTx.c file) is of interest:

    RF_cmdPropTx.pktLen = PAYLOAD_LENGTH;
    RF_cmdPropTx.pPkt = txPacket;
    RF_cmdPropTx.startTrigger.triggerType = TRIG_ABSTIME;
    RF_cmdPropTx.startTrigger.pastTrig = 1;
    RF_cmdPropTx.startTime = 0;
    RF_cmdPropTx.pNextOp = (rfc_radioOp_t *)&RF_cmdPropRx; // Here the radio is put into RX after packet is transmitted
    /* Only run the RX command if TX is successful */
    RF_cmdPropTx.condition.rule = COND_STOP_ON_FALSE;