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.

Incorrect rollover behavior when using RTI 64-bit counters



Until recently, we were using the RTI counters as a 64-bit free-running counter for all timing in our TMS570LS3137-based system.  We'd initialize the counter like so:

void ClockInit() {
RTIGCTRL_bit()->CNT0EN = 0; // Disable counter 0.
 *RTICPUC0() = 0; // Increment RTIUC0 when RTIFRC0 rolls over.
*RTIFRC0() = 0; // Zero upper 32 bits.
*RTIUC0() = 0; // Zero lower 32 bits.
 RTIGCTRL_bit()->COS = 0; // Don't let the clock run while debugger halted.
RTIGCTRL_bit()->CNT0EN = 1; // Enable counter 0.
}

We'd read the clock like so:

int64_t ClockTicks() {
return (static_cast<int64_t>(*RTIFRC0()) << 32) | *RTIUC0();
}

Every ~4 hours of operation, we'd see an odd backwards jump in time.  After writing a test program, I noticed that occasionally the lower 32 bits would read 0, while the upper 32 bits hadn't incremented yet:

ClockTicks() jumped from 0x0000000a ffffffd6 to 0x0000000a 00000000

I'm guessing this is a result of setting RTICPUC0 to 0 rather than 0xFFFFFFFF.  The documentation is not at all clear on what to put in RTICPUC0 to get a 64-bit counter - I assumed that since it specifically called out RTICPUC0 = 0 as causing the rollover frequency fRTIFRCx to be fRTICLK / 232 in section 13.2.1 of the TRM, that setting RTICPUC0 = 0 would work.

How can we get this counter to work correctly?  Could you please update the errata and TRM to document the actual behavior of the chip?

Seth

  • Seth,

    The setting looks correct to me. From your c-code, I could not figure out which register is read first, RTIFRCO or RTIUCO? According to RTI spec, you have to read RTIFRCO register before reading the RTIUCO register. I quoted the spec as follows.

    Up counter 0. This register holds the current value of the up counter 0 and prescales the RTI clock. It will be only updated by a previous read of free running counter 0 (RTIFRC0). This method of updating effectively gives a 64-bit read of both counters, without having the problem of a counter being updated between two consecutive reads on up counter 0 (RTIUC0) and free running counter 0 (RTIFRC0). A read of this counter returns the value of the counter at the time RTIFRC0 was read.

    Please let me know if the above answers your question.

    Thanks and regards,

    Zhaohong

  • (I work on the same project)  We definitely read RTIFRCO first before reading RTIUCO.  (We verified the other way around does not work!)

    Seth's example code doesn't show that, but our actual production code definitely does.

    Almost all the time, it works fine.  The specific issue is around the rollover point.  We definitely get inconsistent values from RTIFRCO and RTIUCO, even reading in the correct order.  RTIUCO seems to roll over to 0 an instant before RTIFRCO increments.

  • Egnor,

    I can try on our EVM if you can share the test code for the wrong behavior.

    Thanks and regards,

    Zhaohong

  • OK, here's some code that reproduces the behavior:

    uint64_t ReadCounter1() {
    uint64_t upper = *RTIFRC1();
    uint32_t lower = *RTIUC1();
    return (upper << 32) | lower;
    }

    void MainIteration() {
    for (int offset = 100; offset < 500; ++offset) {
    // Initialize RTI counter 1.
    RTIGCTRL_bit()->CNT1EN = 0; // Disable counter 1.
    *RTICPUC1() = 0; // Increment RTIUC1 when RTIFRC1 rolls over.
    *RTIUC1() = 0xffffffff - offset;
    // Start near rollover.
    RTIGCTRL_bit()->CNT1EN = 1; // Enable counter 1.

    // Look for jumps.
    uint64_t prev = ReadCounter1();
    for (int i = 0; i < 10000; ++i) {
    uint64_t now = ReadCounter1();
    uint64_t delta = now - prev;
    if (delta > 100) {
    printf("Counter jumped from 0x %08x %08x to 0x %08x %08x offset %d!\n",
    int(prev >> 32), int(prev), int(now >> 32), int(now), offset);
    now = ReadCounter1();
    }
    prev = now;
    }
    }
    }

    Here's the output I see:

    Counter jumped from 0x 000000b5 ffffffe2 to 0x 000000b5 00000000 offset 131!
    Counter jumped from 0x 000000d3 ffffffe2 to 0x 000000d3 00000000 offset 161!
    Counter jumped from 0x 000000f1 ffffffe2 to 0x 000000f1 00000000 offset 191!
    Counter jumped from 0x 0000010f ffffffe2 to 0x 0000010f 00000000 offset 221!
    ... 

    If I change the up-count compare initialization to "*RTICPUC1() = uint32(-1)" then it seems to work correctly.

    Seth

  • Seth,

    What is clock source for RTICLK? Is it OSCIN or VCLK? If it is OSCIN then can you try to see if changing to VCLK will make a difference?

    Thanks and regards,

    Zhaohong

  • Seth,

    I can repeat your observation from our bench. There is no issue when the up counter compare register RTICPUC0/1 is set  to 0xffffffff. I also checked that we do have tests to verify if the free running counter is incremented when the up counter rolls back to 0x0. However,  the case when RTICPUC0/1 equals 0x0 is not covered. I have designers to check the RTL and they told me that some different logic is used when RTICPUC0/1 is set  to 0x0. I have requested a design simulation to see if it is just a register update timing issue. We will update the spec once we get the result. In the mean time, please set RTICPUC0/1 is set  to 0xffffffff.

    Thank you very much for finding this issue for us.

    Zhaohong

  • Seth,

    The simulation data is back. When RTICPUC0/1 register is set to zero, RTIUC0/1 stops at 0x0 for two RTI clcoks when it rolls back to 0x0. The free-running RTI counter is updated at the second cycle. If the read occurs at the first cycle, you will see RTIUC0/1 at 0x0 but the free running counter is not updated. We are updating the RTI user guide. Thanks gain for your help.

    Do you need more information on this topic? Would you please select the "verified" button if you consider that this question is answered?

    Thanks and regards,

    Zhaohong