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.
Hi,
We are developing a wireless m-bus application using the CC1310 and the example provided in the application note 'CC13xx Combined wM-Bus C-Mode and T-Mode' including
https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/689154/cc1310-require-partial-mode-example-of-cc1310
We are able to receive packages but are loosing some once in a while, and would like some advice.
The example is using a thread to activate the radio and a callback every time a package is received, but we have extended the code to handle errors and crc checks and this might be the cause.
Is there a way to use 'partial read' in a back-to-back receive setup?
We have tried to use bRepeatNok/bRepeatOk without luck, but can the callback be reactivated in the callback itself.
Regards Peter
I have checked with R&D and there should no be any reasons for not using repeat mode together with partial read entries. However, we have no code examples for this and have not tested this.
I would assume that it would complicate the code a bit, when it comes to keeping track of the data queues etc.
I cannot see why it should be necessary either. You should not do a lot of processing in the callback, but move it to somewhere else in the application. Then you can restart RX once a packet is received, and then process the received packet, while the RF core is restarted and a receiving a new packet.
Siri
Hi Siri,
Thank you for the fast reply, I'll try it out.
What is the best way to stop and reinitialize the radio in the callback. Currently I'm just setting rxDone and partialReadEntry->status = DATA_ENTRY_PENDING, but is there a better way?
Regards Peter
Hi Peter
I am not sure I understand what you want to do in the callback. Are you not following the example in the thread you were linking to?
There you set the length in the callback like this:
RF_runImmediateCmd(rfHandle, (uint32_t*)&RF_cmdPropSetLen);
This will make sure that the radio exit RX automatically when the correct number of bytes have been received, so you do not have to stop the radio manually.
I did some testing with the repeat mode today, and discovered that this cannot be used when using the SET_LEN command, so you will need to set both repeat modes to 0.
BR
Siri
Hi Siri,
Yes I'm following the example and using the
RF_runImmediateCmd(rfHandle, (uint32_t*)&RF_cmdPropSetLen);
and it works ok, but in some situations an error occurs and I would like to reinitialize before the entire package is received.
Best regards Peter
You should use the RF_cancelCmd to exit RX.
I am working on a more complete code example that also have some error handling in it, and can post it here when it is done
Siri
Hi Siri,
Thank you very much, I really appreciate your help and would look forward to see the example you are working on.
Regards Peter
Good morning,
I've changed the code slightly but there is still a few packages lost. Do you have any suggestions to the code below?
/** * @file protocol/sndp/src/SndpWMBus.c * @brief WMBus message parser * @copyright (C) 2023 ReMoni ApS. * * These computer program listings and specifications, are the property of * ReMoni ApS and shall not be reproduced or copied or used in whole or in * part without written permission from ReMoni ApS. * */ /*--------------------------------------------------------------------------- Include files ---------------------------------------------------------------------------*/ /* *INDENT-OFF* */ #include <ti/devices/DeviceFamily.h> #include DeviceFamily_constructPath(driverlib/rf_data_entry.h) #include <ti/drivers/rf/RF.h> #include <remoni/mode.h> #include <remoni/Device.h> #include <remoni/crc16wmbus.h> #include <pthread.h> #include <unistd.h> #include "Board.h" #include "nvm_cog.h" #include "Sndp.h" #include "SndpApAir_cc1310.h" #include "SndpCfg.h" #include "SndpRoutingTable.h" #include "sndpUart.h" #include "smartrf_settings/smartrf_settings_wmbus.h" #include "SndpWMBus.h" /* BIOS Header files */ #include <ti/sysbios/BIOS.h> #include <ti/sysbios/knl/Task.h> #include <ti/sysbios/knl/Semaphore.h> #include <ti/sysbios/knl/Event.h> #include <ti/sysbios/knl/Clock.h> #include <xdc/runtime/System.h> /* *INDENT-ON* */ /*--------------------------------------------------------------------------- Macro definitions ---------------------------------------------------------------------------*/ #define RF_TASK_PRIORITY 3 /* Packet RX Configuration */ #define DATA_ENTRY_HEADER_SIZE 12 /* Constant header size of a Generic Data Entry */ #define MAX_LENGTH 255 #define LENGTH_POSITION 2 #define APPENDED_BYTES 1 #define NUM_DATA_ENTRIES 1 /* NOTE: Only two data entries supported at the moment */ #define FRAME_IX (DATA_ENTRY_HEADER_SIZE + LENGTH_POSITION - 1) #define RF_QUEUE_DATA_ENTRY_HEADER_SIZE 12 // Constant header size of a Generic Data Entry #define RF_QUEUE_QUEUE_ALIGN_PADDING(length) (4 - ((length + RF_QUEUE_DATA_ENTRY_HEADER_SIZE) % 4)) // Padding offset #define RF_QUEUE_DATA_ENTRY_BUFFER_SIZE(numEntries, dataSize, appendedBytes) \ (numEntries * (RF_QUEUE_DATA_ENTRY_HEADER_SIZE + dataSize + appendedBytes + RF_QUEUE_QUEUE_ALIGN_PADDING(dataSize + appendedBytes))) #define RX_EVT Event_Id_00 /*--------------------------------------------------------------------------- Enumerations/Type definitions/Structs ---------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------- Global variables/const ---------------------------------------------------------------------------*/ extern Task_Params radioTaskParams; // Borrow from radio task - not used in this mode extern Task_Struct radioTask; // Borrow from radio task - not used in this mode extern uint8_t radioTaskStack[]; // Borrow from radio task - not used in this mode extern const size_t radioStackSize; // Borrow from radio task - not used in this mode /*--------------------------------------------------------------------------- Local variables/const ---------------------------------------------------------------------------*/ static RF_Object rfObject; static RF_Handle rfHandle; static uint8_t rxDataEntryBuffer[RF_QUEUE_DATA_ENTRY_BUFFER_SIZE(NUM_DATA_ENTRIES, MAX_LENGTH, APPENDED_BYTES)] __attribute__((aligned(4))); static rfc_dataEntryPartial_t* partialReadEntry = (rfc_dataEntryPartial_t*)&rxDataEntryBuffer; /* Receive dataQueue for RF Core to fill in data */ static dataQueue_t dataQueue; static rfc_propRxOutput_t rxStatistics; static uint8_t lengthWritten = false; static uint8_t rxDone = false; static uint8_t packet[sizeof(rxDataEntryBuffer)]; /* The length byte is stored in a separate variable */ static uint8_t has_packet = false; /* Act as boolean and length of packet when true */ static RF_CmdHandle rf_comm_handle; rfc_CMD_READ_RFREG_t RF_cmdReadRfReg = { .commandNo = 0x0601, .address = 0x5178, .value = 0, }; Event_Handle rxEvent; Event_Params rxEventParams; Event_Struct rxStructEvent; /* Memory allocated at build time */ /*--------------------------------------------------------------------------- Local prototypes ---------------------------------------------------------------------------*/ static void rfTaskFunction(UArg arg0, UArg arg1); static void callback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e); /**************************************************************************** Local functions ****************************************************************************/ /** * rfThread() - Thread initializing radio with callback and keep it going * @param [in] arg0 Passed argument 0 * @param [in] arg1 Passed argument 1 */ static void rfTaskFunction(UArg arg0, UArg arg1) { UInt events; RF_Stat status; RF_Params rfParams; RF_Params_init(&rfParams); partialReadEntry->length = MAX_LENGTH + LENGTH_POSITION + APPENDED_BYTES + 4; partialReadEntry->config.irqIntv = LENGTH_POSITION; partialReadEntry->config.type = DATA_ENTRY_TYPE_PARTIAL; partialReadEntry->status = DATA_ENTRY_PENDING; partialReadEntry->pNextEntry = (uint8_t*)partialReadEntry; dataQueue.pCurrEntry = (uint8_t*)partialReadEntry; dataQueue.pLastEntry = NULL; /* Modify CMD_PROP_RX command for application needs */ RF_cmdPropRx_wmbus.pQueue = &dataQueue; /* Set the Data Entity queue for received data */ RF_cmdPropRx_wmbus.maxPktLen = 0; /* Unlimited length, needed for RF_runImmediateCmd to work */ RF_cmdPropRx_wmbus.rxConf.bAutoFlushCrcErr = 0x0; /* Auto-flush packets with invalid CRC */ RF_cmdPropRx_wmbus.pktConf.bRepeatNok = 0x0; /* Exit RX after a packet is recived */ RF_cmdPropRx_wmbus.pktConf.bRepeatOk = 0x0; /* Exit RX after a packet is recived */ RF_cmdPropRx_wmbus.pOutput = (uint8_t*)&rxStatistics; /* Request access to the radio */ rfHandle = RF_open(&rfObject, &RF_prop_wmbus, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup_wmbus, &rfParams); /* Set the frequency */ rf_comm_handle = RF_postCmd(rfHandle, (RF_Op*)&RF_cmdFs_wmbus, RF_PriorityNormal, NULL, 0); /* Set event */ Event_Params_init(&rxEventParams); Event_construct(&rxStructEvent, &rxEventParams); /* Memory allocated at build time */ rxEvent = Event_handle(&rxStructEvent); /* Memory allocated at build time */ // rxEvent = Event_create(&rxEventParams, NULL); /* Memory allocated in here */ // if (rxEvent == NULL) { System_abort("Event create failed"); } while (!SndpWMBus_ShouldStop()) { rxDone = false; lengthWritten = false; rf_comm_handle = RF_postCmd(rfHandle, (RF_Op*)&RF_cmdPropRx_wmbus, RF_PriorityNormal, &callback, IRQ_RX_N_DATA_WRITTEN); uint32_t timeout_cnt = 7000; // Restart counter if something goes wrong while (!rxDone && !SndpWMBus_ShouldStop()) { // Using events instead of usleep(5000) to get faster response events = Event_pend(rxEvent, Event_Id_NONE, RX_EVT, 5000 / 10); // tickPeriod 10 uS timeout_cnt--; // Filtering on events could be done like if (events & RX_EVT) if (timeout_cnt == 0) { // Restart if nothing received status = RF_flushCmd(rfHandle, rf_comm_handle, 0); RF_close(rfHandle); rfHandle = RF_open(&rfObject, &RF_prop_wmbus, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup_wmbus, &rfParams); rf_comm_handle = RF_postCmd(rfHandle, (RF_Op*)&RF_cmdFs_wmbus, RF_PriorityNormal, NULL, 0); (void)status; // Just to remove warning - System_printf(status) can be used break; } (void)events; // Remove warning } } RF_flushCmd(rfHandle, RF_CMDHANDLE_FLUSH_ALL, 0); RF_close(rfHandle); } /** callback() - Callback to set length and receive full package */ /** * callback() - Callback to set length and receive full package * @param [in] RF_Handle The radio handle * @param [in] RF_CmdHandle The command handle * @param [in] RF_EventMask The event mask initiating the callback */ void callback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e) { if (e & RF_EventNDataWritten) { if (!lengthWritten) { lengthWritten = true; RF_runImmediateCmd(rfHandle, (uint32_t*)&RF_cmdReadRfReg); if (RF_cmdReadRfReg.value == 1) { // C-Mode uint8_t preamble = rxDataEntryBuffer[DATA_ENTRY_HEADER_SIZE]; switch (preamble) { case 0xcd: { uint8_t l_field = rxDataEntryBuffer[DATA_ENTRY_HEADER_SIZE + LENGTH_POSITION - 1]; uint8_t crc_length = (l_field > 9) ? (2 * (l_field - 10) / 16 + 2 + 1) : 0; RF_cmdPropSetLen_wmbus.rxLen = l_field + crc_length + (LENGTH_POSITION - 1) + 2; break; } case 0x3d: // Length is 2 bytes longer than wmbusmeters because it is including CRC at the end RF_cmdPropSetLen_wmbus.rxLen = rxDataEntryBuffer[DATA_ENTRY_HEADER_SIZE + LENGTH_POSITION - 1] + (LENGTH_POSITION - 1) + 1 - 3; break; default: { // Unknown and ungandled package type - future implementation RF_cmdPropSetLen_wmbus.rxLen = 0; break; } } } else { // T-Mode currently unhandled // uint8_t l_field = rxDataEntryBuffer[DATA_ENTRY_HEADER_SIZE]; // RF_cmdPropSetLen_wmbus.rxLen = l_field; // System_printf("%d\n", l_field); RF_cmdPropSetLen_wmbus.rxLen = 0; } if (RF_cmdPropSetLen_wmbus.rxLen == 0) { // Abort RF_Stat status = RF_cancelCmd(h, ch, 1); // Cancel command - callback will be called (void)status; // Remove warning } else { // Set length memset(&rxDataEntryBuffer[30], 0, sizeof(rxDataEntryBuffer) - 30); // Mostly for debug when inspecting data RF_runImmediateCmd(rfHandle, (uint32_t*)&RF_cmdPropSetLen_wmbus); } } } else { uint8_t preamble = rxDataEntryBuffer[DATA_ENTRY_HEADER_SIZE]; uint8_t length = rxDataEntryBuffer[FRAME_IX]; uint8_t is_valid = 0; if (0xcd == preamble) { //uint8_t is_valid = crc16wmbus_check_block(&rxDataEntryBuffer[FRAME_IX], 12); length += (length > 9) ? (2 * (length - 10) / 16 + 2 + 2) : 3; is_valid = crc16wmbus_check_split(&rxDataEntryBuffer[FRAME_IX], length); } else if (0x3d == preamble) { length += 1; //Length is without it self is_valid = crc16wmbus_check_block(&rxDataEntryBuffer[FRAME_IX], length); } // TODO: Look at others if (is_valid) { int8_t rssi = rxStatistics.lastRssi; /* Copy the payload + the status byte to the packet variable */ if (has_packet > 0) { /* packet in use by sndp */ } else if (is_valid) { has_packet = length + 1; memset(packet, 0, sizeof(packet)); memcpy(packet, &rxDataEntryBuffer[DATA_ENTRY_HEADER_SIZE], length + 1); SndpWMBus_NewMessage(packet, &has_packet, rssi); // Non blocking handover // System_printf("Data %d\n", rxStatistics.timeStamp); } } // System_printf("%d %x %x\n", is_valid, preamble, e); partialReadEntry->status = DATA_ENTRY_PENDING; rxDone = true; Event_post(rxEvent, RX_EVT); } } /**************************************************************************** Global functions ****************************************************************************/ /** SndpWMBus_Init() - Initialize WMBus */ void WMBusHW_Init(void) { /* Create the rf task */ Task_Params_init(&radioTaskParams); radioTaskParams.stackSize = radioStackSize; radioTaskParams.priority = RF_TASK_PRIORITY; radioTaskParams.stack = &radioTaskStack; radioTaskParams.instance->name = "WMBus Task"; Task_construct(&radioTask, rfTaskFunction, &radioTaskParams, NULL); }
It is still work in progress, but sort of functional. However, it actually works a bit better to set the length like:
RF_cmdPropSetLen_wmbus.rxLen = DATA_ENTRY_HEADER_SIZE + LENGTH_POSITION;
and not rely on the RF_cancelCmd(). I'm I using it wrong?
Regards Peter
Hi,
It looks like using RF_cancelCmd(h, ch, 0); to quit abruptly made a difference, so using the code above with this slight change.
Regards Peter
Have not completed the demo yet, but working on it.
Just to make sure I understand your issue completely.
Are you loosing packets, as in not finding sync, or are you getting CRC errors in the packets.
If you are loosing packets, have you confirmed that it is a timing issues? I.e, have you verified that the radio has not entered RX yet, when a new packet is being transmitted?
If the problem is related to CRC errors, have you made sure to follow advisory 11 in the errata note?
BR
Siri
Hi Siri,
Thank you for the update.
It isn't clear to me why the packages are lost and I don't really know how to debug it further. With the code above there isn't really any CRC errors and the callback isn't reporting anything out of order.
I'm getting data from a water meter and filtering out all compact packages so expect to see data ever ~2 minutes, but sometimes (Every few hours) there is a gap. It is a bit hard to debug with several meters active and compact packages as well.
I haven't implemented the advisory 11 yet because it is related to the CPU switching from idle and I don't thing it is the case, but I will next week because it won't do any harm.
With your assistance the code above is working better and maybe a lost package every few hours is expected. Can you see any obvious mistakes or suggestions for improvement?
Regards Peter
I will try to give you some general debug hints, so that you can try to narrow down your problem.
If packets are lost in the sense that you are transmitting something, but nothing is received, you should check the following:
Are you sure that your device is in RX state? Check that the status of the RX command is 2 (active)
it might also be a good idea to add the RF_EventMdmSoft to the callback, to see if you receives sync or not. This way you can figure if the packets is being filtered away, or if you do not even find the sync word.
If your device is in RX but you do not find the sync word when you transmit a packet, this can be because there is a jammer present that interfere with the packets so that you miss the sync word. Having a sniffer available to see if the sniffer receives the packet is always a good idea. If the sniffer receives it, but not you (and your device is in RX), there might be something with your HW, cause bad sensitivity.
It is usually not too hard writing SW that will receive all good packets, but it is harder when you try to take care of all the error situations as well.
I have made a code examples that can be useful for debugging. You should make something similar with your settings etc., and then make sure your code handles all error situations.
To test this, I recommend not just trying to receive OK packets from a water meter, but that you have a transmitter you can configure to transmit packets that are too long, too short, with CRC errors, packets causing overflow etc. too make sure your code is handling all these scenarios.
My test code is below:
/***** Includes *****/ /* Standard C Libraries */ #include <stdlib.h> /* TI Drivers */ #include <ti/drivers/rf/RF.h> #include <ti/drivers/GPIO.h> /* Driverlib Header files */ #include DeviceFamily_constructPath(driverlib/rf_prop_mailbox.h) /* Board Header files */ #include "ti_drivers_config.h" /* Application Header files */ #include "RFQueue.h" #include <ti_radio_config.h> #include <ti/sysbios/BIOS.h> #include <ti/sysbios/knl/Semaphore.h> // CMD_PROP_SET_LEN rfc_CMD_PROP_SET_LEN_t RF_cmdPropSetLen = { .commandNo = 0x3401, .rxLen = 0x0000, }; /***** Defines *****/ /* Packet RX Configuration */ // ---------------------------------------------------------------------------------------------------------- // | DATA_ENTRY_HEADER (12 bytes) | H0 | H1 | H2 | H3 | Length N | D0 | D1 | D2 | .. | .. | D(N-2) | D(N-1) | // ---------------------------------------------------------------------------------------------------------- // Optional appended bytes // ------------------------------------------------------- // | CRC1 | CRC0 | RSSI | TS3 | TS2 | TS1 | TS0 | Status | // ------------------------------------------------------- #define DATA_ENTRY_HEADER_SIZE 12 /* Constant header size of a Partial Data Entry */ #define MAX_LENGTH 10 /* Max length byte the application will accept */ #define PACKET_HEADER_SIZE 4 /* Bytes in packet before location of the length byte */ #define LENGTH_POSITION PACKET_HEADER_SIZE + 1 /* Position of length byte (after sync) */ #define NUM_APPENDED_BYTES 0 /* .rxConf.bIncludeCrc = 0x1; // 2 bytes (if default CRC is used) .rxConf.bAppendRssi = 0x1; // 1 byte .rxConf.bAppendTimestamp = 0x1; // 4 bytes .rxConf.bAppendStatus = 0x1; // 1 byte */ /***** Prototypes *****/ static void callback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e); /***** Variable declarations *****/ static RF_Object rfObject; static RF_Handle rfHandle; static RF_CmdHandle rxHandle; /* Receive dataQueue for RF Core to fill in data */ static dataQueue_t dataQueue; #if defined(__TI_COMPILER_VERSION__) #pragma DATA_ALIGN (rxDataEntryBuf0, 4); static uint8_t rxDataEntryBuf0[DATA_ENTRY_HEADER_SIZE + MAX_LENGTH + LENGTH_POSITION - + NUM_APPENDED_BYTES]; #pragma DATA_ALIGN (rxDataEntryBuf1, 4); static uint8_t rxDataEntryBuf1[DATA_ENTRY_HEADER_SIZE + MAX_LENGTH + LENGTH_POSITION - + NUM_APPENDED_BYTES]; #elif defined(__IAR_SYSTEMS_ICC__) #pragma data_alignment = 4 static uint8_t rxDataEntryBuf0[DATA_ENTRY_HEADER_SIZE + MAX_LENGTH + LENGTH_POSITION + NUM_APPENDED_BYTES]; #pragma data_alignment = 4 static uint8_t rxDataEntryBuf1[DATA_ENTRY_HEADER_SIZE + MAX_LENGTH + LENGTH_POSITION + NUM_APPENDED_BYTES]; #elif defined(__GNUC__) static uint8_t rxDataEntryBuf0[DATA_ENTRY_HEADER_SIZE + MAX_LENGTH + LENGTH_POSITION + NUM_APPENDED_BYTES] __attribute__((aligned(4))); static uint8_t rxDataEntryBuf1[DATA_ENTRY_HEADER_SIZE + MAX_LENGTH + LENGTH_POSITION + NUM_APPENDED_BYTES] __attribute__((aligned(4))); #else #error This compiler is not supported. #endif /* Receive dataQueue for RF Core to fill in data */ static dataQueue_t dataQueue; static uint16_t payloadLength; rfc_dataEntryPartial_t* partialReadEntry0 = (rfc_dataEntryPartial_t*)&rxDataEntryBuf0; rfc_dataEntryPartial_t* partialReadEntry1 = (rfc_dataEntryPartial_t*)&rxDataEntryBuf1; rfc_dataEntryPartial_t* currentReadEntry = (rfc_dataEntryPartial_t*)&rxDataEntryBuf0; rfc_propRxOutput_t rxStatistics; static uint8_t lengthWritten = false; static uint8_t cancelRx = false; RF_Stat status = 0xFF; /* RX Semaphore */ static Semaphore_Struct rxSemaphore; static Semaphore_Handle rxSemaphoreHandle; uint8_t packetHeader[PACKET_HEADER_SIZE]; uint8_t packetPayload[MAX_LENGTH + 1]; // Must have room to store the length byte as well uint8_t packetStatusBytes[NUM_APPENDED_BYTES]; //debug uint8_t eventNDataWritten = 0; uint8_t eventRxOk = 0; uint8_t eventCmdAborted = 0; uint8_t eventRxBufFull = 0; uint8_t eventRxEntryDone = 0; uint8_t eventDataWritten = 0; uint8_t eventRxAborted = 0; uint8_t eventMdmSoft = 0; uint8_t eventLastCmdDone = 0; uint8_t dummy = 0; /***** Function definitions *****/ void *mainThread(void *arg0) { RF_Params rfParams; RF_Params_init(&rfParams); GPIO_setConfig(CONFIG_GPIO_RLED, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW); GPIO_write(CONFIG_GPIO_RLED, CONFIG_GPIO_LED_OFF); /* Initialize RX semaphore */ Semaphore_construct(&rxSemaphore, 0, NULL); rxSemaphoreHandle = Semaphore_handle(&rxSemaphore); partialReadEntry0->length = MAX_LENGTH + LENGTH_POSITION + NUM_APPENDED_BYTES + 4; // Make sure there is enough room for a complete packet in one data entry. // Number of bytes following this length field // + 4 is to make room for the pktStatus (2 bytes) and nextIndex (2 bytes) partialReadEntry0->config.irqIntv = LENGTH_POSITION; partialReadEntry0->config.type = DATA_ENTRY_TYPE_PARTIAL; partialReadEntry0->status = DATA_ENTRY_PENDING; partialReadEntry1->length = MAX_LENGTH + LENGTH_POSITION + NUM_APPENDED_BYTES + 4; // Make sure there is enough room for a complete packet in one data entry. // Number of bytes following this length field // + 4 is to make room for the pktStatus (2 bytes) and nextIndex (2 bytes) partialReadEntry1->config.irqIntv = LENGTH_POSITION; partialReadEntry1->config.type = DATA_ENTRY_TYPE_PARTIAL; partialReadEntry1->status = DATA_ENTRY_PENDING; partialReadEntry0->pNextEntry = (uint8_t*)partialReadEntry1; partialReadEntry1->pNextEntry = (uint8_t*)partialReadEntry0; dataQueue.pCurrEntry = (uint8_t*)partialReadEntry0; dataQueue.pLastEntry = NULL; /* Modify CMD_PROP_RX command for application needs */ RF_cmdPropRx.pQueue = &dataQueue; RF_cmdPropRx.pOutput = (uint8_t*)&rxStatistics; RF_cmdPropRx.rxConf.bIncludeHdr = 1; // Must be 1 to receive the first byte after sync in the data entry RF_cmdPropRx.maxPktLen = 0; // Unlimited length RF_cmdPropRx.rxConf.bAutoFlushCrcErr = 1; RF_cmdPropRx.pktConf.bRepeatOk = 0; RF_cmdPropRx.pktConf.bRepeatNok = 0; // Optional status bytes appended AFTER the payload // If these are changed, NUM_APPENDED_BYTES must also be updated RF_cmdPropRx.rxConf.bIncludeCrc = 0x0; // 2 byte (if default CRC is used) RF_cmdPropRx.rxConf.bAppendRssi = 0x0; // 1 byte RF_cmdPropRx.rxConf.bAppendStatus = 0x0; // 1 Byte RF_cmdPropRx.rxConf.bAppendTimestamp = 0x0; // 4 bytes /* Request access to the radio */ rfHandle = RF_open(&rfObject, &RF_prop, (RF_RadioSetup*)&RF_cmdPropRadioDivSetup, &rfParams); /* Set the frequency */ RF_postCmd(rfHandle, (RF_Op*)&RF_cmdFs, RF_PriorityNormal, NULL, 0); while(true) { lengthWritten = false; cancelRx = false; status = 0xFF; eventNDataWritten = 0; eventRxOk = 0; eventCmdAborted = 0; eventRxBufFull = 0; eventRxEntryDone = 0; eventDataWritten = 0; eventRxAborted = 0; eventMdmSoft = 0; eventLastCmdDone = 0; rxHandle = RF_postCmd(rfHandle, (RF_Op*)&RF_cmdPropRx, RF_PriorityNormal, &callback, RF_EventNDataWritten | RF_EventRxOk | RF_EventRxBufFull | RF_EventCmdAborted | RF_EventMdmSoft); Semaphore_pend(rxSemaphoreHandle, BIOS_WAIT_FOREVER); if (cancelRx) { status = RF_cancelCmd(rfHandle, rxHandle, 0); Semaphore_pend(rxSemaphoreHandle, BIOS_WAIT_FOREVER); } } } void callback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e) { if (e & RF_EventNDataWritten) { GPIO_toggle(CONFIG_GPIO_RLED); eventNDataWritten++; if (!lengthWritten) { lengthWritten = true; payloadLength = *(uint8_t*)(¤tReadEntry->rxData + LENGTH_POSITION - 1); if (payloadLength > MAX_LENGTH) { cancelRx = true; Semaphore_post(rxSemaphoreHandle); } else { RF_cmdPropSetLen.rxLen = payloadLength + LENGTH_POSITION - 1; // Must subtract 1 due to rxConf.bIncludeHdr = 1 RF_runImmediateCmd(rfHandle, (uint32_t*)&RF_cmdPropSetLen); } } } if (e & RF_EventMdmSoft) { eventMdmSoft++; } if (e & RF_EventRxOk) { eventRxOk++; memcpy(packetHeader, (uint8_t*)(¤tReadEntry->rxData + 0 ), PACKET_HEADER_SIZE); memcpy(packetPayload, (uint8_t*)(¤tReadEntry->rxData + (LENGTH_POSITION - 1) ), (payloadLength + 1)); memcpy(packetStatusBytes, (uint8_t*)(¤tReadEntry->rxData + LENGTH_POSITION + payloadLength), NUM_APPENDED_BYTES); } if (e & RF_EventLastCmdDone) { eventLastCmdDone++; currentReadEntry->status = DATA_ENTRY_PENDING; currentReadEntry = (rfc_dataEntryPartial_t*)currentReadEntry->pNextEntry; dataQueue.pCurrEntry = (uint8_t*)currentReadEntry; Semaphore_post(rxSemaphoreHandle); } if (e & RF_EventCmdAborted) { eventCmdAborted++; currentReadEntry->status = DATA_ENTRY_PENDING; currentReadEntry = (rfc_dataEntryPartial_t*)currentReadEntry->pNextEntry; dataQueue.pCurrEntry = (uint8_t*)currentReadEntry; Semaphore_post(rxSemaphoreHandle); } if (e & RF_EventRxBufFull) { currentReadEntry->status = DATA_ENTRY_PENDING; currentReadEntry = (rfc_dataEntryPartial_t*)currentReadEntry->pNextEntry; dataQueue.pCurrEntry = (uint8_t*)currentReadEntry; eventRxBufFull++; } }
I have tested the following:
Too short packets:
a1 a2 a3 a4 1 1
nRxStopped is incremented and eventLastCmdDone is set
Too long packets (the RX command will be cancelled by the application)
a1 a2 a3 a4 14 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
nRxStopped is incremented and eventCmdAborted is set
Packet with CRC error:
a1 a2 a3 a4 5 1 2 3 4 5 6
nRxNok is incremented and eventLastCmdDone is set
OK Packet:
a1 a2 a3 a4 5 1 2 3 4 5 6
nRxOk is incremented and eventLastCmdDone and eventRxOk are set
Buffer Overflow:
Set breakpoint in the callback at RF_runImmediateCmd to get an overflow
nBrBuffFull is incremented and eventLastCmdDone and eventRxBufFull are set
Since you are using partial read entries the CPU will execute code while the RF Core is active and in progress of receiving a packet. You therefore need to follow advisory 11.
If you were using normal data entries, and did not get a callback before the radio was done in RX and the packet was received, this would not be necessary, but in your case it is.
However, this will not fix your problem if the problem is lack of sync and not CRC errors, but you should still implement it to avoid un-necessary errors in your packet.
BR
Siri
Hi Siri,
Thank you, I'll give it a try.
I'm currently debugging T-Mode and it looks like
RF_runImmediateCmd(rfHandle, (uint32_t*)&RF_cmdReadRfReg); // Get the Mode value
only is returning the correct value for RF_EventNDataWritten but not RF_EventNDataWritten. Is that true?
Regards Peter
I assume you are asking about RF_EventNDataWritten compared to RF_EventDataWritten????
RF_EventNDataWritten: Specified number of bytes written to partial read Rx buffer
RF_EventDataWritten: Data written to partial read Rx buffer
In my example, the length is byte number 5 after sync word, meaning that I cannot read out the length before at least 5 bytes have been received.
Because of this, partialReadEntry0->config.irqIntv and partialReadEntry1->config.irqIntv= 5;
I therefore need to wait for the first RF_EventNDataWritten event before I can read out the length info.
If I try to read the length (byte 5) the first time I get the RF_EventDataWritten, the length is not yet received.
Siri
Hi siri,
Thank you for answering, the C-Mode is quite stable now. I was referring to my own code but think I've figured it out and changed it slightly from
void callback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e) { if (e & RF_EventNDataWritten) { if (!lengthWritten) { lengthWritten = true; RF_runImmediateCmd(rfHandle, (uint32_t*)&RF_cmdReadRfReg); if (RF_cmdReadRfReg.value == 1) { // C-Mode uint8_t preamble = rxDataEntryBuffer[DATA_ENTRY_HEADER_SIZE]; switch (preamble) { case 0xcd: { uint8_t l_field = rxDataEntryBuffer[DATA_ENTRY_HEADER_SIZE + LENGTH_POSITION - 1]; uint8_t crc_length = (l_field > 9) ? (2 * (l_field - 10) / 16 + 2 + 1) : 0; RF_cmdPropSetLen_wmbus.rxLen = l_field + crc_length + (LENGTH_POSITION - 1) + 2; break; } case 0x3d: // Length is 2 bytes longer than wmbusmeters because it is including CRC at the end RF_cmdPropSetLen_wmbus.rxLen = rxDataEntryBuffer[DATA_ENTRY_HEADER_SIZE + LENGTH_POSITION - 1] + (LENGTH_POSITION - 1) + 1 - 3; break; default: { // Unknown and ungandled package type - future implementation RF_cmdPropSetLen_wmbus.rxLen = 0; break; } } } else { // T-Mode currently unhandled // uint8_t l_field = rxDataEntryBuffer[DATA_ENTRY_HEADER_SIZE]; // RF_cmdPropSetLen_wmbus.rxLen = l_field; // System_printf("%d\n", l_field); RF_cmdPropSetLen_wmbus.rxLen = 0; } if (RF_cmdPropSetLen_wmbus.rxLen == 0) { // Abort RF_Stat status = RF_cancelCmd(h, ch, 1); // Cancel command - callback will be called (void)status; // Remove warning } else { // Set length memset(&rxDataEntryBuffer[30], 0, sizeof(rxDataEntryBuffer) - 30); // Mostly for debug when inspecting data RF_runImmediateCmd(rfHandle, (uint32_t*)&RF_cmdPropSetLen_wmbus); } } } else { uint8_t preamble = rxDataEntryBuffer[DATA_ENTRY_HEADER_SIZE]; uint8_t length = rxDataEntryBuffer[FRAME_IX]; uint8_t is_valid = 0; if (0xcd == preamble) { //uint8_t is_valid = crc16wmbus_check_block(&rxDataEntryBuffer[FRAME_IX], 12); length += (length > 9) ? (2 * (length - 10) / 16 + 2 + 2) : 3; is_valid = crc16wmbus_check_split(&rxDataEntryBuffer[FRAME_IX], length); } else if (0x3d == preamble) { length += 1; //Length is without it self is_valid = crc16wmbus_check_block(&rxDataEntryBuffer[FRAME_IX], length); } // TODO: Look at others if (is_valid) { int8_t rssi = rxStatistics.lastRssi; /* Copy the payload + the status byte to the packet variable */ if (has_packet > 0) { /* packet in use by sndp */ } else if (is_valid) { has_packet = length + 1; memset(packet, 0, sizeof(packet)); memcpy(packet, &rxDataEntryBuffer[DATA_ENTRY_HEADER_SIZE], length + 1); SndpWMBus_NewMessage(packet, &has_packet, rssi); // Non blocking handover // System_printf("Data %d\n", rxStatistics.timeStamp); } } // System_printf("%d %x %x\n", is_valid, preamble, e); partialReadEntry->status = DATA_ENTRY_PENDING; rxDone = true; Event_post(rxEvent, RX_EVT); } }
to
void callback(RF_Handle h, RF_CmdHandle ch, RF_EventMask e) { if (e & RF_EventNDataWritten) { if (!lengthWritten) { lengthWritten = true; RF_runImmediateCmd(rfHandle, (uint32_t*)&RF_cmdReadRfReg); // Get the Mode value rxMode = RF_cmdReadRfReg.value; // Store the mode - reg will change later if (rxMode == 1) { // C-Mode uint8_t preamble = rxDataEntryBuffer[DATA_ENTRY_HEADER_SIZE]; switch (preamble) { case 0xcd: { uint8_t l_field = rxDataEntryBuffer[DATA_ENTRY_HEADER_SIZE + LENGTH_POSITION - 1]; uint8_t crc_length = (l_field > 9) ? (2 * (l_field - 10) / 16 + 2 + 1) : 0; RF_cmdPropSetLen_wmbus.rxLen = l_field + crc_length + (LENGTH_POSITION - 1) + 2; break; } case 0x3d: // Length is 2 bytes longer than wmbusmeters because it is including CRC at the end RF_cmdPropSetLen_wmbus.rxLen = rxDataEntryBuffer[DATA_ENTRY_HEADER_SIZE + LENGTH_POSITION - 1] + (LENGTH_POSITION - 1) + 1 - 3; break; default: { // Unknown and unhandled package type - future implementation RF_cmdPropSetLen_wmbus.rxLen = 0; break; } } } else { // T-Mode is like frame a uint8_t l_field = rxDataEntryBuffer[DATA_ENTRY_HEADER_SIZE]; uint8_t crc_length = (l_field > 9) ? (2 * (l_field - 10) / 16 + 2) : 0; RF_cmdPropSetLen_wmbus.rxLen = l_field + crc_length; } if (RF_cmdPropSetLen_wmbus.rxLen == 0) { // Abort RF_Stat status = RF_cancelCmd(h, ch, 0); // Cancel command - callback will be called (void)status; // Remove warning } else { // Set length memset(&rxDataEntryBuffer[30], 0, sizeof(rxDataEntryBuffer) - 30); // Mostly for debug when inspecting data RF_runImmediateCmd(rfHandle, (uint32_t*)&RF_cmdPropSetLen_wmbus); } } } else { uint8_t preamble = rxDataEntryBuffer[DATA_ENTRY_HEADER_SIZE]; uint8_t length = rxDataEntryBuffer[FRAME_IX]; uint8_t is_valid = 0; if (rxMode == 0) { // T-Mode length = rxDataEntryBuffer[DATA_ENTRY_HEADER_SIZE]; // No preamble length += (length > 9) ? (2 * (length - 10) / 16 + 2 + 2) : 3; length += 1; //Length is without it self if (length + DATA_ENTRY_HEADER_SIZE < MAX_LENGTH) { // Don't process if to big memmove(&rxDataEntryBuffer[DATA_ENTRY_HEADER_SIZE + 1], &rxDataEntryBuffer[DATA_ENTRY_HEADER_SIZE], length); rxDataEntryBuffer[DATA_ENTRY_HEADER_SIZE] = 0xcd; // Fake C-Mode is_valid = crc16wmbus_check_split(&rxDataEntryBuffer[FRAME_IX], length); } } else if (0xcd == preamble) { //uint8_t is_valid = crc16wmbus_check_block(&rxDataEntryBuffer[FRAME_IX], 12); length += (length > 9) ? (2 * (length - 10) / 16 + 2 + 2) : 3; is_valid = crc16wmbus_check_split(&rxDataEntryBuffer[FRAME_IX], length); } else if (0x3d == preamble) { length += 1; //Length is without it self is_valid = crc16wmbus_check_block(&rxDataEntryBuffer[FRAME_IX], length); } // TODO: Look at others if (is_valid) { int8_t rssi = rxStatistics.lastRssi; /* Copy the payload + the status byte to the packet variable */ if (has_packet > 0) { /* packet in use by sndp */ } else if (is_valid) { has_packet = length + 1; memset(packet, 0, sizeof(packet)); memcpy(packet, &rxDataEntryBuffer[DATA_ENTRY_HEADER_SIZE], length + 1); SndpWMBus_NewMessage(packet, &has_packet, rssi); // Non blocking handover // System_printf("Data %d\n", rxStatistics.timeStamp); } } // System_printf("%d %d %d %x %x\n", is_valid, rxMode, length, preamble, e); partialReadEntry->status = DATA_ENTRY_PENDING; rxDone = true; Event_post(rxEvent, RX_EVT); } }
but this causes more T-Mode packages than WMBusMeters can see with invalid CRC and it is also impacting C.Mode. There is actually only 1 meter sending so what is wrong?
Regards Peter
Hi Peter
I am not sure I understand what you are asking about. What do you mean by
“this causes more T-Mode packages than WMBusMeters can see with invalid CRC and it is also impacting C.Mode”
I have not possibility to debug your implementation, and I am not sure I understand what problems you are seeing.
Remember that even if you only have 1 meters transmitting, there might be other meters nearby that you will also be able to receive from. Also, since wmbus only uses a 2 bytes sync word, you will also receive false packets. If your code is occupied receiving a false packet, it will lose any other packets sent at that time.
Until you have verified that your SW works as intended, it might be a good idea to do some testing in a shielded environment, where you have full control on what is sent to the radio (no interferer).
Also, simplifying your code when debugging to only log number of sync found, number of c mode and number of t mode packets and compare that to the number of packets you send, might be useful to figure out how much other stuff is on the air, that can interfere with your packets.
Siri
Hi Siri,
I'll try to explain further and doesn't expect you to debug my code, just have a quick look to see if something is off.
I think the code is almost ok when it is configured for C-Mode only (frame format A and B) but starts to fail when T-Mode is enabled.
I expect that looking for false T-Mode packages might cause C-Mode packages to be lost, but isn't there a way to identify those situations early like restart on new sync?
I was hoping to be able to handle both C-Mode and T-Mode packages reliably.
Regards Peter
Hi Peter
Still not sure I understand what issue you are seeing.
Is the problem that you
I am not able to say what the issue is just by looking at the code, and I can only recommend you continue to debug the issue, to narrow down what is it.
When we know what causes the issues, we can look at solution also.
What you can do, is to set up a CC1310 LP with SmartRF Studio, and use that as a sniffer.
You cannot run the C/T mode patch from Studio, but you can set up the correct PHY parameters, and for example a fixed packet length of 6 bytes.
This will give you an indication as to what is going on, on the air.
From the plots below, I had my CC1310 running for about 3 minutes on my desk.
It received 27 packets, where 3 of them where packets I transmitted from another LP, and the rest was noise or other meters in close vicinity.
You can see from the RSSI levels that the 3 packets I actually sent, was much stronger that the rest that was picked up. Some of the other packets looks like “real” C-mode packets as they have the signaling byte (0x54), and the rest might be T-mode or noise.
Note that the wmbus patch has a programmable Carrier Sense threshold. This is by default set to -107 dBm, so sync words with signal strength lower that this will not be accepted.
For debug purposes, you can increase threshold to a level where the packets you are actually transmitting is being received, while everything else will not be accepted.
How to change the threshold is explained here:
CC13xx Combined wM-Bus C-Mode and T-Mode Application Note (Rev. E)
I have some comments to your code for things that might cause an issue:
In the callback where you set the RF_cmdPropSetLen_wmbus.rxLen, you set it to l_field + something.
This means that the resulting length can be > 255.
Have you made sure that your data entries are big enough for this, so that you do not get an overflow situation?
From your code it seems like you are setting
partialReadEntry->length = MAX_LENGTH + LENGTH_POSITION + APPENDED_BYTES + 4;
and here you are not accounting for rxLen being larger than MAX_LEN
Another possible issue with your code, is that you are not subscribing to RF_EventCmdAborted
if (e & RF_EventNDataWritten) { . . } else { partialReadEntry->status = DATA_ENTRY_PENDING; rxDone = true; Event_post(rxEvent, RX_EVT); }
If you do a RF_cancelCmd, you will not get the eventLastCmdDone, but only the RF_EventCmdAborted, meaning that your code will NOT set partialReadEntry->status = DATA_ENTRY_PENDING; in the case of a cancel.
There might be other things as well, so I strongly recommend that you debug your code, one packet type at the time, to see that all “error cases” / corner cases are handled properly.
Length byte = 0
Length byte = 255
CRC errors
Wrong Frame format for C mode (not Frame A or Frame B)
BR
Siri
Hi Siri,
Thank you once again for the help, I really appreciate it.
What I'm seeing is your option 2
or do you receive these, but you also receive a lot of false T mode packets, and this makes you lose C mode packets as well
I've implemented your suggestions
but setting the Carrier Sense threshold doesn't really affect anything. I'm developing on Linux so using SmartRF Studio is a bit difficult, but I'll try to get a Windows machine as well.
It makes sense that looking for ghost packages will make me loose real packages.
Regards Peter
You should not limit the partialReadEntry->lenght to MAX_LENGTH
You may need to increase it since you can receive packets that are longer than this.
In my example, the length byte is telling how many bytes are following it (not including CRC)
/ ---------------------------------------------------------------------------------------- // | DATA_ENTRY_HEADER (12 bytes) | H0 | H1 | H2 | H3 | Length 5 | D1 | D2 | D3 | D4 | D5 | // ---------------------------------------------------------------------------------------- #define DATA_ENTRY_HEADER_SIZE 12 #define MAX_LENGTH 5 #define PACKET_HEADER_SIZE 4 #define LENGTH_POSITION 5 #define NUM_APPENDED_BYTES 0 static uint8_t rxDataEntryBuf0[DATA_ENTRY_HEADER_SIZE + MAX_LENGTH + LENGTH_POSITION + NUM_APPENDED_BYTES] partialReadEntry0->length = MAX_LENGTH + LENGTH_POSITION + NUM_APPENDED_BYTES + 4; RF_cmdPropSetLen.rxLen = payloadLength + LENGTH_POSITION - 1; // Must subtract 1 due to rxConf.bIncludeHdr = 1 (H0 in the figure above)
payload length is never larger than MAX_LENGTH (5), so max rxLen I will set is 9.
Your MAX_LENGTH is 255. I do not know the format of the wmbus packets, so not sure what is included, but if you have something like below:
/ ------------------------------------------------------------------------------------------------------- // | DATA_ENTRY_HEADER (12 bytes) | H0 | Length 255 | D1 | D2 | D3 | D4 | D5 |------| D255 | CRC1 | CRC2 | // ------------------------------------------------------------------------------------------------------- #define DATA_ENTRY_HEADER_SIZE 12 #define MAX_LENGTH 255 #define PACKET_HEADER_SIZE 1 #define LENGTH_POSITION 2 #define NUM_APPENDED_BYTES 0 static uint8_t rxDataEntryBuf0[DATA_ENTRY_HEADER_SIZE + MAX_LENGTH + LENGTH_POSITION + NUM_APPENDED_BYTES] partialReadEntry0->length = MAX_LENGTH + 2 + LENGTH_POSITION + NUM_APPENDED_BYTES + 4; RF_cmdPropSetLen.rxLen = payloadLength + 2 + LENGTH_POSITION - 1; // Must subtract 1 due to rxConf.bIncludeHdr = 1 (H0 in the figure
2 must be added to both the partialReadEntry0->length and the RF_cmdPropSetLen.rxLen.
If increasing the CS threshold to a high value does not help at all (-50 dBm for example, depending of the strength of your transmitter), my guess would be that the problem is not related to processing noise/false packets.
BR
Siri
Hi Siri,
I think it will be ok to limit the size to MAX_LENGTH at least for now. I haven't seen any packages of that length and we are forwarding the packages via another protocol with an even tighter constraint.
I might not be increasing the CS threshold the correct way or at the correct place. I use
HW_REG_OVERRIDE (0x6090, 0x0ACE); // Carrier Sense Threshold Override
and have tried to do it at different places and even as 0x0AFF without any significant difference.
Regards Peter
The override is already part of the settings that should be used together with the patch, so you should simply just modify it (not add it somewhere else:
#include DEVICE_FAMILY_PATH(driverlib/rf_mailbox.h) #include DEVICE_FAMILY_PATH(driverlib/rf_common_cmd.h) #include DEVICE_FAMILY_PATH(driverlib/rf_prop_cmd.h) #include <ti/drivers/rf/RF.h> #include DEVICE_FAMILY_PATH(rf_patches/rf_patch_cpe_wmbus_ctmode.h) #include DEVICE_FAMILY_PATH(rf_patches/rf_patch_mce_wmbus_ctmode.h) #include DEVICE_FAMILY_PATH(rf_patches/rf_patch_rfe_wmbus_ctmode.h) #include "smartrf_settings.h" uint32_t txShapeTMode[] = {0x00000000, 0x00000000, 0x00000000, 0x4B110200, 0xF2F0E1A6, 0xF2F2F2F2}; uint32_t txShapeCMode[] = {0x00000000, 0x00000000, 0x00000000, 0x440F0200, 0xD9D8CA96, 0xD9D9D9D9}; // TI-RTOS RF Mode Object RF_Mode RF_prop = { .rfMode = RF_MODE_PROPRIETARY_SUB_1, .cpePatchFxn = &rf_patch_cpe_wmbus_ctmode, .mcePatchFxn = &rf_patch_mce_wmbus_ctmode, .rfePatchFxn = &rf_patch_rfe_wmbus_ctmode, }; // Overrides for CMD_PROP_RADIO_DIV_SETUP static uint32_t pOverrides[] = { //Run the MCE and RFE patches MCE_RFE_OVERRIDE(1,0,0,1,0,0), // override_synth_prop_863_930_div5.xml // Synth: Set recommended RTRIM to 7 HW_REG_OVERRIDE(0x4038,0x0037), // Synth: Set Fref to 4 MHz (uint32_t)0x000684A3, // Synth: Configure fine calibration setting HW_REG_OVERRIDE(0x4020,0x7F00), // Synth: Configure fine calibration setting HW_REG_OVERRIDE(0x4064,0x0040), // Synth: Configure fine calibration setting (uint32_t)0xB1070503, // Synth: Configure fine calibration setting (uint32_t)0x05330523, // Synth: Set loop bandwidth after lock to 20 kHz (uint32_t)0x0A480583, // Synth: Set loop bandwidth after lock to 20 kHz (uint32_t)0x7AB80603, // Synth: Configure VCO LDO (in ADI1, set VCOLDOCFG=0x9F to use voltage input reference) ADI_REG_OVERRIDE(1,4,0x9F), // Synth: Configure synth LDO (in ADI1, set SLDOCTL0.COMP_CAP=1) ADI_HALFREG_OVERRIDE(1,7,0x4,0x4), // Synth: Use 24 MHz XOSC as synth clock, enable extra PLL filtering (uint32_t)0x02010403, // Synth: Configure extra PLL filtering (uint32_t)0x00108463, // Synth: Increase synth programming timeout (0x04B0 RAT ticks = 300 us) (uint32_t)0x04B00243, // override_phy_rx_aaf_bw_0xd.xml // Rx: Set anti-aliasing filter bandwidth to 0xD (in ADI0, set IFAMPCTL3[7:4]=0xD) ADI_HALFREG_OVERRIDE(0,61,0xF,0xD), // override_phy_gfsk_rx.xml // Rx: Set LNA bias current trim offset to 3 (uint32_t)0x00038883, // Rx: Freeze RSSI on sync found event HW_REG_OVERRIDE(0x6084,0x35F1), // override_phy_gfsk_pa_ramp_agc_reflevel_0x2e.xml // Tx: Configure PA ramping setting and set AGC reference level to 0x2E HW_REG_OVERRIDE(0x6088,0x082E), // Tx: Configure PA ramping setting and set AGC settle wait = (0x7+1)*2 = 16 samples HW_REG_OVERRIDE(0x608C,0x0407), // override_phy_rx_rssi_offset_5db.xml // Rx: Set RSSI offset to adjust reported RSSI by +5 dB (uint32_t)0x00FB88A3, // TX power override // Tx: Set PA trim to max (in ADI0, set PACTL0=0xF8) ADI_REG_OVERRIDE(0,12,0xF8), // AGC winsize 2 samples HW_REG_OVERRIDE(0x6064,0x1101), // CS threshold to –107 dBm HW_REG_OVERRIDE(0x6090,0xA095),//////////////////////////////////////////Change the override here // Let the patch control the correlator setting (uint32_t)0x00048103, // Clear state in internal radio register due to frequency change HW_REG_OVERRIDE(0x51F8,0x0000), // Set divider bias to disabled HW32_ARRAY_OVERRIDE(0x405C,1), (uint32_t)0x18000200, // TX shape in T-mode 0xC0040031, (uint32_t)&txShapeTMode[0], // TX shape in C-mode //0xC0040031, //(uint32_t)&txShapeCMode[0], (uint32_t)0xFFFFFFFF, };
If you do that, all packets your received will have a RSSI above -50 dBm, so either you have some strong jammers/meters present that you are not aware of, or your problem is not false packets.
adding the sync event to the callback and/or testing with SmartRF Studio will help you figuring this out.
Siri
Hi Siri,
Thank you, it was my mistake.
Now it works and a value of -85 gives reasonable results without many 'ghosts' at my work location which is very noisy. I'll test in a real scenario tomorrow and discuss in the team also.
Does TI recommend to use a value around -90 in a noisy environment or is it supposed to stay at -107?
Regards Peter
It depends, and it is hard to give any good recommendations.
Setting a higher threshold (lets say -90 dBm) will reduce the number of false packets due to noise (or other meters in the vicinity), hence it is more likely that you receive the packets you want, as the receiver is not occupied processing packets not for you.
On the other side, this will also kind of set your sensitivity level, as you will not be able to receive any packets with a signal strength lower that -90 dBm (even if the packets were intended for you).
I assume that there are some info in the beginning of the packet that can be used to determine if the packet is for your or not (some kind of ID etc.?)
If there are, I guess you can check this info, and cancel the RX if the packet is not for you, without having to wait for the whole packet to be received, before checking it.
Siri
Hi Siri,
Ok, thank you it make sense. I think this I'll test and refine this some more, now you have pointed me in the right direction.
Thank you and have a nice day. Regards Peter