Просмотр исходного кода

Merge branch 'feature/post_events_from_isr' into 'master'

Support posting events from ISR

See merge request idf/esp-idf!4283
Angus Gratton 6 лет назад
Родитель
Сommit
0b59b6069e

+ 7 - 0
.gitlab-ci.yml

@@ -1521,6 +1521,13 @@ UT_004_16:
     - UT_T1_1
     - psram
 
+UT_004_17:
+  <<: *unit_test_template
+  tags:
+    - ESP32_IDF
+    - UT_T1_1
+    - psram
+
 UT_005_01:
   <<: *unit_test_template
   tags:

+ 7 - 0
components/esp_event/CMakeLists.txt

@@ -9,4 +9,11 @@ set(COMPONENT_PRIV_INCLUDEDIRS "private_include")
 set(COMPONENT_REQUIRES log tcpip_adapter)
 set(COMPONENT_PRIV_REQUIRES ethernet)
 
+set(COMPONENT_ADD_LDFRAGMENTS linker.lf)
+
 register_component()
+
+if(GCC_NOT_5_2_0 AND CONFIG_EVENT_LOOP_PROFILING)
+    # uses C11 atomic feature
+    set_source_files_properties(esp_event.c PROPERTIES COMPILE_FLAGS -std=gnu11)
+endif()

+ 14 - 0
components/esp_event/Kconfig

@@ -8,4 +8,18 @@ menu "Event Loop Library"
             to/recieved by an event loop, number of callbacks involved, number of events dropped to to a full event
             loop queue, run time of event handlers, and number of times/run time of each event handler.
 
+    config POST_EVENTS_FROM_ISR
+        bool "Support posting events from ISRs"
+        default y
+        help
+            Enable posting events from interrupt handlers.
+
+    config POST_EVENTS_FROM_IRAM_ISR
+        bool "Support posting events from ISRs placed in IRAM"
+        default y
+        depends on POST_EVENTS_FROM_ISR
+        help
+            Enable posting events from interrupt handlers placed in IRAM. Enabling this option places API functions
+            esp_event_post and esp_event_post_to in IRAM.
+
 endmenu

+ 12 - 1
components/esp_event/component.mk

@@ -3,4 +3,15 @@
 #
 COMPONENT_ADD_INCLUDEDIRS := include
 COMPONENT_PRIV_INCLUDEDIRS := private_include
-COMPONENT_SRCDIRS := .
+COMPONENT_SRCDIRS := .
+
+ifdef CONFIG_EVENT_LOOP_PROFILING
+	PROFILING_ENABLED := 1
+else
+	PROFILING_ENABLED := 0
+endif
+
+ifeq ($(and $(GCC_NOT_5_2_0),$(PROFILING_ENABLED)), 1)
+# uses C11 atomic feature
+esp_event.o: CFLAGS += -std=gnu11
+endif

+ 14 - 0
components/esp_event/default_event_loop.c

@@ -55,6 +55,20 @@ esp_err_t esp_event_post(esp_event_base_t event_base, int32_t event_id,
 }
 
 
+#if CONFIG_POST_EVENTS_FROM_ISR
+esp_err_t esp_event_isr_post(esp_event_base_t event_base, int32_t event_id,
+        void* event_data, size_t event_data_size, BaseType_t* task_unblocked)
+{
+    if (s_default_loop == NULL) {
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    return esp_event_isr_post_to(s_default_loop, event_base, event_id,
+            event_data, event_data_size, task_unblocked);
+}
+#endif
+
+
 esp_err_t esp_event_loop_create_default()
 {
     if (s_default_loop) {

+ 94 - 42
components/esp_event/esp_event.c

@@ -58,6 +58,8 @@ static portMUX_TYPE s_event_loops_spinlock = portMUX_INITIALIZER_UNLOCKED;
 /* ------------------------- Static Functions ------------------------------- */
 
 #ifdef CONFIG_EVENT_LOOP_PROFILING
+
+
 static int esp_event_dump_prepare()
 {
     esp_event_loop_instance_t* loop_it;
@@ -129,7 +131,11 @@ static void handler_execute(esp_event_loop_instance_t* loop, esp_event_handler_i
     start = esp_timer_get_time();
 #endif
     // Execute the handler
+#if CONFIG_POST_EVENTS_FROM_ISR
+    (*(handler->handler))(handler->arg, post.base, post.id, post.data_allocd ? post.data.ptr : &post.data.val);
+#else 
     (*(handler->handler))(handler->arg, post.base, post.id, post.data);
+#endif
 
 #ifdef CONFIG_EVENT_LOOP_PROFILING
     diff = esp_timer_get_time() - start;
@@ -371,34 +377,18 @@ static void loop_node_remove_all_handler(esp_event_loop_node_t* loop_node)
     }
 }
 
-static esp_err_t post_instance_create(esp_event_base_t event_base, int32_t event_id, void* event_data, int32_t event_data_size, esp_event_post_instance_t* post)
+static void inline __attribute__((always_inline)) post_instance_delete(esp_event_post_instance_t* post)
 {
-    void* event_data_copy = NULL;
-
-    // Make persistent copy of event data on heap.
-    if (event_data != NULL && event_data_size != 0) {
-        event_data_copy = calloc(1, event_data_size);
-
-        if (event_data_copy == NULL) {
-            ESP_LOGE(TAG, "alloc for post data to event %s:%d failed", event_base, event_id);
-            return ESP_ERR_NO_MEM;
-        }
-
-        memcpy(event_data_copy, event_data, event_data_size);
+#if CONFIG_POST_EVENTS_FROM_ISR
+    if (post->data_allocd && post->data.ptr) {
+        free(post->data.ptr);
     }
-
-    post->base = event_base;
-    post->id = event_id;
-    post->data = event_data_copy;
-
-    ESP_LOGD(TAG, "created post for event %s:%d", event_base, event_id);
-
-    return ESP_OK;
-}
-
-static void post_instance_delete(esp_event_post_instance_t* post)
-{
-    free(post->data);
+#else
+    if (post->data) {
+        free(post->data);
+    }
+#endif
+    memset(post, 0, sizeof(*post));
 }
 
 /* ---------------------------- Public API --------------------------------- */
@@ -556,6 +546,9 @@ esp_err_t esp_event_loop_run(esp_event_loop_handle_t event_loop, TickType_t tick
             }
         }
 
+        esp_event_base_t base = post.base;
+        int32_t id = post.id;
+
         post_instance_delete(&post);
 
         if (ticks_to_run != portMAX_DELAY) {
@@ -576,7 +569,7 @@ esp_err_t esp_event_loop_run(esp_event_loop_handle_t event_loop, TickType_t tick
 
         if (!exec) {
             // No handlers were registered, not even loop/base level handlers
-            ESP_LOGW(TAG, "no handlers have been registered for event %s:%d posted to loop %p", post.base, post.id, event_loop);
+            ESP_LOGW(TAG, "no handlers have been registered for event %s:%d posted to loop %p", base, id, event_loop);
         }
     }
 
@@ -618,7 +611,7 @@ esp_err_t esp_event_loop_delete(esp_event_loop_handle_t event_loop)
     // Drop existing posts on the queue
     esp_event_post_instance_t post;
     while(xQueueReceive(loop->queue, &post, 0) == pdTRUE) {
-        free(post.data);
+        post_instance_delete(&post);
     }
 
     // Cleanup loop
@@ -735,25 +728,38 @@ esp_err_t esp_event_handler_unregister_with(esp_event_loop_handle_t event_loop,
     return ESP_OK;
 }
 
-
 esp_err_t esp_event_post_to(esp_event_loop_handle_t event_loop, esp_event_base_t event_base, int32_t event_id,
                             void* event_data, size_t event_data_size, TickType_t ticks_to_wait)
 {
     assert(event_loop);
 
     if (event_base == ESP_EVENT_ANY_BASE || event_id == ESP_EVENT_ANY_ID) {
-        ESP_LOGE(TAG, "posting nonspecific event base or id unsupported");
         return ESP_ERR_INVALID_ARG;
     }
 
     esp_event_loop_instance_t* loop = (esp_event_loop_instance_t*) event_loop;
 
     esp_event_post_instance_t post;
-    esp_err_t err = post_instance_create(event_base, event_id, event_data, event_data_size, &post);
+    memset((void*)(&(post.data)), 0, sizeof(post.data));
+
+    if (event_data != NULL && event_data_size != 0) {
+        // Make persistent copy of event data on heap.
+        void* event_data_copy = calloc(1, event_data_size);
+
+        if (event_data_copy == NULL) {
+            return ESP_ERR_NO_MEM;
+        }
 
-    if (err != ESP_OK) {
-        return err;
+        memcpy(event_data_copy, event_data, event_data_size);
+#if CONFIG_POST_EVENTS_FROM_ISR
+        post.data.ptr = event_data_copy;
+        post.data_allocd = true;
+#else
+        post.data = event_data_copy;
+#endif
     }
+    post.base = event_base;
+    post.id = event_id;
 
     BaseType_t result = pdFALSE;
 
@@ -785,24 +791,65 @@ esp_err_t esp_event_post_to(esp_event_loop_handle_t event_loop, esp_event_base_t
         post_instance_delete(&post);
 
 #ifdef CONFIG_EVENT_LOOP_PROFILING
-        xSemaphoreTake(loop->profiling_mutex, portMAX_DELAY);
-        loop->events_dropped++;
-        xSemaphoreGive(loop->profiling_mutex);
+        atomic_fetch_add(&loop->events_dropped, 1);
 #endif
         return ESP_ERR_TIMEOUT;
     }
 
 #ifdef CONFIG_EVENT_LOOP_PROFILING
-    xSemaphoreTake(loop->profiling_mutex, portMAX_DELAY);
-    loop->events_recieved++;
-    xSemaphoreGive(loop->profiling_mutex);
+    atomic_fetch_add(&loop->events_recieved, 1);
 #endif
 
-    ESP_LOGD(TAG, "posted %s:%d to loop %p", post.base, post.id, event_loop);
-
     return ESP_OK;
 }
 
+#if CONFIG_POST_EVENTS_FROM_ISR
+esp_err_t esp_event_isr_post_to(esp_event_loop_handle_t event_loop, esp_event_base_t event_base, int32_t event_id,
+                            void* event_data, size_t event_data_size, BaseType_t* task_unblocked)
+{
+    assert(event_loop);
+
+    if (event_base == ESP_EVENT_ANY_BASE || event_id == ESP_EVENT_ANY_ID) {
+        return ESP_ERR_INVALID_ARG;
+    }
+
+    esp_event_loop_instance_t* loop = (esp_event_loop_instance_t*) event_loop;
+
+    esp_event_post_instance_t post;
+    memset((void*)(&(post.data)), 0, sizeof(post.data));
+
+    if (event_data_size > sizeof(post.data.val)) {
+        return ESP_ERR_INVALID_ARG;
+    }
+
+    if (event_data != NULL && event_data_size != 0) {
+        memcpy((void*)(&(post.data.val)), event_data, event_data_size);
+        post.data_allocd = false;
+    }
+    post.base = event_base;
+    post.id = event_id;
+
+    BaseType_t result = pdFALSE;
+
+    // Post the event from an ISR,
+    result = xQueueSendToBackFromISR(loop->queue, &post, task_unblocked);
+
+    if (result != pdTRUE) {
+        post_instance_delete(&post);
+
+#ifdef CONFIG_EVENT_LOOP_PROFILING
+        atomic_fetch_add(&loop->events_dropped, 1);
+#endif
+        return ESP_FAIL;
+    }
+
+#ifdef CONFIG_EVENT_LOOP_PROFILING
+    atomic_fetch_add(&loop->events_recieved, 1);
+#endif
+
+    return ESP_OK;
+}
+#endif
 
 esp_err_t esp_event_dump(FILE* file)
 {
@@ -826,8 +873,13 @@ esp_err_t esp_event_dump(FILE* file)
     portENTER_CRITICAL(&s_event_loops_spinlock);
 
     SLIST_FOREACH(loop_it, &s_event_loops, next) {
+        uint32_t events_recieved, events_dropped;
+
+        events_recieved = atomic_load(&loop_it->events_recieved);
+        events_dropped = atomic_load(&loop_it->events_dropped);
+
         PRINT_DUMP_INFO(dst, sz, LOOP_DUMP_FORMAT, loop_it, loop_it->task != NULL ? loop_it->name : "none" ,
-                        loop_it->events_recieved, loop_it->events_dropped);
+                        events_recieved, events_dropped);
 
         int sz_bak = sz;
 

+ 65 - 9
components/esp_event/include/esp_event.h

@@ -29,7 +29,6 @@
 extern "C" {
 #endif
 
-
 /// Configuration for creating event loops
 typedef struct {
     int32_t queue_size;                         /**< size of the event loop queue */
@@ -224,16 +223,15 @@ esp_err_t esp_event_handler_unregister_with(esp_event_loop_handle_t event_loop,
  * handler recieves is always valid.
  *
  * @param[in] event_base the event base that identifies the event
- * @param[in] event_id the the event id that identifies the event
+ * @param[in] event_id the event id that identifies the event
  * @param[in] event_data the data, specific to the event occurence, that gets passed to the handler
  * @param[in] event_data_size the size of the event data
  * @param[in] ticks_to_wait number of ticks to block on a full event queue
  *
- * @note posting events from an ISR is not supported
- *
  * @return
  *  - ESP_OK: Success
- *  - ESP_ERR_TIMEOUT: Time to wait for event queue to unblock expired
+ *  - ESP_ERR_TIMEOUT: Time to wait for event queue to unblock expired, 
+ *                      queue full when posting from ISR
  *  - ESP_ERR_INVALID_ARG: Invalid combination of event base and event id
  *  - Others: Fail
  */
@@ -253,16 +251,15 @@ esp_err_t esp_event_post(esp_event_base_t event_base,
  *
  * @param[in] event_loop the event loop to post to
  * @param[in] event_base the event base that identifies the event
- * @param[in] event_id the the event id that identifies the event
+ * @param[in] event_id the event id that identifies the event
  * @param[in] event_data the data, specific to the event occurence, that gets passed to the handler
  * @param[in] event_data_size the size of the event data
  * @param[in] ticks_to_wait number of ticks to block on a full event queue
  *
- * @note posting events from an ISR is not supported
- *
  * @return
  *  - ESP_OK: Success
- *  - ESP_ERR_TIMEOUT: Time to wait for event queue to unblock expired
+ *  - ESP_ERR_TIMEOUT: Time to wait for event queue to unblock expired, 
+ *                      queue full when posting from ISR
  *  - ESP_ERR_INVALID_ARG: Invalid combination of event base and event id
  *  - Others: Fail
  */
@@ -273,6 +270,65 @@ esp_err_t esp_event_post_to(esp_event_loop_handle_t event_loop,
                             size_t event_data_size,
                             TickType_t ticks_to_wait);
 
+#if CONFIG_POST_EVENTS_FROM_ISR
+/**
+ * @brief Special variant of esp_event_post for posting events from interrupt handlers.
+ * 
+ * @param[in] event_base the event base that identifies the event
+ * @param[in] event_id the event id that identifies the event
+ * @param[in] event_data the data, specific to the event occurence, that gets passed to the handler
+ * @param[in] event_data_size the size of the event data; max is 4 bytes
+ * @param[out] task_unblocked an optional parameter (can be NULL) which indicates that an event task with 
+ *                            higher priority than currently running task has been unblocked by the posted event;
+ *                            a context switch should be requested before the interrupt is existed.
+ *
+ * @note this function is only available when CONFIG_POST_EVENTS_FROM_ISR is enabled
+ * @note when this function is called from an interrupt handler placed in IRAM, this function should
+ *       be placed in IRAM as well by enabling CONFIG_POST_EVENTS_FROM_IRAM_ISR
+ *
+ * @return
+ *  - ESP_OK: Success
+ *  - ESP_FAIL: Event queue for the default event loop full
+ *  - ESP_ERR_INVALID_ARG: Invalid combination of event base and event id,
+ *                          data size of more than 4 bytes 
+ *  - Others: Fail
+ */
+esp_err_t esp_event_isr_post(esp_event_base_t event_base,
+                            int32_t event_id,
+                            void* event_data,
+                            size_t event_data_size,
+                            BaseType_t* task_unblocked);
+
+/**
+ * @brief Special variant of esp_event_post_to for posting events from interrupt handlers
+ *
+ * @param[in] event_base the event base that identifies the event
+ * @param[in] event_id the event id that identifies the event
+ * @param[in] event_data the data, specific to the event occurence, that gets passed to the handler
+ * @param[in] event_data_size the size of the event data
+ * @param[out] task_unblocked an optional parameter (can be NULL) which indicates that an event task with 
+ *                            higher priority than currently running task has been unblocked by the posted event;
+ *                            a context switch should be requested before the interrupt is existed.
+ *
+ * @note this function is only available when CONFIG_POST_EVENTS_FROM_ISR is enabled
+ * @note when this function is called from an interrupt handler placed in IRAM, this function should
+ *       be placed in IRAM as well by enabling CONFIG_POST_EVENTS_FROM_IRAM_ISR
+ *
+ * @return
+ *  - ESP_OK: Success
+ *  - ESP_FAIL: Event queue for the loop full
+ *  - ESP_ERR_INVALID_ARG: Invalid combination of event base and event id,
+ *                          data size of more than 4 bytes 
+ *  - Others: Fail
+ */
+esp_err_t esp_event_isr_post_to(esp_event_loop_handle_t event_loop,
+                            esp_event_base_t event_base,
+                            int32_t event_id,
+                            void* event_data,
+                            size_t event_data_size,
+                            BaseType_t* task_unblocked);
+#endif
+
 /**
  * @brief Dumps statistics of all event loops.
  *

+ 6 - 0
components/esp_event/linker.lf

@@ -0,0 +1,6 @@
+if POST_EVENTS_FROM_IRAM_ISR = y:
+    [mapping:esp_event]
+    archive: libesp_event.a
+    entries:
+        esp_event:esp_event_isr_post_to (noflash)
+        default_event_loop:esp_event_isr_post (noflash)

+ 16 - 3
components/esp_event/private_include/esp_event_internal.h

@@ -16,6 +16,7 @@
 #define ESP_EVENT_INTERNAL_H_
 
 #include "esp_event.h"
+#include "stdatomic.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -77,18 +78,30 @@ typedef struct esp_event_loop_instance {
     esp_event_loop_nodes_t loop_nodes;                              /**< set of linked lists containing the
                                                                             registered handlers for the loop */
 #ifdef CONFIG_EVENT_LOOP_PROFILING
-    uint32_t events_recieved;                                       /**< number of events successfully posted to the loop */
-    uint32_t events_dropped;                                        /**< number of events dropped due to queue being full */
+    atomic_uint_least32_t events_recieved;                          /**< number of events successfully posted to the loop */
+    atomic_uint_least32_t events_dropped;                           /**< number of events dropped due to queue being full */
     SemaphoreHandle_t profiling_mutex;                              /**< mutex used for profiliing */
     SLIST_ENTRY(esp_event_loop_instance) next;                      /**< next event loop in the list */
 #endif
 } esp_event_loop_instance_t;
 
+#if CONFIG_POST_EVENTS_FROM_ISR
+typedef union esp_event_post_data {
+    uint32_t val;
+    void *ptr;
+} esp_event_post_data_t;
+#else
+typedef void* esp_event_post_data_t;
+#endif
+
 /// Event posted to the event queue
 typedef struct esp_event_post_instance {
+#if CONFIG_POST_EVENTS_FROM_ISR
+    bool data_allocd;                                                /**< indicates whether data is alloc'd */
+#endif
     esp_event_base_t base;                                           /**< the event base */
     int32_t id;                                                      /**< the event id */
-    void* data;                                                      /**< data associated with the event */
+    esp_event_post_data_t data;                                      /**< data associated with the event */
 } esp_event_post_instance_t;
 
 #ifdef __cplusplus

+ 1 - 1
components/esp_event/test/CMakeLists.txt

@@ -1,5 +1,5 @@
 set(COMPONENT_SRCDIRS ".")
 set(COMPONENT_PRIV_INCLUDEDIRS "../private_include" ".")
-set(COMPONENT_PRIV_REQUIRES unity test_utils esp_event)
+set(COMPONENT_PRIV_REQUIRES unity test_utils esp_event driver)
 
 register_component()

+ 84 - 0
components/esp_event/test/test_event.c

@@ -7,7 +7,11 @@
 #include "freertos/FreeRTOS.h"
 #include "esp_event_loop.h"
 #include "freertos/task.h"
+#include "freertos/portmacro.h"
 #include "esp_log.h"
+#include "soc/timer_group_struct.h"
+#include "driver/periph_ctrl.h"
+#include "driver/timer.h"
 
 #include "esp_event.h"
 #include "esp_event_private.h"
@@ -268,6 +272,48 @@ static void test_teardown()
     TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_delete_default());
 }
 
+#define TIMER_DIVIDER         16  //  Hardware timer clock divider
+#define TIMER_SCALE           (TIMER_BASE_CLK / TIMER_DIVIDER)  // convert counter value to seconds
+#define TIMER_INTERVAL0_SEC   (2.0) // sample test interval for the first timer
+
+#if CONFIG_POST_EVENTS_FROM_ISR
+static void test_handler_post_from_isr(void* event_handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
+{
+    SemaphoreHandle_t *sem = (SemaphoreHandle_t*) event_handler_arg;
+    // Event data is just the address value (maybe have been truncated due to casting).
+    int *data = (int*) event_data;
+    TEST_ASSERT_EQUAL(*data, (int) (*sem));
+    xSemaphoreGive(*sem);
+}
+#endif
+
+#if CONFIG_POST_EVENTS_FROM_ISR
+void IRAM_ATTR test_event_on_timer_alarm(void* para)
+{
+    /* Retrieve the interrupt status and the counter value
+       from the timer that reported the interrupt */
+    TIMERG0.hw_timer[TIMER_0].update = 1;
+    uint64_t timer_counter_value =
+        ((uint64_t) TIMERG0.hw_timer[TIMER_0].cnt_high) << 32
+        | TIMERG0.hw_timer[TIMER_0].cnt_low;
+
+    TIMERG0.int_clr_timers.t0 = 1;
+    timer_counter_value += (uint64_t) (TIMER_INTERVAL0_SEC * TIMER_SCALE);
+    TIMERG0.hw_timer[TIMER_0].alarm_high = (uint32_t) (timer_counter_value >> 32);
+    TIMERG0.hw_timer[TIMER_0].alarm_low = (uint32_t) timer_counter_value;
+
+    int data = (int) para;
+    // Posting events with data more than 4 bytes should fail.
+    TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, esp_event_isr_post(s_test_base1, TEST_EVENT_BASE1_EV1, &data, 5, NULL));
+    // This should succeedd, as data is int-sized. The handler for the event checks that the passed event data
+    // is correct.
+    BaseType_t task_unblocked;
+    TEST_ASSERT_EQUAL(ESP_OK, esp_event_isr_post(s_test_base1, TEST_EVENT_BASE1_EV1, &data, sizeof(data), &task_unblocked));
+    if (task_unblocked == pdTRUE) {
+        portYIELD_FROM_ISR();
+    }
+}
+#endif //CONFIG_POST_EVENTS_FROM_ISR
 
 TEST_CASE("can create and delete event loops", "[event]")
 {
@@ -1102,6 +1148,44 @@ TEST_CASE("events are dispatched in the order they are registered", "[event]")
     TEST_TEARDOWN();
 }
 
+#if CONFIG_POST_EVENTS_FROM_ISR
+TEST_CASE("can post events from interrupt handler", "[event]")
+{
+    SemaphoreHandle_t sem = xSemaphoreCreateBinary();
+
+    /* Select and initialize basic parameters of the timer */
+    timer_config_t config;
+    config.divider = TIMER_DIVIDER;
+    config.counter_dir = TIMER_COUNT_UP;
+    config.counter_en = TIMER_PAUSE;
+    config.alarm_en = TIMER_ALARM_EN;
+    config.intr_type = TIMER_INTR_LEVEL;
+    config.auto_reload = false;
+    timer_init(TIMER_GROUP_0, TIMER_0, &config);
+
+    /* Timer's counter will initially start from value below.
+       Also, if auto_reload is set, this value will be automatically reload on alarm */
+    timer_set_counter_value(TIMER_GROUP_0, TIMER_0, 0x00000000ULL);
+
+    /* Configure the alarm value and the interrupt on alarm. */
+    timer_set_alarm_value(TIMER_GROUP_0, TIMER_0, TIMER_INTERVAL0_SEC * TIMER_SCALE);
+    timer_enable_intr(TIMER_GROUP_0, TIMER_0);
+    timer_isr_register(TIMER_GROUP_0, TIMER_0, test_event_on_timer_alarm,
+        (void *) sem, ESP_INTR_FLAG_IRAM, NULL);
+
+    timer_start(TIMER_GROUP_0, TIMER_0);
+
+    TEST_SETUP();
+
+    TEST_ASSERT_EQUAL(ESP_OK, esp_event_handler_register(s_test_base1, TEST_EVENT_BASE1_EV1,
+                                                        test_handler_post_from_isr, &sem));
+
+    xSemaphoreTake(sem, portMAX_DELAY);
+
+    TEST_TEARDOWN();
+}
+#endif
+
 #ifdef CONFIG_EVENT_LOOP_PROFILING
 TEST_CASE("can dump event loop profile", "[event]")
 {