Hello,
I'm playing with the timing subsystem in order to measure some execution time with higher granularity than the RTC tick on nRF52840 (using PCA10056 DK).
I'm specifically using the Nordic SoC implementation (NOT the architecture default for all Cortex-M using DWT):
... CONFIG_TIMING_FUNCTIONS=y CONFIG_CORTEX_M_DWT=n ...
This means that the backend is using this file https://github.com/zephyrproject-rtos/zephyr/blob/main/soc/arm/nordic_nrf/timing.c
The TIMER instance is initialised with 16MHZ frequency and 32-bit resolution.
When getting the cycle count over a period, the developer needs to use this function:
uint64_t soc_timing_cycles_get(volatile timing_t *const start,
volatile timing_t *const end)
{
#if defined(CONFIG_SOC_SERIES_NRF51X)
#define COUNTER_SPAN BIT(16)
if (*end >= *start) {
return (*end - *start);
} else {
return COUNTER_SPAN + *end - *start;
}
#else
return (*end - *start);
#endif
}
Now, I believe that there are cases where the natural 64-bit unsigned modulo arithmetic is not working properly here, since start and end are 32-bit values (just casted), and as such an explicit handling of the overflow (e.g. start == (UINT32_MAX - t1) and end == t2) is needed.
I discovered this by using a routines measuring an average of execution over time, as the problem is occurring only in the specific overflow cases.
This is my quick and dirty solution:
.... uint32_t delta = ((uint32_t)*end) - ((uint32_t)*start); return delta;
Can you please confirm me if this does make sense to you or the problem is somewhere else?
In case I can just open a PR on Zephyr itself, as this is part of that codebase...
Thanks!
D