Sfoglia il codice sorgente

Merge branch 'feature/dedic_gpio_esp32s3' into 'master'

Dedicated gpio driver on esp32s3

Closes IDF-3387

See merge request espressif/esp-idf!14196
morris 4 anni fa
parent
commit
d9d4db43a1

+ 38 - 44
components/driver/dedic_gpio.c

@@ -3,7 +3,9 @@
  *
  * SPDX-License-Identifier: Apache-2.0
  */
+
 // #define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
+
 #include <stdlib.h>
 #include <string.h>
 #include <sys/lock.h>
@@ -12,6 +14,7 @@
 #include "esp_heap_caps.h"
 #include "esp_intr_alloc.h"
 #include "esp_log.h"
+#include "esp_check.h"
 #include "soc/soc_caps.h"
 #include "soc/gpio_periph.h"
 #include "soc/io_mux_reg.h"
@@ -31,15 +34,6 @@
 
 static const char *TAG = "dedic_gpio";
 
-#define DEDIC_CHECK(a, msg, tag, ret, ...)                                        \
-    do {                                                                          \
-        if (unlikely(!(a))) {                                                     \
-            ESP_LOGE(TAG, "%s(%d): " msg, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
-            ret_code = ret;                                                       \
-            goto tag;                                                             \
-        }                                                                         \
-    } while (0)
-
 typedef struct dedic_gpio_platform_t dedic_gpio_platform_t;
 typedef struct dedic_gpio_bundle_t dedic_gpio_bundle_t;
 
@@ -70,12 +64,12 @@ struct dedic_gpio_bundle_t {
     uint32_t out_offset; // offset in the bank (seen from output channel)
     uint32_t in_offset;  // offset in the bank (seen from input channel)
     size_t nr_gpio;    // number of GPIOs in the gpio_array
-    int gpio_array[0];   // array of GPIO numbers (configured by user)
+    int gpio_array[];   // array of GPIO numbers (configured by user)
 };
 
 static esp_err_t dedic_gpio_build_platform(uint32_t core_id)
 {
-    esp_err_t ret_code = ESP_OK;
+    esp_err_t ret = ESP_OK;
     if (!s_platform[core_id]) {
         // prevent building platform concurrently
         _lock_acquire(&s_platform_mutexlock[core_id]);
@@ -92,12 +86,12 @@ static esp_err_t dedic_gpio_build_platform(uint32_t core_id)
         }
         _lock_release(&s_platform_mutexlock[core_id]);
 
-        DEDIC_CHECK(s_platform[core_id], "no mem for s_platform[%d]", err, ESP_ERR_NO_MEM, core_id);
+        ESP_GOTO_ON_FALSE(s_platform[core_id], ESP_ERR_NO_MEM, err, TAG, "no mem for s_platform[%d]", core_id);
         ESP_LOGD(TAG, "build platform on core[%d] at %p", core_id, s_platform);
     }
 
 err:
-    return ret_code;
+    return ret;
 }
 
 static void dedic_gpio_break_platform(uint32_t core_id)
@@ -144,23 +138,23 @@ static void dedic_gpio_default_isr(void *arg)
 
 static esp_err_t dedic_gpio_install_interrupt(uint32_t core_id)
 {
-    esp_err_t ret_code = ESP_OK;
+    esp_err_t ret = ESP_OK;
     if (!s_platform[core_id]->intr_hdl) {
         // prevent install interrupt concurrently
         _lock_acquire(&s_platform_mutexlock[core_id]);
         if (!s_platform[core_id]->intr_hdl) {
             int isr_flags = 0;
-            ret_code = esp_intr_alloc(dedic_gpio_periph_signals.irq, isr_flags, dedic_gpio_default_isr, s_platform[core_id], &s_platform[core_id]->intr_hdl);
+            ret = esp_intr_alloc(dedic_gpio_periph_signals.irq, isr_flags, dedic_gpio_default_isr, s_platform[core_id], &s_platform[core_id]->intr_hdl);
             // clear pending interrupt
             uint32_t status = dedic_gpio_ll_get_interrupt_status(s_platform[core_id]->dev);
             dedic_gpio_ll_clear_interrupt_status(s_platform[core_id]->dev, status);
         }
         _lock_release(&s_platform_mutexlock[core_id]);
-        DEDIC_CHECK(ret_code == ESP_OK, "alloc interrupt failed", err, ret_code);
+        ESP_GOTO_ON_ERROR(ret, err, TAG, "alloc interrupt failed");
     }
 
 err:
-    return ret_code;
+    return ret;
 }
 
 static void dedic_gpio_uninstall_interrupt(uint32_t core_id)
@@ -191,29 +185,29 @@ static void dedic_gpio_set_interrupt(uint32_t core_id, uint32_t channel, dedic_g
 
 esp_err_t dedic_gpio_new_bundle(const dedic_gpio_bundle_config_t *config, dedic_gpio_bundle_handle_t *ret_bundle)
 {
-    esp_err_t ret_code = ESP_OK;
+    esp_err_t ret = ESP_OK;
     dedic_gpio_bundle_t *bundle = NULL;
     uint32_t out_mask = 0;
     uint32_t in_mask = 0;
     uint32_t core_id = cpu_hal_get_core_id(); // dedicated GPIO will be binded to the CPU who invokes this API
 
-    DEDIC_CHECK(config && ret_bundle, "invalid argument", err, ESP_ERR_INVALID_ARG);
-    DEDIC_CHECK(config->gpio_array && config->array_size > 0, "invalid GPIO array or size", err, ESP_ERR_INVALID_ARG);
-    DEDIC_CHECK(config->flags.in_en || config->flags.out_en, "no input/output mode specified", err, ESP_ERR_INVALID_ARG);
+    ESP_GOTO_ON_FALSE(config && ret_bundle, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
+    ESP_GOTO_ON_FALSE(config->gpio_array && config->array_size > 0, ESP_ERR_INVALID_ARG, err, TAG, "invalid GPIO array or size");
+    ESP_GOTO_ON_FALSE(config->flags.in_en || config->flags.out_en, ESP_ERR_INVALID_ARG, err, TAG, "no input/output mode specified");
     // lazy install s_platform[core_id]
-    DEDIC_CHECK(dedic_gpio_build_platform(core_id) == ESP_OK, "build platform %d failed", err, ESP_FAIL, core_id);
+    ESP_GOTO_ON_ERROR(dedic_gpio_build_platform(core_id), err, TAG, "build platform %d failed", core_id);
 
     size_t bundle_size = sizeof(dedic_gpio_bundle_t) + config->array_size * sizeof(config->gpio_array[0]);
     bundle = calloc(1, bundle_size);
-    DEDIC_CHECK(bundle, "no mem for bundle", err, ESP_ERR_NO_MEM);
+    ESP_GOTO_ON_FALSE(bundle, ESP_ERR_NO_MEM, err, TAG, "no mem for bundle");
 
     // for performance reasons, we only search for continuous channels
     uint32_t pattern = (1 << config->array_size) - 1;
     // configure outwards channels
     uint32_t out_offset = 0;
     if (config->flags.out_en) {
-        DEDIC_CHECK(SOC_DEDIC_GPIO_OUT_CHANNELS_NUM >= config->array_size, "array size(%d) exceeds maximum supported out channels(%d)",
-                    err, ESP_ERR_INVALID_ARG, config->array_size, SOC_DEDIC_GPIO_OUT_CHANNELS_NUM);
+        ESP_GOTO_ON_FALSE(config->array_size <= SOC_DEDIC_GPIO_OUT_CHANNELS_NUM, ESP_ERR_INVALID_ARG, err, TAG,
+                          "array size(%d) exceeds maximum supported out channels(%d)", config->array_size, SOC_DEDIC_GPIO_OUT_CHANNELS_NUM);
         // prevent install bundle concurrently
         portENTER_CRITICAL(&s_platform[core_id]->spinlock);
         for (size_t i = 0; i <= SOC_DEDIC_GPIO_OUT_CHANNELS_NUM - config->array_size; i++) {
@@ -231,15 +225,15 @@ esp_err_t dedic_gpio_new_bundle(const dedic_gpio_bundle_config_t *config, dedic_
 #endif
         }
         portEXIT_CRITICAL(&s_platform[core_id]->spinlock);
-        DEDIC_CHECK(out_mask, "no free outward channels on core[%d]", err, ESP_ERR_NOT_FOUND, core_id);
+        ESP_GOTO_ON_FALSE(out_mask, ESP_ERR_NOT_FOUND, err, TAG, "no free outward channels on core[%d]", core_id);
         ESP_LOGD(TAG, "new outward bundle(%p) on core[%d], offset=%d, mask(%x)", bundle, core_id, out_offset, out_mask);
     }
 
     // configure inwards channels
     uint32_t in_offset = 0;
     if (config->flags.in_en) {
-        DEDIC_CHECK(SOC_DEDIC_GPIO_IN_CHANNELS_NUM >= config->array_size, "array size(%d) exceeds maximum supported in channels(%d)",
-                    err, ESP_ERR_INVALID_ARG, config->array_size, SOC_DEDIC_GPIO_IN_CHANNELS_NUM);
+        ESP_GOTO_ON_FALSE(config->array_size <= SOC_DEDIC_GPIO_IN_CHANNELS_NUM, ESP_ERR_INVALID_ARG, err, TAG,
+                          "array size(%d) exceeds maximum supported in channels(%d)", config->array_size, SOC_DEDIC_GPIO_IN_CHANNELS_NUM);
         // prevent install bundle concurrently
         portENTER_CRITICAL(&s_platform[core_id]->spinlock);
         for (size_t i = 0; i <= SOC_DEDIC_GPIO_IN_CHANNELS_NUM - config->array_size; i++) {
@@ -253,7 +247,7 @@ esp_err_t dedic_gpio_new_bundle(const dedic_gpio_bundle_config_t *config, dedic_
             s_platform[core_id]->in_occupied_mask |= in_mask;
         }
         portEXIT_CRITICAL(&s_platform[core_id]->spinlock);
-        DEDIC_CHECK(in_mask, "no free inward channels on core[%d]", err, ESP_ERR_NOT_FOUND, core_id);
+        ESP_GOTO_ON_FALSE(in_mask, ESP_ERR_NOT_FOUND, err, TAG, "no free inward channels on core[%d]", core_id);
         ESP_LOGD(TAG, "new inward bundle(%p) on core[%d], offset=%d, mask(%x)", bundle, core_id, in_offset, in_mask);
     }
 
@@ -293,17 +287,17 @@ err:
     if (bundle) {
         free(bundle);
     }
-    return ret_code;
+    return ret;
 }
 
 esp_err_t dedic_gpio_del_bundle(dedic_gpio_bundle_handle_t bundle)
 {
-    esp_err_t ret_code = ESP_OK;
+    esp_err_t ret = ESP_OK;
     bool recycle_all = false;
-    DEDIC_CHECK(bundle, "invalid argument", err, ESP_ERR_INVALID_ARG);
+    ESP_GOTO_ON_FALSE(bundle, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
 
     uint32_t core_id = cpu_hal_get_core_id();
-    DEDIC_CHECK(core_id == bundle->core_id, "del bundle on wrong CPU", err, ESP_FAIL);
+    ESP_GOTO_ON_FALSE(core_id == bundle->core_id, ESP_FAIL, err, TAG, "del bundle on wrong CPU");
 
     portENTER_CRITICAL(&s_platform[core_id]->spinlock);
     s_platform[core_id]->out_occupied_mask &= ~(bundle->out_mask);
@@ -323,25 +317,25 @@ esp_err_t dedic_gpio_del_bundle(dedic_gpio_bundle_handle_t bundle)
     }
 
 err:
-    return ret_code;
+    return ret;
 }
 
 esp_err_t dedic_gpio_get_out_mask(dedic_gpio_bundle_handle_t bundle, uint32_t *mask)
 {
-    esp_err_t ret_code = ESP_OK;
-    DEDIC_CHECK(bundle && mask, "invalid argument", err, ESP_ERR_INVALID_ARG);
+    esp_err_t ret = ESP_OK;
+    ESP_GOTO_ON_FALSE(bundle && mask, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
     *mask = bundle->out_mask;
 err:
-    return ret_code;
+    return ret;
 }
 
 esp_err_t dedic_gpio_get_in_mask(dedic_gpio_bundle_handle_t bundle, uint32_t *mask)
 {
-    esp_err_t ret_code = ESP_OK;
-    DEDIC_CHECK(bundle && mask, "invalid argument", err, ESP_ERR_INVALID_ARG);
+    esp_err_t ret = ESP_OK;
+    ESP_GOTO_ON_FALSE(bundle && mask, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
     *mask = bundle->in_mask;
 err:
-    return ret_code;
+    return ret;
 }
 
 void dedic_gpio_bundle_write(dedic_gpio_bundle_handle_t bundle, uint32_t mask, uint32_t value)
@@ -370,11 +364,11 @@ uint32_t dedic_gpio_bundle_read_in(dedic_gpio_bundle_handle_t bundle)
 #if SOC_DEDIC_GPIO_HAS_INTERRUPT
 esp_err_t dedic_gpio_bundle_set_interrupt_and_callback(dedic_gpio_bundle_handle_t bundle, uint32_t mask, dedic_gpio_intr_type_t intr_type, dedic_gpio_isr_callback_t cb_isr, void *cb_args)
 {
-    esp_err_t ret_code = ESP_OK;
-    DEDIC_CHECK(bundle, "invalid argument", err, ESP_ERR_INVALID_ARG);
+    esp_err_t ret = ESP_OK;
+    ESP_GOTO_ON_FALSE(bundle, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
     uint32_t core_id = cpu_hal_get_core_id();
     // lazy alloc interrupt
-    DEDIC_CHECK(dedic_gpio_install_interrupt(core_id) == ESP_OK, "allocate interrupt on core %d failed", err, ESP_FAIL, core_id);
+    ESP_GOTO_ON_ERROR(dedic_gpio_install_interrupt(core_id), err, TAG, "allocate interrupt on core %d failed", core_id);
 
     uint32_t channel_mask = bundle->in_mask & (mask << bundle->in_offset);
     uint32_t channel = 0;
@@ -391,6 +385,6 @@ esp_err_t dedic_gpio_bundle_set_interrupt_and_callback(dedic_gpio_bundle_handle_
     }
 
 err:
-    return ret_code;
+    return ret;
 }
 #endif // SOC_DEDIC_GPIO_HAS_INTERRUPT

+ 4 - 4
components/driver/include/driver/dedic_gpio.h

@@ -30,10 +30,10 @@ typedef struct {
     const int *gpio_array; /*!< Array of GPIO numbers, gpio_array[0] ~ gpio_array[size-1] <=> low_dedic_channel_num ~ high_dedic_channel_num */
     size_t array_size;     /*!< Number of GPIOs in gpio_array */
     struct {
-        int in_en: 1;      /*!< Enable input */
-        int in_invert: 1;  /*!< Invert input signal */
-        int out_en: 1;     /*!< Enable output */
-        int out_invert: 1; /*!< Invert output signal */
+        unsigned int in_en: 1;      /*!< Enable input */
+        unsigned int in_invert: 1;  /*!< Invert input signal */
+        unsigned int out_en: 1;     /*!< Enable output */
+        unsigned int out_invert: 1; /*!< Invert output signal */
     } flags; /*!< Flags to control specific behaviour of GPIO bundle */
 } dedic_gpio_bundle_config_t;
 

+ 0 - 4
components/driver/test/test_dedicated_gpio.c

@@ -58,8 +58,6 @@ TEST_CASE("Dedicated GPIO bundle install/uninstall", "[dedic_gpio]")
 
 #define TEST_GPIO_GROUP_SIZE (4)
 
-#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S3)
-// TODO ESP32-S3 IDF-3387
 typedef struct {
     SemaphoreHandle_t sem;
     const int gpios[TEST_GPIO_GROUP_SIZE];
@@ -161,8 +159,6 @@ TEST_CASE("Dedicated GPIO run on multiple CPU core", "[dedic_gpio]")
     vSemaphoreDelete(sem);
 }
 
-#endif //#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S3)
-
 IRAM_ATTR static void test_dedic_gpio_isr_callback(void *args)
 {
     SemaphoreHandle_t sem = (SemaphoreHandle_t)args;

+ 1 - 6
components/hal/esp32s3/include/hal/cpu_ll.h

@@ -203,12 +203,7 @@ static inline void cpu_ll_write_dedic_gpio_all(uint32_t value)
 
 static inline void cpu_ll_write_dedic_gpio_mask(uint32_t mask, uint32_t value)
 {
-    // ToDo: check if ESP32-S3 supports mask write instruction
-    uint32_t orig = 0;
-    asm volatile("rur.gpio_out %0" : "=r"(orig) : :);
-    orig &= ~mask;
-    orig |= value & mask;
-    asm volatile("wur.gpio_out %0"::"r"(orig):);
+    asm volatile("ee.wr_mask_gpio_out %0, %1" : : "r"(value), "r"(mask):);
 }
 
 #ifdef __cplusplus

+ 24 - 8
components/soc/esp32s3/dedic_gpio_periph.c

@@ -25,26 +25,42 @@ const dedic_gpio_signal_conn_t dedic_gpio_periph_signals = {
                 [1] = PRO_ALONEGPIO_IN1_IDX,
                 [2] = PRO_ALONEGPIO_IN2_IDX,
                 [3] = PRO_ALONEGPIO_IN3_IDX,
+                [4] = PRO_ALONEGPIO_IN4_IDX,
+                [5] = PRO_ALONEGPIO_IN5_IDX,
+                [6] = PRO_ALONEGPIO_IN6_IDX,
+                [7] = PRO_ALONEGPIO_IN7_IDX,
             },
             .out_sig_per_channel = {
                 [0] = PRO_ALONEGPIO_OUT0_IDX,
                 [1] = PRO_ALONEGPIO_OUT1_IDX,
                 [2] = PRO_ALONEGPIO_OUT2_IDX,
                 [3] = PRO_ALONEGPIO_OUT3_IDX,
+                [4] = PRO_ALONEGPIO_OUT4_IDX,
+                [5] = PRO_ALONEGPIO_OUT5_IDX,
+                [6] = PRO_ALONEGPIO_OUT6_IDX,
+                [7] = PRO_ALONEGPIO_OUT7_IDX,
             }
         },
         [1] = {
             .in_sig_per_channel = {
-                [0] = PRO_ALONEGPIO_IN4_IDX,
-                [1] = PRO_ALONEGPIO_IN5_IDX,
-                [2] = PRO_ALONEGPIO_IN6_IDX,
-                [3] = PRO_ALONEGPIO_IN7_IDX,
+                [0] = CORE1_GPIO_IN0_IDX,
+                [1] = CORE1_GPIO_IN1_IDX,
+                [2] = CORE1_GPIO_IN2_IDX,
+                [3] = CORE1_GPIO_IN3_IDX,
+                [4] = CORE1_GPIO_IN4_IDX,
+                [5] = CORE1_GPIO_IN5_IDX,
+                [6] = CORE1_GPIO_IN6_IDX,
+                [7] = CORE1_GPIO_IN7_IDX,
             },
             .out_sig_per_channel = {
-                [0] = PRO_ALONEGPIO_OUT4_IDX,
-                [1] = PRO_ALONEGPIO_OUT5_IDX,
-                [2] = PRO_ALONEGPIO_OUT6_IDX,
-                [3] = PRO_ALONEGPIO_OUT7_IDX,
+                [0] = CORE1_GPIO_OUT0_IDX,
+                [1] = CORE1_GPIO_OUT1_IDX,
+                [2] = CORE1_GPIO_OUT2_IDX,
+                [3] = CORE1_GPIO_OUT3_IDX,
+                [4] = CORE1_GPIO_OUT4_IDX,
+                [5] = CORE1_GPIO_OUT5_IDX,
+                [6] = CORE1_GPIO_OUT6_IDX,
+                [7] = CORE1_GPIO_OUT7_IDX,
             }
         },
     },

+ 2 - 2
components/soc/esp32s3/include/soc/soc_caps.h

@@ -44,8 +44,8 @@
 #include "gpio_caps.h"
 
 /*-------------------------- Dedicated GPIO CAPS -----------------------------*/
-#define SOC_DEDIC_GPIO_OUT_CHANNELS_NUM (4) /*!< 4 outward channels on each CPU core */
-#define SOC_DEDIC_GPIO_IN_CHANNELS_NUM  (4) /*!< 4 inward channels on each CPU core */
+#define SOC_DEDIC_GPIO_OUT_CHANNELS_NUM (8) /*!< 8 outward channels on each CPU core */
+#define SOC_DEDIC_GPIO_IN_CHANNELS_NUM  (8) /*!< 8 inward channels on each CPU core */
 
 /*-------------------------- I2C CAPS ----------------------------------------*/
 #include "i2c_caps.h"