LP-CC1312R7: How to switching the Rf Rx/Tx

Part Number: LP-CC1312R7

Tool/software:

Hello

This is an inquiry about the RFRx/Tx conversion of TICC1312R7.

We are planning to connect one Gateway and eight Sensor Node to Sub-1GHz.
SDK version is simplelink_cc13xx_cc26xx_sdk_8_30_01_01, and we proceeded by referring to examples of rfEchoTx and rfEchoRx.
However, I try to proceed with Rx/Tx switching to proceed with Time Slot at 120mS interval using TDMA method, but it does not work.

The order that we're going to do is
1. Gateway
Time Slot 0 : Tx ( Gateway [aka beacon])
Time Slot 1 : Rx (sensor 0)
Time Slot 2 : Rx (sensor 1)
Time Slot 3 : Rx (sensor 2)
Time Slot 4 : Rx (sensor 3)
Time Slot 5 : Rx (sensor 4)
Time Slot 6 : Rx (sensor 5)
Time Slot 7 : Rx (sensor 6)
Time Slot 8 : Rx (sensor 7)

2. sensor
Time Slot 0 : Rx ( get Gateway Information [aka beacon])
Time Slot 1 : Tx (sensor 0 data)
Time Slot 2 : Tx (sensor 1 data)
Time Slot 3 : Tx (sensor 2 data)
Time Slot 4 : Tx (sensor 3 data)
Time Slot 5 : Tx (sensor 4 data)
Time Slot 6 : Tx (sensor 5 data)
Time Slot 7 : Tx (sensor 6 data)
Time Slot 8 : Tx (sensor 7 data)

In this way, I want to send and receive data while switching between Tx and Rx.

But the rfEchoRx/rfEchoTx example is that Tx only does Tx and Rx only does Rx, so I need your advice.

Thank you.

  • Hi Peter,

    Is using one of our stacks an option? I would recommend the 15.4 stack for your use case: Sensor and Collector

    It will save you lots of implementation work.

    Else, here is an example on how to switch between TX and RX, using command chains: (+) CC1352P: Radio command chain for TDMA - Sub-1 GHz forum - Sub-1 GHz - TI E2E support forums

    Regards,

    Arthur

  • 15.4 stacks will not be used.

    15.4 stacks will not be used.

    I'm only going to use rf cmd.

    Please tell me how to set the config to perform with the RF_cmdPropTxAdv and RF_cmdPropRxAdv commands.

  • Hi Peter,

    Understood.  I still recommend you to have a look at that thread, which is about rf cmds: CC1352P: Radio command chain for TDMA 

    And here, I will join a code snippet that switches between CS, TX, and RX using chains, when messages are received over the UART.  It is very similar to the rfUartBridge example, except that it uses ADV commands:

    /*
     * Copyright (c) 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.
     */
    
    /***** Includes *****/
    
    /* Standard C Libraries */
    #include <stdlib.h>
    #include <stdint.h>
    #include <stddef.h>
    
    
    /* TI Drivers */
    #include <ti/drivers/rf/RF.h>
    #include <ti/drivers/GPIO.h>
    #include <ti/drivers/dpl/TaskP.h>
    #include <ti/drivers/dpl/SemaphoreP.h>
    #include <ti/drivers/dpl/MessageQueueP.h>
    
    /* Driverlib Header files */
    #include DeviceFamily_constructPath(driverlib/rf_prop_mailbox.h)
    
    /* Board Header files */
    #include "ti_drivers_config.h"
    
    /* Application Header files */
    #include "RFQueue.h"
    #include <ti_radio_config.h>
    
    /* ======== uart2 ======== */
    #include <ti/drivers/UART2.h>
    
    /***** Defines *****/
    
    /* Packet RX Configuration */
    #define DATA_ENTRY_HEADER_SIZE 8  /* Constant header size of a Generic Data Entry */
    #define MAX_LENGTH             2048 /* 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     4  /* The Data Entries data field will contain:
                                       * 2 Header byte (RF_cmdPropTxAdv.numHdrBits = 16) */
    #define NO_PACKET              0
    #define PACKET_RECEIVED        1
    
    #define NO_OF_MESSAGE          16
    
    #define USE_CCA                1
    
    /******* Global variable declarations *********/
    TaskP_Handle TaskTx;
    TaskP_Handle TaskRx;
    
    TaskP_Params ParamsTaskTx;
    TaskP_Params ParamsTaskRx;
    
    MessageQueueP_Handle MqRx;
    MessageQueueP_Handle MqTx;
    
    MessageQueueP_Struct MqRxObj;
    
    uint8_t MqRxBuf[MessageQueueP_BUFFER_SIZE(MAX_LENGTH, NO_OF_MESSAGE)];
    
    SemaphoreP_Handle SemTx;
    
    typedef enum {
        STATE_CCA,
        STATE_TX,
    } txStateMachine_t;
    
    volatile txStateMachine_t fsm = STATE_CCA;
    
    static RF_Object rfObject;
    static RF_Handle rfHandle;
    RF_CmdHandle rfPostHandle;
    
    UART2_Handle uart;
    UART2_Params uartParams;
    
    static char input[MAX_LENGTH] = {0};
    static char output[MAX_LENGTH] = {0};
    static char buffer[MAX_LENGTH] = {0};
    
    size_t bytesReadCount = 0;
    size_t bytesWritten = 0;
    int_fast16_t        status = UART2_STATUS_SUCCESS;
    volatile uint8_t packetRxCb;
    
    /* 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)];
    #elif defined(__IAR_SYSTEMS_ICC__)
    #pragma data_alignment = 4
    static uint8_t
    rxDataEntryBuffer[RF_QUEUE_DATA_ENTRY_BUFFER_SIZE(NUM_DATA_ENTRIES,
                                                      MAX_LENGTH,
                                                      NUM_APPENDED_BYTES)];
    #elif defined(__GNUC__)
    static uint8_t
    rxDataEntryBuffer[RF_QUEUE_DATA_ENTRY_BUFFER_SIZE(NUM_DATA_ENTRIES,
                                                      MAX_LENGTH,
                                                      NUM_APPENDED_BYTES)]
                                                      __attribute__((aligned(4)));
    #else
    #error This compiler is not supported.
    #endif
    
    /* Receive dataQueue for RF Core to fill in data */
    static dataQueue_t dataQueue;
    static rfc_dataEntryGeneral_t* currentDataEntry;
    static uint16_t packetLength;
    static uint8_t* packetDataPointer;
    
    static uint8_t packet[MAX_LENGTH]; /* The length byte is stored in a separate variable */
    
    /***** Function definitions *****/
    static void ReceivedOnRFcallback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e);
    void ReceiveonUARTcallback(UART2_Handle handle, void *buffer, size_t count, void *userArg, int_fast16_t status);
    
    void txThread(void *arg0)
    {
        while (1)
        {
            /* Resume UART read */
            MessageQueueP_pend(MqRx, &packet, MessageQueueP_WAIT_FOREVER);
    
            /* Cancel the ongoing command*/
            RF_cancelCmd(rfHandle, rfPostHandle, 1);
    
            /* Send packet and go back to RX. Schedule command in the future */
            /* The packet length is set to the number of
             * bytes read by UART2_read() + the header length (32 bits)*/
    
            /* In TX adv, one has to manually provide length. */
            volatile uint16_t bytesToSend = (packet[1] << 8) | (packet[0] & 0xFF);
            RF_cmdPropTxAdv.pktLen = bytesToSend + NUM_APPENDED_BYTES;
            RF_cmdPropTxAdv.pPkt = packet;
    
    #ifdef USE_CCA
            rfPostHandle = RF_postCmd(rfHandle, (RF_Op*)&RF_cmdPropCs,
                                                               RF_PriorityNormal, &ReceivedOnRFcallback,
                                                               RF_EventRxEntryDone | RF_EventCmdDone );
    #else
            rfPostHandle = RF_postCmd(rfHandle, (RF_Op*)&RF_cmdPropTxAdv,
                                                                       RF_PriorityNormal, &ReceivedOnRFcallback,
                                                                       RF_EventRxEntryDone | RF_EventCmdDone );
    #endif
            SemaphoreP_pend(SemTx, SemaphoreP_WAIT_FOREVER);
    
            /* Toggle green led to indicate TX */
            GPIO_toggle(CONFIG_GPIO_GLED);
    
            /* Resume RF RX */
            //rfPostHandle = RF_postCmd(rfHandle, (RF_Op*)&RF_cmdPropRxAdv, RF_PriorityNormal, &ReceivedOnRFcallback, RF_EventRxEntryDone);
        }
    }
    
    void *mainThread(void *arg0)
    {
        packetRxCb = NO_PACKET;
    
        RF_Params rfParams;
        RF_Params_init(&rfParams);
    
        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);
        }
    
        GPIO_setConfig(CONFIG_GPIO_RLED, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
        GPIO_write(CONFIG_GPIO_RLED, CONFIG_GPIO_LED_OFF);
    
        GPIO_setConfig(CONFIG_GPIO_GLED, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
        GPIO_write(CONFIG_GPIO_GLED, CONFIG_GPIO_LED_OFF);
    
        // Map RFC_GPO0 to IO 23
        GPIO_setConfigAndMux(CONFIG_GPIO_MOD, GPIO_CFG_NO_DIR, IOC_PORT_RFC_GPO0);
    
        // Map IO 26 to RFC_GPI1
        GPIO_setConfigAndMux(CONFIG_GPIO_DEMOD, GPIO_CFG_NO_DIR, IOC_PORT_RFC_GPO1);
    
        /*Modifies settings to be able to do RX*/
        /* Set the Data Entity queue for received data */
        RF_cmdPropRxAdv.pQueue = &dataQueue;
        /* Discard ignored packets from Rx queue */
        RF_cmdPropRxAdv.rxConf.bAutoFlushIgnored = 1;
        /* Discard packets with CRC error from Rx queue */
        RF_cmdPropRxAdv.rxConf.bAutoFlushCrcErr = 1;
        /* Implement packet length filtering to avoid PROP_ERROR_RXBUF */
        RF_cmdPropRxAdv.maxPktLen = MAX_LENGTH;
        RF_cmdPropRxAdv.pktConf.bRepeatOk = 1;
        RF_cmdPropRxAdv.pktConf.bRepeatNok = 1;
        RF_cmdPropRxAdv.rxConf.bIncludeHdr = 1,
        RF_cmdPropRxAdv.hdrConf.numHdrBits = NUM_APPENDED_BYTES * 8;
        RF_cmdPropRxAdv.hdrConf.lenPos = 0;
        RF_cmdPropRxAdv.hdrConf.numLenBits = 16;
        RF_cmdPropRxAdv.lenOffset = 0x00;
        RF_cmdPropRxAdv.startTrigger.triggerType = TRIG_NOW;
        RF_cmdPropRxAdv.endTrigger.triggerType = TRIG_NEVER;
        RF_cmdPropRxAdv.condition.rule = COND_NEVER;
        RF_cmdPropRxAdv.pktConf.bUseCrc = 1;
    
        RF_cmdPropCs.startTrigger.triggerType = TRIG_NOW;
        RF_cmdPropCs.condition.rule = COND_ALWAYS;
        RF_cmdPropCs.pNextOp = (RF_Op*)&RF_cmdPropTxAdv;
        RF_cmdPropCs.csConf.bEnaRssi = 1;
        RF_cmdPropCs.csConf.busyOp = 0;
        RF_cmdPropCs.csConf.idleOp = 1;
        RF_cmdPropCs.rssiThr = 0xC3; // - 61 dB
        RF_cmdPropCs.csEndTrigger.triggerType = TRIG_REL_START;
        RF_cmdPropCs.csEndTime = RF_convertMsToRatTicks(500);
    
        RF_cmdPropTxAdv.startTrigger.triggerType = TRIG_NOW;
        RF_cmdPropTxAdv.condition.rule = COND_ALWAYS;
        RF_cmdPropTxAdv.pPkt = packet;
        RF_cmdPropTxAdv.pNextOp = (RF_Op*)&RF_cmdPropRxAdv;
        RF_cmdPropTxAdv.pktLen = MAX_LENGTH;
        RF_cmdPropTxAdv.numHdrBits = RF_cmdPropRxAdv.hdrConf.numHdrBits;
        RF_cmdPropTxAdv.pktConf.bUseCrc = 1;
        RF_cmdPropTxAdv.preTrigger.triggerType = 0x0;
        RF_cmdPropTxAdv.preTrigger.bEnaCmd = 0x0;
        RF_cmdPropTxAdv.preTrigger.triggerNo= 0x0;
        RF_cmdPropTxAdv.preTrigger.pastTrig = 0x0;
    
        /* Initialize UART with callback read mode */
        UART2_Params_init(&uartParams);
        uartParams.baudRate = 460800;
        uartParams.readMode = UART2_Mode_CALLBACK;
        uartParams.writeMode = UART2_Mode_NONBLOCKING;
        uartParams.readReturnMode = UART2_ReadReturnMode_PARTIAL;
        uartParams.readCallback = &ReceiveonUARTcallback;
    
        /* Access UART */
        uart = UART2_open(CONFIG_UART2_0, &uartParams);
        UART2_rxEnable(uart);
    
        /* 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);
    
        rfPostHandle = RF_postCmd(rfHandle, (RF_Op*)&RF_cmdPropRxAdv,
                                                               RF_PriorityNormal, &ReceivedOnRFcallback,
                                                               RF_EventRxEntryDone);
    
        SemaphoreP_Params semParams;
        SemaphoreP_Params_init(&semParams);
        SemTx = SemaphoreP_create(0, &semParams);
    
        MqRx = MessageQueueP_construct(&MqRxObj, MAX_LENGTH, NO_OF_MESSAGE, MqRxBuf);
        if (MqRx == NULL)
        {
            while (1);
        }
    
        status = UART2_read(uart, input + NUM_APPENDED_BYTES, MAX_LENGTH - NUM_APPENDED_BYTES, &bytesReadCount);
    
        TaskP_Params_init(&ParamsTaskTx);
        TaskP_Params_init(&ParamsTaskRx);
    
        ParamsTaskTx.name = "TX Task";
        ParamsTaskTx.priority = 5;
        ParamsTaskTx.stackSize = 4096;
    
        TaskTx = TaskP_create(txThread, &ParamsTaskTx);
        if (TaskTx == NULL)
        {
            while (1);
        }
    
    #if 0
        ParamsTaskRx.name = "RX Task";
        ParamsTaskRx.priority = 2;
        ParamsTaskRx.stackSize = 1024;
    
        TaskRx = TaskP_create(rxThread, &ParamsTaskRx);
        if (TaskRx == NULL)
        {
            while (1);
        }
    #endif
    
        return 0;
    }
    
    /* Callback function called when data is received via RF
     * Function copies the data in a variable, packet, and sets packetRxCb */
    void ReceivedOnRFcallback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e)
    {
        if (e & RF_EventRxEntryDone)
        {
            GPIO_toggle(CONFIG_GPIO_RLED);
    
            /* Get current unhandled data entry */
            currentDataEntry = RFQueue_getDataEntry(); //loads data from entry
    
            /* Handle the packet data, located at &currentDataEntry->data:
             * - Length is the first byte with the current configuration
             * - Data starts from the third byte */
            packetLength      = *(uint16_t*)(&currentDataEntry->data); //gets the packet length (send over with packet)
    
            packetDataPointer = (uint8_t*)(&currentDataEntry->data + NUM_APPENDED_BYTES); //data starts from 2nd byte, but we want the length with the packet
    
            /* Copy the payload */
            memcpy(output, packetDataPointer, (packetLength));
    
            /* Move read entry pointer to next entry */
            RFQueue_nextEntry();
    
            status = UART2_write(uart, output, packetLength, &bytesWritten);
            if (status != UART2_STATUS_SUCCESS)
            {
                /* UART2_write() failed */
                //while (1);
            }
    
            packetRxCb = PACKET_RECEIVED;
        }
    
        /* supposed to be only tx */
        if (e & RF_EventCmdDone)
        {
    #ifdef USE_CCA
            switch (fsm)
            {
                case STATE_CCA:
                    fsm = STATE_TX;
                    break;
                case STATE_TX:
                    fsm = STATE_CCA;
                    SemaphoreP_post(SemTx);
                    break;
            }
    #else
            SemaphoreP_post(SemTx);
    #endif
        }
    }
    
    /* Callback function called when data is received via UART */
    void ReceiveonUARTcallback(UART2_Handle handle, void *buffer, size_t count, void *userArg, int_fast16_t status)
    {
        GPIO_toggle(CONFIG_GPIO_DEBUG);
        if (status != UART2_STATUS_SUCCESS)
        {
            /* RX error occured in UART2_read() */
            while (1) {}
        }
    
        input[0] = count & 0xFF;
        input[1] = (count >> 8) & 0xFF;
        input[2] = 0;
        input[3] = 0;
    
        MessageQueueP_post(MqRx, input, MessageQueueP_NO_WAIT);
        bytesReadCount = 0;
        UART2_read(uart, input + NUM_APPENDED_BYTES, MAX_LENGTH - NUM_APPENDED_BYTES, &bytesReadCount);
        if (status != UART2_STATUS_SUCCESS)
        {
            /* RX error occured in UART2_read() */
            while (1) {}
        }
    
    
        GPIO_toggle(CONFIG_GPIO_DEBUG);
    }

    If it still does not work with those informations, I can provide you with a very short TDMA example, but it will take longer.

    Regards,

    Arthur

  • The problem has been resolved.
    Thank you for your support.