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.

problem clearing simultaneous RTC_{CH0,CH1} events

inside my RTC interrupt routine, i'm individually handling RTC_CH0 and RTC_CH1 events as follows:

/* enter critical section */

if (AONRTCEventGet(AON_RTC_CH0)) {
    /* process event */
    AONRTCClearEvent(AON_RTC_CH0);
}

if (AONRTCEventGet(AON_RTC_CH1)) {
    /* process event */
    AONRTCClearEvent(AON_RTC_CH1);
}

/* leave critical section */

using a synthetic test, i'm able to force CH0 and CH1 to simultaneously trigger events....  in this case, i find that the act of clearing the CH0 event in fact clears the CH1 event as well!!!!

looking at the underlying AON_RTC_O_EVFLAGS registers, i find that its value is 0x101 upon entry to the interrupt routine -- signifying that CH0 and CH1 have events pending -- but then find that is value become 0x000 after the first AONRTCClearEvent(AON_RTC_CH0) call....  when i subsequently test for an event on CH1 by calling AONRTCEventGet, none is found....

to remove any doubt, i tried directly writing a 1 to the appropriate bit-band alias; i also tried various combinations of reading/writing the SYNC register....  i'm using the IAR compiler and have inspected the generated code; nothing suspicious here either....

question -- shouldn't i be able to atomically clear a single bit inside EVFLAGS???  perhaps there is a problem since the RTC registers reside in the AON domain???

  • Hello BIOS Bob,

    I've placed an inquiry with our driver team. Due to the holidays, it may take a bit longer to get an answer.

    Best wishes
  • Hello Bob,

    Are you running this within TI-RTOS?

    Could you share your project with me so that i could take a look at it?

  • hi erik,

    i'm not using TI-RTOS -- just the driverlib from CC26xxWare....

    i have, however, seen code similar to what i've shown above in the BLESTACK (hal_rtc_wrapper.c) as well as in Timer.c within the TI-RTOS....

    once again, i have a situation where an RTC_CHO *and* RTC_CH1 events have occurred at the same time -- something that you be able to easily force in a test program....

    would it possible for you to create such a test program using TI-RTOS, which would then verify that we don't in fact have a problem with the underlying HW???

    thanks, bob.
  • Hello Bob,

    The TI-RTOS kernel use the AON RTC for timing so I am not sure I can setup a RTOS test program for it. I will check.

    • How do you trigger the two events?
    • Does this issue occur every time (from the first time you trigger the two events and subsequentially)?
    • Are you sure you are not reading an outdated value when you enter your ISR?
    • Have your read chapter "14.3.1 Register Access" chapter in the RTC chapter in the TRM?

  • hi erik,

    i work directly with the AONRTC functions in the CC26xx driverlib; these allow you to setup the RTC, etc....

    i trigger the two events simultaneous by simply having both channels setup in compare mode, and then loading the same (future) time in their respective compare registers....

    yes, the issue occurs repeatedly....

    i'm familiar with the protocol around sync'ing the AON domain, and have taken the necessary steps in my code....

    bob.

  • Hello Bob,
    I have reproduced the issue using a direct driverlib implementation. I will inquire our driverlib team for further investigation. Due to holidays it might take some time. I tried to read-modify-write the register directly instead of using the bit-band region to clear the single bit without any luck.
  • hi erik,

    good news in a funny way....

    at one point, i actually did a read-modify-write of the underlying register to obtain and clear *all* of the status flags at once....  this in fact did work for me -- though there is small window which in fact my application exposed.....

    bottom line: the device was designed to allow individual events to be cleared via writes to the bit-band alias....  and there is definitely a reason for this....

    thanks for the effort....

    bob.

  • Hello bios.bob,

    It turns out that the CM3 architecture will do a read, modify write when writing to the bit-banding region, meaning that the AONRTCClearEvent function in aon_rtc.h is incorrect. For strobe registers such as this (like the EVFLAGS Register) only direct writes much be issued to set a single bit and hence clear the single event. For now try out this version instead until we update driverlib in CC26xxWare:

    void AONRTCEventClear(uint32_t ui32Channel)
    {
    uint32_t evFlags = 0;
    // Check the arguments. ASSERT((ui32Channel == AON_RTC_CH0) || (ui32Channel == AON_RTC_CH1) || (ui32Channel == AON_RTC_CH2)); if(ui32Channel & AON_RTC_CH0) { evFlags = AON_RTC_EVFLAGS_CH0; } if(ui32Channel & AON_RTC_CH1) { evFlags |= AON_RTC_EVFLAGS_CH1; } if(ui32Channel & AON_RTC_CH2) { evFlags |= AON_RTC_EVFLAGS_CH2; } HWREG(AON_RTC_BASE + AON_RTC_O_EVFLAGS) = evFlags;
  • hi erik,

    i currently do something like this in my workaround, but there is still a problem....

    suppose in your code above that a CH0 event occurs *after* your tested for that event but *before* you perform the write to EVFLAGS....

    in this case, you would effectively dismiss an event that you never really knew has occurred....

    now, you can make the window even smaller by essentially reading EVFLAGS and then immediately writing EVFLAGS to clear incoming events; you would then test the value read initially to see which events actually occurred....

    but even this is not safe -- for another event can occur between the read and write of EVFLAGS; and turning off interrupts doesn't help here, since the RTC continues to operate....

    i think the "root cause" is that *any* write to EVFLAGS seems to clear *all* events that are outstanding!!!!   said another way, even if just one bit is set in your evFlags variable, the write will clear any other events that may be current at that moment....  that's why the bit-banding doesn't work -- because writing one bit seems to have this nasty side-effect....

    bob. 

  • Hello bob,
    You can clear a single flag by doing a direct register write as I do in the code snippet above. In my code above all I do is to collect all the flags to be cleared at once instead of potentially sending multiple clears flag writes "back2back". You cannot clear using the bit-banding region because the memory bus will effectively read-modify-write, meaning that if you get for example:
    tmp = EVFLAGS (0x101);
    tmp |= 0x01; (value is still 0x101)
    EVFLAGS = tmp; (now both ch0 and ch1 will be cleared)

    All strobe registers cannot use the bit-banding region if there are more than a single bit to clear in the register. Then you have to use direct access.

    By setting the bit directly you can clear a single channel. I tested this successfully. For example:
    HWREG(AON_RTC_BASE + AON_RTC_O_EVFLAGS) = 0x01; // Clear channel 0.

    Or did I misunderstand? Will this not fix your issue?

  • erik,

    there is a small window between the time you check EVFLAGS and actually clear EVFLAGS.....

    this means that you can potentially have an event occur *after* your read EVFLAGS but *before* you clear EVFLAGS.....

    this would not be that bad, except for what i believe is the root problem:::

    suppose EVFLAGS had that value 0x101 (meaning two channels are ready)....  if you were to actually write that value 0x1 to EVFLAGS, it would essentially clear the entire register -- dismissing the other event....

    if both events had occurred at the time of the check, there is no issue.....   but suppose the second event occurred *after* the check (which only revealed 0x1)????

    bottom line -- i can find a way to clear these events *individually*, as writing to EVFLAGS seems to clear them all!!!!

    bob.

  • Hello Bob,
    I think we are misunderstanding each other. Let me know if I am the one out of sync :).

    It works to clear a single flag. You just have to access it directly like this:
    HWREG(AON_RTC_BASE + AON_RTC_O_EVFLAGS) = 0x01; // Clear channel 0 only
    // Only evflag for RTC channel 0 will be cleared.

    Simply alter the AONRTCEventClear function to use direct registers calls (HWREG) instead of using the bit.banding region.
  • here's a scenario that illustrates the underlying problem...

    suppose EVFLAGS == 0x101  // events pending on CH0 and CH1

    if i then assign EVFLAGS = 0x1  // i just want to clear CH0

    i find that the value of EVFLAGS == 0x0 // that is, i have actually cleared *both* events through the assignment

    clearly, if i *know* EVFLAGS == 0x101, then i can simply clear both events by writing EVFLAGS = 0x101

    but what happens if CH0 and CH1 events occur *slightly* out of sync -- that is, the CH1 event occurs *after* i test EVFLAGS but *before* i assign EVFLAGS

    for what reason, writing to 1 to *any* of the bits in EVFLAGS seems to clear *all* of the events....

    without the ability to clear only one channel *without* the side-effect of clear all the channels, there is a window of vulnerability when incoming events can be silently cleared....

    going back to the hardware, if EVFLAGS == 0x101 and i assign EVFLAGS = 0x1, i would think that EVFLAGS would then equal 0x100....  said another way, i have cleared CH0 *without* dismissing CH1 at the same time.... 

  • Hello Bob,

    I totally agree, but what I mean is that the following is not true:

    without the ability to clear only one channel *without* the side-effect of clear all the channels,

    You can clear any single flag without the others being cleared. I have tested this and described the direct register write procedure to use above. You just cannot use the current function in cc26xxware (need to be modified to use direct 32-bit register write instead of the bit-band region, HWREG instead of HWREGBITW). 

  • hi eirik,

    my bad!!!!!

    i was accidently assigning EVFLAGS with a |= operator instead of a simple assignment....

    i have verified that i can in fact clear events individually....

    as a small optimization, i read/clear *all* the pending events as follows:

    uint32_t evflags = HWREG(AON_RTC_BASE + AON_RTC_O_EVFLAGS);

    HWREG(AON_RTC_BASE + AON_RTC_O_EVFLAGS) = evflags;

    if (evflags & 0x1) { `handle CH0 event` }

    if (evflags & 0x100) { `handle CH1 event` }

    if (evflags & 0x10000) { `handle CH2 event` }

    note that it is not necessary to perform this read/clear of EVFLAGS with interrupts disabled, since the register itself would latch any *additional* events that might occur between the read and write....  also note that any events that occur *after* the read will simply trigger another interrupt after the initial set of events have been handled....

    problem solved....

    thanks, bob.

  • Great! Indeed.