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.

TASKDONE Flag in Proprietary Mode Advertiser

Other Parts Discussed in Thread: CC2541

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))
    ;
}

  • There are no known issues with getting TASKDONE. A few questions to help the find the problem:

    What are the settings of the RAM-based registers, in particular the PRF_TASK_CONF register?

    After having waited for TASKDONE some time, what are the values of the LLESTAT and RFSTAT registers?

  • Hello Dan,

    As mentioned by Hec, it would help us to know the settings of the RAM-based registers that you use.You have to make sure that the LLE does not deallocate the packet after it has been transmitted. Set the REUSE (bit2) the following way:

    PRF.ADDR_ENTRY[0].CONF.REUSE    = 1;    // Reuse packet. 
  • Thanks for your quick responses and sorry for the delay in replying.  I wanted to try to understand the problem better.  Here's what I know so far:

    The problem is hardware dependent.  I depanelized two panels of our advertiser boards and binned them according to the failure modes:  1) Hangs in while loop after CMD_TX, 2) Hangs in while loop after CMD_TXFIFO_RETRY, 3) No problem found.  The failure modes are 100% repeatable, meaning a board that exhibits a particular failure mode will always do so.  Visual inspection showed no observable differences.  These are all run on our own SMT line, no hand-made devices or anything like that.

    So the combination of this plus your response that there is no known issue with TASKDONE has us looking at hardware.  This is an incremental revision of a previous prototype, with minimal changes to the design, so at this point we're mystified.  Previous versions did not exhibit this behavior, at least in such a clearly noticeable way.  I still need to get together with the hardware engineer to discuss possible causes.

    Meanwhile, I spent some time looking at LLESTAT and RFSTAT as hec suggested.  First, my code for the CMD_TX checks only whether one of the flags is set:

      while (!(RFIRQF1 & TXDONE) && !(RFIRQF1 & TASKDONE));

    and it appears that TASKDONE can be set while TXDONE remains un-set. Of course the task can complete and TX can fail, but we're never getting out of the while() loop at all, so that's not what's happening in our case.  When we do exit the while() loop, PRF_ENDCAUSE is always 0.

    When the command succeeds, LLESTAT = 0x04 and RFSTAT = 0, as would be expected.  When it fails, I am seeing LLESTAT = 0x01 and RFSTAT = 0x16, which are clearly showing that the TX was not finished.  These are viewed at breakpoints in the code, after 0xFFFF iterations through a brief loop, but clearly a long time after the TX should have finished.  (Successful TX took 329 iterations with one device and 362 with another, so 0xFFFF is a long time.)

    I also found that resetting the LLE (LLECTRL = 0; LLECTRL = 1;) enabled the device to transmit successfully, but I haven't determined if the error is on all three channels and of course resetting the LLE once every second is not a solution.  The TI Packet Sniffer does one channel at time; I may try to set up three dongles and three instances of the sniffer.

    It's interesting to see that the code Eirik V. provided simply waits for TASKDONE the way my code does.  And I do believe PRF_ADDR_ENTRY0_0 was set correctly with REUSE enabled.

    So, at this point, there are mostly still questions.  I still suspect hardware but we need to understand the cause and we need to implement something more robust than the current while() loops.

    Regards,
    Dan Lewis


    RAM-based registers:

      #define DONTCARE 0
      #define TXPACKETSIZE 0x0C

      PRF_TASK_CONF = 0;
      PRF_FIFO_CONF = 0;
      PRF_PKT_CONF = 0;
      PRF_CRC_LEN = 3;
      PRF_RSSI_LIMIT = DONTCARE;
      PRF_RSSI_COUNTH = DONTCARE;
      PRF_RSSI_COUNTL = DONTCARE;
      PRF_RETRANS_CNT  = DONTCARE;
      PRF_TX_DELAY = 1;
      PRF_RETRANS_DELAY = DONTCARE;
      PRF_SEARCH_TIMEH = DONTCARE;
      PRF_SEARCH_TIMEL = DONTCARE;
      PRF_RX_TX_TIME = DONTCARE;
      PRF_TX_RX_TIME = DONTCARE;
      PRF_ADDR_ENTRY0_0 = 4;
      PRF_ADDR_ENTRY0_1 = TXPACKETSIZE + 3;
      PRF_N_TX = DONTCARE;
      PRF_LAST_RSSI = DONTCARE;
      PRF_LAST_DCOFF = DONTCARE;
      PRF_ENDCAUSE = DONTCARE;
      PRF_ADDR_ENTRY0_A = 0;
      PRF_ADDR_ENTRY0_B = 0;




  • Update:  This is somehow related to the wakeup after sleep.  If I change the code so the device will only enter Power Mode 2 after, say, the fifth advertisement, I get five advertisements but on the next pass (after sleep + wakeup) the code hangs waiting for TASKDONE.

    Our code to initialize the clock settings after reset comes from the BLE library and is the same code that everyone seems to be using.  We use the sleep timer set to interrupt once per second (+/- a random advDelay per the BLE spec).

    After wakeup, we use

      while (!(SLEEPSTA & XOSC_STB))
        ;

    before using the radio.  I have tried different settings for the clocks, using 32 kHz XOSC vs. ROSC, etc, but nothing has made a difference.  However, if I change the code so the device goes to sleep in Power Mode 1 instead instead of Power Mode 2, the problem does not occur.  Perhaps the difference between PM1 and PM2 contains a clue -- I have to study this some more.

    So at this point, the mystery is more clearly defined but still a mystery:  How can entering Power Mode 2 and waking cause the radio to hang waiting for TASKDONE?  

    To restate, this is 100% repeatable and follows a specific LLE command (CMD_TX or CMD_TXFIFO_RETRY) for specific devices, while other devices do not exhibit the problem.

    Next, a hardware engineer will take a close look at the oscillators.

  • Hi,

    A few more things to check: Are there any FIFO errors reported in the RFERRF register? For the PRF_ENDCAUSE register, I would recommend to set it to an unused value (e.g. 0xCC)  before you send the command so that you can check if it has been set to TASK_ENDOK (0) or if it has not been written by the LLE.

    The sleep information is absolutely interesting. First, I assume you do not go to sleep while the radio is running? That is not supported and has not been tested, so I don't quite know what could happen in that case.

    One thing you can do is to set the CRC_RESET_EN bit in the SRCRC register to 1. If you then observe that the chip resets when coming up from PM2, you have an explanation for the problem, as this means that some of the retained registers have changed their value. If this is the case, I would look at the power supply during PM2.

    For the clock check on coming up from PM2, you should check that the system is actually running on XOSC, not just that the XOSC is stable, i.e.,
    while (CLKCONSTA & 0x40);
    I am not sure if this gives any difference, but it is at least as safe as what you are doing.

  • A further update.  

    I haven't tried hec's latest suggestions yet.  We have seen some differences in behavior at different voltage levels, 3.0V vs. 3.4V, for example, but it's still anecdotal and we're still investigating.

    We have been looking at what is supposed to happen when the CC2541 comes up out of PM2, and whether something needs to be done to reinitialize the radio.  I find nothing in the User's Guide that suggests anything is required, and of course we have a set of boards that works perfectly without any reinitialization.  Page 0 (RAM registers) and Page 7 (Tx FIFO) are preserved in all power modes.  In any case, I tried reinitializing all of the RAM registers, and then all of the other registers, but no difference.  I also tried resetting the page 5 values, just in case I was misinterpreting the User's Guide, but that made no difference.

    The one thing that *does* work on devices that exhibit the problem is resetting the radio (LLECTRL = 0 followed by LLECTRL = 1), any time after the CC2541 returns to active mode and before the first TX_CMD.  The device transmits once per second as expected.

    We will continue looking at the hardware including the oscillators, but it seems that if there were something wrong with the oscillators, resetting the radio wouldn't fix the problem.

    The User's Guide (Table 25-7, in the note) says that "the LLE is reset when the device enters PM2 or PM3".  Is it possible this is not happening?  Are there any requirements for the radio after coming out of PM2 that we are missing?  I assume there is no reason why we couldn't "manually" reset the radio after returning to active mode, but we still want to understand what's causing the problem.

  • We have identified an issue in the chip when it goes to PM2/PM3 while bit 0 of LLECTRL is 1. Because of this, LLECTRL must be set to 0 before entering PM2/PM3. It may be set back to 1 at any time after waking up. We will add this information to the next revision of the user guide.

    I believe this simple workaround should solve your issue.