Friday, February 14, 2020

Using EmberZnet DynamicMultiprotocolLightSoc example showing how to use custom token in EFR32 NVM3.

You can follow the steps to use custom token (using EFR32 NVM3) on EmberZnet DynamicMultiprotocolLightSoc example.

1. Create customer-token.h with the following defines and place it to project folder.

#define NVM3KEY_APP_VERSION_INFO  (NVM3KEY_DOMAIN_USER | 0x000A)
#if defined(DEFINETYPES)
typedef uint16_t tokenTypeAppVersionInfo;
#endif //DEFINETYPES
#ifdef DEFINETOKENS
DEFINE_BASIC_TOKEN(APP_VERSION_INFO,
                    tokenTypeAppVersionInfo,
                    0x0000)
#endif

2. Add customer-token.h to project include path and press "Generate" to generate codes.


3. You can use the following code to write and read the custom token.

    tokenTypeAppVersionInfo tokenVerInfo = 0x0101;
    halCommonSetToken(TOKEN_APP_VERSION_INFO, &tokenVerInfo);
    tokenTypeAppVersionInfo tokenVerInfoR;
    halCommonGetToken(&tokenVerInfoR, TOKEN_APP_VERSION_INFO);

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.


Wednesday, December 18, 2019

How to change CC26xx/CC13xx UART baudrate dynamically in your application.

The following steps show you how to change CC26xx/CC13xx UART baudrate dynamically in your application.

1. In port pininterrupt example into your CCS.

2. Add the following header files for UART and task related stuffs.

    #include <ti/sysbios/knl/Task.h>
    #include <ti/drivers/UART.h>
    #include <stdint.h>

3. Add the following defines and global variables for UART and task related stuffs.

    #define TASKSTACKSIZE     768
    uint32_t baudrate=115200;
    bool baudrate_change=false;
    UART_Handle uart;
    UART_Params uartParams;

    Task_Struct task0Struct;
    Char task0Stack[TASKSTACKSIZE];

4. Add the following red codes into buttonCallbackFxn to change baudrate when BTN1 is pressed.

            case Board_BUTTON1:
                currVal =  PIN_getOutputValue(Board_LED1);
                PIN_setOutputValue(ledPinHandle, Board_LED1, !currVal);
                if(baudrate==115200){
                    const char echoBaudrateChange[] = "\fChange Baudrate to 9600:\r\n";
                    UART_write(uart, echoBaudrateChange, sizeof(echoBaudrateChange));
                    baudrate=9600;
                }else{
                    const char echoBaudrateChange[] = "\fChange Baudrate to 115200:\r\n";
                    UART_write(uart, echoBaudrateChange, sizeof(echoBaudrateChange));
                    baudrate=115200;
                }
                baudrate_change=true;
                break;


5. Add the following function echoFxn()

Void echoFxn(UArg arg0, UArg arg1)
{
    char input;
    const char echoPrompt[] = "\fEchoing characters:\r\n";

    /* Create a UART with data processing off. */
    UART_Params_init(&uartParams);

RESTART_UART:
    uartParams.writeDataMode = UART_DATA_BINARY;
    uartParams.readDataMode = UART_DATA_BINARY;
    uartParams.readReturnMode = UART_RETURN_FULL;
    uartParams.readEcho = UART_ECHO_OFF;
    uartParams.baudRate = baudrate;
    uart = UART_open(Board_UART0, &uartParams);

    if (uart == NULL) {
        System_abort("Error opening the UART");
    }

    UART_write(uart, echoPrompt, sizeof(echoPrompt));

    /* Loop forever echoing */
    while (1) {
        if(baudrate_change){
            UART_close(uart);
            uart=NULL;
            baudrate_change=false;
            goto RESTART_UART;
        }
        UART_read(uart, &input, 1);
        UART_write(uart, &input, 1);
    }
}


6. Add the following red codes in main function to start UART task.

int main(void)
{
    Task_Params taskParams;
    /* Call board init functions */
    Board_initGeneral();
    Board_initUART();

    /* Construct BIOS objects */
    Task_Params_init(&taskParams);
    taskParams.stackSize = TASKSTACKSIZE;
    taskParams.stack = &task0Stack;
    Task_construct(&task0Struct, (Task_FuncPtr)echoFxn, &taskParams, NULL);
...
}


7. Build and download firmware into LaunchPad to test it.

Tuesday, December 17, 2019

How to create a periodic event to toggle BLE Advertising in CC26xx simple_peripheral example

The following steps show you how to create a periodic event to toggle BLE Advertising every 10 seconds in CC26xx simple_peripheral example.

In simple_peripheral.c, add the following codes:

1. Add "#define ADV_PERIODIC_EVT Event_Id_01" for new periodic event.

2. Add "#define ADV_PERIODIC_EVT_PERIOD 10000" to define the period as 10 seconds.

3. Add ADV_PERIODIC_EVT to Bitwise OR of all events to pend on.

    #define SBP_ALL_EVENTS       (SBP_ICALL_EVT        | \
                                                         SBP_QUEUE_EVT        | \
                                                         ADV_PERIODIC_EVT     | \
                                                         SBP_PERIODIC_EVT)

4. Add "advertEnabledPeriod = TRUE;" as a global variable for toggling BLE advertising.

5. Add "static Clock_Struct periodicClockAdv;" for periodic clock.

6. In SimplePeripheral_init(), add the following lines to start periodic event for toggling BLE advertising.

    Util_constructClock(&periodicClockAdv, SimplePeripheral_clockHandler,
                      ADV_PERIODIC_EVT_PERIOD, 0, false, ADV_PERIODIC_EVT);
    Util_startClock(&periodicClockAdv);



7.  Add the following codes in SimplePeripheral_taskFxn() to toggle BLE advertising in ADV_PERIODIC_EVT event which is triggered every 10 seconds.

      if (events & ADV_PERIODIC_EVT)
      {
        Util_startClock(&periodicClockAdv);
        if(advertEnabledPeriod==TRUE){
            advertEnabledPeriod=FALSE;
        } else {
            advertEnabledPeriod=TRUE;
        }
        GAPRole_SetParameter(GAPROLE_ADVERT_ENABLED, sizeof(uint8_t),
                                 &advertEnabledPeriod);

      }


8. After building and download hex into your CC26xx device, you can use SimpleLink Starter APP to scan and check if BLE advertising is toggled every 10 seconds.