1 /*
2  * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include "freertos/FreeRTOS.h"
7 #include "freertos/task.h"
8 #include "freertos/semphr.h"
9 #include "unity.h"
10 #include "test_utils.h"
11 #include "esp_rom_sys.h"
12 #include "soc/soc_caps.h"
13 #include "hal/cpu_ll.h"
14 #include "driver/gpio.h"
15 #if SOC_DEDICATED_GPIO_SUPPORTED
16 #include "driver/dedic_gpio.h"
17 
18 TEST_CASE("Dedicated GPIO bundle install/uninstall", "[dedic_gpio]")
19 {
20     const int test_gpios[SOC_DEDIC_GPIO_OUT_CHANNELS_NUM / 2] = {0};
21     const int test2_gpios[SOC_DEDIC_GPIO_OUT_CHANNELS_NUM / 2 + 1] = {0};
22     const int test3_gpios[SOC_DEDIC_GPIO_OUT_CHANNELS_NUM + 1] = {0};
23     dedic_gpio_bundle_handle_t test_bundle, test_bundle2, test_bundle3 = NULL;
24     dedic_gpio_bundle_config_t bundle_config = {
25         .gpio_array = test_gpios,
26         .array_size = sizeof(test_gpios) / sizeof(test_gpios[0]),
27     };
28     dedic_gpio_bundle_config_t bundle_config2 = {
29         .gpio_array = test2_gpios,
30         .array_size = sizeof(test2_gpios) / sizeof(test2_gpios[0]),
31         .flags = {
32             .out_en = 1,
33         },
34     };
35     dedic_gpio_bundle_config_t bundle_config3 = {
36         .gpio_array = test3_gpios,
37         .array_size = sizeof(test3_gpios) / sizeof(test3_gpios[0]),
38         .flags = {
39             .out_en = 1,
40         },
41     };
42 
43     TEST_ASSERT_EQUAL_MESSAGE(ESP_ERR_INVALID_ARG, dedic_gpio_new_bundle(&bundle_config, &test_bundle), "shouldn't create bundle if no mode is specified");
44 
45     bundle_config.flags.out_en = 1;
46     TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, dedic_gpio_new_bundle(&bundle_config, &test_bundle), "create bundle with half channels failed");
47     uint32_t mask = 0;
48     TEST_ESP_OK(dedic_gpio_get_out_mask(test_bundle, &mask));
49     TEST_ASSERT_EQUAL_MESSAGE((1 << (SOC_DEDIC_GPIO_OUT_CHANNELS_NUM / 2)) - 1, mask, "wrong out mask");
50     TEST_ESP_OK(dedic_gpio_get_in_mask(test_bundle, &mask));
51     TEST_ASSERT_EQUAL_MESSAGE(0, mask, "wrong in mask");
52 
53     TEST_ASSERT_EQUAL_MESSAGE(ESP_ERR_NOT_FOUND, dedic_gpio_new_bundle(&bundle_config2, &test_bundle2), "shouldn't create bundle if there's no enough channels");
54     TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, dedic_gpio_del_bundle(test_bundle), "delete bundle failed");
55 
56     TEST_ASSERT_EQUAL_MESSAGE(ESP_ERR_INVALID_ARG, dedic_gpio_new_bundle(&bundle_config3, &test_bundle3), "shouldn't create bundle if the array size exceeds maximum");
57 }
58 
59 #define TEST_GPIO_GROUP_SIZE (4)
60 
61 typedef struct {
62     SemaphoreHandle_t sem;
63     const int gpios[TEST_GPIO_GROUP_SIZE];
64 } test_dedic_task_context_t;
65 
test_dedic_gpio_on_specific_core(void * args)66 static void test_dedic_gpio_on_specific_core(void *args)
67 {
68     test_dedic_task_context_t *ctx = (test_dedic_task_context_t *)args;
69     uint32_t value = 0;
70     cpu_ll_write_dedic_gpio_all(0x0); // clear all out channels
71 
72     // configure a group of GPIOs, output only
73     const int bundleA_gpios[] = {ctx->gpios[0], ctx->gpios[1]};
74     gpio_config_t io_conf = {
75         .mode = GPIO_MODE_OUTPUT,
76     };
77     for (int i = 0; i < sizeof(bundleA_gpios) / sizeof(bundleA_gpios[0]); i++) {
78         io_conf.pin_bit_mask = 1ULL << bundleA_gpios[i];
79         gpio_config(&io_conf);
80     }
81     // Create bundleA, output only
82     dedic_gpio_bundle_handle_t bundleA = NULL;
83     dedic_gpio_bundle_config_t bundleA_config = {
84         .gpio_array = bundleA_gpios,
85         .array_size = sizeof(bundleA_gpios) / sizeof(bundleA_gpios[0]),
86         .flags = {
87             .out_en = 1,
88         },
89     };
90     TEST_ESP_OK(dedic_gpio_new_bundle(&bundleA_config, &bundleA));
91 
92     // configure another group of GPIOs, input and output
93     const int bundleB_gpios[] = {ctx->gpios[2], ctx->gpios[3]};
94     io_conf.mode = GPIO_MODE_INPUT_OUTPUT;
95     for (int i = 0; i < sizeof(bundleB_gpios) / sizeof(bundleB_gpios[0]); i++) {
96         io_conf.pin_bit_mask = 1ULL << bundleB_gpios[i];
97         gpio_config(&io_conf);
98     }
99 
100     // GPIO bundleB, input and output
101     dedic_gpio_bundle_handle_t bundleB = NULL;
102     dedic_gpio_bundle_config_t bundleB_config = {
103         .gpio_array = bundleB_gpios,
104         .array_size = sizeof(bundleB_gpios) / sizeof(bundleB_gpios[0]),
105         .flags = {
106             .in_en = 1,
107             .out_en = 1,
108         },
109     };
110     TEST_ESP_OK(dedic_gpio_new_bundle(&bundleB_config, &bundleB));
111 
112     dedic_gpio_bundle_write(bundleA, 0x01, 0x01);
113     dedic_gpio_bundle_write(bundleB, 0x03, 0x03);
114 
115     value = cpu_ll_read_dedic_gpio_out();
116     TEST_ASSERT_EQUAL(0x0D, value); // 1101
117     value = cpu_ll_read_dedic_gpio_in();
118     TEST_ASSERT_EQUAL(0x03, value); // 11
119 
120     dedic_gpio_bundle_write(bundleB, 0x02, 0x0);
121     value = cpu_ll_read_dedic_gpio_out();
122     TEST_ASSERT_EQUAL(0x05, value); // 0101
123     value = cpu_ll_read_dedic_gpio_in();
124     TEST_ASSERT_EQUAL(0x01, value); // 01
125 
126     cpu_ll_write_dedic_gpio_all(0x0F); // Set all out channels
127     value = cpu_ll_read_dedic_gpio_out();
128     TEST_ASSERT_EQUAL(0x0F, value);
129     value = cpu_ll_read_dedic_gpio_in();
130     TEST_ASSERT_EQUAL(0x03, value);                               // 11
131     TEST_ASSERT_EQUAL(0x03, dedic_gpio_bundle_read_out(bundleA)); // 11
132     TEST_ASSERT_EQUAL(0x00, dedic_gpio_bundle_read_in(bundleA));  // input is not enabled for bundleA
133     TEST_ASSERT_EQUAL(0x03, dedic_gpio_bundle_read_out(bundleB)); // 11
134     TEST_ASSERT_EQUAL(0x03, dedic_gpio_bundle_read_in(bundleB));  // 11
135 
136     TEST_ESP_OK(dedic_gpio_del_bundle(bundleA));
137     TEST_ESP_OK(dedic_gpio_del_bundle(bundleB));
138 
139     xSemaphoreGive(ctx->sem);
140     vTaskDelete(NULL);
141 }
142 
143 TEST_CASE("Dedicated GPIO run on multiple CPU core", "[dedic_gpio]")
144 {
145     SemaphoreHandle_t sem = xSemaphoreCreateCounting(SOC_CPU_CORES_NUM, 0);
146 
147     for (int i = 0; i < SOC_CPU_CORES_NUM; i++) {
148         int start_gpio = i * TEST_GPIO_GROUP_SIZE;
149         test_dedic_task_context_t isr_ctx = {
150             .sem = sem,
151             .gpios = {start_gpio, start_gpio + 1, start_gpio + 2, start_gpio + 3}
152         };
153         xTaskCreatePinnedToCore(test_dedic_gpio_on_specific_core, "dedic_gpio_test_tsk", 4096, &isr_ctx, 1, NULL, i);
154     }
155 
156     for (int i = 0; i < SOC_CPU_CORES_NUM; i++) {
157         xSemaphoreTake(sem, pdMS_TO_TICKS(1000));
158     }
159     vSemaphoreDelete(sem);
160 }
161 
test_dedic_gpio_isr_callback(void * args)162 IRAM_ATTR static void test_dedic_gpio_isr_callback(void *args)
163 {
164     SemaphoreHandle_t sem = (SemaphoreHandle_t)args;
165     BaseType_t high_task_wakeup = pdFALSE;
166     esp_rom_printf("GPIO event\r\n");
167     xSemaphoreGiveFromISR(sem, &high_task_wakeup);
168     if (high_task_wakeup) {
169         esp_rom_printf("high priority task wake up\r\n");
170     }
171 }
172 
173 TEST_CASE("Dedicated GPIO interrupt and callback", "[dedic_gpio]")
174 {
175     SemaphoreHandle_t sem = xSemaphoreCreateBinary();
176 
177     // configure GPIO
178     const int bundle_gpios[] = {0, 1};
179     gpio_config_t io_conf = {
180         .mode = GPIO_MODE_INPUT_OUTPUT,
181     };
182     for (int i = 0; i < sizeof(bundle_gpios) / sizeof(bundle_gpios[0]); i++) {
183         io_conf.pin_bit_mask = 1ULL << bundle_gpios[i];
184         gpio_config(&io_conf);
185     }
186     dedic_gpio_bundle_handle_t bundle = NULL;
187     dedic_gpio_bundle_config_t bundle_config = {
188         .gpio_array = bundle_gpios,
189         .array_size = sizeof(bundle_gpios) / sizeof(bundle_gpios[0]),
190         .flags = {
191             .in_en = 1,
192             .out_en = 1,
193         },
194     };
195     TEST_ESP_OK(dedic_gpio_new_bundle(&bundle_config, &bundle));
196 
197     // enable interrupt on GPIO1
198     TEST_ESP_OK(gpio_set_intr_type(1, GPIO_INTR_POSEDGE));
199     // install gpio isr service
200     TEST_ESP_OK(gpio_install_isr_service(0));
201     // hook isr handler for specific gpio pin
202     TEST_ESP_OK(gpio_isr_handler_add(1, test_dedic_gpio_isr_callback, sem));
203 
204     // trigger a posedge on GPIO1
205     dedic_gpio_bundle_write(bundle, BIT(1), 0x00);
206     dedic_gpio_bundle_write(bundle, BIT(1), 0xFF);
207     // wait for done semaphore
208     TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(sem, pdMS_TO_TICKS(1000)));
209 
210     // remove isr handler for gpio number
211     TEST_ESP_OK(gpio_isr_handler_remove(1));
212     // uninstall GPIO interrupt service
213     gpio_uninstall_isr_service();
214 
215     TEST_ESP_OK(dedic_gpio_del_bundle(bundle));
216     vSemaphoreDelete(sem);
217 }
218 
219 #endif // #if SOC_DEDICATED_GPIO_SUPPORTED
220