// rt-ng-esp32-timercountingsem // https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/ // https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/freertos-smp.html // https://microcontrollerslab.com/freertos-counting-semaphore-examples-arduino/ // JDN 2021 // ------------------- // ESP32 way to do timed semaphores for periodic signalling to be used for sampling etc char taskList[3000]; hw_timer_t *timer0; const int prescale = 80; // 80 MHz => 1 MHz SemaphoreHandle_t sem0; const int sem0PerCnt = 100; // means sem0 will be signalled every 100th interrupt volatile int sem0Cnt = 0; SemaphoreHandle_t sem1; const int sem1PerCnt = 500; // means sem1 will be signalled every 500th interrupt volatile int sem1Cnt = 0; void IRAM_ATTR onTimer0 () { // standard functinodeclaration + (!) IRAM_ATTR which force compiler to place function in interal high speed RAM - for quick run of code // periodic timer on sem0 sem0Cnt++; if (sem0PerCnt <= sem0Cnt) { sem0Cnt = 0; xSemaphoreGiveFromISR (sem0, NULL); } // periodic timer on sem1 sem1Cnt++; if (sem1PerCnt <= sem1Cnt) { sem1Cnt = 0; xSemaphoreGiveFromISR (sem1, NULL); } // etc } // DEBUG ONLY volatile int loop0 = 0, loop1 = 0; void task0 (void *pParms) { int i = 0; while (1) { while (xSemaphoreTake (sem0, 1000) != pdTRUE); // wait until next periodic signal from timer ISR loop0++; vTaskDelay (100 / portTICK_PERIOD_MS); // eat 100 msec cputime } } void task1 (void *pParms) { int i = 0; while (1) { while (xSemaphoreTake (sem1, 1000) != pdTRUE); // wait until next periodic signal from timer ISR loop1++; vTaskDelay (80 / portTICK_PERIOD_MS); // eat 80 msec cputime // test only // if uxSemaphoreGetCount(sem1) return 1 or larger it indicates we are behing because signals from ISR is pilling up Serial.print (millis ()); Serial.print (" sem1 value "); Serial.print (uxSemaphoreGetCount (sem1)); Serial.print (" "); Serial.print (loop0); Serial.print (" "); Serial.println (loop1); } } void setup () { Serial.begin (115200); delay (2000); Serial.println ("starting"); // sem0,sem1 .... sem0 = xSemaphoreCreateCounting (100, 0); sem1 = xSemaphoreCreateCounting (100, 0); xTaskCreate (task0, "t0", 2000, NULL, 2, NULL); xTaskCreate (task1, "t1", 2000, NULL, 2, NULL); // start reaktime timer to be used for doing signalling timer0 = timerBegin (0, 80, true); // 1usec pr tick timerAlarmWrite (timer0, 1000, true); // cyclic timer @ 1 Hz timerAttachInterrupt (timer0, onTimer0, true); // sem1 ... timer0 = timerBegin (0, prescale, true); // 1 usec pr tick - we have timer 0,1,2,3 - we do only use timert0 timerAlarmWrite (timer0, 1000, true); // cyclic timer @ 1000 Hz timerAttachInterrupt (timer0, onTimer0, true); // GOGO for timers timerAlarmEnable (timer0); } int fl = 0; void loop () { vTaskDelay (100); if (!fl) { fl = 1; vTaskList (taskList); Serial.print (taskList); } }