1Dedicated GPIO
2==============
3
4Overview
5--------
6
7The dedicated GPIO is designed for CPU interaction with GPIO matrix and IO MUX. Any GPIO that is configured as "dedicated" can be access by CPU instructions directly, which makes it easy to achieve a high GPIO flip speed, and simulate serial/parallel interface in a bit-banging way. As toggling a GPIO in this "CPU Dedicated" way costs few overhead, it would be great for cases like performance measurement using an oscilloscope.
8
9
10Create/Destroy GPIO Bundle
11--------------------------
12
13A GPIO bundle is a group of GPIOs, which can be manipulated at the same time in one CPU cycle. The maximal number of GPIOs that a bundle can contain is limited by each CPU. What's more, the GPIO bundle has a strong relevance to the CPU which it derives from. **Any operations on the GPIO bundle should be put inside a task which is running on the same CPU core to the GPIO bundle belongs to.** Likewise, only those ISRs who are installed on the same CPU core are allowed to do operations on that GPIO bundle.
14
15.. note::
16    Dedicated GPIO is more of a CPU peripheral, so it has a strong relationship with CPU core. It's highly recommended to install and operate GPIO bundle in a pin-to-core task. For example, if GPIOA is connected to CPU0, and the dedicated GPIO instruction is issued from CPU1, then it's impossible to control GPIOA.
17
18To install a GPIO bundle, one needs to call :cpp:func:`dedic_gpio_new_bundle` to allocate the software resources and connect the dedicated channels to user selected GPIOs. Configurations for a GPIO bundle are covered in :cpp:type:`dedic_gpio_bundle_config_t` structure:
19
20- :cpp:member:`gpio_array`: An array that contains GPIO number.
21- :cpp:member:`array_size`: Element number of :cpp:member:`gpio_array`.
22- :cpp:member:`flags`: Extra flags to control the behavior of GPIO Bundle.
23
24  - :cpp:member:`in_en` and :cpp:member:`out_en` are used to select whether to enable the input and output function (note, they can be enabled together).
25  - :cpp:member:`in_invert` and :cpp:member:`out_invert` are used to select whether to invert the GPIO signal.
26
27The following code shows how to install a output only GPIO bundle:
28
29.. highlight:: c
30
31::
32
33    // configure GPIO
34    const int bundleA_gpios[] = {0, 1};
35    gpio_config_t io_conf = {
36        .mode = GPIO_MODE_OUTPUT,
37    };
38    for (int i = 0; i < sizeof(bundleA_gpios) / sizeof(bundleA_gpios[0]); i++) {
39        io_conf.pin_bit_mask = 1ULL << bundleA_gpios[i];
40        gpio_config(&io_conf);
41    }
42    // Create bundleA, output only
43    dedic_gpio_bundle_handle_t bundleA = NULL;
44    dedic_gpio_bundle_config_t bundleA_config = {
45        .gpio_array = bundleA_gpios,
46        .array_size = sizeof(bundleA_gpios) / sizeof(bundleA_gpios[0]),
47        .flags = {
48            .out_en = 1,
49        },
50    };
51    ESP_ERROR_CHECK(dedic_gpio_new_bundle(&bundleA_config, &bundleA));
52
53To uninstall the GPIO bundle, one needs to call :cpp:func:`dedic_gpio_del_bundle`.
54
55.. note::
56    :cpp:func:`dedic_gpio_new_bundle` doesn't cover any GPIO pad configuration (e.g. pull up/down, drive ability, output/input enable), so before installing a dedicated GPIO bundle, you have to configure the GPIO separately using GPIO driver API (e.g. :cpp:func:`gpio_config`). For more information about GPIO driver, please refer to :doc:`GPIO API Reference <gpio>`.
57
58
59GPIO Bundle Operations
60----------------------
61
62.. list-table::
63   :widths: 50 50
64   :header-rows: 1
65
66   * - Operations
67     - Functions
68   * - Write to GPIOs in the bundle by mask
69     - :cpp:func:`dedic_gpio_bundle_write`
70   * - Read the value that input to bundle
71     - :cpp:func:`dedic_gpio_bundle_read_out`
72   * - Read the value that output from bundle
73     - :cpp:func:`dedic_gpio_bundle_read_in`
74
75.. note::
76    The functions above just wrap the customized instructions defined for {IDF_TARGET_NAME}, for the details of those instructions, please refer to *{IDF_TARGET_NAME} Technical Reference Manual* > *IO MUX and GPIO Matrix (GPIO, IO_MUX)* [`PDF <{IDF_TARGET_TRM_EN_URL}#iomuxgpio>`__].
77
78.. only:: SOC_DEDIC_GPIO_HAS_INTERRUPT
79
80    Interrupt Handling
81    ------------------
82
83    Dedicated GPIO can also trigger interrupt on specific input event. All supported events are defined in :cpp:type:`dedic_gpio_intr_type_t`.
84
85    One can enable and register interrupt callback by calling :cpp:func:`dedic_gpio_bundle_set_interrupt_and_callback`. The prototype of the callback function is defined in :cpp:type:`dedic_gpio_isr_callback_t`. Keep in mind, the callback should return true if there's some high priority task woken up.
86
87    .. highlight:: c
88
89    ::
90
91        // user defined ISR callback
92        IRAM_ATTR bool dedic_gpio_isr_callback(dedic_gpio_bundle_handle_t bundle, uint32_t index, void *args)
93        {
94            SemaphoreHandle_t sem = (SemaphoreHandle_t)args;
95            BaseType_t high_task_wakeup = pdFALSE;
96            xSemaphoreGiveFromISR(sem, &high_task_wakeup);
97            return high_task_wakeup == pdTRUE;
98        }
99
100        // enable positive edge interrupt on the second GPIO in the bundle (i.e. index 1)
101        ESP_ERROR_CHECK(dedic_gpio_bundle_set_interrupt_and_callback(bundle, BIT(1), DEDIC_GPIO_INTR_POS_EDGE, dedic_gpio_isr_callback, sem));
102
103        // wait for done semaphore
104        xSemaphoreTake(sem, portMAX_DELAY);
105
106
107Manipulate GPIOs by Writing Assembly Code
108------------------------------------------
109
110For advanced users, they can always manipulate the GPIOs by writing assembly code or invoking CPU Low Level APIs. The usual procedure could be:
111
1121. Allocate a GPIO bundle: :cpp:func:`dedic_gpio_new_bundle`
1132. Query the mask occupied by that bundle: :cpp:func:`dedic_gpio_get_out_mask` or/and :cpp:func:`dedic_gpio_get_in_mask`
1143. Call CPU LL apis (e.g. `cpu_ll_write_dedic_gpio_mask`) or write assembly code with that mask
1154. The fasted way of toggling IO is to use the dedicated "set/clear" instructions:
116
117+----------+---------------------------+---------------------------+------------------------------------------------------------------------+
118| CPU Arch | Set bits of GPIO          | Clear bits of GPIO        | Remarks                                                                |
119+==========+===========================+===========================+========================================================================+
120| Xtensa   | set_bit_gpio_out imm[7:0] | clr_bit_gpio_out imm[7:0] | immediate value width depends on the number of dedicated GPIO channels |
121+----------+---------------------------+---------------------------+------------------------------------------------------------------------+
122| RISC-V   | csrrsi rd, csr, imm[4:0]  | csrrci rd, csr, imm[4:0]  | can only control the lowest 4 GPIO channels                            |
123+----------+---------------------------+---------------------------+------------------------------------------------------------------------+
124
125
126For details of supported dedicated GPIO instructions, please refer to *{IDF_TARGET_NAME} Technical Reference Manual* > *IO MUX and GPIO Matrix (GPIO, IO_MUX)* [`PDF <{IDF_TARGET_TRM_EN_URL}#iomuxgpio>`__]. The supported dedicated CPU instructions are also wrapped inside `soc/cpu_ll.h` as helper inline functions.
127
128.. note::
129    Writing assembly code in application could make your code hard to port between targets, because those customized instructions are not guaranteed to remain the same format on different targets.
130
131
132Application Example
133-------------------
134
135Matrix keyboard example based on dedicated GPIO: :example:`peripherals/gpio/matrix_keyboard`.
136
137
138API Reference
139-------------
140
141.. include-build-file:: inc/dedic_gpio.inc
142