10 years, 9 months ago.

Why is timer an int_32 rather than uint_32 ?

Doing some tests on the timer (on an LPC1768) I'm finding that the output cunts up to 2^31-1, then jumps to -1*2^31 - as would be expected if the actualy counter on the hardware wasa 32 bit unsigned register, but the mbed copmpiler was doing a conversion to signed int in 2's complement. So - why is the mbed library making this timer feature less useful - as it is it runs for about 35 minutes before going negative but if it was an unsigned int you'd get over an hour.

Any chance of an explanation or a fix would be appreciated.

Question relating to:

Hello,

have you read https://mbed.org/forum/helloworld/topic/1749/ ? I highlight also Timer's handbook where is a warning that it is designed to int intentionally.

Regards, 0xc0170

posted by Martin Kojtal 25 Jul 2013

2 Answers

9 years ago.

I suggest a more detailed dive into Timer.read_us and read_ms.

There is a basic claim that every SW timer should fulfill: The Overflow occurs in an unsigned form, i.e. from 2^N-1 (=max. type value) to 0. N is the full bit range of the unsigned function type. (The reason for this is that elapsed time is often measured by (ActualTime - LastTime) f. e.)

This is not the case for read_us because int Timer::read_us() is signed instead of unsigned. This is Problem #1.

Additionally I cannot say if the HW-timer behind read_us is a full 32 bit timer always. If not we have Problem #2.

With respect to read_ms I can say clearly that the overflow will not occur at the variable's max value because of

int Timer::read_ms() {
    return read_us() / 1000;
}

This is Problem #3.

Solving Problems 1&2 I expect the following. After 2^32 microseconds read_us overflows correctly to 0. Ok so far. Unfortunately due to Problem 3 read_ms overflows from (2^32-1)/1000 to 0. This happens roughly after 1100 45 days. Few people will have systems that will run up to this crash but some will.

Please confirm. If desired I may help to patch mbed sources since I have long time experience with µs resolution timing control combining HW and SW timers. Cheers. Edited on 2015-04-31

Might be handier to make a seperate question/topic.

Problem 3 will be far sooner, it will happen after 2^32 microseconds, so thats about an hour iirc. Your code should not crash on this generally, and it is not intended you use timer for such long operations, but instead use time (RTC). I do agree a natural overflow would be nice for ms, but i don't see a direct way to implement it.

Problem 1 shouldn't be an issue: Want unsigned? Add (uint32_t) in front of your code. From a binary pov it is exactly the same.

Problem 2: For most it is HW timer, some combine it with SW part to get to 32-bit at 1us resolution. That is only a problem if done incorrectly. For the K20 this is done correctly, because I did it :P (/smug). For the last version of the NRF I saw I don't think it is correct, but when I pointed it out they went into "lalalla I don't hear you" mode.

But of course you are always welcome to submit pull request for the mbed code. (Just to be clear, I am also a random user, no mbed staff).

posted by Erik - 30 Mar 2015

Brilliant. Thanks. I will have a look into your K20 code. Regarding milliseconds I have published an Arduino-lib which contains a full uint32_t millis(). You may have a glimpse. With respect to the NRF people I have a good personal relation to a manager and may give him a hint If you think it's good.

posted by Eduardo de Mier 31 Mar 2015
10 years, 9 months ago.

Thanks for this - no I'd not found this and it does give an excuse for the apparent limitation. It does seem a bit shortsighted to limit the utility of timer. On the LPC11U24 there's no realtime clock so this is quite a useful feature.

At present I've got a bit of a bodge that gets round this using type conversion to remove the negative and a seond variable to account for the rollovers. This method works fine as long as the calling routine polls the counter at least twice per 70 minute run.

Comparing to the rtc on a 1768 this goes no more than 300ms out after 4 hours...

Import programTimer_longtimes

Demo program to use the internal timer for long times

Timer for long times demo

#include "mbed.h"
#include "mbed.h"
//  Expanding the TIMER function to allow timing to very long times 
// Demo written for lpc1768 to compare to onboard realtime clock.
// uses highusecs to encode the top 32 bits of the timer output
// and an int to uint conversion to get rid of the annoying negative.

Timer t;

 
int main() {
set_time(1256729737);  // Set RTC time to Wed, 28 Oct 2009 11:35:37
float umax=0,seconds=0;
unsigned int realusecs=0,oldusecs=0,highusecs=0,minutes=0;;
int dtime,usecs=0;

    t.start();
    usecs=t.read_us();
    realusecs=(unsigned int)usecs;
    time_t rtcstart = time(NULL);
    printf("\n\n\r");
    while(1)
    {
    wait(1);
    oldusecs=realusecs;
    usecs=t.read_us();
    realusecs=(unsigned int)usecs;
    //if(realusecs==0) t.reset(); // timer counts back up to 0 and finishes there
   if(realusecs<oldusecs) { // its rolled over
    highusecs++; // increment highbyte
   }
   seconds=((float)realusecs/1000000.0)+4294.967296*(float)highusecs;
   minutes=(int)(seconds/60);
    
    if(umax<realusecs) umax=realusecs;
    time_t rtcsecs = time(NULL);
    dtime=rtcsecs-rtcstart;
    printf("Seconds=%6.2f  mins=%d   realus=%u     hus=%u     us=%d       rtcs=%d         oldusecs=%u          \r",seconds,minutes,realusecs,highusecs,usecs,dtime,oldusecs);
   
    }
}