A faster way to get time in microseconds? Timer API is very slow with STM32f103RB

I am trying to get microsecond time values between similar events.
Being measured in microseconds isn’t important. It could be system clock ticks, but milliseconds aren’t accurate enough. Elapsed times over a few seconds are ignored so overflow past 32 bits isn’t important.

What I’ve tried:
timer.elapsed_time().count() This returns an accurate time, but it takes about 87us.
|clk tiks 5601 |us 87 |

timer.read_us() This is nearly as slow, AND doesn’t work correctly. The return appears constrained to an unsigned 16bit integer.
|clk tiks 5280 |us 82 |

us_ticker_read() This is much faster, but also seems constrained to 16 bit integers.
|clk tiks 107 |us 1 |

This is running on a nucleo -F103RB using mbed 6.17.0
The for loop is used to figure out long it takes to read the timer.

Timer timer;
MidiIn midi_in;
int main() {
  timer.start();

  uint32_t ct = 1;
  uint32_t starttime;
  uint32_t endtime;
  uint32_t timeelapsed;

  starttime = timer.elapsed_time().count();
  for (int i = 0; i < 100000; i++) {
    ct = timer.elapsed_time().count();
  }
  endtime = timer.elapsed_time().count();
  timeelapsed = endtime - starttime;
  printf("ct %u\n", ct);
  printf("time %7d |", timeelapsed);
  printf("clk tiks %4d |", (timeelapsed * 64) / 10000);
  printf("us %4d |\n", timeelapsed / 10000);

  while (true) {
  }
}

I’ve had luck on other micros like the Novoton M453 just accessing system timers by registers and returning values with in a few system clock cycles, but the method to do that with STM under mbed seems opaque, or at least much more complicated.

Hi,
I tried your program with small modification as below.

#include "mbed.h"
#define NUM_LOOP 100000
Timer timer;
int main() {
    uint32_t ct = 1;
    uint32_t starttime;
    uint32_t endtime;
    uint32_t timeelapsed;
    uint32_t ave_time_ns;

    timer.start();
    printf("line:%d\n", __LINE__);
    while (us_ticker_read() < 120000) {  // waiting over 16bit
        ;
    }
    printf("line:%d\n", __LINE__);
    starttime = timer.elapsed_time().count();
    for (int i = 0; i < NUM_LOOP; i++) {
#if 0
        ct = timer.elapsed_time().count();
#else
        ct = us_ticker_read();
#endif
    }
    endtime = timer.elapsed_time().count();
    timeelapsed = endtime - starttime;
    printf("ct=%u, hex=0x%x\n", ct, ct);
    printf("time=%7d [us]\n", timeelapsed);
    printf("read average time for ticker_read -> %4d [microSec]\n", timeelapsed / NUM_LOOP);
    ave_time_ns = timeelapsed * 1000 / NUM_LOOP;
    printf("read average time for ticker_read -> %4d [nanoSec]\n", ave_time_ns);
    while (true) {
        ;
    }
}

tested board: Nucleo-F303K8
mbed-os: 6.17.0
resulet(copied from screen):

<timer.elapsed_time().count()>
line:12
line:16
ct=1178689, hex=0x11fc41
time=1051575 [us]
read average time for ticker_read → 10 [microSec]
read average time for ticker_read → 10515 [nanoSec]

<us_ticker_read()>
line:12
line:16
ct=143003, hex=0x22e9b
time= 15701 [us]
read average time for ticker_read → 0 [microSec]
read average time for ticker_read-> 157 [nanoSec]

Please try my program for your F103RB and hope similar result.
You can use us_ticker_read() function for your application because return value is uint32_t.
157nS is not a time for use us_ticker_read() but it includes for loop control time.
Inside mbed-os, us_ticker_read() is macro call.
#define us_ticker_read() (TIM_MST->CNT) (\target\TARGET_STM\us_ticker_define.h line35)
TIM_MST is 32bit Timer2 or 5.

I hope you can use us_ticker_read() function and go to next step for your application.

I copied it into a new file. When using us_ticker_read() with the 103RB it never passes line 12.

I can’t find my F303K8 board, but I tried it with a Nucelo-F446RB and it worked.
It seems that us_ticker_read() isn’t working correctly on the 103RB.

I found that earlier and tried calling TIM_MST->CNT directly but it was the same result.
I was hoping I’d not need to dive too deep into the mbed library files, but I’m looking now, although I’m not sure I know enough about STM’s clock setup to recognize an error.

I found this line in mbed-os/targets/TARGET_STM/TARGET_STM32F1/us_ticker_data.h

#define TIM_MST_BIT_WIDTH 16 // 16 or 32

For other targets it’s set to 32. I tried changing it to 32, but it’s still looks constrained to 16bits.

I 'm sorry for giving you incorrect information.
I did not have Nucleo- F103RB board and thought it was a generic STM32series with the same specifications, but not same.
F103RB uses Timer4 for tick and not 32bit but 16bit timer.
Therefor

 while (us_ticker_read() < 120000) {;} 

part will never exit.
Unfortunately, F103RB does not have 32bit timer.

1 Like