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:
- The LCD does not update to "Receiving..." even though packets are being sent.
- 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.
- 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
}
}