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.

LP-EM-CC1354P10: Tx-Rx integration using onboard GPIO LED's (Walkie-Talkie project help)

Part Number: LP-EM-CC1354P10


Tool/software:

Hi there!

I'm a student at Texas A&M, and I'm working on an RF project using the CC1354P10-1 LaunchPad. I'm using the rfEchoTx.c demo as a foundation and integrating it with an LCD display, which I built a driver for last semester.

Project Goal:

The goal is to create a walkie-talkie-style network, where each LaunchPad can transmit and receive audio packets dynamically. The LCD should update based on the device’s state, showing "Transmitting...", "Receiving...", or a default message "Push-To-Talk" when idle. I wanted to first start using LED's to indicate these states as well. Green when transmitting, Red when receiving, and toggling between red and green when idle. When I press the button on one launchpad, it will enter transmit mode, while the other launchpad will enter receiving mode. The idle and transmitting states work as expected, but the receiving state does not. 

Issue I'm Facing:

I'm currently experiencing issues with RF reception handling. Specifically:

  1. The LCD does not update to "Receiving..." even though packets are being sent.
  2. The Red LED (CONFIG_GPIO_RLED) does not stay ON when receiving. Instead, it rapidly toggles between red and green, indicating that the launchpad IS receiving at some capacity, but the logic is not executing as expected. The red LED should simply stay on when receiving without blinking/toggling between red and green.
  3. RF reception seems inconsistent, and I suspect the issue is in my rfCallback() function.

Here is my code:

#include <stdlib.h>
#include <stdint.h>
#include <stddef.h>
#include <stdio.h>
#include <unistd.h>

/* TI Drivers */
#include <ti/drivers/rf/RF.h>
#include <ti/drivers/GPIO.h>
#include <ti/drivers/I2C.h>
#include "ti_drivers_config.h"
#include <ti_radio_config.h>

/* Custom LCD library */
#include "lcd.h"

/* Packet Configuration */
#define PAYLOAD_LENGTH 30
#define PACKET_INTERVAL (uint32_t)(4000000 * 1.0f)
#define RX_TIMEOUT (uint32_t)(4000000 * 0.5f)
#define NUM_DATA_ENTRIES 2
#define NUM_APPENDED_BYTES 2

/* LED Blinking Interval */
#define LED_TOGGLE_INTERVAL 500000 // 500ms

/* Echo Mode Hold Time */
#define ECHO_HOLD_TIME (uint32_t)(4000000 * 0.2f) // 200ms delay

/* Radio States */
typedef enum {
LISTEN_MODE,
TRANSMIT_MODE,
ECHO_MODE
} RadioState;

/* Global Variables */
static RF_Object rfObject;
static RF_Handle rfHandle;
static RadioState radioState = LISTEN_MODE;
static uint8_t txPacket[PAYLOAD_LENGTH];
static uint16_t seqNumber;
static dataQueue_t dataQueue;
static rfc_propRxOutput_t rxStatistics;
static volatile bool buttonPressed = false;
static volatile bool isReceiving = false;
static uint32_t lastStateChangeTime = 0;
static I2C_Handle i2cHandle; // Global I2C handle

/* Function Prototypes */
static void rfCallback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e);
static void buttonCallback(uint_least8_t index);
void setupRadio();
void transmitPacket();
void receivePacket();
void echoPacket();
void updateLEDState();
void holdEchoMode();
void displayDefaultMessage();
void displayTransmittingMessage();
void displayReceivingMessage();

/* Button Interrupt Handler */
static void buttonCallback(uint_least8_t index) {
buttonPressed = !buttonPressed; // Toggle transmit state
}

/* Radio Event Callback */
/* Radio Event Callback */
/* Radio Event Callback */
static void rfCallback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e) {
if (e & RF_EventRxEntryDone) {
GPIO_write(CONFIG_GPIO_RLED, CONFIG_GPIO_LED_ON); // **Red ON when Receiving**
usleep(50000); // **Brief delay**
GPIO_write(CONFIG_GPIO_RLED, CONFIG_GPIO_LED_OFF);

radioState = ECHO_MODE;
isReceiving = true;
lastStateChangeTime = RF_getCurrentTime();
updateLEDState();
displayReceivingMessage();
}


else if (e & RF_EventCmdDone) {
if (radioState == TRANSMIT_MODE) {
// **Stay in transmit mode until button release**
radioState = TRANSMIT_MODE;
}
else if (radioState == ECHO_MODE) {
isReceiving = false; // **Exit receive mode**
radioState = LISTEN_MODE;
displayDefaultMessage();
}
}
}

/* Hold Echo Mode for a Short Time */
void holdEchoMode() {
while ((RF_getCurrentTime() - lastStateChangeTime) < ECHO_HOLD_TIME) {
// Do nothing (hold ECHO_MODE)

}
radioState = LISTEN_MODE; // Only switch after delay
displayDefaultMessage();
}

/* Initialize RF */
void setupRadio() {
RF_Params rfParams;
RF_Params_init(&rfParams);
rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, &rfParams);
RF_postCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0);
}

/* Send Packet */
void transmitPacket() {
txPacket[0] = (uint8_t)(seqNumber >> 8);
txPacket[1] = (uint8_t)(seqNumber++);

for (uint8_t i = 2; i < PAYLOAD_LENGTH; i++) {
txPacket[i] = rand();
}

RF_cmdPropTx.pktLen = PAYLOAD_LENGTH;
RF_cmdPropTx.pPkt = txPacket;
RF_cmdPropTx.startTrigger.triggerType = TRIG_NOW;

RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropTx, RF_PriorityNormal, rfCallback, RF_EventCmdDone);
}

/* Echo Packet */
void echoPacket() {
RF_cmdPropTx.pktLen = PAYLOAD_LENGTH;
RF_cmdPropTx.pPkt = txPacket;
RF_cmdPropTx.startTrigger.triggerType = TRIG_NOW;

RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropTx, RF_PriorityNormal, rfCallback, RF_EventCmdDone);
}

/* Receive Packet */
void receivePacket() {
if (isReceiving) {
return;
}

RF_cmdPropRx.pQueue = &dataQueue;
RF_cmdPropRx.rxConf.bAutoFlushIgnored = 1;
RF_cmdPropRx.rxConf.bAutoFlushCrcErr = 1;
RF_cmdPropRx.maxPktLen = PAYLOAD_LENGTH;
RF_cmdPropRx.pOutput = (uint8_t *)&rxStatistics;
RF_cmdPropRx.endTrigger.triggerType = TRIG_REL_PREVEND;
RF_cmdPropRx.endTime = RX_TIMEOUT;

RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropRx, RF_PriorityNormal, rfCallback, RF_EventRxEntryDone);
}

/* Update LED Behavior */
void updateLEDState() {
static uint32_t lastToggleTime = 0;

if (radioState == TRANSMIT_MODE) {
GPIO_write(CONFIG_GPIO_GLED, CONFIG_GPIO_LED_ON);
GPIO_write(CONFIG_GPIO_RLED, CONFIG_GPIO_LED_OFF);
}
else if (radioState == ECHO_MODE || isReceiving) {
GPIO_write(CONFIG_GPIO_GLED, CONFIG_GPIO_LED_OFF);
GPIO_write(CONFIG_GPIO_RLED, CONFIG_GPIO_LED_ON);
}
else if (radioState == LISTEN_MODE && !isReceiving) {
if ((RF_getCurrentTime() - lastToggleTime) > LED_TOGGLE_INTERVAL) {
GPIO_toggle(CONFIG_GPIO_GLED);
GPIO_toggle(CONFIG_GPIO_RLED);
lastToggleTime = RF_getCurrentTime();
}
}

}


/* Display Default Message */
void displayDefaultMessage(void) {
LCD_setCursor(i2cHandle, 0, 0); // Move cursor to line 1
LCD_print(i2cHandle, "Push-To-Talk "); // Extra spaces to overwrite old text
}

/* Display Transmitting Message */
void displayTransmittingMessage(void) {
LCD_setCursor(i2cHandle, 0, 0); // Move cursor to line 1
LCD_print(i2cHandle, "Transmitting..");
}


/* Display Receiving Message */
void displayReceivingMessage(void) {
LCD_setCursor(i2cHandle, 0, 0); // Move cursor to line 1
LCD_print(i2cHandle, "Receiving... ");
}

/* Main Program */
void *mainThread(void *arg0) {
/* Initialize peripherals */
GPIO_init();
I2C_init();

/* Initialize I2C parameters */
I2C_Params i2cParams;
I2C_Params_init(&i2cParams);
i2cParams.bitRate = I2C_100kHz;

/* Open I2C instance */
i2cHandle = I2C_open(CONFIG_I2C_1, &i2cParams);
if (i2cHandle == NULL) {
printf("I2C Open failed!\n");
while (1);
}

/* Configure the button pin and register callback */
GPIO_setConfig(CONFIG_GPIO_BUTTON_0, GPIO_CFG_IN_PU | GPIO_CFG_IN_INT_BOTH_EDGES);
GPIO_setCallback(CONFIG_GPIO_BUTTON_0, buttonCallback);
GPIO_enableInt(CONFIG_GPIO_BUTTON_0); // Enable interrupts for the button

/* Initialize the LCD */
LCD_init(i2cHandle);

/* Display the default message */
displayDefaultMessage();

/* Initialize RF */
setupRadio();

while (1) {
if (buttonPressed) {
radioState = TRANSMIT_MODE;
isReceiving = false;
transmitPacket();
displayTransmittingMessage();
}
else if (radioState == ECHO_MODE) {
echoPacket();
holdEchoMode(); // Ensures Echo Mode is held before returning to LISTEN_MODE
}
else if (!isReceiving) {

radioState = LISTEN_MODE;
displayDefaultMessage();
receivePacket();

}

updateLEDState();
usleep(50000); // Sleep for 50 ms to reduce CPU usage
}
}

  • I am afraid it is not possible to tell you from just looking at your code what is going wrong.

    You will simply need to try to narrow down the problem yourself and then we can try to help you if you can figure out what is failing.

    If your problem seem related to your rx code, you should try to debug this without anything else going on in your project.

    Simply implement code that put one board in RX, and have the other board transmit 1 packet every time the button is being pushed.

    Make sure that you not only receive the packet OK that you are sending, but also that you handle all possible error cases correctly (if you receive a packet with CRC error, a packet that is no room for in the data entry, no more available data entries etc.)

    Once this is working you can add more of your protocol. A good idea is to use toggling of pins before and after calling functions, in callback etc. and then use a logic analyser to monitor these signals, this will in most cases give you good indication as to what goes wrong.

    Routing out the LNA and PA signals from the RF Core (Routing RF Core Signals to Physical Pins — SimpleLinkTm CC13XX/CC26XX SDK Proprietary RF User's Guide 7.30.00 documentation) is always good for debugging as this will tell you what state the radio is in.

    You should monitor these signals both on the receiver and the transmitter at the same time.

    Just looking briefly at your code, you should not use usleep in your callback, and you should also consider moving the LCD stuff out of the callback (do not call blocking functions in a callback))

    Siri

  • Hi Siri. I have been trying to narrow down the problem over the last few days. I added UART debugging statements to try to figure out what the problem is and I will show you the current state of my code. I have narrowed down where the problem lies between a few functions:

    void receivePacket() {
    uartPrint("[RX] Receive Packet Start\r\n");
    if (isReceiving) {
    uartPrint("[RX] Already Receiving, Skipping\r\n");
    return;
    }

    RF_cmdPropRx.pQueue = &dataQueue;
    RF_cmdPropRx.rxConf.bAutoFlushIgnored = 1;
    RF_cmdPropRx.rxConf.bAutoFlushCrcErr = 1;
    RF_cmdPropRx.maxPktLen = PAYLOAD_LENGTH;
    RF_cmdPropRx.pOutput = (uint8_t *)&rxStatistics;
    RF_cmdPropRx.endTrigger.triggerType = TRIG_REL_PREVEND;
    RF_cmdPropRx.endTime = RX_TIMEOUT;

    uartPrint("[RX] Running RF Command...\r\n");
    RF_CmdHandle cmd = RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropRx, RF_PriorityNormal, rfCallback, RF_EventRxEntryDone);

    if (cmd < 0) {
    uartPrint("[RX] ERROR: RF_runCmd failed!\r\n");
    } else {
    uartPrint("[RX] RF Command Success\r\n");
    }
    uartPrint("[RX] Packet Ready to Receive\r\n");
    uartPrint("[RX] RF Command Handle: ");
    char buffer[20];
    snprintf(buffer, sizeof(buffer), "%d\r\n", cmd);
    uartPrint(buffer);
    }

    void transmitPacket() {
    uartPrint("[TX] Transmit Packet Start\r\n");
    txPacket[0] = (uint8_t)(seqNumber >> 8);
    txPacket[1] = (uint8_t)(seqNumber++);

    for (uint8_t i = 2; i < PAYLOAD_LENGTH; i++) {
    txPacket[i] = rand();
    }

    RF_cmdPropTx.pktLen = PAYLOAD_LENGTH;
    RF_cmdPropTx.pPkt = txPacket;
    RF_cmdPropTx.startTrigger.triggerType = TRIG_NOW;

    uartPrint("[TX] Running RF Command...\r\n");
    RF_CmdHandle cmd = RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropTx, RF_PriorityNormal, rfCallback, RF_EventCmdDone);

    if (cmd < 0) {
    uartPrint("[TX] ERROR: RF_runCmd failed!\r\n");
    } else {
    uartPrint("[TX] RF Command Success\r\n");
    }
    uartPrint("[TX] Packet Sent\r\n");
    }

    static void rfCallback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e) {
    if (e & RF_EventRxEntryDone) {
    GPIO_write(CONFIG_GPIO_RLED, CONFIG_GPIO_LED_ON); // **Red ON when Receiving**
    usleep(50000); // **Brief delay**
    GPIO_write(CONFIG_GPIO_RLED, CONFIG_GPIO_LED_OFF);

    radioState = ECHO_MODE;
    isReceiving = true;
    lastStateChangeTime = RF_getCurrentTime();
    updateLEDState();
    displayReceivingMessage();
    } else if (e & RF_EventCmdDone) {
    if (radioState == TRANSMIT_MODE) {
    // **Stay in transmit mode until button release**
    radioState = TRANSMIT_MODE;
    } else if (radioState == ECHO_MODE) {
    isReceiving = false; // **Exit receive mode**
    radioState = LISTEN_MODE;
    displayDefaultMessage();
    }
    }
    }

    I am almost certain the problem lies in receivepacket()

    When idle, this is the serial output: 

    [RX] RF Command Success
    [RX] Packet Ready to Receive
    [RX] RF Command Handle: 2
    [RX] Receive Packet Start
    [RX] Running RF Command...
    [RX] RF Command Success
    [RX] Packet Ready to Receive
    [RX] RF Command Handle: 2
    [RX] Receive Packet Start
    [RX] Running RF Command...
    [RX] RF Command Success
    [RX] Packet Ready to Receive
    [RX] RF Command Handle: 2
    [RX] Receive Packet Start
    [RX] Running RF Command...
    [RX] RF Command Success
    [RX] Packet Ready to Receive
    [RX] RF Command Handle: 2
    [RX] Receive Packet Start
    [RX] Running RF Command...

    This terminal output shows a repeating cycle of receiving operations. The system continuously attempts to receive packets, prints a success message when the RF command is executed, indicates that a packet is ready to receive, and displays the RF command handle (value 2). This loop continues indefinitely, suggesting the device is in a constant receive state, even when no new packets are being transmitted. When the launchpad is receiving a signal from another, the speed of the serial output increases but remains the same cycle. When transmitting, this is the output: 


    [Main] Button Pressed**
    [TX] Transmit Packet Start**
    [TX] Running RF Command...**
    [TX] RF Command Success**
    [TX] Packet Sent**

    This indicates that each time the button is pressed, the device starts the transmission process, runs the RF command successfully, and sends a packet. The repetition of these lines means that the button is being pressed, triggering the transmit sequence each time.

    For reference, here is my main loop:  while (1) {
    if (buttonPressed) {
    radioState = TRANSMIT_MODE;
    isReceiving = false;
    uartPrint("[Main] Button Pressed\r\n");
    transmitPacket();
    displayTransmittingMessage();
    } else if (radioState == ECHO_MODE) {
    echoPacket();
    holdEchoMode();
    } else if (!isReceiving) {
    radioState = LISTEN_MODE;
    displayDefaultMessage();
    receivePacket();
    }
    updateLEDState();
    usleep(50000); // Sleep for 50 ms
    }
    Any help or debugging suggestions would be greatly appreciated

  • Hi

    I already gave you debugging hints, but you have not followed them (see my first answer).

    Printing stuff to the UART is not a good way of debugging, as this take much time, and does not tell you when things are happening.

    I cannot see anywhere in your callback that you are handling the queue.

    Also, what is the status of your rx command?

    Siri