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.
Tool/software:
Hi everyone,
I am working on the CC1352R to capture IQ samples, using the rfPacketRx
example from the SDK. I am following the TI document SWRA571.pdf. Currently, I receive data in the callback function, but when I try to print this data using Display_printf()
, the callback function stops. I believe this is happening due to buffer overwrites in the RF core, which then causes the callback to stop. I am looking for guidance on how to handle the buffer so that data is received continuously and can be sent to UART without interruptions. Any help on this issue would be greatly appreciated.
Hi Yasir,
as you are in continuous Rx the radio core will forward all incoming data to the application and trigger the callback function to write the data to the buffer. If you slow down the callback function by any data processing it will end in buffer overflow. If you want to observe how fast the data is received I would suggest you to implement toggling an led in the callback function.
Printing data on the UART is a very slow process compared and if you need to implement it then it must be outside of the callback function so that you are not interrupting it.
Alternatively you can use the memory overview to copy the received data directly from the buffer.
Kind regards,
Theo
#include <stdlib.h> #include <stdio.h> #include <FreeRTOS.h> #include <task.h> #include <semphr.h> #include <ti/drivers/rf/RF.h> #include <ti/drivers/GPIO.h> #include <ti/drivers/UART2.h> #include <ti/display/Display.h> #include "FreeRTOSConfig.h" #include DeviceFamily_constructPath(driverlib/rf_prop_mailbox.h) #include "ti_drivers_config.h" /* Application Header files */ #include "RFQueue.h" #include "smartrf_settings/smartrf_settings.h" /***** Defines *****/ /* Packet RX Configuration */ #define DATA_ENTRY_HEADER_SIZE 8 /* Constant header size of a Generic Data Entry */ #define MAX_LENGTH 30 /* 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 2 /* The Data Entries data field will contain: * 1 Header byte (RF_cmdPropRx.rxConf.bIncludeHdr = 0x1) * Max 30 payload bytes * 1 status byte (RF_cmdPropRx.rxConf.bAppendStatus = 0x1) */ #define NUMBER_OF_SAMPLE_PAIRS 50 #define MAX_DIGITS 6 #define PARTIAL_RX_ENTRY_HEADER_SIZE 12 /***** Prototypes *****/ static void callback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e); void print_samples(UART2_Handle uart); void dataProcessingTask(void *pvParameters); /***** Variable declarations *****/ static RF_Object rfObject; static RF_Handle rfHandle; /* 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))); #pragma DATA_ALIGN (rxDataEntryBuf1, 4); static uint8_t rxDataEntryBuf1[PARTIAL_RX_ENTRY_HEADER_SIZE + (NUMBER_OF_SAMPLE_PAIRS * 3)]; #pragma DATA_ALIGN (rxDataEntryBuf2, 4); static uint8_t rxDataEntryBuf2[PARTIAL_RX_ENTRY_HEADER_SIZE + (NUMBER_OF_SAMPLE_PAIRS * 3)]; #else #error This compiler is not supported. #endif rfc_dataEntryPartial_t* partialReadEntry1 = (rfc_dataEntryPartial_t*)&rxDataEntryBuf1; rfc_dataEntryPartial_t* partialReadEntry2 = (rfc_dataEntryPartial_t*)&rxDataEntryBuf2; rfc_dataEntryPartial_t* currentReadEntry = (rfc_dataEntryPartial_t*)&rxDataEntryBuf1; /* Receive dataQueue for RF Core to fill in data */ static dataQueue_t dataQueue; static rfc_dataEntryGeneral_t* currentDataEntry; static uint8_t packetLength; static uint8_t* packetDataPointer; SemaphoreHandle_t bufferSemaphore; //static uint8_t packet[MAX_LENGTH + NUM_APPENDED_BYTES - 1]; /* The length byte is stored in a separate variable */ /***** Function definitions *****/ #define NUMBER_OF_BUFFERS 5 static uint16_t iSamples[NUMBER_OF_SAMPLE_PAIRS*NUMBER_OF_BUFFERS]; static uint16_t qSamples[NUMBER_OF_SAMPLE_PAIRS*NUMBER_OF_BUFFERS]; static uint8_t buffer1[NUMBER_OF_SAMPLE_PAIRS * 3]; static uint8_t buffer2[NUMBER_OF_SAMPLE_PAIRS * 3]; static uint8_t *activeBuffer; static uint8_t *processingBuffer; //#define NUMBER_OF_SAMPLE_PAIRS 8 UART2_Handle uart; UART2_Params uartParams; uint32_t status = UART2_STATUS_SUCCESS; Display_Handle hSerial; uint32_t bufferVersion = 0; uint32_t counter = 0; void dataProcessingTask(void *pvParameters) { while(1) { if (xSemaphoreTake(bufferSemaphore, portMAX_DELAY) == pdTRUE) { print_samples(uart); } else { Display_printf(hSerial, 0, 0, "Failed to take semaphore"); } vTaskDelay(1); } } void *mainThread(void *arg0) { bufferSemaphore = xSemaphoreCreateBinary(); if (bufferSemaphore == NULL) { // Handle error: semaphore creation failed while (1); } activeBuffer = buffer1; processingBuffer = buffer2; xTaskCreate(dataProcessingTask, "DataProcessingTask", configMINIMAL_STACK_SIZE + 100, NULL, 1, NULL); Display_init(); /* Initialize display and try to open both UART and LCD types of display. */ Display_Params params; Display_Params_init(¶ms); hSerial = Display_open(Display_Type_UART, ¶ms); RF_Params rfParams; RF_Params_init(&rfParams); partialReadEntry1->length = (NUMBER_OF_SAMPLE_PAIRS * 3) + 4; partialReadEntry1->config.type = DATA_ENTRY_TYPE_PARTIAL; partialReadEntry1->status = DATA_ENTRY_PENDING; partialReadEntry2->length = (NUMBER_OF_SAMPLE_PAIRS * 3) + 4; partialReadEntry2->config.type = DATA_ENTRY_TYPE_PARTIAL; partialReadEntry2->status = DATA_ENTRY_PENDING; partialReadEntry1->pNextEntry = (uint8_t*)partialReadEntry2; partialReadEntry2->pNextEntry = (uint8_t*)partialReadEntry1; dataQueue.pCurrEntry = (uint8_t*)partialReadEntry1; dataQueue.pLastEntry = NULL; GPIO_init(); GPIO_setConfig(CONFIG_GPIO_RLED, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW); GPIO_write(CONFIG_GPIO_RLED, CONFIG_GPIO_LED_OFF); // 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); // } /* Modify CMD_PROP_RX command for application needs */ /* Set the Data Entity queue for received data */ RF_cmdPropRx.pQueue = &dataQueue; // /* Discard ignored packets from Rx queue */ // RF_cmdPropRx.rxConf.bAutoFlushIgnored = 1; // /* Discard packets with CRC error from Rx queue */ // RF_cmdPropRx.rxConf.bAutoFlushCrcErr = 1; // /* Implement packet length filtering to avoid PROP_ERROR_RXBUF */ // RF_cmdPropRx.maxPktLen = MAX_LENGTH; // RF_cmdPropRx.pktConf.bRepeatOk = 1; // RF_cmdPropRx.pktConf.bRepeatNok = 1; /* 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_postCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0); RF_EventMask terminationReason = RF_EventCmdAborted | RF_EventCmdPreempted; terminationReason = RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropRx, RF_PriorityNormal, &callback, RF_EventRxEntryDone); // while(( terminationReason & RF_EventCmdAborted ) && ( terminationReason & RF_EventCmdPreempted )) // { // /* Enter RX mode and stay forever in RX */ // // Re-run if command was aborted due to SW TCXO compensation // terminationReason = RF_runCmd(rfHandle, (RF_Op*)&RF_cmdPropRx, // RF_PriorityNormal, &callback, // RF_EventRxEntryDone); // } switch(terminationReason) { case RF_EventLastCmdDone: // A stand-alone radio operation command or the last radio // operation command in a chain finished. break; case RF_EventCmdCancelled: // Command cancelled before it was started; it can be caused // by RF_cancelCmd() or RF_flushCmd(). break; case RF_EventCmdAborted: // Abrupt command termination caused by RF_cancelCmd() or // RF_flushCmd(). break; case RF_EventCmdStopped: // Graceful command termination caused by RF_cancelCmd() or // RF_flushCmd(). break; default: // Uncaught error event while(1); } uint32_t cmdStatus = ((volatile RF_Op*)&RF_cmdPropRx)->status; switch(cmdStatus) { case PROP_DONE_OK: // Packet received with CRC OK break; case PROP_DONE_RXERR: // Packet received with CRC error break; case PROP_DONE_RXTIMEOUT: // Observed end trigger while in sync search break; case PROP_DONE_BREAK: // Observed end trigger while receiving packet when the command is // configured with endType set to 1 break; case PROP_DONE_ENDED: // Received packet after having observed the end trigger; if the // command is configured with endType set to 0, the end trigger // will not terminate an ongoing reception break; case PROP_DONE_STOPPED: // received CMD_STOP after command started and, if sync found, // packet is received break; case PROP_DONE_ABORT: // Received CMD_ABORT after command started break; case PROP_ERROR_RXBUF: // No RX buffer large enough for the received data available at // the start of a packet break; case PROP_ERROR_RXFULL: // Out of RX buffer space during reception in a partial read break; case PROP_ERROR_PAR: // Observed illegal parameter break; case PROP_ERROR_NO_SETUP: // Command sent without setting up the radio in a supported // mode using CMD_PROP_RADIO_SETUP or CMD_RADIO_SETUP break; case PROP_ERROR_NO_FS: // Command sent without the synthesizer being programmed break; case PROP_ERROR_RXOVF: // RX overflow observed during operation break; default: // Uncaught error event - these could come from the // pool of states defined in rf_mailbox.h while(1); } while(1); } void uint16_to_str(uint16_t value, char *buffer) { int pos = 0; // Convert integer to string by extracting digits from the right do { buffer[pos++] = (value % 10) + '0'; value /= 10; } while (value > 0 && pos < MAX_DIGITS - 1); // Reverse the string as we built it backward for (int i = 0; i < pos / 2; i++) { char temp = buffer[i]; buffer[i] = buffer[pos - i - 1]; buffer[pos - i - 1] = temp; } buffer[pos] = '\0'; // Null-terminate the string } void print_samples(UART2_Handle uart) { UART2_write(uart, "iSample qSample\n", 19, &bytesWritten); UART2_write(uart, "------------------\n", 19, &bytesWritten); // Loop through the iSamples and qSamples arrays for (int i = 0; i < NUMBER_OF_SAMPLE_PAIRS * NUMBER_OF_BUFFERS; i++) { //Display_printf(hSerial, 0, 0, "%5d %5d\n", iSamples[i], qSamples[i]); Display_printf(hSerial, 0, 0, "Buffer[%d] = %d", i, processingBuffer[i]); } } //static uint16_t index = 0; void callback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e) { if (e & RF_EventRxEntryDone) { bufferVersion++; GPIO_write(CONFIG_GPIO_RLED, CONFIG_GPIO_LED_ON); //GPIO_toggle(CONFIG_GPIO_RLED); //status = UART2_write(uart, input, sizeof(input), &bytesWritten); // Get a pointer to the first IQ sample byte packetDataPointer = ¤tReadEntry->rxData; memcpy(activeBuffer, packetDataPointer, (NUMBER_OF_SAMPLE_PAIRS * 3)); uint8_t *temp = activeBuffer; activeBuffer = processingBuffer; processingBuffer = temp; GPIO_write(CONFIG_GPIO_RLED, CONFIG_GPIO_LED_OFF); xSemaphoreGiveFromISR(bufferSemaphore, NULL); // // RFQueue_nextEntry(); currentReadEntry->status = DATA_ENTRY_PENDING; currentReadEntry = (rfc_dataEntryPartial_t*)currentReadEntry->pNextEntry; } }
Hi @Theo Lange,
Thank you for your quick reply. I have not processed much in the callback function. I am using a semaphore for synchronization. I copy data to a buffer, signal to give the semaphore, and then print the contents of the buffer on UART to see what’s inside. I will retrieve IQ samples later. However, the callback stops after a while, and nothing happens. I have attached the code that I am using with it. If you could point out any potential issues if I am doing something wrong or any alternative approach please let me know.
Thank you
When you stop getting callbacks, I assume that the status of the RX command is:
RF_cmdPropRx.status = 0x3802 (ROP_ERROR_RXFULL)
Which indicates that you are out of RX buffer during reception in a partial read buffer.
This again, is most likely because stuff in your application is taking too long (Display_printf) so that your buffers are not released fast enough
currentReadEntry->status = DATA_ENTRY_PENDING;
currentReadEntry = (rfc_dataEntryPartial_t*)currentReadEntry->pNextEntry;
If you want to print the received IQ samples over UART, you should do this AFTER you have received the samples that you want to view.
I do not think you are able to print this while handling the callback at a fast enough speed.
siri
So, Is it not possible to get IQ samples and send them to UART in continuous mode? I wanted to analyze IQ sample data in constant mode, It should be like a receiver that always looks for a data value.
If I make changes in RF configurations like decreasing symbol rate make it possible by slowing the interrupt of the callback function?
I guess that depends on your UART code, the UART speed, the data rate you are using, your buffer sizes etc.
I am simply saying that if you see a problem that the callback suddenly stops, that most likely means that the radio has exit RX state due to an error, and that this error most likely is an overflow (since RX is configured for infinite mode, it will not exit unless an error occurs).
To confirm this I have asked you to check the status of the RX command when the error occurs.
As the app note state, we will not provide any example code etc. on how to handle/process the incoming data. We simply show how you can get hold of the data.
Siri