Having completed a BLE observer using the CC2541 radio in proprietary mode, we decided to implement an advertiser in proprietary mode as well, because it eliminated some of the overhead of the SimpleBLEBroadcaster project, and left the CC2541 in active mode for a shorter period. (Battery life is critical for our product.) This is essentially a beacon, broadcasting a brief 13-byte packet with a ADV_NONCONN_IND PDU, once each second.
Problem: Our program sometimes hangs waiting for the TASKDONE flag. The applicable part of our code is attached. When the advertiser is unresponsive, stopping program execution always shows it is in one of the two while() loops. After that, when stepping or running the code, the flag is never set and the code never exits the while() loop. We use IAR Embedded Workbench and the CC Debugger.
We've tried various other sequences, such as checking TASKDONE and TXDONE separately after the CMD_TX, but it does not seem to make any difference. Adding a counter so the code exits the loop doesn't help because the radio still isn't working on the next advertisement.
At first, this problem did not occur outside the debugger, so we thought it might be an ideosynchracy of the debugger. However, as we finalize hardware and build larger numbers of advertisers, we are seeing this outside the debugger. After attaching a battery, some advertisers send zero packets or one packet after reset. When we reconnect the device in the debug environment, we can see it hangs in one of the while() loops.
So far, the problem seems random, meaning that a few boards from a batch exhibit the problem and we have not found any hardware differences (even subtle ones) between boards.
Questions:
Should we be handling the flags differently?
Are there any known issues with the TASKDONE flag in the CC2541 proprietary mode radio?
Thanks and regards,
Dan Lewis
void radio_lle_command(uint8 command)
{
/* Make sure RFST is 0, then send the command to the LLE
See 25.9.1, Command Register */
while (RFST != 0)
;
RFST = command;
}
void advertise(uint8 channel_number)
{
set_channel(channel_number);
// Clear the interrupt flags
S1CON = 0;
RFERRF = 0;
RFIRQF0 = 0;
RFIRQF1 = 0;
radio_lle_command(CMD_TX);
// Wait for the radio to finish
while (!(RFIRQF1 & TXDONE) && !(RFIRQF1 & TASKDONE))
;
// Clear the interrupt flag
RFIRQF1 = 0;
// Reuse the FIFO
radio_lle_command(CMD_TXFIFO_RETRY);
// Wait for the radio to finish
while (!(RFIRQF1 & TASKDONE))
;
}