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.

CCS/CC2650: RX/TX Mode Switching

Part Number: CC2650
Other Parts Discussed in Thread: CC1350, SYSBIOS,

Tool/software: Code Composer Studio

I'm trying to modify the rfPacketRx example project to switch between RX and TX modes.  When attempting to setup the radio, the program breaks somewhere in the C:\ti\tirtos_cc13xx_cc26xx_2_21_00_06\products\tidrivers_cc13xx_cc26xx_2_21_00_04\packages\ti\drivers\rf\RFCC26XX_singleMode.c file.  I've nearly copied an example I found in the forums but it was based on the CC1350 part.  Can you review the code below and offer any suggestions to where the application is configured incorrectly?  The code compiles just fine and I do not use the RTOS as the program is a very simple operation of: RX Mode, wait 500mS and/or wait for UART command, TX updated status, Back to RX Mode and UART Receive mode.

Below is the rfPacketRx.c file I've modified.

/***** Includes *****/
#include <stdlib.h>
#include <xdc/std.h>
#include <xdc/cfg/global.h>
#include <xdc/runtime/System.h>

#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Task.h>
#include <ti/sysbios/hal/Hwi.h>

#include <driverlib/interrupt.h>

/* Drivers */
#include <ti/drivers/rf/RF.h>
#include <ti/drivers/PIN.h>
#include <ti/drivers/pin/PINCC26XX.h>
#include <driverlib/rf_prop_mailbox.h>
#include <driverlib/systick.h>

/* Board Header files */
#include "Board.h"

#include "RFQueue.h"
#include "smartrf_settings/smartrf_settings.h"

#include <stdlib.h>

/* Global memory storage for a PIN_Config table */
static PIN_State buttonPinState;
static PIN_State ledPinState;
static PIN_Handle ledPinHandle;
static PIN_Handle buttonPinHandle;

PIN_Config ledPinTable[] = {
Board_LED0 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX,
Board_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
Dimmer_Control | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
PIN_TERMINATE
};

PIN_Config buttonPinTable[] = {
Board_BUTTON0 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE,
Board_BUTTON1 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE,
Zero_Cross_Detect | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE,
PIN_TERMINATE
};

PIN_Config pinTable[] =
{
Board_LED2 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
PIN_TERMINATE
};

/***** Defines *****/
#define RX_TASK_STACK_SIZE 1024
#define RX_TASK_PRIORITY 2
#define TX_TASK_STACK_SIZE 1024
#define TX_TASK_PRIORITY 2

/* Packet TX Configuration */
#define PAYLOAD_LENGTH 30
#define PACKET_INTERVAL (uint32_t)(4000000*0.5f) /* Set packet interval to 500ms */
#define DATA_ENTRY_HEADER_SIZE 8 /* Constant header size of a Generic Data Entry */
#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) */
#define RX_TIMEOUT (uint32_t)(4000000*0.5f)
#define DUTY_CYCLE_MULT 3840

/***** Function Prototypes *****/
static void Receive(void);
static void rxCallback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e);
static void txCallback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e);
static void Transmit(void);
void TickTimerISR(void);
static void TickTimerInit(void);
static uint8_t TimerExpired(uint32_t *timer, uint32_t delay_time);
static void SetTimer(uint32_t *timer);

static rfc_propRxOutput_t rxStatistics;
static dataQueue_t dataQueue;
static rfc_dataEntryGeneral_t* currentDataEntry;
static uint8_t packetLength;
static uint8_t* packetDataPointer;
extern uint32_t clk_ticks = 0;
static uint32_t curtime;
static uint8_t DimmingLevel = 30; //default of 30% Duty Cycle
static uint16_t seqNumber;
static uint16_t DUTY_CYCLE_NUMBER = 10;
static RF_Object rfObject;
static RF_Handle rfHandle;


#ifdef LOG_RADIO_EVENTS
static volatile RF_EventMask eventLog[32];
static volatile uint8_t evIndex = 0;
#endif // LOG_RADIO_EVENTS

static uint8_t txPacket[PAYLOAD_LENGTH];
static uint8_t rxPacket[PAYLOAD_LENGTH + NUM_APPENDED_BYTES - 1];
static uint16_t seqNumber;
int nReceived = 0;
static uint32_t curtime;
static volatile bool bRxSuccess = false;

union FLAG_REG{ /** Data type for flags register */
uint16_t Flag_Status;
struct flagStatusStruct{
uint8_t Reserved_1 :1;
uint8_t Reserved_2 :1;
uint8_t Reserved_3 :1;
uint8_t Reserved_4 :1;
uint8_t Reserved_5 :1;
uint8_t Reserved_6 :1;
uint8_t Reserved_7 :1;
uint8_t Reserved_8 :1;
uint8_t Reserved_9 :1;
uint8_t Reserved_10 :1;
uint8_t Reserved_11 :1;
uint8_t Reserved_12 :1;
uint8_t Reserved_13 :1;
uint8_t Reserved_14 :1;
uint8_t Reserved_15 :1;
uint8_t UartMessageReceived :1;
} Bits;
};

union FLAG_REG statusFlags;

/* 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,
PAYLOAD_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,
PAYLOAD_LENGTH,
NUM_APPENDED_BYTES)];
#elif defined(__GNUC__)
static uint8_t rxDataEntryBuffer [RF_QUEUE_DATA_ENTRY_BUFFER_SIZE(NUM_DATA_ENTRIES,
PAYLOAD_LENGTH, NUM_APPENDED_BYTES)] __attribute__ ((aligned (4)));
#else
#error This compiler is not supported.
#endif

void TickTimerInit(void){

Hwi_Params hwiParams;
Hwi_Struct hwi;

SysTickDisable();
SysTickPeriodSet(48000); // 1mS interrupt timing

/* Create Hwi object for this peripheral */
Hwi_Params_init(&hwiParams);
hwiParams.priority = 4; // Lowest
Hwi_construct(&hwi, INT_SYSTICK, TickTimerISR, &hwiParams, NULL);

SysTickEnable();

} //end of void TickTimerInit(void){

void SetTimer(uint32_t *timer){
*timer = clk_ticks;
} //end of void SetTimer(int timer){

uint8_t TimerExpired(uint32_t *timer, uint32_t delay_time){

if((clk_ticks - *timer) >= delay_time) return 1;
else return 0;
} //end of int TimerExpired(int timer, int time){

void TickTimerISR(void){
clk_ticks++;
}

void buttonCallbackFxn(PIN_Handle handle, PIN_Id pinId) {
/* Debounce logic, only toggle if the button is still pushed (low) */
CPUdelay(5); //short debounce for ZeroCross Detector
if (!PIN_getInputValue(pinId)) {
switch (pinId) {
case Board_BUTTON0:
if (DUTY_CYCLE_NUMBER >=100) DUTY_CYCLE_NUMBER = 100;
else DUTY_CYCLE_NUMBER++;
break;
case Board_BUTTON1:
if (DUTY_CYCLE_NUMBER == 0)
{
DUTY_CYCLE_NUMBER = 0;
}
else DUTY_CYCLE_NUMBER--;
break;
case Zero_Cross_Detect:
PIN_setOutputValue(ledPinHandle, Dimmer_Control, 0);//Disable Triac
CPUdelay(DUTY_CYCLE_MULT * DUTY_CYCLE_NUMBER); //max time is 38400 CPU cycles in 8mS (half of 60Hz)
PIN_setOutputValue(ledPinHandle, Dimmer_Control, 1);
break;
default:
/* Do nothing */
break;
}
}
}

static void rxCallback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e)
{
#ifdef LOG_RADIO_EVENTS
eventLog[evIndex++ & 0x1F] = e;
#endif// LOG_RADIO_EVENTS
if (e & RF_EventRxEntryDone)
{
bRxSuccess = true;
currentDataEntry = RFQueue_getDataEntry();
packetLength = *(uint8_t*)(&currentDataEntry->data);
packetDataPointer = (uint8_t*)(&currentDataEntry->data + 1);
memcpy(rxPacket, packetDataPointer, (packetLength + 1));
nReceived++;
//dimming range boudry check
if(rxPacket[3] >= 100) rxPacket[3] = 100;
else if(rxPacket[3] <= 0) rxPacket[3] = 0;
DUTY_CYCLE_NUMBER = 100 - rxPacket[3];
RFQueue_nextEntry();
}
}

static void txCallback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e)
{
if(e & RF_EventCmdDone)
{
PIN_setOutputValue(ledPinHandle, Board_LED1,
!PIN_getOutputValue(Board_LED1));
PIN_setOutputValue(ledPinHandle, Board_LED2, 0);
}
else
{
PIN_setOutputValue(ledPinHandle, Board_LED1, 1);
PIN_setOutputValue(ledPinHandle, Board_LED2, 1);
}
}

static void Transmit(void)
{
txPacket[0] = (uint8_t)(seqNumber >> 8);
txPacket[1] = (uint8_t)(seqNumber++);
txPacket[2] = (uint8_t)(0xFF);
txPacket[3] = DimmingLevel; // increment from 0 - 100 for 0% to 100% Dimming duty cycle
uint8_t i;
for (i = 4; i < PAYLOAD_LENGTH; i++)
{
txPacket[i] = 0; //set remaining bytes to 0 for now
}
RF_EventMask terminationReason = RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropTx, RF_PriorityNormal, txCallback, RF_EventCmdDone);
// RF_EventMask terminationReason = RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropTx, RF_PriorityNormal, NULL, 0);
}

void Receive()
{
nReceived = 0;
while (nReceived <= 1)
{
RF_EventMask terminationReason = RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropRx, RF_PriorityNormal, rxCallback, RF_EventRxEntryDone);
}
}

int main(void)
{
uint32_t txTimer;
uint32_t currVal = 0;

RF_Params rfParams;
RF_Params_init(&rfParams);

/* Call board init functions. */
Board_initGeneral();
TickTimerInit();
IntMasterEnable();
/* Open LED pins */
ledPinHandle = PIN_open(&ledPinState, ledPinTable);
if(!ledPinHandle) {
System_abort("Error initializing board LED pins\n");
}

buttonPinHandle = PIN_open(&buttonPinState, buttonPinTable);
if(!buttonPinHandle) {
System_abort("Error initializing button pins\n");
}
if(RFQueue_defineQueue(&dataQueue,
rxDataEntryBuffer,
sizeof(rxDataEntryBuffer),
NUM_DATA_ENTRIES,
PAYLOAD_LENGTH + NUM_APPENDED_BYTES))

/* Setup callback for button pins */
if (PIN_registerIntCb(buttonPinHandle, &buttonCallbackFxn) != 0) {
System_abort("Error registering button callback function");
}

//CMD_PRO_TX and CMD_PROP_RX command setup
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_cmdPropRx.pQueue = &dataQueue; /* Set the Data Entity queue for received data */
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.maxPktLen = PAYLOAD_LENGTH; /* Implement packet length filtering to avoid PROP_ERROR_RXBUF */
RF_cmdPropRx.pktConf.bRepeatOk = 0; //no repeat
RF_cmdPropRx.pktConf.bRepeatNok = 0; //no repeat
RF_cmdPropRx.pOutput = (uint8_t *)&rxStatistics;
/* 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);
/* Get current time */
curtime = RF_getCurrentTime();
Receive();// place radio into receive mode prior to entering tx loop
SetTimer(&txTimer); //set timer

while(1){
//trigger tx every ~500mS for now
if(TimerExpired(&txTimer, 500)){ //trigger every 500mS

currVal = PIN_getOutputValue(Board_LED1);
PIN_setOutputValue(ledPinHandle, Board_LED1, !currVal);
Transmit(); //Send Data
SetTimer(&txTimer); // reset timer here, may nned to move to the top of the function if the function timing takes too long...dlh
Receive();// go back to receive mode
} // end of if(TimerExpired(&txTimer, 500)){

if(statusFlags.Bits.UartMessageReceived){//wait for new message(via RF or UART) to update status etc
//processMessage(); //update packet info
// sendAck(); //reply with ACK would need to add a NACK handler here DLH
} //end of if(UartMessageReceived){

//
}
/* Start BIOS */
// BIOS_start();

return (0);
}

  • Hi Daniel,

    In order to use the TI Drivers, you would have to either use TI-RTOS or NoRTOS (the later is a DPL implementation that enabled the user to use TI Drivers while not using TI-RTOS).

    In the the most basic implementations we provide you could not simply add in your code and comment out "BIOS_start()", if the example was originally a TI-RTOS project it will still be just that. In that case, using driver APIs such as RF_open(), RF_postCmd() etc would most likely crash the application as the BIOS is not yet started.

    I would suggest you actually move this to be a "TI-RTOS like" example where you create a task to run your application and put your application code inside that task.
  • I've attempted to place my code within a task function and get the exact same results.

    The code errors in the function below:

    RF_EventMask RF_runCmd(RF_Handle h, RF_Op* pOp, RF_Priority ePri, RF_Callback pCb, RF_EventMask bmEvent)
    {
    if (pCb == NULL)
    {
    pCb = syncCb;
    }

    RF_CmdHandle ch = RF_postCmd(h, pOp, ePri, pCb, bmEvent);

    if (ch<0)
    {
    return RF_EventCmdError;
    }
    return RF_pendCmd(h, ch, (RF_EventLastCmdDone | RF_EventCmdAborted | RF_EventCmdStopped | RF_EventCmdCancelled));
    }

    Dan

  • Hi Dan,

    Have you verified the arguments you pass to the the RF Driver APIs so that all of them are valid (for example the RF handle)? I would recommend you have a look at how the rfPacketTx and rfPacketRx examples work and start to verify these examples and then do the TX/RX merge.

    I attached both source files, but the full projects can be found in the "TI-RTOS" installation folder you get with the SDK:

    C:\ti\tirtos_cc13xx_cc26xx_2_21_01_08\examples\TI\CC2650_LAUNCHXL\rfPacketTx (the path to rfPacketTx assuming you installed the SDK in the defualt location).

    /cfs-file/__key/communityserver-discussions-components-files/81/rfPacketTx.c

    /cfs-file/__key/communityserver-discussions-components-files/81/rfPacketRx.c

  • I've refactored all the code to use the RTOS just like the examples.  I've not been able to verify the parameters as when I trace the parameters through the code, it goes to the rf.h file that was supplied.  The only thing I can think of is the two examples use two different rf.h files which set the parameters differently for both rx and tx functions.  Can you point me in the right direction to narrow down this issue?  I still receive the same error as mentioned above.

    Dan

  • Here is the function where the code gets hung up.

    * ======== Hwi_getfunc ========
    */
    Hwi_FuncPtr Hwi_getFunc(Hwi_Object *hwi, UArg *arg)
    {
    *arg = hwi->arg;

    return (hwi->fxn);
    }


    Below is the file I've edited for my project: It's a straight merge of the rxPacket.c and txPacket.c files from the examples. The intent is to transmit every 500mS and be in receive mode when not transmitting.


    /***** Includes *****/
    #include <stdlib.h>
    #include <xdc/std.h>
    #include <xdc/cfg/global.h>
    #include <xdc/runtime/System.h>

    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Task.h>
    //#include <ti/sysbios/hal/Hwi.h>

    //#include <driverlib/interrupt.h>

    /* Drivers */
    #include <ti/drivers/rf/RF.h>
    #include <ti/drivers/PIN.h>
    //#include <ti/drivers/pin/PINCC26XX.h>
    #include <driverlib/rf_prop_mailbox.h>
    //#include <driverlib/systick.h>

    /* Board Header files */
    #include "Board.h"

    #include "RFQueue.h"
    #include "smartrf_settings/smartrf_settings.h"

    //#include <stdlib.h>

    /* Global memory storage for a PIN_Config table */
    static PIN_State buttonPinState;
    static PIN_State ledPinState;
    static PIN_Handle ledPinHandle;
    static PIN_Handle buttonPinHandle;
    static RF_Object rfObject;
    static RF_Handle rfHandle;
    static PIN_Handle pinHandle;

    PIN_Config ledPinTable[] = {
    Board_LED0 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX,
    Board_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
    Dimmer_Control | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
    PIN_TERMINATE
    };

    PIN_Config buttonPinTable[] = {
    Board_BUTTON0 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE,
    Board_BUTTON1 | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE,
    Zero_Cross_Detect | PIN_INPUT_EN | PIN_PULLUP | PIN_IRQ_NEGEDGE,
    PIN_TERMINATE
    };

    PIN_Config pinTable[] =
    {
    Board_LED2 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
    PIN_TERMINATE
    };

    /***** Defines *****/
    #define RX_TASK_STACK_SIZE 1024
    #define RX_TASK_PRIORITY 2
    #define TX_TASK_STACK_SIZE 1024
    #define TX_TASK_PRIORITY 2

    /* Packet TX Configuration */
    #define PAYLOAD_LENGTH 30
    #define PACKET_INTERVAL (uint32_t)(4000000*0.5f) /* Set packet interval to 500ms */
    #define DATA_ENTRY_HEADER_SIZE 8 /* Constant header size of a Generic Data Entry */
    #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) */
    #define RX_TIMEOUT (uint32_t)(4000000*0.5f)
    #define DUTY_CYCLE_MULT 3840

    /***** Function Prototypes *****/
    static void rxCallback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e);
    static void txCallback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e);

    /***** Prototypes *****/
    static void rxTaskFunction(UArg arg0, UArg arg1);
    static void txTaskFunction(UArg arg0, UArg arg1);

    /***** Variable declarations *****/
    static Task_Params rxTaskParams;
    static Task_Params txTaskParams;
    Task_Struct rxTask; /* not static so you can see in ROV */
    Task_Struct txTask; /* not static so you can see in ROV */
    static uint8_t rxTaskStack[RX_TASK_STACK_SIZE];
    static uint8_t txTaskStack[TX_TASK_STACK_SIZE];

    static dataQueue_t dataQueue;
    static rfc_dataEntryGeneral_t* currentDataEntry;
    static uint8_t packetLength;
    static uint8_t* packetDataPointer;
    static uint32_t curtime;
    static uint8_t DimmingLevel = 30; //default of 30% Duty Cycle
    static uint16_t seqNumber;
    static uint16_t DUTY_CYCLE_NUMBER = 10;
    uint32_t currVal = 0;

    static uint8_t txPacket[PAYLOAD_LENGTH];
    static uint8_t rxPacket[PAYLOAD_LENGTH + NUM_APPENDED_BYTES - 1];
    static uint16_t seqNumber;
    static uint32_t curtime;

    union FLAG_REG{ /** Data type for flags register */
    uint16_t Flag_Status;
    struct flagStatusStruct{
    uint8_t Reserved_1 :1;
    uint8_t Reserved_2 :1;
    uint8_t Reserved_3 :1;
    uint8_t Reserved_4 :1;
    uint8_t Reserved_5 :1;
    uint8_t Reserved_6 :1;
    uint8_t Reserved_7 :1;
    uint8_t Reserved_8 :1;
    uint8_t Reserved_9 :1;
    uint8_t Reserved_10 :1;
    uint8_t Reserved_11 :1;
    uint8_t Reserved_12 :1;
    uint8_t Reserved_13 :1;
    uint8_t Reserved_14 :1;
    uint8_t Reserved_15 :1;
    uint8_t UartMessageReceived :1;
    } Bits;
    };

    union FLAG_REG statusFlags;

    /* 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,
    PAYLOAD_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,
    PAYLOAD_LENGTH,
    NUM_APPENDED_BYTES)];
    #elif defined(__GNUC__)
    static uint8_t rxDataEntryBuffer [RF_QUEUE_DATA_ENTRY_BUFFER_SIZE(NUM_DATA_ENTRIES,
    PAYLOAD_LENGTH, NUM_APPENDED_BYTES)] __attribute__ ((aligned (4)));
    #else
    #error This compiler is not supported.
    #endif

    void buttonCallbackFxn(PIN_Handle handle, PIN_Id pinId) {
    /* Debounce logic, only toggle if the button is still pushed (low) */
    CPUdelay(5); //short debounce for ZeroCross Detector
    if (!PIN_getInputValue(pinId)) {
    switch (pinId) {
    case Board_BUTTON0:
    if (DUTY_CYCLE_NUMBER >=100) DUTY_CYCLE_NUMBER = 100;
    else DUTY_CYCLE_NUMBER++;
    break;
    case Board_BUTTON1:
    if (DUTY_CYCLE_NUMBER == 0)
    {
    DUTY_CYCLE_NUMBER = 0;
    }
    else DUTY_CYCLE_NUMBER--;
    break;
    case Zero_Cross_Detect:
    PIN_setOutputValue(ledPinHandle, Dimmer_Control, 0);//Disable Triac
    CPUdelay(DUTY_CYCLE_MULT * DUTY_CYCLE_NUMBER); //max time is 38400 CPU cycles in 8mS (half of 60Hz)
    PIN_setOutputValue(ledPinHandle, Dimmer_Control, 1);
    break;
    default:
    /* Do nothing */
    break;
    }
    }
    }

    static void rxCallback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e)
    {
    #ifdef LOG_RADIO_EVENTS
    eventLog[evIndex++ & 0x1F] = e;
    #endif// LOG_RADIO_EVENTS
    if (e & RF_EventRxEntryDone)
    {

    currentDataEntry = RFQueue_getDataEntry();
    packetLength = *(uint8_t*)(&currentDataEntry->data);
    packetDataPointer = (uint8_t*)(&currentDataEntry->data + 1);
    memcpy(rxPacket, packetDataPointer, (packetLength + 1));
    //dimming range boudry check
    if(rxPacket[3] >= 100) rxPacket[3] = 100;
    else if(rxPacket[3] <= 0) rxPacket[3] = 0;
    DUTY_CYCLE_NUMBER = 100 - rxPacket[3];
    RFQueue_nextEntry();
    }
    }

    static void txCallback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e)
    {
    if(e & RF_EventCmdDone)
    {
    PIN_setOutputValue(pinHandle, Board_LED1,!PIN_getOutputValue(Board_LED1));
    }
    }

    void TxTask_init(PIN_Handle inPinHandle)
    {
    pinHandle = inPinHandle;

    Task_Params_init(&txTaskParams);
    txTaskParams.stackSize = TX_TASK_STACK_SIZE;
    txTaskParams.priority = TX_TASK_PRIORITY;
    txTaskParams.stack = &txTaskStack;
    txTaskParams.arg0 = (UInt)1000000;

    Task_construct(&txTask, txTaskFunction, &txTaskParams, NULL);
    }

    static void txTaskFunction(UArg arg0, UArg arg1)
    {
    uint32_t time;
    RF_Params rfParams;
    RF_Params_init(&rfParams);

    RF_cmdPropTx.pktLen = PAYLOAD_LENGTH;
    RF_cmdPropTx.pPkt = txPacket;
    RF_cmdPropTx.startTrigger.triggerType = TRIG_ABSTIME;
    RF_cmdPropTx.startTrigger.pastTrig = 1;
    RF_cmdPropTx.startTime = 0;

    /* 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);

    /* Get current time */
    time = RF_getCurrentTime();
    //while(1)
    //{
    /* Create packet with incrementing sequence number and random payload */
    txPacket[0] = (uint8_t)(seqNumber >> 8);
    txPacket[1] = (uint8_t)(seqNumber++);
    txPacket[2] = (uint8_t)(0xFF);
    txPacket[3] = DimmingLevel; // increment from 0 - 100 for 0% to 100% Dimming duty cycle
    uint8_t i;
    for (i = 4; i < PAYLOAD_LENGTH; i++)
    {
    txPacket[i] = 0; //set remaining bytes to 0 for now
    }
    /* Set absolute TX time to utilize automatic power management */
    time += PACKET_INTERVAL;
    RF_cmdPropTx.startTime = time;
    /* Send packet */
    RF_EventMask result = RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropTx, RF_PriorityNormal, &txCallback, 0);
    if (!(result & RF_EventLastCmdDone))
    {
    /* Error */
    while(1);
    }

    //}
    }

    /***** Function definitions *****/
    void RxTask_init(PIN_Handle ledPinHandle) {
    pinHandle = ledPinHandle;

    Task_Params_init(&rxTaskParams);
    rxTaskParams.stackSize = RX_TASK_STACK_SIZE;
    rxTaskParams.priority = RX_TASK_PRIORITY;
    rxTaskParams.stack = &rxTaskStack;
    rxTaskParams.arg0 = (UInt)1000000;

    Task_construct(&rxTask, rxTaskFunction, &rxTaskParams, NULL);
    }

    static void rxTaskFunction(UArg arg0, UArg arg1)
    {
    RF_Params rfParams;
    RF_Params_init(&rfParams);

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

    /* Modify CMD_PROP_RX command for application needs */
    RF_cmdPropRx.pQueue = &dataQueue; /* Set the Data Entity queue for received data */
    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.maxPktLen = PAYLOAD_LENGTH; /* Implement packet length filtering to avoid PROP_ERROR_RXBUF */
    RF_cmdPropRx.pktConf.bRepeatOk = 1;
    RF_cmdPropRx.pktConf.bRepeatNok = 1;
    //RF_cmdPropRx.pktConf.bRepeatOk = 0; //no repeat
    //RF_cmdPropRx.pktConf.bRepeatNok = 0; //no repeat
    /* 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);

    /* Enter RX mode and stay forever in RX */
    RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropRx, RF_PriorityNormal, &rxCallback, IRQ_RX_ENTRY_DONE);
    PIN_setOutputValue(pinHandle, Board_LED2,0); //turn off Red LED
    while(1){

    if(statusFlags.Bits.UartMessageReceived){//wait for new message(via RF or UART) to update status etc
    PIN_setOutputValue(pinHandle, Board_LED2,!PIN_getOutputValue(Board_LED2)); //turn off Red LED
    //processMessage(); //update packet info
    // sendAck(); //reply with ACK would need to add a NACK handler here DLH
    } //end of if(UartMessageReceived){
    }

    }

    int main(void)
    {
    /* Call board init functions. */
    Board_initGeneral();
    //TickTimerInit();
    //IntMasterEnable();
    /* Open LED pins */
    ledPinHandle = PIN_open(&ledPinState, ledPinTable);
    if(!ledPinHandle) {
    System_abort("Error initializing board LED pins\n");
    }

    buttonPinHandle = PIN_open(&buttonPinState, buttonPinTable);
    if(!buttonPinHandle) {
    System_abort("Error initializing button pins\n");
    }
    TxTask_init(ledPinHandle);
    RxTask_init(ledPinHandle);
    // SetTimer(&txTimer); //set timer

    // while(1){
    //trigger tx every ~500mS for now
    // if(TimerExpired(&txTimer, 500)){ //trigger every 500mS

    // currVal = PIN_getOutputValue(Board_LED1);
    // PIN_setOutputValue(ledPinHandle, Board_LED1, !currVal);
    // Transmit(); //Send Data
    // SetTimer(&txTimer); // reset timer here, may nned to move to the top of the function if the function timing takes too long...dlh
    // Receive();// go back to receive mode
    // } // end of if(TimerExpired(&txTimer, 500)){

    // if(statusFlags.Bits.UartMessageReceived){//wait for new message(via RF or UART) to update status etc
    //processMessage(); //update packet info
    // sendAck(); //reply with ACK would need to add a NACK handler here DLH
    // } //end of if(UartMessageReceived){
    // }


    /* Start BIOS */
    BIOS_start();

    return (0);
    }
  • Hi Daniel,

    What you are doing wrong here is the way you open the RF driver. In both the TX and RX task you duplicate the RF_open() call with the exact same parameters. This means that the first task to run will properly open up the driver and populate the structures (rfHandle, etc).

    When your second task then run, it will fail to open the same instance again and overwrite the previous value of rfHandle (setting it to NULL as you failed to open). You then later call driver APIs with this NULL handle, and your application crashes.

    Fixing this will solve the Hwi exception issue, but I don't think you will get the behavior you expect from your application. There is a few things you would like to consider:

    * There is no end to the RX operation, which is OK as implemented in the packetRX example where we want to stay in RX forever. In your merge where you want to do TX->RX->TX->RX and so on, this means you would need to abort the RX to clear the radio of for the TX operation and then restart the RX again.

    * If the "forever RX" where to return, your program would get stuck in the while(1) loop in the RX thread.

    * the TX task function has an end, this means the task function can exit and the TX task would stop to run. You typically want to keep your task alive for ever (have them contain a super loop for example).

    A pseudo code structure in your case could be something like this:

    void radioTask() {
    
    // Setup
    
    while ( forever ) {
    
    // Do TX
    
    // Do RX with timeout
    
    }
    
    }

    Of course the "while forever" loop could contain more logic, including semaphores, timers, etc. Using an event driven processing loop could be a good idea in your case.

  • Thanks M-W.

    Are you suggesting there is a way to setup the radio to transmit once, then go into receive with timeout in the same rfopen() call?  If so, do you have examples of this?  If not, then I understand your comment to mean that I should call a TX function from an event loop, close the radio, reopen the radio for RX with time out, then close after receive or timeout and repeat.

    Clearly I'm not familiar with the TI tools or software so understanding how it was intended to be used isn't so easy.

    Thanks for all your help.

    Dan

  • Hi Dan,

    Sure, in the end of the day, you would never need to close the driver in between TX and RX assuming you are using the same settings. Even in the case where you might use multiple protocols (and thus different RF settings) you could do it with a "single open" by re-configuring the radio when moving between settings.

    In your case where you are staying with the exact same PHY and settings, moving from TX to RX and vice versa you could simply do (for example):

    RF_runCmd(TX); // "Run" is blocking, so it will return when the TX is done

    RF_runCmd(RX);

    Regarding RX timeout, you can see by looking at the "RF_cmdPropRx" structure that there is "endTime" and "endTrigger" parameters you can setup to limit the length of your RX operation.

    For the RX, you can for example set the following configuration to set a 500 ms timeout(in addition to any other configs you might want to do):

    RF_cmdPropRx.pktConf.bRepeatOk = 1; // Do not start over if the RX was OK
    RF_cmdPropRx.pktConf.bRepeatNok = 1; // Do not start over if the RX was not OK
    RF_cmdPropRx.endTime = RF_convertMsToRatTicks(500); /* Set RX timeout to 500 ms*/
    RF_cmdPropRx.endTrigger.triggerType = TRIG_REL_START; /* End is relative to start */
    RF_cmdPropRx.endTrigger.pastTrig = 1; /* End past trigger is allowed */

    Note that this timeout is related to "idle" RX. If you would detect a valid package just at the end of the timeout, the RX would finish before ending.
  • Thanks M-W.

    I'm following what you are saying but still can't figure out what I'm doing wrong. I've refactored the code back to the way I was doing it before (without the RTOS). The code breaks when I call the RF_runCmd the first time inside the Transmit(); function. Below is my main, transmit() and receive() functions for your review. I'd really appreciate some help getting through this.

    Dan

    void Transmit(void){

    RF_Params rfParams;
    RF_Params_init(&rfParams);

    RF_cmdPropTx.pktLen = PAYLOAD_LENGTH;
    RF_cmdPropTx.pPkt = txPacket;
    RF_cmdPropTx.startTrigger.triggerType = TRIG_ABSTIME;
    RF_cmdPropTx.startTrigger.pastTrig = 1;
    RF_cmdPropTx.startTime = 0;
    /* 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, &txCallback, 0);

    /* Get current time */
    curtime = RF_getCurrentTime();
    //while(1)
    //{
    /* Create packet with incrementing sequence number and payload */
    txPacket[0] = (uint8_t)(seqNumber >> 8);
    txPacket[1] = (uint8_t)(seqNumber++);
    txPacket[2] = (uint8_t)(0xFF);
    txPacket[3] = DimmingLevel; // increment from 0 - 100 for 0% to 100% Dimming duty cycle
    uint8_t i;
    for (i = 4; i < PAYLOAD_LENGTH; i++)
    {
    txPacket[i] = 0; //set remaining bytes to 0 for now
    }
    /* Set absolute TX time to utilize automatic power management */
    curtime += PACKET_INTERVAL;
    RF_cmdPropTx.startTime = curtime;
    /* Send packet */
    RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropTx, RF_PriorityNormal, &txCallback, 0);
    //RF_EventMask result = RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropTx, RF_PriorityNormal, &txCallback, 0);
    }

    void Receive(void){

    RF_Params rfParams;
    RF_Params_init(&rfParams);
    if( RFQueue_defineQueue(&dataQueue,
    rxDataEntryBuffer,
    sizeof(rxDataEntryBuffer),
    NUM_DATA_ENTRIES,
    PAYLOAD_LENGTH + NUM_APPENDED_BYTES))
    {
    /* Failed to allocate space for all data entries */
    while(1);
    }
    /* Modify CMD_PROP_RX command for application needs */
    RF_cmdPropRx.pQueue = &dataQueue; /* Set the Data Entity queue for received data */
    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.maxPktLen = PAYLOAD_LENGTH; /* Implement packet length filtering to avoid PROP_ERROR_RXBUF */
    RF_cmdPropRx.pktConf.bRepeatOk = 1; // Do not start over if the RX was OK
    RF_cmdPropRx.pktConf.bRepeatNok = 1; // Do not start over if the RX was not OK
    RF_cmdPropRx.endTime = RX_TIMEOUT; //RF_convertMsToRatTicks(500); /* Set RX timeout to 500 ms*/
    RF_cmdPropRx.endTrigger.triggerType = TRIG_REL_START; /* End is relative to start */
    RF_cmdPropRx.endTrigger.pastTrig = 1; /* End past trigger is allowed */
    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);

    RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropRx, RF_PriorityNormal, &rxCallback, IRQ_RX_ENTRY_DONE);
    PIN_setOutputValue(pinHandle, Board_LED2,0); //turn off Red LED
    }

    int main(void)
    {
    /* Call board init functions. */
    Board_initGeneral();
    TickTimerInit();
    IntMasterEnable();
    // RF_Init();
    /* Open LED pins */
    ledPinHandle = PIN_open(&ledPinState, ledPinTable);
    if(!ledPinHandle) {
    System_abort("Error initializing board LED pins\n");
    }

    buttonPinHandle = PIN_open(&buttonPinState, buttonPinTable);
    if(!buttonPinHandle) {
    System_abort("Error initializing button pins\n");
    }
    PIN_setOutputValue(ledPinHandle, Board_LED2, 0);
    PIN_setOutputValue(ledPinHandle, Board_LED2, 0);
    //TxTask_init(ledPinHandle);
    //RxTask_init(ledPinHandle);
    SetTimer(&txTimer); //set timer

    while(1){
    //trigger tx every ~500mS for now
    if(TimerExpired(&txTimer, 500)){ //trigger every 500mS

    currVal = PIN_getOutputValue(Board_LED1);
    PIN_setOutputValue(ledPinHandle, Board_LED1, !currVal);
    Transmit(); //Send Data
    SetTimer(&txTimer); // reset timer here, may nned to move to the top of the function if the function timing takes too long...dlh
    Receive();// go back to receive mode
    } // end of if(TimerExpired(&txTimer, 500)){

    if(statusFlags.Bits.UartMessageReceived){//wait for new message(via RF or UART) to update status etc
    //processMessage(); //update packet info
    // sendAck(); //reply with ACK would need to add a NACK handler here DLH
    } //end of if(UartMessageReceived){
    }
    /* Start BIOS */
    // BIOS_start();
    return (0);
    }
  • Hi Daniel,

    As I said earlier, in order to use the TI Drivers (such as the RF Driver) you need to use TI-RTOS or at least NoRTOS. As NoRTOS is not available for CC2650, you would need to use TI-RTOS. The alternative if doing it "bare-metal" is to build your application based on DriverLib but this is not recommended.

    In your case, I would try something like this (in a TI-RTOS thread). Keep in mind that I simply copy paste now so there is possibly (most likely) some syntax to fix. It is also not a complete example, but rather a hint on "how it could look":

    void *mainThread(void *arg0) {
    
    RF_Params rfParams;
    RF_Params_init(&rfParams);
    
    /* Request access to the radio */
    rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, &rfParams);
    
    /* init RX queue */
    if( RFQueue_defineQueue(&dataQueue,
                            rxDataEntryBuffer,
                            sizeof(rxDataEntryBuffer),
                            NUM_DATA_ENTRIES,
                            PAYLOAD_LENGTH + NUM_APPENDED_BYTES))
    {
        /* Failed to allocate space for all data entries */
        while(1);
    }
    
    /* Setup TX and RX commands default values */
    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_cmdPropRx.pQueue = &dataQueue; /* Set the Data Entity queue for received data */
    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.maxPktLen = PAYLOAD_LENGTH; /* Implement packet length filtering to avoid PROP_ERROR_RXBUF */
    RF_cmdPropRx.pktConf.bRepeatOk = 1; // Do not start over if the RX was OK
    RF_cmdPropRx.pktConf.bRepeatNok = 1; // Do not start over if the RX was not OK
    RF_cmdPropRx.endTime = RX_TIMEOUT; //RF_convertMsToRatTicks(500); /* Set RX timeout to 500 ms*/
    RF_cmdPropRx.endTrigger.triggerType = TRIG_REL_START; /* End is relative to start */
    RF_cmdPropRx.endTrigger.pastTrig = 1; /* End past trigger is allowed */
    
    /* Run the setup command */
    RF_runCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0);
    
    /* TX/RX loop */
    
    /* Get current time */
    while(1) {
       curtime = RF_getCurrentTime();
       /* TX */ 
      /* Create packet with incrementing sequence number and payload */ 
      txPacket[0] = (uint8_t)(seqNumber >> 8); 
      txPacket[1] = (uint8_t)(seqNumber++); 
      txPacket[2] = (uint8_t)(0xFF); 
      txPacket[3] = DimmingLevel; 
      // increment from 0 - 100 for 0% to 100% Dimming duty cycle 
      uint8_t i; for (i = 4; i < PAYLOAD_LENGTH; i++) { 
      txPacket[i] = 0; //set remaining bytes to 0 for now 
      } 
      /* Set absolute TX time to utilize automatic power management */ 
      curtime += PACKET_INTERVAL; 
      RF_cmdPropTx.startTime = curtime; 
      /* Send packet */ 
      RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropTx, RF_PriorityNormal, &txCallback, 0);
    
      /* RX */ 
      RF_EventMask radioDoneEvent = RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropRx, RF_PriorityNormal, &rxCallback, RF_EventRxEntryDone | RF_EventRxOk);
    
      if (radioDoneEvent & (RF_EventRxEntryDone | RF_EventRxOk)) {
            /* We received a packet OK */
      } else {
      /* RX ended due to some other reason */  
      } 
    } 
    }
    

  • Thanks M-W.  I finally get what you've been trying to explain to me :)  

    One last question, there are many defines, functions etc... created with the examples, RTOS, etc...

    Where do I find these explained in the documentation?  I've tried searching several times and only find variables within structures but not the functions, defines etc.  

    Dan

  • Hi Daniel,

    Most of the documentation can be found in the TI-RTOS docs folder, if you installed this as the default location you would find it at this location: file:///C:/ti/tirtos_cc13xx_cc26xx_2_21_01_08/docs/Documentation_Overview_cc13xx_cc26xx.html

    You can find TI-RTOS, Drives and CC26xxWares all linked from this document.