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: SimpleLink SDK WOR Null Pointer Hard Fault

Part Number: CC1310

I have 25 CC1310 boards that are running TI-RTOS and the latest SimpleLink CC13x0 SDK (4.20.02.07).  The boards are programmed to perform a WOR every second using RF_runCmd to check if someone is trying to talk to it among other things.  I have a problem where the boards are hard faulting randomly while in the WOR thread.  I usually get 1-2 boards that hard fault each day, each with this same problem.  I haven't found a way to replicate the problem repeatedly, so I have to wait until one hard faults to then debug it.

Here is the ROV Hwi exception:

After changing the PC, SP, and LR register values to the ones in the exception, I can see what looks to be a null pointer in List_put's elem variable:

Going back in the stack trace where List_put is called in RF_postCmd, I see that there are checks in place to make sure pCmd isn't null, so I'm not sure why this is happening:

How can I debug this further?  All of this points to the SDK code, so I don't know if there's something I'm doing wrong or if it's a bug in the SDK...

  • Hi Steven,

    I am assuming you are basing off of WakeOnRadioRX and not on TX?

    Also, please can you share the structure/settings of your sniff command? And also, is it a simple loop like the example? 

    Regards,

    Sid

  • Yes, this is using WakeOnRadioRx.  Below are all the relevant RF settings:

    void init_RF(void) {
        RF_Params rfParams;
        RF_Params_init(&rfParams);
    
        rfParams.nInactivityTimeout = 1;  //Power down the radio if there are no pending commands after 1us
    
        /****** TX ******/
    
        RF_cmdPropTx.pPkt = packet;
        RF_cmdPropTx.startTrigger.triggerType = TRIG_NOW;
        RF_cmdPropTx.startTrigger.pastTrig = 1;
        RF_cmdPropTx.syncWord = DEFAULT_SYNC_WORD;  //Everything sent uses the default sync word
    
        /****** TX WHEN CLEAR ******/
        /* Check if channel is busy before sending packet */
        /* Customize the CMD_PROP_TX command for this application */
        RF_cmdNop.startTrigger.triggerType = TRIG_NOW;
        RF_cmdNop.startTrigger.pastTrig = 1;
    
        /* Set up the next pointers for the command chain */
        RF_cmdNop.pNextOp = (rfc_radioOp_t*)&RF_cmdPropCs;
        RF_cmdPropCs.pNextOp = (rfc_radioOp_t*)&RF_cmdCountBranch;
        RF_cmdCountBranch.pNextOp = (rfc_radioOp_t*)&RF_cmdPropTx;
        RF_cmdCountBranch.pNextOpIfOk = (rfc_radioOp_t*)&RF_cmdPropCs;
        RF_cmdPropTx.pNextOp = (rfc_radioOp_t*)&RF_cmdPropRx;
    
        RF_cmdPropTx.condition.rule = COND_STOP_ON_FALSE;  //Only run the RX command if TX is successful
    
        RF_cmdCountBranch.counter = CS_RETRIES_WHEN_BUSY;
    
    
        /****** TX WHEN CLEAR CS ******/
        /* Set correct trigger types */
        RF_cmdPropCs.startTrigger.triggerType = TRIG_NOW;
        RF_cmdPropCs.startTrigger.pastTrig    = 1;
        RF_cmdPropCs.csEndTrigger.triggerType   = TRIG_REL_START;
    
    
        /****** RX/WOR ******/
        /* Create queue and data entries */
        if (RFQueue_defineQueue(&dataQueue,
                                rxDataEntryBuffer,
                                sizeof(rxDataEntryBuffer),
                                NUM_DATA_ENTRIES,
                                MAX_PACKET_SIZE + NUM_APPENDED_BYTES))
        {
            /* Failed to allocate space for all data entries */
            while(1);
        }
    
        /****** RX (used for receiving ACKs after TX) ******/
        RF_cmdPropRx.pQueue = &dataQueue;           // Set the Data Entity queue for received data
        RF_cmdPropRx.pktConf.bRepeatOk = 0;         // End operation after receiving a packet correctly
        RF_cmdPropRx.pktConf.bRepeatNok = 1;        // Go back to sync search after receiving a packet with CRC error
        RF_cmdPropRx.pktConf.bUseCrc = 1;           // Check CRC
        RF_cmdPropRx.pktConf.bVarLen = 1;           // Receive length as first byte
        RF_cmdPropRx.pktConf.bChkAddress = 1;       // Check address
    
        RF_cmdPropRx.rxConf.bAutoFlushIgnored = 1;  // Discard ignored packets from Rx queue
        RF_cmdPropRx.rxConf.bAutoFlushCrcErr = 1;   // Discard packets with CRC error from Rx queue
        RF_cmdPropRx.rxConf.bIncludeHdr = 1;        // Include the received header or length byte in the stored packet
    
        RF_cmdPropRx.maxPktLen = MAX_PACKET_SIZE; // Implement packet length filtering (excluding length byte)
    
        RF_cmdPropRx.startTrigger.triggerType = TRIG_NOW;
        RF_cmdPropRx.startTrigger.pastTrig = 1;
    
        RF_cmdPropRx.endTrigger.triggerType   = TRIG_REL_PREVEND;
        RF_cmdPropRx.endTime                  = (uint32_t)(ACK_MILLISECONDS * 1000 * US_TO_RAT_TICKS);
    
        RF_cmdPropRx.syncWord = DEFAULT_SYNC_WORD;  //Everything received (except the first packet of a command in RF_cmdPropRxSniff) uses the default sync word
    
    
        /****** WOR (used for receiving commands) ******/
        /* Copy all RX options from the SmartRF Studio exported RX command to the RX Sniff command */
        initializeSniffCmdFromRxCmd(&RF_cmdPropRxSniff, &RF_cmdPropRx);
    
        RF_cmdPropRxSniff.endTrigger.triggerType = TRIG_REL_START;
    
        RF_cmdPropRxSniff.pOutput   = (uint8_t*)&rxStatistics;
    
        /****** WOR/CS ******/
        /* Configure Sniff-mode part of the RX_SNIFF command */
        configureSniffandCsCmd(&RF_cmdPropRxSniff, &RF_cmdPropCs);
    
    
    
        rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, &rfParams);
    
        if (rfHandle == NULL) {  //RF_open() failed
            while(1);
        }
    }

    /* Copies all RX options from the SmartRF Studio exported RX command to the RX Sniff command */
    static void initializeSniffCmdFromRxCmd(rfc_CMD_PROP_RX_SNIFF_t* rxSniffCmd, rfc_CMD_PROP_RX_t* rxCmd)
    {
    
        /* Copy RX configuration from RX command */
        memcpy(rxSniffCmd, rxCmd, sizeof(rfc_CMD_PROP_RX_t));
    
        /* Change to RX_SNIFF command from RX command */
        rxSniffCmd->commandNo = CMD_PROP_RX_SNIFF;
    }

    static void configureSniffandCsCmd(rfc_CMD_PROP_RX_SNIFF_t* rxSniffCmd, rfc_CMD_PROP_CS_t* rxCsCmd) {
        /* Enable or disable RSSI */
        if ((WOR_MODE == CarrierSenseMode_RSSI) || (WOR_MODE)) {
            rxSniffCmd->csConf.bEnaRssi         = 1;
            rxCsCmd->csConf.bEnaRssi            = 1;
        } else {
            rxSniffCmd->csConf.bEnaRssi         = 0;
            rxCsCmd->csConf.bEnaRssi            = 0;
        }
    
        /* Enable or disable PQT */
        if ((WOR_MODE == CarrierSenseMode_PQT) || (WOR_MODE == CarrierSenseMode_RSSIandPQT)) {
            rxSniffCmd->csConf.bEnaCorr             = 1;
            rxCsCmd->csConf.bEnaCorr                = 1;
            rxSniffCmd->csEndTrigger.triggerType    = TRIG_REL_START;
            rxCsCmd->csEndTrigger.triggerType       = TRIG_REL_START;
        } else {
            rxSniffCmd->csConf.bEnaCorr             = 0;
            rxCsCmd->csConf.bEnaCorr                = 0;
            rxSniffCmd->csEndTrigger.triggerType    = TRIG_NEVER;
            rxCsCmd->csEndTrigger.triggerType       = TRIG_NEVER;
        }
    
        /* General Carrier Sense configuration */
        rxSniffCmd->csConf.operation        = 1; /* Report Idle if RSSI reports Idle to quickly exit if not above RSSI threshold */
        rxCsCmd->csConf.operation           = 1;
        rxSniffCmd->csConf.busyOp           = 0; /* End carrier sense on channel Busy (the receiver will continue when carrier sense ends, but it will then not end if channel goes Idle) */
        rxCsCmd->csConf.busyOp              = 0;
        rxSniffCmd->csConf.idleOp           = 1; /* End on channel Idle */
        rxCsCmd->csConf.idleOp              = 1;
        rxSniffCmd->csConf.timeoutRes       = 1; /* If the channel is invalid, it will return PROP_DONE_IDLE_TIMEOUT */
        rxCsCmd->csConf.timeoutRes          = 1;
    
        /* RSSI configuration */
        rxSniffCmd->rssiThr                 = RSSI_THRESHOLD; /* Set the RSSI threshold in dBm */
        rxCsCmd->rssiThr                    = RSSI_THRESHOLD;
        rxSniffCmd->numRssiIdle             = NUM_RSSI_MEASUREMENTS; /* 50 idle RSSI samples signals that the channel is idle */
        rxCsCmd->numRssiIdle                = NUM_RSSI_MEASUREMENTS;
        rxSniffCmd->numRssiBusy             = NUM_RSSI_MEASUREMENTS; /* 50 busy RSSI samples signals that the channel is busy */
        rxCsCmd->numRssiBusy                = NUM_RSSI_MEASUREMENTS;
    
        /* Calculate basic timing parameters */
        uint32_t datarate = calculateSymbolRate(RF_cmdPropRadioDivSetup.symbolRate.preScale, RF_cmdPropRadioDivSetup.symbolRate.rateWord);
        uint32_t symbolLengthUs  = 1000000UL/datarate;
        uint32_t preambleSymbols = 8*8;
        uint32_t payloadSymbols = MAX_PACKET_SIZE*8;
        uint8_t syncWordSymbols  = RF_cmdPropRadioDivSetup.formatConf.nSwBits;
    
        /* Calculate sniff mode parameters */
    
        /* Represents the maximum time from the startTrigger to when we expect a sync word to be received. */
        uint32_t rxEndTimeUs = (preambleSymbols + syncWordSymbols + payloadSymbols)*symbolLengthUs;
    
        /* Set sniff mode timing configuration in sniff command in RAT ticks */
        rxSniffCmd->endTime     = (uint32_t)(rxEndTimeUs * US_TO_RAT_TICKS);
    }

    And here is the WOR function:

    static void WOR_Function(UArg arg0, UArg arg1) {
        Semaphore_pend(WOR_SemHandle, BIOS_WAIT_FOREVER);
    
        while (1) {
            /* Run WOR */
            RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropRxSniff, RF_PriorityNormal, &receivePacket_Callback, RF_EventRxEntryDone);
    
            if (RF_cmdPropRxSniff.status == PROP_DONE_OK) {
                Task_sleep(TASK_SLEEP_SECONDS(BASE_WAKE_INTERVAL_SECONDS));
    
                //If we successfully received a packet, send an ACK
                if (sendACKpacket == true) {
                    sendACKpacket = false;
    
                    //Send the bytes in ACKpacket instead of packet
                    RF_cmdPropTx.pPkt = ACKpacket;
    
                    setPayloadLength(0);
    
                    setFrequencyMHz(secondary_freq_MHz);
    
                    /* Send ACK when clear */
                    RF_cmdPropTx.pNextOp = NULL;  //We don't want to chain the TX to an RX when we send ACKs
                    RF_runCmd(rfHandle, (RF_Op*)&RF_cmdNop, RF_PriorityNormal, NULL, 0);
    
                    //Send bytes again from packet
                    RF_cmdPropTx.pPkt = packet;
                }
            } else {
                Task_sleep(TASK_SLEEP_SECONDS(WAKE_INTERVAL));
            }
        }
    }

    I haven't yet tried taking out all other functionality to see if this is being caused by another task, but I can try that next to narrow down the problem.

  • Hi Steven,

    It is not obvious what the issue could be. There seems to be some logic and decision made during the command chain execution. 

    But please can you try calling the RF_FlushCmd() api before you call the RF_runCmd to run the wake on radio, to ensure that the radio queue is reset before executing the sniff. 

    Please use this command. These arguments cancel all commands and flush the command queue.

    rfStatus = RF_flushCmd(rfHandle, RF_CMDHANDLE_FLUSH_ALL , 0);

  • This seems to have resolved the issue.  I think it may have been caused by TX and RX tasks preempting each other, but your suggestion worked.