Showing posts with label CC1310 LaunchPad. Show all posts
Showing posts with label CC1310 LaunchPad. Show all posts

Tuesday, February 4, 2020

CC13xx TRX WOR project

The following steps show you how to combine CC13xx  rfWakeOnRadioRx into rfWakeOnRadioTx to do TX/RX in the same WOR project.

1. Import LAUNCHXL-CC1310 rfWakeOnRadioTx example from simplelink_cc13x0_sdk_3_20_00_23

2. Create a rfWakeOnRadioRx.c with the following code and save rfWakeOnRadioRx.c into project folder:

/***** Includes *****/
/* Standard C Libraries */
#include < stdlib.h >

/* XDCtools Header files */
#include < xdc/std.h >
#include < xdc/runtime/Assert.h >

/* BIOS Header files */
#include < ti/sysbios/BIOS.h >
#include < ti/sysbios/knl/Task.h >

/* TI-RTOS Header files */
#include < ti/drivers/rf/RF.h >
#include < ti/drivers/PIN.h >
#include < ti/drivers/pin/PINCC26XX.h >
#include < ti/drivers/UART.h >

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

/* Application Header files */
#include "RFQueue.h"
#include "smartrf_settings/smartrf_settings.h"

#include < ti/devices/DeviceFamily.h >
#include DeviceFamily_constructPath(driverlib/rf_prop_mailbox.h)


/***** Defines *****/
/* Wake-on-Radio wakeups per second */
#define WOR_WAKEUPS_PER_SECOND  2

/* Wake-on-Radio mode. Can be:
 * - RSSI only
 * - PQT, preamble detection
 * - Both, first RSSI and then PQT if RSSI  */
#define WOR_MODE CarrierSenseMode_RSSIandPQT

/* Threshold for RSSI based Carrier Sense in dBm */
#define WOR_RSSI_THRESHOLD      ((int8_t)(-111))

/* Data Rate in use */
#define WOR_RF_PHY_DATARATE_50KBPS  0 // 2-GFSK 50Kbps
#define WOR_RF_PHY_DATARATE_100KBPS 1 // 2-GFSK 100Kbps
#define WOR_RF_PHY_DATARATE_200KBPS 2 // 2-GFSK 200Kbps
#define WOR_RF_PHY_DATARATE_300KBPS 3 // 2-GFSK 300Kbps
#define WOR_RF_PHY_DATARATE_400KBPS 4 // 2-GFSK 400Kbps
#define WOR_RF_PHY_DATARATE_500KBPS 5 // 2-GFSK 500Kbps

#define WOR_RF_PHY_DATARATE WOR_RF_PHY_DATARATE_50KBPS

/* Macro used to set actual wakeup interval */
#define WOR_WAKE_UP_MARGIN_S 0.005f
#define WOR_WAKE_UP_INTERVAL_RAT_TICKS(x) \
    ((uint32_t)(4000000*(1.0f/(x) - (WOR_WAKE_UP_MARGIN_S))))

/* TI-RTOS Task configuration */
#define RX_TASK_STACK_SIZE 1024
#define RX_TASK_PRIORITY   2

/* TX Configuration */
#define DATA_ENTRY_HEADER_SIZE 8  /* Constant header size of a Generic Data Entry */
#define MAX_LENGTH             31 /* 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     1  /* Length byte included in the stored packet */

/***** Type declarations *****/
/* General wake-on-radio RX statistics */
struct WorStatistics {
  uint32_t doneIdle;
  uint32_t doneIdleTimeout;
  uint32_t doneRxTimeout;
  uint32_t doneOk;
};

/* Modes of carrier sense possible */
enum CarrierSenseMode {
    CarrierSenseMode_RSSI,
    CarrierSenseMode_PQT,
    CarrierSenseMode_RSSIandPQT,
};


/***** Variable declarations *****/
/* TX task objects and task stack */
static Task_Params rxTaskParams;
static Task_Struct rxTask;
static uint8_t rxTaskStack[RX_TASK_STACK_SIZE];

/* RF driver object and handle */
static RF_Object rfObject;
static RF_Handle rfHandle;

/* Pin driver object and handle */
extern PIN_Handle ledPinHandle;
extern PIN_State ledPinState;

/* General wake-on-radio sniff status statistics and statistics from the RF Core about received packets */
static volatile struct WorStatistics worStatistics;
static rfc_propRxOutput_t rxStatistics;

/*
 * Application LED pin configuration table:
 *   - All LEDs board LEDs are off.
 */
static PIN_Config pinTable[] =
{
    Board_PIN_LED0 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
    Board_PIN_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
    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)];
#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

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

static volatile uint8_t dummy;

/* Sniff command for doing combined Carrier Sense and RX*/
static rfc_CMD_PROP_RX_SNIFF_t RF_cmdPropRxSniff;

/***** Prototypes *****/
static void rxTaskFunction(UArg arg0, UArg arg1);
static void callback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e);
static void initializeSniffCmdFromRxCmd(rfc_CMD_PROP_RX_SNIFF_t* rxSniffCmd, rfc_CMD_PROP_RX_t* rxCmd);
static void configureSniffCmd(rfc_CMD_PROP_RX_SNIFF_t* rxSniffCmd, enum CarrierSenseMode mode, uint32_t datarate, uint8_t wakeupPerSecond);
static uint32_t calculateSymbolRate(uint8_t prescaler, uint32_t rateWord);

const char  rxechoPrompt[] = "RX Echoing characters:\r\n";
extern UART_Handle uart;
extern UART_Params uartParams;


void rxTaskInit();
/***** Function definitions *****/
/* RX task initialization function. Runs once from main() */
void rxTaskInit()
{
    Task_Params_init(&rxTaskParams);
    rxTaskParams.stackSize = RX_TASK_STACK_SIZE;
    rxTaskParams.priority = RX_TASK_PRIORITY;
    rxTaskParams.stack = &rxTaskStack;

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

/* RX task function. Executed in Task context by TI-RTOS when the scheduler starts. */
static void rxTaskFunction(UArg arg0, UArg arg1)
{
    RF_Params rfParams;
    RF_Params_init(&rfParams);

    /* Route out LNA active pin to LED1 */
    PINCC26XX_setMux(ledPinHandle, Board_PIN_LED0, PINCC26XX_MUX_RFC_GPO0);

    /* Create queue and data entries */
    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);
    }

    /* Copy all RX options from the SmartRF Studio exported RX command to the RX Sniff command */
    initializeSniffCmdFromRxCmd(&RF_cmdPropRxSniff, &RF_cmdPropRx);

    /* Configure RX part of RX_SNIFF command */
    RF_cmdPropRxSniff.pQueue    = &dataQueue;
    RF_cmdPropRxSniff.pOutput   = (uint8_t*)&rxStatistics;
    RF_cmdPropRxSniff.maxPktLen = MAX_LENGTH;

    /* Discard ignored packets and CRC errors from Rx queue */
    RF_cmdPropRxSniff.rxConf.bAutoFlushIgnored = 1;
    RF_cmdPropRxSniff.rxConf.bAutoFlushCrcErr  = 1;

    /* Calculate datarate from prescaler and rate word */
#if defined(DeviceFamily_CC26X0R2)
    uint32_t datarate = calculateSymbolRate(RF_cmdPropRadioSetup.symbolRate.preScale,
                                            RF_cmdPropRadioSetup.symbolRate.rateWord);
#else
    uint32_t datarate = calculateSymbolRate(RF_cmdPropRadioDivSetup.symbolRate.preScale,
                                            RF_cmdPropRadioDivSetup.symbolRate.rateWord);
#endif// DeviceFamily_CC26X0R2

    /* Configure Sniff-mode part of the RX_SNIFF command */
    configureSniffCmd(&RF_cmdPropRxSniff, WOR_MODE, datarate, WOR_WAKEUPS_PER_SECOND);

    /* Request access to the radio */
#if defined(DeviceFamily_CC26X0R2)
    rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioSetup, &rfParams);
#else
    rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, &rfParams);
#endif// DeviceFamily_CC26X0R2

    /* Set frequency */
    RF_runCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, &callback, 0);

    /* Save the current radio time */
    RF_cmdPropRxSniff.startTime = RF_getCurrentTime();

    UART_write(uart, rxechoPrompt, sizeof(rxechoPrompt));

    /* Enter main loop */
    while(1)
    {
        /* Set next wakeup time in the future */
        RF_cmdPropRxSniff.startTime += WOR_WAKE_UP_INTERVAL_RAT_TICKS(WOR_WAKEUPS_PER_SECOND);

        RF_yield(rfHandle);

        /* Schedule RX */
        RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropRxSniff, RF_PriorityNormal, &callback, RF_EventRxEntryDone);

        /* Log RX_SNIFF status */
        switch(RF_cmdPropRxSniff.status) {
            case PROP_DONE_IDLE:
                /* Idle based on RSSI */
                worStatistics.doneIdle++;
                break;
            case PROP_DONE_IDLETIMEOUT:
                /* Idle based on PQT */
                worStatistics.doneIdleTimeout++;
                break;
            case PROP_DONE_RXTIMEOUT:
                /* Got valid preamble on the air, but did not find sync word */
                worStatistics.doneRxTimeout++;
                break;
            case PROP_DONE_OK:
                /* Received packet */
                worStatistics.doneOk++;
                UART_write(uart, packetDataPointer, packetLength);
                break;
            default:
                /* Unhandled status */
                break;
        };
    }
}

/* Calculates datarate from prescaler and rate word */
static uint32_t calculateSymbolRate(uint8_t prescaler, uint32_t rateWord)
{
    /* Calculate datarate according to TRM Section 23.7.5.2:
     * f_baudrate = (R * f_ref)/(p * 2^20)
     *   - R = rateWord
     *   - f_ref = 24Mhz
     *   - p = prescaler */
    uint64_t numerator = rateWord*24000000ULL;
    uint64_t denominator = prescaler*1048576ULL;
    uint32_t result = (uint32_t)(numerator/denominator);
    return result;
}

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

/* Configures Sniff-mode part of the RX_SNIFF command based on mode, datarate and wakeup interval */
static void configureSniffCmd(rfc_CMD_PROP_RX_SNIFF_t* rxSniffCmd, enum CarrierSenseMode mode, uint32_t datarate, uint8_t wakeupPerSecond)
{
    /* Enable or disable RSSI */
    if ((mode == CarrierSenseMode_RSSI) || (mode == CarrierSenseMode_RSSIandPQT)) {
        rxSniffCmd->csConf.bEnaRssi        = 1;
    } else {
        rxSniffCmd->csConf.bEnaRssi        = 0;
    }

    /* Enable or disable PQT */
    if ((mode == CarrierSenseMode_PQT) || (mode == CarrierSenseMode_RSSIandPQT)) {
        rxSniffCmd->csConf.bEnaCorr        = 1;
        rxSniffCmd->csEndTrigger.triggerType  = TRIG_REL_START;
    } else {
        rxSniffCmd->csConf.bEnaCorr        = 0;
        rxSniffCmd->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 */
    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) */
    rxSniffCmd->csConf.idleOp          = 1; /* End on channel Idle */
    rxSniffCmd->csConf.timeoutRes      = 1; /* If the channel is invalid, it will return PROP_DONE_IDLE_TIMEOUT */

    /* RSSI configuration */
    rxSniffCmd->numRssiIdle            = 1; /* One idle RSSI samples signals that the channel is idle */
    rxSniffCmd->numRssiBusy            = 1; /* One busy RSSI samples signals that the channel is busy */
    rxSniffCmd->rssiThr    = (int8_t)WOR_RSSI_THRESHOLD; /* Set the RSSI threshold in dBm */

    /* PQT configuration */
    rxSniffCmd->corrConfig.numCorrBusy = 1;   /* One busy PQT samples signals that the channel is busy */
    rxSniffCmd->corrConfig.numCorrInv  = 1;   /* One busy PQT samples signals that the channel is busy */

    /* Calculate basic timing parameters */
    uint32_t symbolLengthUs  = 1000000UL/datarate;
    uint32_t preambleSymbols = (1000000UL/wakeupPerSecond)/symbolLengthUs;
#if defined(DeviceFamily_CC26X0R2)
    uint8_t syncWordSymbols  = RF_cmdPropRadioSetup.formatConf.nSwBits;
#else
    uint8_t syncWordSymbols  = RF_cmdPropRadioDivSetup.formatConf.nSwBits;
#endif// DeviceFamily_CC26X0R2

    /* Calculate sniff mode parameters */
    #define US_TO_RAT_TICKS 4
    #define CORR_PERIOD_SYM_MARGIN 16
    #define RX_END_TIME_SYM_MARGIN 8
    #define CS_END_TIME_MIN_TIME_SYM 30
#if ((WOR_RF_PHY_DATARATE == WOR_RF_PHY_DATARATE_50KBPS)  || \
     (WOR_RF_PHY_DATARATE == WOR_RF_PHY_DATARATE_100KBPS) || \
     (WOR_RF_PHY_DATARATE == WOR_RF_PHY_DATARATE_200KBPS))
    #define CS_END_TIME_MIN_TIME_STATIC_US 150
#elif ((WOR_RF_PHY_DATARATE == WOR_RF_PHY_DATARATE_300KBPS) || \
       (WOR_RF_PHY_DATARATE == WOR_RF_PHY_DATARATE_400KBPS))
    #define CS_END_TIME_MIN_TIME_STATIC_US 200
#elif (WOR_RF_PHY_DATARATE == WOR_RF_PHY_DATARATE_500KBPS)
    #define CS_END_TIME_MIN_TIME_STATIC_US 250
#else
#error "WOR_RF_PHY_DATARATE is undefined or has an invalid option"
#endif

    /* Represents the time in which we need to receive corrConfig.numCorr* correlation peaks to detect preamble.
     * When continously checking the preamble quality, this period has to be wide enough to also contain the sync
     * word, with a margin. If it is not, then there is a chance the SNIFF command will abort while receiving the
     * sync word, as it no longer detects a preamble. */
    uint32_t correlationPeriodUs = (syncWordSymbols + CORR_PERIOD_SYM_MARGIN)*symbolLengthUs;

    /* Represents the time where we will force a check if preamble is present (only done once).
     * The main idea is that his should be shorter than "correlationPeriodUs" so that if we get RSSI valid, but
     * there is not a valid preamble on the air, we will leave RX as quickly as possible. */
    uint32_t csEndTimeUs = (CS_END_TIME_MIN_TIME_SYM*symbolLengthUs + CS_END_TIME_MIN_TIME_STATIC_US);

    /* Represents the maximum time from the startTrigger to when we expect a sync word to be received. */
    uint32_t rxEndTimeUs = (preambleSymbols + syncWordSymbols + RX_END_TIME_SYM_MARGIN)*symbolLengthUs;

    /* Set sniff mode timing configuration in sniff command in RAT ticks */
    rxSniffCmd->corrPeriod = (uint16_t)(correlationPeriodUs * US_TO_RAT_TICKS);
    rxSniffCmd->csEndTime  = (uint32_t)(csEndTimeUs * US_TO_RAT_TICKS);
    rxSniffCmd->endTime    = (uint32_t)(rxEndTimeUs * US_TO_RAT_TICKS);

    /* Set correct trigger types */
    rxSniffCmd->endTrigger.triggerType   = TRIG_REL_START;
    rxSniffCmd->startTrigger.triggerType = TRIG_ABSTIME;
    rxSniffCmd->startTrigger.pastTrig    = 1;
}

/* Called for every received packet and command done */
void callback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e)
{
    /* If we've received a new packet and it's available to read out */
    if (e & RF_EventRxEntryDone)
    {
        do
        {
            /* Toggle LED on RX */
            PIN_setOutputValue(ledPinHandle, Board_PIN_LED1, !PIN_getOutputValue(Board_PIN_LED1));

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

            /* This code block is added to avoid a compiler warning.
            * Normally, an application will reference these variables for
            * useful data. */
            dummy = packetLength + packetDataPointer[0];

        } while(RFQueue_nextEntry() == DATA_ENTRY_FINISHED);
    }
}



3. Add/revise the following codes in red into rfWakeOnRadioTx.c:

/***** Includes *****/
#include < stdlib.h >

/* XDCtools Header files */
#include < xdc/std.h >
#include < xdc/runtime/Assert.h >

/* BIOS Header files */
#include < ti/sysbios/BIOS.h >
#include < ti/sysbios/knl/Semaphore.h >
#include < ti/sysbios/knl/Task.h  >

/* TI-RTOS Header files */
#include < ti/drivers/rf/RF.h >
#include < ti/drivers/PIN.h >
#include < ti/display/Display.h >

#include < ti/devices/DeviceFamily.h >
#include DeviceFamily_constructPath(driverlib/cpu.h)
#include < ti/drivers/UART.h >


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

/* RF settings */
#include "smartrf_settings/smartrf_settings.h"

/***** Defines *****/
/* Wake-on-Radio configuration */
#define WOR_WAKEUPS_PER_SECOND 2

/* TX number of random payload bytes */
#define PAYLOAD_LENGTH 30

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


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


/***** Variable declarations *****/
/* 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];
static uint16_t seqNumber;

/* RF driver objects and handles */
static RF_Object rfObject;
static RF_Handle rfHandle;

/* Pin driver objects and handles */
PIN_Handle ledPinHandle;
static PIN_Handle buttonPinHandle;
PIN_State ledPinState;
static PIN_State buttonPinState;

/* TX Semaphore */
static Semaphore_Struct txSemaphore;
static Semaphore_Handle txSemaphoreHandle;

/* Advanced TX command for sending long preamble */
static rfc_CMD_PROP_TX_ADV_t RF_cmdPropTxAdv;

/*
 * 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,
    Board_PIN_LED1 | 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_NEGEDGE,
    PIN_TERMINATE
};

char        input;
const char  echoPrompt[] = "Echoing characters:\r\n";
UART_Handle uart;
UART_Params uartParams;

/***** Function definitions *****/
/* Pin interrupt Callback function board buttons configured in the pinTable. */
void buttonCallbackFunction(PIN_Handle handle, PIN_Id pinId) {

    /* Simple debounce logic, only toggle if the button is still pushed (low) */
    CPUdelay((uint32_t)((48000000/3)*0.050f));
    if (!PIN_getInputValue(pinId)) {
        /* 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 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)
{
    UART_init();
    /* 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);
    }

    UART_write(uart, echoPrompt, sizeof(echoPrompt));
#if 0
    /* Initialize the display and try to open both UART and LCD types of display. */
    Display_Params params;
    Display_Params_init(&params);
    params.lineClearMode = DISPLAY_CLEAR_BOTH;
    Display_Handle uartDisplayHandle = Display_open(Display_Type_UART, &params);
    Display_Handle lcdDisplayHandle = Display_open(Display_Type_LCD, &params);

    /* Print initial display content on both UART and any LCD present */
    Display_printf(uartDisplayHandle, 0, 0, "Wake-on-Radio TX");
    Display_printf(uartDisplayHandle, 0, 0, "Pkts sent: %u", seqNumber);
    Display_printf(lcdDisplayHandle, 0, 0, "Wake-on-Radio TX");
    Display_printf(lcdDisplayHandle, 1, 0, "Pkts sent: %u", seqNumber);
#endif    /* 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);

    /* Request access to the radio */
#if defined(DeviceFamily_CC26X0R2)
    rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioSetup, &rfParams);
#else
    rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, &rfParams);
#endif// DeviceFamily_CC26X0R2

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

    /* Enter main TX loop */
    while(1)
    {
        RF_yield(rfHandle);        /* Wait for a button press */
        Semaphore_pend(txSemaphoreHandle, BIOS_WAIT_FOREVER);
#if 0        /* Create packet with incrementing sequence number and random payload */
        packet[0] = PAYLOAD_LENGTH;
        packet[1] = (uint8_t)(seqNumber >> 8);
        packet[2] = (uint8_t)(seqNumber++);
        uint8_t i;
        for (i = 3; i < PAYLOAD_LENGTH +1; i++)
        {
            packet[i] = rand();
        }
#else
        uint8_t i = 1;
              do
              {
                  UART_read(uart, &input, 1);
                  UART_write(uart, &input, 1);
                  packet[i++] = input;
              }
              while (input != '\r');
              UART_write(uart, &input, 6);
              packet[0] = i - 1;
              RF_cmdPropTxAdv.pktLen = packet[0] + 1;
#endif

        /* Send packet */
        RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropTxAdv, RF_PriorityNormal, NULL, 0);
#if 0
        /* Update display */
        Display_printf(uartDisplayHandle, 0, 0, "Pkts sent: %u", seqNumber);
        Display_printf(lcdDisplayHandle, 1, 0, "Pkts sent: %u", seqNumber);
#endif
        /* Toggle LED */
        PIN_setOutputValue(ledPinHandle, Board_PIN_LED1, !PIN_getOutputValue(Board_PIN_LED1));
    }
}

/* Copy the basic RX configuration from CMD_PROP_RX to CMD_PROP_RX_SNIFF command. */
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;
}

extern void rxTaskInit();
/*
 *  ======== main ========
 */
int main(void)
{
    /* Call driver init functions. */
    Board_initGeneral();
    Display_init();

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

    /* Initialize task */
    rxTaskInit();
    txTaskInit();

    /* Start BIOS */
    BIOS_start();

    return (0);
}


4. Rebuild and download rfWakeOnRadioTx into two LAUNCHXL-CC1310.

5. Open two application UART COM ports simulated by two LAUNCHXL-CC1310

6. You can press BTN-1 on one of LAUNCHXL-CC1310 to input any string ended with "enter" to send the string to another LAUNCHXL-CC1310 to print the received string on UART.


Tuesday, August 13, 2019

How to use usleep/sleep function in CC1310 TI 15.4 Stack

The following steps show you how to use usleep/sleep function in CC1310 TI 15.4 Stack:

1. Add "var Settings = xdc.useModule('ti.sysbios.posix.Settings');" into app.cfg
2. Add "#include <unistd.h>" in your C file.
3. You can use usleep or sleep function in your C file now.

Thursday, October 11, 2018

How to use serial bootloader mode to download binary to LAUNCHXL-CC1310/LAUNCHXL-CC2650 using Flash Programmer 2

The following steps show you how to use serial bootloader mode to download binary to LAUNCHXL-CC1310/LAUNCHXL-CC2650 using Flash Programmer 2.

1. Select XDS110 CC1310 connection to do mass erase.


2. Select CC1310 and connect it to XDS110 Class Application/User Uart.




3. Select binary to download and you should see "Sucess!" after download.


Thursday, April 19, 2018

Build and run 6lbr/Contiki-NG cc26xx-web-demo on Rasperry Pi with LAUNCHXL-CC1310/LAUNCHXL-CC2650

The following steps show how to build and run 6lbr/Contiki-NG cc26xx-web-demo on Rasperry Pi with LAUNCHXL-CC1310/LAUNCHXL-CC2650:

1. Build Contiki-NG slip radio for LAUNCHXL-CC1310 on InstantContiki 3.0 or Cygwin (you can refer here to setup Cygwin build environment)
  • 1.1 Do "git clone --recursive https://github.com/contiki-ng/contiki-ng"
  • 1.2 Switch to directory contiki-ng/
  • 1.3 Do "git submodule sync" and "git submodule update --init"
  • 1.4 Switch to directory contiki-ng/examples/slip-radio
  • 1.5 Since 6lbr/Contiki-NG only supports RPL-CLASSIC now, we use "make TARGET=cc26x0-cc13x0 srf06-cc26xx BOARD=launchpad/cc1310 MAKE_ROUTING=MAKE_ROUTING_RPL_CLASSIC  slip-radio.bin" to build slip radio for LAUNCHXL-CC1310.
  • 1.6 Download slip-radio.bin to one LAUNCHXL-CC1310 to act as slip radio for Raspberry Pi later.

2. Build Contiki-NG cc26x0-web-demo for LAUNCHXL-CC1310 on InstantContiki 3.0 or Cygwin
  • 2.1 Apply Fixing cc26xx 6lbr client example patch first.
  • 2.2 Switch to directory contiki-ng/examples/platform-specific/cc26xx/cc26x0-web-demo
  • 2.3 Since 6lbr/Contiki-NG only supports RPL-CLASSIC now, we use "make TARGET=srf06-cc26xx BOARD=launchpad/cc1310 MAKE_ROUTING=MAKE_ROUTING_RPL_CLASSIC  cc26xx-web-demo.bin" to build cc26xx-web-demo for LAUNCHXL-CC1310.
  • 2.4 Download cc26xx-web-demo.bin to another LAUNCHXL-CC1310 to join Raspberry Pi 6lbr later.

3. Build 6lbr/Contiki-NG on Rasperry Pi
  • 3.1 SSH login to Raspberry Pi.
  • 3.2 Change directory to home folder and git clone --recursive https://github.com/cetic/6lbr.git
  • 3.3 Change directory to 6lbr folder and do "git submodule update --init" git checkout contiki-ng
  • 3.4 Change directory to home folder and git clone --recursive https://github.com/cetic/contiki-ng.git
  • 3.5 Change directory to contiki-ng folder and do "git submodule update --init" git checkout sixlbr
  • 3.6 Change directory to 6lbr/examples/6lbr folder and run the following build command
    "make WITH_CONTIKI=0 CONTIKI=~/contiki-ng WERROR=0 all"
  • 3.7  After build successfully, do "sudo make install". You will see "install: cannot stat ‘tools/nvm_tool’: No such file or directory" issue since nvm_tool doens't make properly for current version. It might be fixed later but you can use nvm_tool built by previous 6lbr to do the following steps.
  • 3.8 Run "sudo /usr/lib/6lbr/bin/nvm_tool --update --channel 25 /etc/6lbr/nvm.dat" to change 6lbr/Contiki-NG to use channel 25.
  • 3.9 Run "/usr/lib/6lbr/bin/nvm_tool --print /etc/6lbr/nvm.dat" to make sure it switches to channel 25.
  • 3.10 Connect LAUNCHXL-CC1310 running slip radio to Raspberry Pi.
  • 3.11 Run "sudo service 6lbr start" to start 6lbr/Contiki-NG and you can use Firefox to access to [bbbb::100]


 4. Power on LAUNCHXL-CC1310 running cc26xx-web-demo and you will see it pops on sensors tab of 6lbr web page. You can test http or coap function on cc26xx-web-demo now.






Wednesday, November 29, 2017

Using Contiki UDP client to send ON/OFF command to remote UDP server to toggle LED on CC13xx/CC26xx.

The following steps show you how to revise Contiki UDP client/server examples to allow you send UART ON/OFF command to UDP client, UDP client sends ON/OFF command over the air to UDP server, and UDP server toggles red LED. The following tests are done using two LAUNCHXL-CC1310.

1. Revise the following red lines in udp-client.c
...
#include "net/ip/uip-udp-packet.h"
#include "sys/ctimer.h"
#include "dev/leds.h"
#ifdef WITH_COMPOWER
#include "powertrace.h"
#endif
#include
#include

...
static struct uip_udp_conn *client_conn;
static uip_ipaddr_t server_ipaddr;

char cmd[16];

/*---------------------------------------------------------------------------*/
PROCESS(udp_client_process, "UDP client process");
AUTOSTART_PROCESSES(&udp_client_process);
/*---------------------------------------------------------------------------*/
static int seq_id;
static int reply;
...

/*---------------------------------------------------------------------------*/
static void
send_packet(void *ptr)
{
  char buf[MAX_PAYLOAD_LEN];

#ifdef SERVER_REPLY
  uint8_t num_used = 0;
  uip_ds6_nbr_t *nbr;

  nbr = nbr_table_head(ds6_neighbors);
  while(nbr != NULL) {
    nbr = nbr_table_next(ds6_neighbors, nbr);
    num_used++;
  }

  if(seq_id > 0) {
    ANNOTATE("#A r=%d/%d,color=%s,n=%d %d\n", reply, seq_id,
             reply == seq_id ? "GREEN" : "RED", uip_ds6_route_num_routes(), num_used);
  }
#endif /* SERVER_REPLY */

  seq_id++;
  PRINTF("CMD:%s send to %d SEQ_ID:%d\n",cmd,
         server_ipaddr.u8[sizeof(server_ipaddr.u8) - 1], seq_id);
  sprintf(buf, "%s from the client SEQ_ID:%d ",cmd, seq_id);
  uip_udp_packet_sendto(client_conn, buf, strlen(buf),
                        &server_ipaddr, UIP_HTONS(UDP_SERVER_PORT));
}
/*---------------------------------------------------------------------------*/
...

/*---------------------------------------------------------------------------*/
PROCESS_THREAD(udp_client_process, ev, data)
{
  static struct etimer periodic;
  static struct ctimer backoff_timer;
#if WITH_COMPOWER
  static int print = 0;
#endif

  PROCESS_BEGIN();

  PROCESS_PAUSE();

  cc26xx_uart_set_input(serial_line_input_byte);
 
  set_global_address();

  PRINTF("UDP client process started nbr:%d routes:%d\n",
         NBR_TABLE_CONF_MAX_NEIGHBORS, UIP_CONF_MAX_ROUTES);

  print_local_addresses();

  /* new connection with remote host */
  client_conn = udp_new(NULL, UIP_HTONS(UDP_SERVER_PORT), NULL);
  if(client_conn == NULL) {
    PRINTF("No UDP connection available, exiting the process!\n");
    PROCESS_EXIT();
  }
  udp_bind(client_conn, UIP_HTONS(UDP_CLIENT_PORT));

  PRINTF("Created a connection with the server ");
  PRINT6ADDR(&client_conn->ripaddr);
  PRINTF(" local/remote port %u/%u\n",
    UIP_HTONS(client_conn->lport), UIP_HTONS(client_conn->rport));

#if WITH_COMPOWER
  powertrace_sniff(POWERTRACE_ON);
#endif

  etimer_set(&periodic, SEND_INTERVAL);
  while(1) {
    PROCESS_YIELD();
    if(ev == tcpip_event) {
      tcpip_handler();
    }

    if(ev == serial_line_event_message && data != NULL) {
      printf("command received:%s\n",(char *)data);
      
if(strcmp(data,"ON")==0){
         for(int i=0; i < 16 ; i=i+1) cmd[i]=0x0;
         cmd[0]=0x4F;
         cmd[1]=0x4E;
         leds_on(LEDS_RED);
      }else if(strcmp(data,"OFF")==0){
 
         for(int i=0; i < 16 ; i=i+1) cmd[i]=0x0;        
         cmd[0]=0x4F;
         cmd[1]=0x46;
         cmd[2]=0x46;
         leds_off(LEDS_RED);
      }
      send_packet(NULL); 

    }

    if(etimer_expired(&periodic)) {
      etimer_reset(&periodic);
      ctimer_set(&backoff_timer, SEND_TIME, send_packet, NULL);

#if WITH_COMPOWER
      if (print == 0) {
    powertrace_print("#P");
      }
      if (++print == 3) {
    print = 0;
      }
#endif

    }
  }

  PROCESS_END();
}
/*---------------------------------------------------------------------------*/

2. Build udp-client.bin by "make TARGET=srf06-cc26xx BOARD=launchpad/cc1310 udp-client.bin" and download udp-client.bin to one LAUNCHXL-CC1310.


3. Revise the following red lines in udp-server.c
...
#define DEBUG DEBUG_PRINT
#include "net/ip/uip-debug.h"
#include "dev/leds.h"

#define UIP_IP_BUF   ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
...
/*---------------------------------------------------------------------------*/
static void
tcpip_handler(void)
{
  char *appdata;

  if(uip_newdata()) {
    appdata = (char *)uip_appdata;
    appdata[uip_datalen()] = 0;
    PRINTF("DATA recv '%s' from ", appdata);
    if(appdata[0]==0x4F && appdata[1]==0x4E ){
        leds_on(LEDS_RED);
    }
    if(appdata[0]==0x4F && appdata[1]==0x46 && appdata[2]==0x46){
        leds_off(LEDS_RED);
    }
   
    PRINTF("%d",
           UIP_IP_BUF->srcipaddr.u8[sizeof(UIP_IP_BUF->srcipaddr.u8) - 1]);
    PRINTF("\n");
#if SERVER_REPLY
    PRINTF("DATA sending reply\n");
    uip_ipaddr_copy(&server_conn->ripaddr, &UIP_IP_BUF->srcipaddr);
    uip_udp_packet_send(server_conn, "Reply", sizeof("Reply"));
    uip_create_unspecified(&server_conn->ripaddr);
#endif
  }
}
/*---------------------------------------------------------------------------*/
...


4. Build udp-server.bin by "make TARGET=srf06-cc26xx BOARD=launchpad/cc1310 udp-server.bin" and download udp-server.bin to another LAUNCHXL-CC1310.

5. Start UDP server on one LAUNCHXL-CC1310 running udp-server.bin and start UDP client on another LAUNCHXL-CC1310 running udp-client.bin.

  

6. You can enter "ON" and "CTRL+Enter" to send ON command with end character "0x0A" to COM port of LAUNCHXL-CC1310 running UDP client and you will see red led is turned ON on another LAUNCHXL-CC1310 running UDP server.

7. You can enter "OFF" and "CTRL+Enter" to send OFF command with end character "0x0A" to COM port of LAUNCHXL-CC1310 running UDP client and you will see red led is turned OFF on another LAUNCHXL-CC1310 running UDP server.

Thursday, October 19, 2017

Using CC13xx/CC26xx running Contiki OS to toggle LED from UART.

The following example shows how to using CC13xx/CC26xx running Contiki OS to toggle LED from UART.

1. Replace the following code into hell-world.c

#include "contiki.h"
#include "dev/cc26xx-uart.h"
#include "dev/serial-line.h"
#include "dev/leds.h"

#include < stdio.h >/* For printf() */
#include  < string.h >


 PROCESS(test_serial, "Serial line test process");
 AUTOSTART_PROCESSES(&test_serial);

 PROCESS_THREAD(test_serial, ev, data)
 {
   PROCESS_BEGIN();
   cc26xx_uart_set_input(serial_line_input_byte);
  
   printf("Hello, world Serial line test\n");

   for(;;) {
     PROCESS_YIELD();
     if(ev == serial_line_event_message) {
       printf("received line: %s\n", (char *)data);
       if(strcmp(data,"ON")==0)
           leds_on(LEDS_GREEN);
       else if(strcmp(data,"OFF")==0)
           leds_off(LEDS_GREEN);
     }
   }
   PROCESS_END();
 }


2. Build hello-world.bin for LAUNCHXL-CC1310 using  "make TARGET=srf06-cc26xx BOARD=launchpad/cc1310 hello-world.bin"

3. Download hello-world.bin to LAUNCHXL-CC1310 using Flash Programmer 2.

4. Start a terminal tool like teraterm to connect to LAUNCHXL-CC1310 application virtual COM port..

5. Enter "ON" and "CTRL+Enter" to send ON command with end character "0x0A" to LAUNCHXL-CC1310 and you will see green led is turned on

6. Enter "OFF" and "CTRL+Enter" to send OFF command with end character "0x0A" to LAUNCHXL-CC1310 and you will see green led is turned on

Tuesday, September 6, 2016

How to porting collector example in TI-15.4 Stack from CC1310 LaunchPad to CC1310DK

You only have to revise the following red codes in  CC1310_LAUNCHXL.h to make it work. RLED on CC1310 LaunchPad is mapped to LED1 on CC1310DK, GLED on CC1310 LaunchPad is mapped to LED2 on CC1310DK, BTN-1 on  CC1310 LaunchPad is mapped to LEFT BTN on CC1310DK, and BTN-2 on  CC1310 LaunchPad is mapped to RIGHT BTN on CC1310DK.

/* Discrete outputs */
#define Board_RLED                  IOID_25
#define Board_GLED                  IOID_27
#define Board_LED_ON                1
#define Board_LED_OFF               0

/* Discrete inputs */
#define Board_BTN1                  IOID_15
#define Board_BTN2                  IOID_18

/* UART Board */
#define Board_UART_RX               IOID_2          /* RXD  */
#define Board_UART_TX               IOID_3          /* TXD  */
#define Board_UART_CTS              IOID_19         /* CTS  */
#define Board_UART_RTS              IOID_14         /* RTS */

/* SPI Board */
#define Board_SPI0_MISO             IOID_8          /* RF1.20 */
#define Board_SPI0_MOSI             IOID_9          /* RF1.18 */
#define Board_SPI0_CLK              IOID_10         /* RF1.16 */
#define Board_SPI0_CSN              PIN_UNASSIGNED
#define Board_SPI1_MISO             PIN_UNASSIGNED
#define Board_SPI1_MOSI             PIN_UNASSIGNED
#define Board_SPI1_CLK              PIN_UNASSIGNED
#define Board_SPI1_CSN              PIN_UNASSIGNED

/* I2C */
#define Board_I2C0_SCL0             IOID_4
#define Board_I2C0_SDA0             IOID_5

/* SPI */
#define Board_SPI_FLASH_CS          IOID_20
#define Board_FLASH_CS_ON           0
#define Board_FLASH_CS_OFF          1

/* Booster pack generic */
#define Board_DIO0                  IOID_0
#define Board_DIO1_RFSW             IOID_1
#define Board_DIO12                 IOID_12
#define Board_DIO15                 IOID_13
#define Board_DIO16_TDO             IOID_16
#define Board_DIO17_TDI             IOID_17
#define Board_DIO21                 IOID_21
#define Board_DIO22                 IOID_22

#define Board_DIO23_ANALOG          IOID_23
#define Board_DIO24_ANALOG          IOID_24
#define Board_DIO25_ANALOG          IOID_26
#define Board_DIO26_ANALOG          IOID_26
#define Board_DIO27_ANALOG          IOID_26
#define Board_DIO28_ANALOG          IOID_28
#define Board_DIO29_ANALOG          IOID_29
#define Board_DIO30_ANALOG          IOID_30

Wednesday, June 29, 2016

How to debug two CC1310 or CC2650 LaunchPads at the same PC with two CCS instance.

The following steps show you how to debug two CC1310 or CC2650 LaunchPads at the
same PC with two CCS instance.

1. Connect CC1310/CC2650 LaunchPad to PC and start Flash Programmer 2 to get serial number of XDS110 embedded on LaunchPa. In my example, it's L2003001.



2. Start first CCS instance and open a CC1310/CC2650 example. In this case, I use CC1310 Collector node in TI-15.4-stack. Click CC1310F128.ccxml under targetConfigs folder in Project Explore and click "Target Configuration:" to proceed next step.


3. Choose "Select by serial number" in combobox "Debug Probe Selection".


4. Key in serial number "L2003001" which specifies the LaunchPad you intend to download and debug in this project and save.


5. Open another CCS and do the same steps to another example. In my case, I use CC1310 Sensor node in TI-15.4-stack.

6. You can download and debug Collector and Sensor node on the same PC with two CCS instances.