Skip to content

Commit 7141e3e

Browse files
stickbreakerme-no-dev
authored andcommitted
micros() returning inconsistend values when call from different tasks (#1165)
The cycle count that micros() is using to report timing is a PER Task value. When micros() or delayMicroseconds() is called from different Tasks, the lastCycleCount value may have no relationship to the current Task specific cycleCount. If the current cycleCount is less than the saved lastCycleCount a rollover condition is assumed. This erroneous conditions results in incorrect delays and reported microseconds. This fix creates thread local storage so that each Task will have accurate microsecond reporting and delays. The reported microseconds are not real time, they are microseconds of the current Task execution.
1 parent 1256f2e commit 7141e3e

File tree

1 file changed

+32
-7
lines changed

1 file changed

+32
-7
lines changed

cores/esp32/esp32-hal-misc.c

+32-7
Original file line numberDiff line numberDiff line change
@@ -38,20 +38,45 @@ void yield()
3838
}
3939

4040
portMUX_TYPE microsMux = portMUX_INITIALIZER_UNLOCKED;
41+
static pthread_key_t microsStore=NULL; // Thread Local Storage Handle
42+
43+
void* microsStoreDelete(void * storage) { // release thread local data when task is delete.
44+
if(storage) free(storage);
45+
}
4146

4247
unsigned long IRAM_ATTR micros()
4348
{
44-
static unsigned long lccount = 0;
45-
static unsigned long overflow = 0;
49+
if (!microsStore) { // first Time Ever thread local not init'd
50+
portENTER_CRITICAL_ISR(&microsMux);
51+
pthread_key_create(&microsStore,microsStoreDelete); // create initial holder
52+
portEXIT_CRITICAL_ISR(&microsMux);
53+
}
54+
55+
uint32_t *ptr;// [0] is lastCount, [1] is overFlow
56+
57+
ptr = pthread_getspecific(microsStore); // get address of storage
58+
59+
if(ptr == NULL) { // first time in this thread, allocate mem, init it.
60+
portENTER_CRITICAL_ISR(&microsMux);
61+
ptr = (uint32_t*)malloc(sizeof(uint32_t)*2);
62+
pthread_setspecific(microsStore,ptr); // store the pointer to this thread's values
63+
ptr[0] = 0; // lastCount value
64+
ptr[1] = 0; // overFlow
65+
portEXIT_CRITICAL_ISR(&microsMux);
66+
}
67+
4668
unsigned long ccount;
69+
4770
portENTER_CRITICAL_ISR(&microsMux);
48-
__asm__ __volatile__ ( "rsr %0, ccount" : "=a" (ccount) );
49-
if(ccount < lccount){
50-
overflow += UINT32_MAX / CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ;
71+
__asm__ __volatile__ ( "rsr %0, ccount" : "=a" (ccount) ); //get cycle count
72+
if(ccount < ptr[0]) { // overflow occurred
73+
ptr[1] += UINT32_MAX / CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ;
5174
}
52-
lccount = ccount;
75+
76+
ptr[0] = ccount;
5377
portEXIT_CRITICAL_ISR(&microsMux);
54-
return overflow + (ccount / CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ);
78+
79+
return ptr[1] + (ccount / CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ);
5580
}
5681

5782
unsigned long IRAM_ATTR millis()

0 commit comments

Comments
 (0)