diff --git a/Doxyfile b/Doxyfile index 8714b0476..ba612fc33 100644 --- a/Doxyfile +++ b/Doxyfile @@ -4,6 +4,7 @@ INPUT = src INPUT += docs/doxygen_index.md RECURSIVE = YES EXCLUDE = examples +EXCLUDE += src/hal MULTILINE_CPP_IS_BRIEF = YES TAB_SIZE = 2 EXTRACT_ALL = YES diff --git a/src/IRrecv.cpp b/src/IRrecv.cpp index 97fb10c6c..e76cacbd9 100644 --- a/src/IRrecv.cpp +++ b/src/IRrecv.cpp @@ -56,20 +56,24 @@ static ETSTimer timer; } // namespace _IRrecv #endif // ESP8266 #if defined(ESP32) +#if ( defined(ESP_ARDUINO_VERSION) && \ + (ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0)) ) +#define _ESP32_ARDUINO_CORE_V3PLUS +#endif // ESP_ARDUINO_VERSION >= 3 // We need a horrible timer hack for ESP32 Arduino framework < v2.0.0 -#if !defined(_ESP32_IRRECV_TIMER_HACK) +#if !defined(_ESP32_ARDUINO_CORE_V2PLUS) // Version check #if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 2) ) // No need for the hack if we are running version >= 2.0.0 -#define _ESP32_IRRECV_TIMER_HACK false +#define _ESP32_ARDUINO_CORE_V2PLUS false #else // Version check // If no ESP_ARDUINO_VERSION_MAJOR is defined, or less than 2, then we are // using an old ESP32 core, so we need the hack. -#define _ESP32_IRRECV_TIMER_HACK true +#define _ESP32_ARDUINO_CORE_V2PLUS true #endif // Version check -#endif // !defined(_ESP32_IRRECV_TIMER_HACK) +#endif // !defined(_ESP32_ARDUINO_CORE_V2PLUS) -#if _ESP32_IRRECV_TIMER_HACK +#if _ESP32_ARDUINO_CORE_V2PLUS // Required structs/types from: // https://github.com/espressif/arduino-esp32/blob/6b0114366baf986c155e8173ab7c22bc0c5fcedc/cores/esp32/esp32-hal-timer.c#L28-L58 // These are needed to be able to directly manipulate the timer registers from @@ -131,10 +135,10 @@ typedef struct hw_timer_s { uint8_t timer; portMUX_TYPE lock; } hw_timer_t; -#endif // _ESP32_IRRECV_TIMER_HACK / End of Horrible Hack. +#endif // _ESP32_ARDUINO_CORE_V2PLUS / End of Horrible Hack. namespace _IRrecv { -static hw_timer_t * timer = NULL; +static hw_timer_t *timer = NULL; } // namespace _IRrecv #endif // ESP32 using _IRrecv::timer; @@ -215,7 +219,7 @@ static void USE_IRAM_ATTR gpio_intr() { else params.rawbuf[rawlen] = (now - start) / kRawTick; } - params.rawlen++; + params.rawlen = params.rawlen + 1; // C++20 fix start = now; @@ -225,8 +229,8 @@ static void USE_IRAM_ATTR gpio_intr() { #if defined(ESP32) // Reset the timeout. // -#if _ESP32_IRRECV_TIMER_HACK - // The following three lines of code are the equiv of: +#if _ESP32_ARDUINO_CORE_V2PLUS + // The following three lines of code are the equivalent of: // `timerWrite(timer, 0);` // We can't call that routine safely from inside an ISR as that procedure // is not stored in IRAM. Hence, we do it manually so that it's covered by @@ -241,10 +245,15 @@ static void USE_IRAM_ATTR gpio_intr() { // @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1350 // @see https://github.com/espressif/arduino-esp32/blob/6b0114366baf986c155e8173ab7c22bc0c5fcedc/cores/esp32/esp32-hal-timer.c#L176-L178 timer->dev->config.alarm_en = 1; -#else // _ESP32_IRRECV_TIMER_HACK +#elif defined(_ESP32_ARDUINO_CORE_V3PLUS) + // For ESP32 core version 3.x, replace `timerAlarmEnable` + timerWrite(timer, 0); + uint64_t alarm_value = 50000; // Example value (50ms) + timerAlarm(timer, alarm_value, false, 0); +#else // !_ESP32_ARDUINO_CORE_V3PLUS timerWrite(timer, 0); timerAlarmEnable(timer); -#endif // _ESP32_IRRECV_TIMER_HACK +#endif // _ESP32_ARDUINO_CORE_V2PLUS #endif // ESP32 } #endif // UNIT_TEST @@ -366,8 +375,15 @@ void IRrecv::enableIRIn(const bool pullup) { } #if defined(ESP32) // Initialise the ESP32 timer. +#if defined(_ESP32_ARDUINO_CORE_V3PLUS) + // Use newer timerBegin signature for ESP32 core version 3.x + timer = timerBegin(1000000); // Initialize with 1MHz (1us per tick) +#else // _ESP32_ARDUINO_CORE_V3PLUS // 80MHz / 80 = 1 uSec granularity. timer = timerBegin(_timer_num, 80, true); +#endif // _ESP32_ARDUINO_CORE_V3PLUS + + // Ensure the timer is successfully initialized #ifdef IR_DEBUG if (timer == NULL) { DPRINT("FATAL: Unable enable system timer: "); @@ -375,12 +391,17 @@ void IRrecv::enableIRIn(const bool pullup) { } #endif // IR_DEBUG assert(timer != NULL); // Check we actually got the timer. - // Set the timer so it only fires once, and set it's trigger in uSeconds. + // Set the timer so it only fires once, and set its trigger in microseconds. +#if defined(_ESP32_ARDUINO_CORE_V3PLUS) + timerWrite(timer, 0); // Reset the timer for ESP32 core version 3.x + timerAttachInterrupt(timer, &read_timeout); +#else // _ESP32_ARDUINO_CORE_V3PLUS timerAlarmWrite(timer, MS_TO_USEC(params.timeout), ONCE); // Note: Interrupt needs to be attached before it can be enabled or disabled. // Note: EDGE (true) is not supported, use LEVEL (false). Ref: #1713 // See: https://github.com/espressif/arduino-esp32/blob/caef4006af491130136b219c1205bdcf8f08bf2b/cores/esp32/esp32-hal-timer.c#L224-L227 timerAttachInterrupt(timer, &read_timeout, false); +#endif // _ESP32_ARDUINO_CORE_V3PLUS #endif // ESP32 // Initialise state machine variables @@ -404,8 +425,11 @@ void IRrecv::disableIRIn(void) { #ifndef UNIT_TEST #if defined(ESP8266) os_timer_disarm(&timer); -#endif // ESP8266 -#if defined(ESP32) +#elif defined(_ESP32_ARDUINO_CORE_V3PLUS) + timerWrite(timer, 0); // Reset the timer + timerDetachInterrupt(timer); + timerEnd(timer); +#elif defined(ESP32) timerAlarmDisable(timer); timerDetachInterrupt(timer); timerEnd(timer); @@ -434,7 +458,13 @@ void IRrecv::resume(void) { params.rawlen = 0; params.overflow = false; #if defined(ESP32) + // Check for ESP32 core version and handle timer functions differently +#if defined(_ESP32_ARDUINO_CORE_V3PLUS) + timerWrite(timer, 0); // Reset the timer (no need for timerAlarmDisable) +#else // _ESP32_ARDUINO_CORE_V3PLUS timerAlarmDisable(timer); +#endif // _ESP32_ARDUINO_CORE_V3PLUS + // Re-enable GPIO interrupt in both versions gpio_intr_enable((gpio_num_t)params.recvpin); #endif // ESP32 } @@ -510,8 +540,8 @@ void IRrecv::crudeNoiseFilter(decode_results *results, const uint16_t floor) { for (uint16_t i = offset + 2; i <= results->rawlen && i < kBufSize; i++) results->rawbuf[i - 2] = results->rawbuf[i]; if (offset > 1) { // There is a previous pair we can add to. - // Merge this pair into into the previous space. - results->rawbuf[offset - 1] += addition; + // Merge this pair into into the previous space. // C++20 fix applied + results->rawbuf[offset - 1] = results->rawbuf[offset - 1] + addition; } results->rawlen -= 2; // Adjust the length. } else { diff --git a/src/IRutils.cpp b/src/IRutils.cpp index d798040a5..bce3df976 100644 --- a/src/IRutils.cpp +++ b/src/IRutils.cpp @@ -822,16 +822,13 @@ String addDayToString(const uint8_t day_of_week, const int8_t offset, /// @return The resulting String. String dayToString(const uint8_t day_of_week, const int8_t offset) { if ((uint8_t)(day_of_week + offset) < 7) -#if UNIT_TEST - return String(kThreeLetterDayOfWeekStr).substr( - (day_of_week + offset) * 3, 3); -#elif defined(ARDUINO) - return String(kThreeLetterDayOfWeekStr).substring( - (day_of_week + offset) * 3, (day_of_week + offset) * 3 + 3); -#else // UNIT_TEST +#if defined(ARDUINO) return String(kThreeLetterDayOfWeekStr).substring( (day_of_week + offset) * 3, (day_of_week + offset) * 3 + 3); -#endif // UNIT_TEST +#else // ARDUINO + return String(kThreeLetterDayOfWeekStr).substr( + (day_of_week + offset) * 3, 3); +#endif // ARDUINO else return kUnknownStr; } diff --git a/src/hal/esp32-hal-cpu.c b/src/hal/esp32-hal-cpu.c index 76ce77b91..1eddb6771 100644 --- a/src/hal/esp32-hal-cpu.c +++ b/src/hal/esp32-hal-cpu.c @@ -12,141 +12,155 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Source: https://github.com/espressif/arduino-esp32/blob/09a6770320b75c219053aa19d630afe1a7c61147/cores/esp32/esp32-hal-cpu.c +// Source: https://github.com/espressif/arduino-esp32/blob/idf-release/v5.4/cores/esp32/esp32-hal-cpu.c +// Stripped down version, only required code for IRremoteESP8266 is included -#include "sdkconfig.h" +#include "esp_attr.h" +#include "esp_log.h" #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" #include "freertos/task.h" -#include "esp_attr.h" -#include "esp_log.h" #include "soc/rtc.h" + +#include "sdkconfig.h" +#if !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) && \ + !defined(CONFIG_IDF_TARGET_ESP32H2) && !defined(CONFIG_IDF_TARGET_ESP32P4) #include "soc/rtc_cntl_reg.h" -#include "soc/apb_ctrl_reg.h" -#include "soc/efuse_reg.h" -#include "esp32-hal.h" +#include "soc/syscon_reg.h" +#endif #include "esp32-hal-cpu.h" - +#include "esp32-hal.h" #include "esp_system.h" -#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+ -#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 -#include "freertos/xtensa_timer.h" +#include "soc/efuse_reg.h" +#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+ +#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 #include "esp32/rom/rtc.h" + +#include "xtensa_timer.h" #elif CONFIG_IDF_TARGET_ESP32S2 -#include "freertos/xtensa_timer.h" #include "esp32s2/rom/rtc.h" -#elif CONFIG_IDF_TARGET_ESP32S3 + #include "xtensa_timer.h" +#elif CONFIG_IDF_TARGET_ESP32S3 #include "esp32s3/rom/rtc.h" + +#include "xtensa_timer.h" +#elif CONFIG_IDF_TARGET_ESP32C2 +#include "esp32c2/rom/rtc.h" #elif CONFIG_IDF_TARGET_ESP32C3 #include "esp32c3/rom/rtc.h" -#else +#elif CONFIG_IDF_TARGET_ESP32C6 +#include "esp32c6/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32H2 +#include "esp32h2/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32P4 +#include "esp32p4/rom/rtc.h" +#else #error Target CONFIG_IDF_TARGET is not supported #endif -#else // ESP32 Before IDF 4.0 +#else // ESP32 Before IDF 4.0 #include "rom/rtc.h" #endif static const char *TAG = "IR"; typedef struct apb_change_cb_s { - struct apb_change_cb_s * prev; - struct apb_change_cb_s * next; - void * arg; - apb_change_cb_t cb; + struct apb_change_cb_s *prev; + struct apb_change_cb_s *next; + void *arg; + apb_change_cb_t cb; } apb_change_t; - -static apb_change_t * apb_change_callbacks = NULL; +static apb_change_t *apb_change_callbacks = NULL; static SemaphoreHandle_t apb_change_lock = NULL; -static void initApbChangeCallback(){ +static void initApbChangeCallback() { static volatile bool initialized = false; - if(!initialized){ + if (!initialized) { initialized = true; apb_change_lock = xSemaphoreCreateMutex(); - if(!apb_change_lock){ + if (!apb_change_lock) { initialized = false; } } } bool addApbChangeCallback(void *arg, apb_change_cb_t cb) { - initApbChangeCallback(); - apb_change_t *c = (apb_change_t *)malloc(sizeof(apb_change_t)); - if (!c) { - ESP_LOGE(TAG, "Callback Object Malloc Failed"); - return false; - } - c->next = NULL; - c->prev = NULL; - c->arg = arg; - c->cb = cb; - xSemaphoreTake(apb_change_lock, portMAX_DELAY); - if (apb_change_callbacks == NULL) { - apb_change_callbacks = c; - } else { - apb_change_t *r = apb_change_callbacks; - // look for duplicate callbacks - while ((r != NULL) && !((r->cb == cb) && (r->arg == arg))) { - r = r->next; + initApbChangeCallback(); + apb_change_t *c = (apb_change_t *)malloc(sizeof(apb_change_t)); + if (!c) { + ESP_LOGE(TAG, "Callback Object Malloc Failed"); + return false; } - if (r) { - ESP_LOGE(TAG, "duplicate func=%8p arg=%8p", c->cb, c->arg); - free(c); - xSemaphoreGive(apb_change_lock); - return false; + c->next = NULL; + c->prev = NULL; + c->arg = arg; + c->cb = cb; + xSemaphoreTake(apb_change_lock, portMAX_DELAY); + if (apb_change_callbacks == NULL) { + apb_change_callbacks = c; } else { - c->next = apb_change_callbacks; - apb_change_callbacks->prev = c; - apb_change_callbacks = c; + apb_change_t *r = apb_change_callbacks; + // look for duplicate callbacks + while ((r != NULL) && !((r->cb == cb) && (r->arg == arg))) { + r = r->next; + } + if (r) { + ESP_LOGE(TAG, "duplicate func=%8p arg=%8p", c->cb, c->arg); + free(c); + xSemaphoreGive(apb_change_lock); + return false; + } else { + c->next = apb_change_callbacks; + apb_change_callbacks->prev = c; + apb_change_callbacks = c; + } } - } - xSemaphoreGive(apb_change_lock); - return true; + xSemaphoreGive(apb_change_lock); + return true; } bool removeApbChangeCallback(void *arg, apb_change_cb_t cb) { - initApbChangeCallback(); - xSemaphoreTake(apb_change_lock, portMAX_DELAY); - apb_change_t *r = apb_change_callbacks; - // look for matching callback - while ((r != NULL) && !((r->cb == cb) && (r->arg == arg))) { - r = r->next; - } - if (r == NULL) { - ESP_LOGE(TAG, "not found func=%8p arg=%8p", cb, arg); - xSemaphoreGive(apb_change_lock); - return false; - } else { - // patch links - if (r->prev) { - r->prev->next = r->next; - } else { // this is first link - apb_change_callbacks = r->next; + initApbChangeCallback(); + xSemaphoreTake(apb_change_lock, portMAX_DELAY); + apb_change_t *r = apb_change_callbacks; + // look for matching callback + while ((r != NULL) && !((r->cb == cb) && (r->arg == arg))) { + r = r->next; } - if (r->next) { - r->next->prev = r->prev; + if (r == NULL) { + ESP_LOGE(TAG, "not found func=%8p arg=%8p", cb, arg); + xSemaphoreGive(apb_change_lock); + return false; + } else { + // patch links + if (r->prev) { + r->prev->next = r->next; + } else { // this is first link + apb_change_callbacks = r->next; + } + if (r->next) { + r->next->prev = r->prev; + } + free(r); } - free(r); - } - xSemaphoreGive(apb_change_lock); - return true; + xSemaphoreGive(apb_change_lock); + return true; } static uint32_t calculateApb(rtc_cpu_freq_config_t *conf) { -#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32H2 - return APB_CLK_FREQ; +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 + if (conf->freq_mhz >= 80) { + return 80 * MHZ; + } + return (conf->source_freq_mhz * MHZ) / conf->div; #else - if (conf->freq_mhz >= 80) { - return 80 * MHZ; - } - return (conf->source_freq_mhz * MHZ) / conf->div; + return APB_CLK_FREQ; #endif } uint32_t getApbFrequency() { - rtc_cpu_freq_config_t conf; - rtc_clk_cpu_freq_get_config(&conf); - return calculateApb(&conf); + rtc_cpu_freq_config_t conf; + rtc_clk_cpu_freq_get_config(&conf); + return calculateApb(&conf); } diff --git a/src/hal/esp32-hal-cpu.h b/src/hal/esp32-hal-cpu.h index b1240d6c5..44582ecb2 100644 --- a/src/hal/esp32-hal-cpu.h +++ b/src/hal/esp32-hal-cpu.h @@ -12,7 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Source: https://github.com/espressif/arduino-esp32/blob/09a6770320b75c219053aa19d630afe1a7c61147/cores/esp32/esp32-hal-cpu.c +// Source: https://github.com/espressif/arduino-esp32/blob/idf-release/v5.4/cores/esp32/esp32-hal-cpu.h +// Stripped down version, only required code for IRremoteESP8266 is included #ifndef _ESP32_HAL_CPU_H_ #define _ESP32_HAL_CPU_H_ @@ -21,18 +22,18 @@ extern "C" { #endif -#include #include +#include #include typedef enum { APB_BEFORE_CHANGE, APB_AFTER_CHANGE } apb_change_ev_t; -typedef void (* apb_change_cb_t)(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb); +typedef void (*apb_change_cb_t)(void *arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb); -bool addApbChangeCallback(void * arg, apb_change_cb_t cb); -bool removeApbChangeCallback(void * arg, apb_change_cb_t cb); +bool addApbChangeCallback(void *arg, apb_change_cb_t cb); +bool removeApbChangeCallback(void *arg, apb_change_cb_t cb); -uint32_t getApbFrequency(); +uint32_t getApbFrequency(); // In Hz #ifdef __cplusplus } diff --git a/src/hal/esp32-hal-gpio.c b/src/hal/esp32-hal-gpio.c index edef2236a..503affe13 100644 --- a/src/hal/esp32-hal-gpio.c +++ b/src/hal/esp32-hal-gpio.c @@ -12,156 +12,159 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Source: https://github.com/espressif/arduino-esp32/blob/09a6770320b75c219053aa19d630afe1a7c61147/cores/esp32/esp32-hal-gpio.c -// Stripped down version +// Source: https://github.com/espressif/arduino-esp32/blob/idf-release/v5.4/cores/esp32/esp32-hal-gpio.c +// Stripped down version, only required code for IRremoteESP8266 is included #include "esp32-hal-gpio.h" -// #include "esp32-hal-periman.h" + +#include "esp_log.h" #include "hal/gpio_hal.h" #include "soc/soc_caps.h" -#include "esp_log.h" static const char *TAG = "IR"; typedef void (*voidFuncPtr)(void); typedef void (*voidFuncPtrArg)(void *); typedef struct { - voidFuncPtr fn; - void *arg; - bool functional; + voidFuncPtr fn; + void *arg; + bool functional; } InterruptHandle_t; static InterruptHandle_t __pinInterruptHandlers[SOC_GPIO_PIN_COUNT] = { - 0, + 0, }; #include "driver/rtc_io.h" extern void ARDUINO_ISR_ATTR __pinMode(uint8_t pin, uint8_t mode) { - if (pin >= SOC_GPIO_PIN_COUNT) { - ESP_LOGE(TAG, "Invalid IO %i selected", pin); - return; - } - - gpio_hal_context_t gpiohal; - gpiohal.dev = GPIO_LL_GET_HW(GPIO_PORT_0); - - gpio_config_t conf = { - .pin_bit_mask = (1ULL << pin), /*!< GPIO pin: set with bit mask, each bit maps to a GPIO */ - .mode = GPIO_MODE_DISABLE, /*!< GPIO mode: set input/output mode */ - .pull_up_en = GPIO_PULLUP_DISABLE, /*!< GPIO pull-up */ - .pull_down_en = GPIO_PULLDOWN_DISABLE, /*!< GPIO pull-down */ - .intr_type = gpiohal.dev->pin[pin].int_type /*!< GPIO interrupt type - previously set */ - }; - if (mode < 0x20) { //io - conf.mode = mode & (INPUT | OUTPUT); - if (mode & OPEN_DRAIN) { - conf.mode |= GPIO_MODE_DEF_OD; + if (pin >= SOC_GPIO_PIN_COUNT) { + ESP_LOGE(TAG, "Invalid IO %i selected", pin); + return; } - if (mode & PULLUP) { - conf.pull_up_en = GPIO_PULLUP_ENABLE; + + gpio_hal_context_t gpiohal; + gpiohal.dev = GPIO_LL_GET_HW(GPIO_PORT_0); + + gpio_config_t conf = { + .pin_bit_mask = (1ULL << pin), /*!< GPIO pin: set with bit mask, each bit maps to a GPIO */ + .mode = GPIO_MODE_DISABLE, /*!< GPIO mode: set input/output mode */ + .pull_up_en = GPIO_PULLUP_DISABLE, /*!< GPIO pull-up */ + .pull_down_en = GPIO_PULLDOWN_DISABLE, /*!< GPIO pull-down */ + .intr_type = gpiohal.dev->pin[pin].int_type /*!< GPIO interrupt type - previously set */ + }; + if (mode < 0x20) { // io + conf.mode = mode & (INPUT | OUTPUT); + if (mode & OPEN_DRAIN) { + conf.mode |= GPIO_MODE_DEF_OD; + } + if (mode & PULLUP) { + conf.pull_up_en = GPIO_PULLUP_ENABLE; + } + if (mode & PULLDOWN) { + conf.pull_down_en = GPIO_PULLDOWN_ENABLE; + } } - if (mode & PULLDOWN) { - conf.pull_down_en = GPIO_PULLDOWN_ENABLE; + if (gpio_config(&conf) != ESP_OK) { + ESP_LOGE(TAG, "IO %i config failed", pin); + return; } - } - if (gpio_config(&conf) != ESP_OK) { - ESP_LOGE(TAG, "IO %i config failed", pin); - return; - } } extern void ARDUINO_ISR_ATTR __digitalWrite(uint8_t pin, uint8_t val) { - gpio_set_level((gpio_num_t)pin, val); + gpio_set_level((gpio_num_t)pin, val); } extern int ARDUINO_ISR_ATTR __digitalRead(uint8_t pin) { - return gpio_get_level((gpio_num_t)pin); + return gpio_get_level((gpio_num_t)pin); } static void ARDUINO_ISR_ATTR __onPinInterrupt(void *arg) { - InterruptHandle_t *isr = (InterruptHandle_t *)arg; - if (isr->fn) { - if (isr->arg) { - ((voidFuncPtrArg)isr->fn)(isr->arg); - } else { - isr->fn(); + InterruptHandle_t *isr = (InterruptHandle_t *)arg; + if (isr->fn) { + if (isr->arg) { + ((voidFuncPtrArg)isr->fn)(isr->arg); + } else { + isr->fn(); + } } - } } extern void cleanupFunctional(void *arg); -extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc, void *arg, int intr_type, bool functional) { - static bool interrupt_initialized = false; - - // makes sure that pin -1 (255) will never work -- this follows Arduino standard - if (pin >= SOC_GPIO_PIN_COUNT) { - return; - } - - if (!interrupt_initialized) { - esp_err_t err = gpio_install_isr_service((int)ARDUINO_ISR_FLAG); - interrupt_initialized = (err == ESP_OK) || (err == ESP_ERR_INVALID_STATE); - } - if (!interrupt_initialized) { - ESP_LOGE(TAG, "IO %i ISR Service Failed To Start", pin); - return; - } - - // if new attach without detach remove old info - if (__pinInterruptHandlers[pin].functional && __pinInterruptHandlers[pin].arg) { - cleanupFunctional(__pinInterruptHandlers[pin].arg); - } - __pinInterruptHandlers[pin].fn = (voidFuncPtr)userFunc; - __pinInterruptHandlers[pin].arg = arg; - __pinInterruptHandlers[pin].functional = functional; - - gpio_set_intr_type((gpio_num_t)pin, (gpio_int_type_t)(intr_type & 0x7)); - if (intr_type & 0x8) { - gpio_wakeup_enable((gpio_num_t)pin, (gpio_int_type_t)(intr_type & 0x7)); - } - gpio_isr_handler_add((gpio_num_t)pin, __onPinInterrupt, &__pinInterruptHandlers[pin]); - - //FIX interrupts on peripherals outputs (eg. LEDC,...) - //Enable input in GPIO register - gpio_hal_context_t gpiohal; - gpiohal.dev = GPIO_LL_GET_HW(GPIO_PORT_0); - gpio_hal_input_enable(&gpiohal, pin); +extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc, void *arg, int intr_type, + bool functional) { + static bool interrupt_initialized = false; + + // makes sure that pin -1 (255) will never work -- this follows Arduino standard + if (pin >= SOC_GPIO_PIN_COUNT) { + return; + } + + if (!interrupt_initialized) { + esp_err_t err = gpio_install_isr_service((int)ARDUINO_ISR_FLAG); + interrupt_initialized = (err == ESP_OK) || (err == ESP_ERR_INVALID_STATE); + } + if (!interrupt_initialized) { + ESP_LOGE(TAG, "IO %i ISR Service Failed To Start", pin); + return; + } + + // if new attach without detach remove old info + if (__pinInterruptHandlers[pin].functional && __pinInterruptHandlers[pin].arg) { + cleanupFunctional(__pinInterruptHandlers[pin].arg); + } + __pinInterruptHandlers[pin].fn = (voidFuncPtr)userFunc; + __pinInterruptHandlers[pin].arg = arg; + __pinInterruptHandlers[pin].functional = functional; + + gpio_set_intr_type((gpio_num_t)pin, (gpio_int_type_t)(intr_type & 0x7)); + if (intr_type & 0x8) { + gpio_wakeup_enable((gpio_num_t)pin, (gpio_int_type_t)(intr_type & 0x7)); + } + gpio_isr_handler_add((gpio_num_t)pin, __onPinInterrupt, &__pinInterruptHandlers[pin]); + + // FIX interrupts on peripherals outputs (eg. LEDC,...) + // Enable input in GPIO register + gpio_hal_context_t gpiohal; + gpiohal.dev = GPIO_LL_GET_HW(GPIO_PORT_0); + gpio_hal_input_enable(&gpiohal, pin); } extern void __attachInterruptArg(uint8_t pin, voidFuncPtrArg userFunc, void *arg, int intr_type) { - __attachInterruptFunctionalArg(pin, userFunc, arg, intr_type, false); + __attachInterruptFunctionalArg(pin, userFunc, arg, intr_type, false); } extern void __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int intr_type) { - __attachInterruptFunctionalArg(pin, (voidFuncPtrArg)userFunc, NULL, intr_type, false); + __attachInterruptFunctionalArg(pin, (voidFuncPtrArg)userFunc, NULL, intr_type, false); } extern void __detachInterrupt(uint8_t pin) { - gpio_isr_handler_remove((gpio_num_t)pin); //remove handle and disable isr for pin - gpio_wakeup_disable((gpio_num_t)pin); + gpio_isr_handler_remove((gpio_num_t)pin); // remove handle and disable isr for pin + gpio_wakeup_disable((gpio_num_t)pin); - if (__pinInterruptHandlers[pin].functional && __pinInterruptHandlers[pin].arg) { - cleanupFunctional(__pinInterruptHandlers[pin].arg); - } - __pinInterruptHandlers[pin].fn = NULL; - __pinInterruptHandlers[pin].arg = NULL; - __pinInterruptHandlers[pin].functional = false; + if (__pinInterruptHandlers[pin].functional && __pinInterruptHandlers[pin].arg) { + cleanupFunctional(__pinInterruptHandlers[pin].arg); + } + __pinInterruptHandlers[pin].fn = NULL; + __pinInterruptHandlers[pin].arg = NULL; + __pinInterruptHandlers[pin].functional = false; - gpio_set_intr_type((gpio_num_t)pin, GPIO_INTR_DISABLE); + gpio_set_intr_type((gpio_num_t)pin, GPIO_INTR_DISABLE); } extern void enableInterrupt(uint8_t pin) { - gpio_intr_enable((gpio_num_t)pin); + gpio_intr_enable((gpio_num_t)pin); } extern void disableInterrupt(uint8_t pin) { - gpio_intr_disable((gpio_num_t)pin); + gpio_intr_disable((gpio_num_t)pin); } extern void pinMode(uint8_t pin, uint8_t mode) __attribute__((weak, alias("__pinMode"))); extern void digitalWrite(uint8_t pin, uint8_t val) __attribute__((weak, alias("__digitalWrite"))); -extern int digitalRead(uint8_t pin) __attribute__((weak, alias("__digitalRead"))); -extern void attachInterrupt(uint8_t pin, voidFuncPtr handler, int mode) __attribute__((weak, alias("__attachInterrupt"))); -extern void attachInterruptArg(uint8_t pin, voidFuncPtrArg handler, void *arg, int mode) __attribute__((weak, alias("__attachInterruptArg"))); +extern int digitalRead(uint8_t pin) __attribute__((weak, alias("__digitalRead"))); +extern void attachInterrupt(uint8_t pin, voidFuncPtr handler, int mode) + __attribute__((weak, alias("__attachInterrupt"))); +extern void attachInterruptArg(uint8_t pin, voidFuncPtrArg handler, void *arg, int mode) + __attribute__((weak, alias("__attachInterruptArg"))); extern void detachInterrupt(uint8_t pin) __attribute__((weak, alias("__detachInterrupt"))); \ No newline at end of file diff --git a/src/hal/esp32-hal-gpio.h b/src/hal/esp32-hal-gpio.h index abf1dd795..69d73553d 100644 --- a/src/hal/esp32-hal-gpio.h +++ b/src/hal/esp32-hal-gpio.h @@ -17,7 +17,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -// Source: https://github.com/espressif/arduino-esp32/blob/09a6770320b75c219053aa19d630afe1a7c61147/cores/esp32/esp32-hal-gpio.h +// Source: https://github.com/espressif/arduino-esp32/blob/idf-release/v5.4/cores/esp32/esp32-hal-gpio.h #ifndef MAIN_ESP32_HAL_GPIO_H_ #define MAIN_ESP32_HAL_GPIO_H_ @@ -87,4 +87,4 @@ void disableInterrupt(uint8_t pin); } #endif -#endif /* MAIN_ESP32_HAL_GPIO_H_ */ \ No newline at end of file +#endif /* MAIN_ESP32_HAL_GPIO_H_ */ diff --git a/src/hal/esp32-hal-misc.c b/src/hal/esp32-hal-misc.c index 0cc24b450..4d5aeeb1c 100644 --- a/src/hal/esp32-hal-misc.c +++ b/src/hal/esp32-hal-misc.c @@ -12,27 +12,31 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Source: https://github.com/espressif/arduino-esp32/blob/idf-release/v5.4/cores/esp32/esp32-hal-misc.c +// Stripped down version, only required code for IRremoteESP8266 is included -// Source: https://github.com/espressif/arduino-esp32/blob/09a6770320b75c219053aa19d630afe1a7c61147/cores/esp32/esp32-hal-misc.c#L207 -// Stripped down version - -#include "sdkconfig.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" #include "esp_attr.h" #include "esp_log.h" #include "esp_timer.h" -#include "esp_private/startup_internal.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "sdkconfig.h" +#ifdef CONFIG_APP_ROLLBACK_ENABLE +#include "esp_ota_ops.h" +#endif // CONFIG_APP_ROLLBACK_ENABLE #include + +#include "esp_private/startup_internal.h" #include "soc/rtc.h" -#if !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2) +#if !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) && \ + !defined(CONFIG_IDF_TARGET_ESP32H2) && !defined(CONFIG_IDF_TARGET_ESP32P4) #include "soc/rtc_cntl_reg.h" -#include "soc/apb_ctrl_reg.h" +#include "soc/syscon_reg.h" #endif -#include "esp_task_wdt.h" #include "esp32-hal.h" - #include "esp_system.h" +#include "esp_task_wdt.h" #ifdef ESP_IDF_VERSION_MAJOR // IDF 4+ #if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 @@ -49,48 +53,46 @@ #include "esp32c6/rom/rtc.h" #elif CONFIG_IDF_TARGET_ESP32H2 #include "esp32h2/rom/rtc.h" +#elif CONFIG_IDF_TARGET_ESP32P4 +#include "esp32p4/rom/rtc.h" #else #error Target CONFIG_IDF_TARGET is not supported #endif -#if SOC_TEMP_SENSOR_SUPPORTED -#include "driver/temperature_sensor.h" -#endif - #else // ESP32 Before IDF 4.0 #include "rom/rtc.h" #endif void __yield() { - vPortYield(); + vPortYield(); } void yield() __attribute__((weak, alias("__yield"))); unsigned long ARDUINO_ISR_ATTR micros() { - return (unsigned long)(esp_timer_get_time()); + return (unsigned long)(esp_timer_get_time()); } unsigned long ARDUINO_ISR_ATTR millis() { - return (unsigned long)(esp_timer_get_time() / 1000ULL); + return (unsigned long)(esp_timer_get_time() / 1000ULL); } void delay(uint32_t ms) { - vTaskDelay(ms / portTICK_PERIOD_MS); + vTaskDelay(ms / portTICK_PERIOD_MS); } void ARDUINO_ISR_ATTR delayMicroseconds(uint32_t us) { - uint64_t m = (uint64_t)esp_timer_get_time(); - if (us) { - uint64_t e = (m + us); - if (m > e) { //overflow - while ((uint64_t)esp_timer_get_time() > e) { - NOP(); - } - } - while ((uint64_t)esp_timer_get_time() < e) { - NOP(); + uint64_t m = (uint64_t)esp_timer_get_time(); + if (us) { + uint64_t e = (m + us); + if (m > e) { // overflow + while ((uint64_t)esp_timer_get_time() > e) { + NOP(); + } + } + while ((uint64_t)esp_timer_get_time() < e) { + NOP(); + } } - } } diff --git a/src/hal/esp32-hal-timer.c b/src/hal/esp32-hal-timer.c index 4f918d3d7..66672a8b1 100644 --- a/src/hal/esp32-hal-timer.c +++ b/src/hal/esp32-hal-timer.c @@ -12,269 +12,266 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Source: https://github.com/espressif/arduino-esp32/blob/b31c9361ec73b043ff9175b4cd48388637a7171b/cores/esp32/esp32-hal-timer.c +// Source: +// https://github.com/espressif/arduino-esp32/blob/idf-release/v5.4/cores/esp32/esp32-hal-timer.c #include "esp32-hal-timer.h" + #include "esp_log.h" -#include "driver/timer.h" #include "soc/soc_caps.h" +#if SOC_GPTIMER_SUPPORTED +#include "driver/gptimer.h" +#if defined __has_include && __has_include("clk_tree.h") +#include "clk_tree.h" +#else +#include "esp_clk_tree.h" +#endif + +// #include "driver/timer.h" + #include "esp32-hal.h" static const char *TAG = "IR"; -typedef union { - struct { - uint32_t reserved0: 10; - uint32_t alarm_en: 1; /*When set alarm is enabled*/ - uint32_t level_int_en: 1; /*When set level type interrupt will be generated during alarm*/ - uint32_t edge_int_en: 1; /*When set edge type interrupt will be generated during alarm*/ - uint32_t divider: 16; /*Timer clock (T0/1_clk) pre-scale value.*/ - uint32_t autoreload: 1; /*When set timer 0/1 auto-reload at alarming is enabled*/ - uint32_t increase: 1; /*When set timer 0/1 time-base counter increment. When cleared timer 0 time-base counter decrement.*/ - uint32_t enable: 1; /*When set timer 0/1 time-base counter is enabled*/ - }; - uint32_t val; -} timer_cfg_t; - -#define NUM_OF_TIMERS SOC_TIMER_GROUP_TOTAL_TIMERS +typedef void (*voidFuncPtr)(void); +typedef void (*voidFuncPtrArg)(void *); -typedef struct hw_timer_s -{ - uint8_t group; - uint8_t num; -} hw_timer_t; +typedef struct { + voidFuncPtr fn; + void *arg; +} interrupt_config_t; -// Works for all chips -static hw_timer_t timer_dev[4] = { - {0,0}, {1,0}, {0,1}, {1,1} +struct timer_struct_t { + gptimer_handle_t timer_handle; + interrupt_config_t interrupt_handle; + bool timer_started; }; -// NOTE: (in IDF 5.0 there wont be need to know groups/numbers -// timer_init() will list thru all timers and return free timer handle) - - -inline uint64_t timerRead(hw_timer_t *timer){ - - uint64_t value; - timer_get_counter_value(timer->group, timer->num,&value); - return value; -} - -uint64_t timerAlarmRead(hw_timer_t *timer){ +inline uint64_t timerRead(hw_timer_t *timer) { + if (timer == NULL) { + ESP_LOGE(TAG, "Timer handle is NULL"); + return 0; + } uint64_t value; - timer_get_alarm_value(timer->group, timer->num, &value); + gptimer_get_raw_count(timer->timer_handle, &value); return value; } -void timerWrite(hw_timer_t *timer, uint64_t val){ - timer_set_counter_value(timer->group, timer->num, val); -} - -void timerAlarmWrite(hw_timer_t *timer, uint64_t alarm_value, bool autoreload){ - timer_set_alarm_value(timer->group, timer->num, alarm_value); - timerSetAutoReload(timer,autoreload); +void timerWrite(hw_timer_t *timer, uint64_t val) { + if (timer == NULL) { + ESP_LOGE(TAG, "Timer handle is NULL"); + return; + } + gptimer_set_raw_count(timer->timer_handle, val); } -void timerSetConfig(hw_timer_t *timer, uint32_t config){ - timer_cfg_t cfg; - cfg.val = config; - timer_set_alarm(timer->group, timer->num, cfg.alarm_en); - timerSetDivider(timer,cfg.divider); - timerSetAutoReload(timer,cfg.autoreload); - timerSetCountUp(timer, cfg.increase); - - if (cfg.enable) { - timerStart(timer); +void timerAlarm(hw_timer_t *timer, uint64_t alarm_value, bool autoreload, uint64_t reload_count) { + if (timer == NULL) { + ESP_LOGE(TAG, "Timer handle is NULL"); + return; } - else{ - timerStop(timer); + esp_err_t err = ESP_OK; + gptimer_alarm_config_t alarm_cfg = { + .alarm_count = alarm_value, + .reload_count = reload_count, + .flags.auto_reload_on_alarm = autoreload, + }; + err = gptimer_set_alarm_action(timer->timer_handle, &alarm_cfg); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Timer Alarm Write failed, error num=%d", err); } - return; } -uint32_t timerGetConfig(hw_timer_t *timer){ - timer_config_t timer_cfg; - timer_get_config(timer->group, timer->num,&timer_cfg); - - //Translate to default uint32_t - timer_cfg_t cfg; - cfg.alarm_en = timer_cfg.alarm_en; - cfg.autoreload = timer_cfg.auto_reload; - cfg.divider = timer_cfg.divider; - cfg.edge_int_en = timer_cfg.intr_type; - cfg.level_int_en = !timer_cfg.intr_type; - cfg.enable = timer_cfg.counter_en; - cfg.increase = timer_cfg.counter_dir; - - return cfg.val; -} - -void timerSetCountUp(hw_timer_t *timer, bool countUp){ - timer_set_counter_mode(timer->group, timer->num,countUp); -} - -bool timerGetCountUp(hw_timer_t *timer){ - timer_cfg_t config; - config.val = timerGetConfig(timer); - return config.increase; -} - -void timerSetAutoReload(hw_timer_t *timer, bool autoreload){ - timer_set_auto_reload(timer->group, timer->num,autoreload); -} - -bool timerGetAutoReload(hw_timer_t *timer){ - timer_cfg_t config; - config.val= timerGetConfig(timer); - return config.autoreload; +uint32_t timerGetFrequency(hw_timer_t *timer) { + if (timer == NULL) { + return 0; + } + uint32_t frequency; + gptimer_get_resolution(timer->timer_handle, &frequency); + return frequency; } -// Set divider from 2 to 65535 -void timerSetDivider(hw_timer_t *timer, uint16_t divider){ - if(divider < 2) - { - ESP_LOGE(TAG, "Timer divider must be set in range of 2 to 65535"); +void timerStart(hw_timer_t *timer) { + if (timer == NULL) { + ESP_LOGE(TAG, "Timer handle is NULL"); return; } - timer_set_divider(timer->group, timer->num,divider); -} - -uint16_t timerGetDivider(hw_timer_t *timer){ - timer_cfg_t config; - config.val = timerGetConfig(timer); - return config.divider; -} - -void timerStart(hw_timer_t *timer){ - timer_start(timer->group, timer->num); -} - -void timerStop(hw_timer_t *timer){ - timer_pause(timer->group, timer->num); + gptimer_start(timer->timer_handle); + timer->timer_started = true; } -void timerRestart(hw_timer_t *timer){ - timerWrite(timer,0); +void timerStop(hw_timer_t *timer) { + if (timer == NULL) { + ESP_LOGE(TAG, "Timer handle is NULL"); + return; + } + gptimer_stop(timer->timer_handle); + timer->timer_started = false; } -bool timerStarted(hw_timer_t *timer){ - timer_cfg_t config; - config.val = timerGetConfig(timer); - return config.enable; +void timerRestart(hw_timer_t *timer) { + if (timer == NULL) { + ESP_LOGE(TAG, "Timer handle is NULL"); + return; + } + gptimer_set_raw_count(timer->timer_handle, 0); } -void timerAlarmEnable(hw_timer_t *timer){ - timer_set_alarm(timer->group, timer->num,true); -} +hw_timer_t *timerBegin(uint32_t frequency) { + esp_err_t err = ESP_OK; + uint32_t counter_src_hz = 0; + uint32_t divider = 0; + soc_periph_gptimer_clk_src_t clk; + + soc_periph_gptimer_clk_src_t gptimer_clks[] = SOC_GPTIMER_CLKS; + for (size_t i = 0; i < sizeof(gptimer_clks) / sizeof(gptimer_clks[0]); i++) { + clk = gptimer_clks[i]; +#if defined __has_include && __has_include("clk_tree.h") + clk_tree_src_get_freq_hz(clk, CLK_TREE_SRC_FREQ_PRECISION_CACHED, &counter_src_hz); +#else + esp_clk_tree_src_get_freq_hz(clk, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &counter_src_hz); +#endif + divider = counter_src_hz / frequency; + if ((divider >= 2) && (divider <= 65536)) { + break; + } else { + divider = 0; + } + } -void timerAlarmDisable(hw_timer_t *timer){ - timer_set_alarm(timer->group, timer->num,false); -} + if (divider == 0) { + ESP_LOGE(TAG, "Resolution cannot be reached with any clock source, aborting!"); + return NULL; + } -bool timerAlarmEnabled(hw_timer_t *timer){ - timer_cfg_t config; - config.val = timerGetConfig(timer); - return config.alarm_en; -} + gptimer_config_t config = { + .clk_src = clk, + .direction = GPTIMER_COUNT_UP, + .resolution_hz = frequency, + .flags.intr_shared = true, + }; -static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb){ - hw_timer_t * timer = (hw_timer_t *)arg; - if(ev_type == APB_BEFORE_CHANGE){ - timerStop(timer); - } else { - old_apb /= 1000000; - new_apb /= 1000000; - uint16_t divider = (new_apb * timerGetDivider(timer)) / old_apb; - timerSetDivider(timer,divider); - timerStart(timer); - } -} + hw_timer_t *timer = malloc(sizeof(hw_timer_t)); -hw_timer_t * timerBegin(uint8_t num, uint16_t divider, bool countUp){ - if(num >= NUM_OF_TIMERS) - { - ESP_LOGE(TAG, "Timer number %u exceeds available number of Timers.", num); + err = gptimer_new_timer(&config, &timer->timer_handle); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to create a new GPTimer, error num=%d", err); + free(timer); return NULL; } - - hw_timer_t * timer = &timer_dev[num]; //Get Timer group/num from 0-3 number - - timer_config_t config = { - .divider = divider, - .counter_dir = countUp, - .counter_en = TIMER_PAUSE, - .alarm_en = TIMER_ALARM_DIS, - .auto_reload = false, - }; - - timer_init(timer->group, timer->num, &config); - timer_set_counter_value(timer->group, timer->num, 0); - timerStart(timer); - addApbChangeCallback(timer, _on_apb_change); + gptimer_enable(timer->timer_handle); + gptimer_start(timer->timer_handle); + timer->timer_started = true; return timer; } -void timerEnd(hw_timer_t *timer){ - removeApbChangeCallback(timer, _on_apb_change); - timer_deinit(timer->group, timer->num); +void timerEnd(hw_timer_t *timer) { + if (timer != NULL) { + esp_err_t err = ESP_OK; + if (timer->timer_started == true) { + gptimer_stop(timer->timer_handle); + } + gptimer_disable(timer->timer_handle); + err = gptimer_del_timer(timer->timer_handle); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to destroy GPTimer, error num=%d", err); + return; + } + free(timer); + } } -bool IRAM_ATTR timerFnWrapper(void *arg){ - void (*fn)(void) = arg; - fn(); - - // some additional logic or handling may be required here to approriately yield or not +bool IRAM_ATTR timerFnWrapper(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *args) { + interrupt_config_t *isr = (interrupt_config_t *)args; + if (isr->fn) { + if (isr->arg) { + ((voidFuncPtrArg)isr->fn)(isr->arg); + } else { + isr->fn(); + } + } + // some additional logic or handling may be required here to appropriately yield or not return false; } -void timerAttachInterruptFlag(hw_timer_t *timer, void (*fn)(void), bool edge, int intr_alloc_flags){ - if(edge){ - ESP_LOGW(TAG, "EDGE timer interrupt is not supported! Setting to LEVEL..."); +void timerAttachInterruptFunctionalArg(hw_timer_t *timer, void (*userFunc)(void *), void *arg) { + if (timer == NULL) { + ESP_LOGE(TAG, "Timer handle is NULL"); + return; } - timer_isr_callback_add(timer->group, timer->num, timerFnWrapper, fn, intr_alloc_flags); -} + esp_err_t err = ESP_OK; + gptimer_event_callbacks_t cbs = { + .on_alarm = timerFnWrapper, + }; -void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge){ - timerAttachInterruptFlag(timer, fn, edge, 0); + timer->interrupt_handle.fn = (voidFuncPtr)userFunc; + timer->interrupt_handle.arg = arg; + + if (timer->timer_started == true) { + gptimer_stop(timer->timer_handle); + } + gptimer_disable(timer->timer_handle); + err = gptimer_register_event_callbacks(timer->timer_handle, &cbs, &timer->interrupt_handle); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Timer Attach Interrupt failed, error num=%d", err); + } + gptimer_enable(timer->timer_handle); + if (timer->timer_started == true) { + gptimer_start(timer->timer_handle); + } } -void timerDetachInterrupt(hw_timer_t *timer){ - timer_isr_callback_remove(timer->group, timer->num); +void timerAttachInterruptArg(hw_timer_t *timer, void (*userFunc)(void *), void *arg) { + timerAttachInterruptFunctionalArg(timer, userFunc, arg); } -uint64_t timerReadMicros(hw_timer_t *timer){ - uint64_t timer_val = timerRead(timer); - uint16_t div = timerGetDivider(timer); - return timer_val * div / (getApbFrequency() / 1000000); +void timerAttachInterrupt(hw_timer_t *timer, voidFuncPtr userFunc) { + timerAttachInterruptFunctionalArg(timer, (voidFuncPtrArg)userFunc, NULL); } -uint64_t timerReadMilis(hw_timer_t *timer){ - uint64_t timer_val = timerRead(timer); - uint16_t div = timerGetDivider(timer); - return timer_val * div / (getApbFrequency() / 1000); +void timerDetachInterrupt(hw_timer_t *timer) { + if (timer == NULL) { + ESP_LOGE(TAG, "Timer handle is NULL"); + return; + } + esp_err_t err = ESP_OK; + err = gptimer_set_alarm_action(timer->timer_handle, NULL); + timer->interrupt_handle.fn = NULL; + timer->interrupt_handle.arg = NULL; + if (err != ESP_OK) { + ESP_LOGE(TAG, "Timer Detach Interrupt failed, error num=%d", err); + } } -double timerReadSeconds(hw_timer_t *timer){ +uint64_t timerReadMicros(hw_timer_t *timer) { + if (timer == NULL) { + ESP_LOGE(TAG, "Timer handle is NULL"); + return 0; + } uint64_t timer_val = timerRead(timer); - uint16_t div = timerGetDivider(timer); - return (double)timer_val * div / getApbFrequency(); + uint32_t frequency = timerGetFrequency(timer); + return timer_val * 1000000 / frequency; } -uint64_t timerAlarmReadMicros(hw_timer_t *timer){ - uint64_t timer_val = timerAlarmRead(timer); - uint16_t div = timerGetDivider(timer); - return timer_val * div / (getApbFrequency() / 1000000); +uint64_t timerReadMillis(hw_timer_t *timer) { + if (timer == NULL) { + ESP_LOGE(TAG, "Timer handle is NULL"); + return 0; + } + uint64_t timer_val = timerRead(timer); + uint32_t frequency = timerGetFrequency(timer); + return timer_val * 1000 / frequency; } -uint64_t timerAlarmReadMilis(hw_timer_t *timer){ - uint64_t timer_val = timerAlarmRead(timer); - uint16_t div = timerGetDivider(timer); - return timer_val * div / (getApbFrequency() / 1000); +double timerReadSeconds(hw_timer_t *timer) { + if (timer == NULL) { + ESP_LOGE(TAG, "Timer handle is NULL"); + return 0; + } + uint64_t timer_val = timerRead(timer); + uint32_t frequency = timerGetFrequency(timer); + return (double)timer_val / frequency; } -double timerAlarmReadSeconds(hw_timer_t *timer){ - uint64_t timer_val = timerAlarmRead(timer); - uint16_t div = timerGetDivider(timer); - return (double)timer_val * div / getApbFrequency(); -} \ No newline at end of file +#endif /* SOC_GPTIMER_SUPPORTED */ \ No newline at end of file diff --git a/src/hal/esp32-hal-timer.h b/src/hal/esp32-hal-timer.h index 61e982cd2..c6dcaf9d0 100644 --- a/src/hal/esp32-hal-timer.h +++ b/src/hal/esp32-hal-timer.h @@ -17,61 +17,47 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +// Source: +// https://github.com/espressif/arduino-esp32/blob/idf-release/v5.4/cores/esp32/esp32-hal-timer.h -// Source: https://github.com/espressif/arduino-esp32/blob/b31c9361ec73b043ff9175b4cd48388637a7171b/cores/esp32/esp32-hal-timer.h +#pragma once -#ifndef MAIN_ESP32_HAL_TIMER_H_ -#define MAIN_ESP32_HAL_TIMER_H_ +#include "soc/soc_caps.h" +#if SOC_GPTIMER_SUPPORTED -// #include "esp32-hal.h" -#include "freertos/FreeRTOS.h" +#include "driver/gptimer_types.h" +#include "esp32-hal.h" #ifdef __cplusplus extern "C" { #endif -struct hw_timer_s; -typedef struct hw_timer_s hw_timer_t; +struct timer_struct_t; +typedef struct timer_struct_t hw_timer_t; -hw_timer_t * timerBegin(uint8_t timer, uint16_t divider, bool countUp); -void timerEnd(hw_timer_t *timer); - -void timerSetConfig(hw_timer_t *timer, uint32_t config); -uint32_t timerGetConfig(hw_timer_t *timer); - -void timerAttachInterruptFlag(hw_timer_t *timer, void (*fn)(void), bool edge, int intr_alloc_flags); -void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge); -void timerDetachInterrupt(hw_timer_t *timer); +hw_timer_t *timerBegin(uint32_t frequency); +void timerEnd(hw_timer_t *timer); void timerStart(hw_timer_t *timer); void timerStop(hw_timer_t *timer); void timerRestart(hw_timer_t *timer); void timerWrite(hw_timer_t *timer, uint64_t val); -void timerSetDivider(hw_timer_t *timer, uint16_t divider); -void timerSetCountUp(hw_timer_t *timer, bool countUp); -void timerSetAutoReload(hw_timer_t *timer, bool autoreload); -bool timerStarted(hw_timer_t *timer); uint64_t timerRead(hw_timer_t *timer); uint64_t timerReadMicros(hw_timer_t *timer); -uint64_t timerReadMilis(hw_timer_t *timer); -double timerReadSeconds(hw_timer_t *timer); -uint16_t timerGetDivider(hw_timer_t *timer); -bool timerGetCountUp(hw_timer_t *timer); -bool timerGetAutoReload(hw_timer_t *timer); +uint64_t timerReadMillis(hw_timer_t *timer); +double timerReadSeconds(hw_timer_t *timer); -void timerAlarmEnable(hw_timer_t *timer); -void timerAlarmDisable(hw_timer_t *timer); -void timerAlarmWrite(hw_timer_t *timer, uint64_t alarm_value, bool autoreload); +uint32_t timerGetFrequency(hw_timer_t *timer); -bool timerAlarmEnabled(hw_timer_t *timer); -uint64_t timerAlarmRead(hw_timer_t *timer); -uint64_t timerAlarmReadMicros(hw_timer_t *timer); -double timerAlarmReadSeconds(hw_timer_t *timer); +void timerAttachInterrupt(hw_timer_t *timer, void (*userFunc)(void)); +void timerAttachInterruptArg(hw_timer_t *timer, void (*userFunc)(void *), void *arg); +void timerDetachInterrupt(hw_timer_t *timer); +void timerAlarm(hw_timer_t *timer, uint64_t alarm_value, bool autoreload, uint64_t reload_count); #ifdef __cplusplus } #endif -#endif /* MAIN_ESP32_HAL_TIMER_H_ */ \ No newline at end of file +#endif /* SOC_GPTIMER_SUPPORTED */ \ No newline at end of file diff --git a/src/hal/esp32-hal.h b/src/hal/esp32-hal.h index 1375b33fc..6da170641 100644 --- a/src/hal/esp32-hal.h +++ b/src/hal/esp32-hal.h @@ -18,34 +18,37 @@ */ // Stripped down version -// Source: https://github.com/espressif/arduino-esp32/blob/b31c9361ec73b043ff9175b4cd48388637a7171b/cores/esp32/esp32-hal.h +// Source: +// https://github.com/espressif/arduino-esp32/blob/b31c9361ec73b043ff9175b4cd48388637a7171b/cores/esp32/esp32-hal.h #ifndef HAL_ESP32_HAL_H_ #define HAL_ESP32_HAL_H_ -#include +#include +#include +#include #include +#include #include #include -#include -#include #include -#include -#include "sdkconfig.h" -#include "esp_system.h" + #include "esp_sleep.h" +#include "esp_system.h" #include "freertos/FreeRTOS.h" -#include "freertos/task.h" +#include "freertos/event_groups.h" #include "freertos/queue.h" #include "freertos/semphr.h" -#include "freertos/event_groups.h" +#include "freertos/task.h" + +#include "sdkconfig.h" #ifdef __cplusplus extern "C" { #endif #ifndef F_CPU -#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 +#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 #define F_CPU (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ * 1000000U) #elif CONFIG_IDF_TARGET_ESP32S2 #define F_CPU (CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ * 1000000U) @@ -68,22 +71,23 @@ extern "C" { #define ARDUINO_EVENT_RUNNING_CORE CONFIG_ARDUINO_EVENT_RUNNING_CORE #endif -//forward declaration from freertos/portmacro.h +// forward declaration from freertos/portmacro.h void vPortYield(void); void yield(void); #define optimistic_yield(u) #define ESP_REG(addr) *((volatile uint32_t *)(addr)) -#define NOP() asm volatile ("nop") +#define NOP() asm volatile("nop") +#include "esp32-hal-cpu.h" #include "esp32-hal-gpio.h" #include "esp32-hal-timer.h" -#include "esp32-hal-cpu.h" +#include "esp_arduino_version.h" unsigned long micros(); unsigned long millis(); -void delay(uint32_t); -void delayMicroseconds(uint32_t us); +void delay(uint32_t); +void delayMicroseconds(uint32_t us); #ifdef __cplusplus } diff --git a/src/hal/esp_arduino_version.h b/src/hal/esp_arduino_version.h new file mode 100644 index 000000000..1a7b2e513 --- /dev/null +++ b/src/hal/esp_arduino_version.h @@ -0,0 +1,55 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Source: https://github.com/espressif/arduino-esp32/blob/idf-release/v5.4/cores/esp32/esp_arduino_version.h + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/** Major version number (X.x.x) */ +#define ESP_ARDUINO_VERSION_MAJOR 3 +/** Minor version number (x.X.x) */ +#define ESP_ARDUINO_VERSION_MINOR 1 +/** Patch version number (x.x.X) */ +#define ESP_ARDUINO_VERSION_PATCH 1 + +/** + * Macro to convert ARDUINO version number into an integer + * + * To be used in comparisons, such as ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(2, 0, 0) + */ +#define ESP_ARDUINO_VERSION_VAL(major, minor, patch) ((major << 16) | (minor << 8) | (patch)) + +/** + * Current ARDUINO version, as an integer + * + * To be used in comparisons, such as ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(2, 0, 0) + */ +#define ESP_ARDUINO_VERSION \ + ESP_ARDUINO_VERSION_VAL(ESP_ARDUINO_VERSION_MAJOR, ESP_ARDUINO_VERSION_MINOR, ESP_ARDUINO_VERSION_PATCH) + +/** + * Current ARDUINO version, as string + */ +#define df2xstr(s) #s +#define df2str(s) df2xstr(s) +#define ESP_ARDUINO_VERSION_STR \ + df2str(ESP_ARDUINO_VERSION_MAJOR) "." df2str(ESP_ARDUINO_VERSION_MINOR) "." df2str(ESP_ARDUINO_VERSION_PATCH) + +#ifdef __cplusplus +} +#endif \ No newline at end of file