]> granicus.if.org Git - esp-idf/commitdiff
gpio/driver: Sped the gpio_intr_service ISR up by 1.5 uSeconds (+-50% faster).
authorPieter du Preez <pdupreez@gmail.com>
Fri, 21 Dec 2018 14:07:51 +0000 (14:07 +0000)
committerbot <bot@espressif.com>
Wed, 13 Mar 2019 13:50:43 +0000 (13:50 +0000)
Removed as much branching (if statements) from the
gpio_intr_service ISR, as possible and split the while loop into
two. Also forced writing the two status*_w1tc variables only once,
instead of every time after calling the external function hooks.

The measurements below, was done using the following tools:

Toolchain version: crosstool-ng-1.22.0-80-g6c4433a
Compiler version: 5.2.0

Here follows a comparison of the gpio_intr_service ISR's
execution time, using a DS1054 oscilloscope. All the time spent
calling external functions, via the function pointers
gpio_isr_func[gpio_num].fn, were disregarded.

With OPTIMIZATION_FLAGS = -Og, 1.34 uSeconds faster:

3.22 uSec (with this patch)
4.56 uSec (with commit 71c90ac4)

100 - (100 * 4.56 / 3.22) = 42% faster

With OPTIMIZATION_FLAGS = -Os, 1.65 uSeconds faster:

2.89 uSec (with this patch)
4.54 uSec (with commit 71c90ac4)

100 - (100 * 4.54 / 2.89) = 57% faster

Signed-off-by: Konstantin Kondrashov <konstantin@espressif.com>
Merges https://github.com/espressif/esp-idf/pull/2861

components/driver/gpio.c

index 302aa850fc6665a3a64d88b54e1c2edfb940bd0b..0c9f553883b2651a456c657cd125177a665c591e 100644 (file)
@@ -327,37 +327,37 @@ esp_err_t gpio_reset_pin(gpio_num_t gpio_num)
     return ESP_OK;
 }
 
-void IRAM_ATTR gpio_intr_service(void* arg)
+static inline void IRAM_ATTR gpio_isr_loop(uint32_t status, const uint32_t gpio_num_start) {
+    while (status) {
+        int nbit = __builtin_ffs(status) - 1;
+        status &= ~(1 << nbit);
+        int gpio_num = gpio_num_start + nbit;
+        if (gpio_isr_func[gpio_num].fn != NULL) {
+            gpio_isr_func[gpio_num].fn(gpio_isr_func[gpio_num].args);
+        }
+    }
+}
+
+static void IRAM_ATTR gpio_intr_service(void* arg)
 {
     //GPIO intr process
-    uint32_t gpio_num = 0;
-    //read status to get interrupt status for GPIO0-31
-    uint32_t gpio_intr_status;
-    gpio_intr_status = GPIO.status;
-    //read status1 to get interrupt status for GPIO32-39
-    uint32_t gpio_intr_status_h;
-    gpio_intr_status_h = GPIO.status1.intr_st;
-
     if (gpio_isr_func == NULL) {
         return;
     }
-    do {
-        if (gpio_num < 32) {
-            if (gpio_intr_status & BIT(gpio_num)) { //gpio0-gpio31
-                if (gpio_isr_func[gpio_num].fn != NULL) {
-                    gpio_isr_func[gpio_num].fn(gpio_isr_func[gpio_num].args);
-                }
-                GPIO.status_w1tc = BIT(gpio_num);
-            }
-        } else {
-            if (gpio_intr_status_h & BIT(gpio_num - 32)) {
-                if (gpio_isr_func[gpio_num].fn != NULL) {
-                    gpio_isr_func[gpio_num].fn(gpio_isr_func[gpio_num].args);
-                }
-                GPIO.status1_w1tc.intr_st = BIT(gpio_num - 32);
-            }
-        }
-    } while (++gpio_num < GPIO_PIN_COUNT);
+
+    //read status to get interrupt status for GPIO0-31
+    const uint32_t gpio_intr_status = GPIO.status;
+    if (gpio_intr_status) {
+        gpio_isr_loop(gpio_intr_status, 0);
+        GPIO.status_w1tc = gpio_intr_status;
+    }
+
+    //read status1 to get interrupt status for GPIO32-39
+    const uint32_t gpio_intr_status_h = GPIO.status1.intr_st;
+    if (gpio_intr_status_h) {
+        gpio_isr_loop(gpio_intr_status_h, 32);
+        GPIO.status1_w1tc.intr_st = gpio_intr_status_h;
+    }
 }
 
 esp_err_t gpio_isr_handler_add(gpio_num_t gpio_num, gpio_isr_t isr_handler, void* args)