mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-11-04 09:01:40 +01:00 
			
		
		
		
	
		
			
	
	
		
			215 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			215 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								#include "freertos/FreeRTOS.h"
							 | 
						||
| 
								 | 
							
								#include "freertos/task.h"
							 | 
						||
| 
								 | 
							
								#include "freertos/semphr.h"
							 | 
						||
| 
								 | 
							
								#include "unity.h"
							 | 
						||
| 
								 | 
							
								#include "test_utils.h"
							 | 
						||
| 
								 | 
							
								#include "esp_rom_sys.h"
							 | 
						||
| 
								 | 
							
								#include "soc/soc_caps.h"
							 | 
						||
| 
								 | 
							
								#include "hal/cpu_ll.h"
							 | 
						||
| 
								 | 
							
								#include "driver/gpio.h"
							 | 
						||
| 
								 | 
							
								#if SOC_DEDICATED_GPIO_SUPPORTED
							 | 
						||
| 
								 | 
							
								#include "driver/dedic_gpio.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								TEST_CASE("Dedicated GPIO bundle install/uninstall", "[dedic_gpio]")
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    const int test_gpios[SOC_DEDIC_GPIO_OUT_CHANNELS_NUM / 2] = {0};
							 | 
						||
| 
								 | 
							
								    const int test2_gpios[SOC_DEDIC_GPIO_OUT_CHANNELS_NUM / 2 + 1] = {0};
							 | 
						||
| 
								 | 
							
								    const int test3_gpios[SOC_DEDIC_GPIO_OUT_CHANNELS_NUM + 1] = {0};
							 | 
						||
| 
								 | 
							
								    dedic_gpio_bundle_handle_t test_bundle, test_bundle2, test_bundle3 = NULL;
							 | 
						||
| 
								 | 
							
								    dedic_gpio_bundle_config_t bundle_config = {
							 | 
						||
| 
								 | 
							
								        .gpio_array = test_gpios,
							 | 
						||
| 
								 | 
							
								        .array_size = sizeof(test_gpios) / sizeof(test_gpios[0]),
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								    dedic_gpio_bundle_config_t bundle_config2 = {
							 | 
						||
| 
								 | 
							
								        .gpio_array = test2_gpios,
							 | 
						||
| 
								 | 
							
								        .array_size = sizeof(test2_gpios) / sizeof(test2_gpios[0]),
							 | 
						||
| 
								 | 
							
								        .flags = {
							 | 
						||
| 
								 | 
							
								            .out_en = 1,
							 | 
						||
| 
								 | 
							
								        },
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								    dedic_gpio_bundle_config_t bundle_config3 = {
							 | 
						||
| 
								 | 
							
								        .gpio_array = test3_gpios,
							 | 
						||
| 
								 | 
							
								        .array_size = sizeof(test3_gpios) / sizeof(test3_gpios[0]),
							 | 
						||
| 
								 | 
							
								        .flags = {
							 | 
						||
| 
								 | 
							
								            .out_en = 1,
							 | 
						||
| 
								 | 
							
								        },
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    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");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    bundle_config.flags.out_en = 1;
							 | 
						||
| 
								 | 
							
								    TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, dedic_gpio_new_bundle(&bundle_config, &test_bundle), "create bundle with half channels failed");
							 | 
						||
| 
								 | 
							
								    uint32_t mask = 0;
							 | 
						||
| 
								 | 
							
								    TEST_ESP_OK(dedic_gpio_get_out_mask(test_bundle, &mask));
							 | 
						||
| 
								 | 
							
								    TEST_ASSERT_EQUAL_MESSAGE((1 << (SOC_DEDIC_GPIO_OUT_CHANNELS_NUM / 2)) - 1, mask, "wrong out mask");
							 | 
						||
| 
								 | 
							
								    TEST_ESP_OK(dedic_gpio_get_in_mask(test_bundle, &mask));
							 | 
						||
| 
								 | 
							
								    TEST_ASSERT_EQUAL_MESSAGE(0, mask, "wrong in mask");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    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");
							 | 
						||
| 
								 | 
							
								    TEST_ASSERT_EQUAL_MESSAGE(ESP_OK, dedic_gpio_del_bundle(test_bundle), "delete bundle failed");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    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");
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define TEST_GPIO_GROUP_SIZE (4)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								typedef struct {
							 | 
						||
| 
								 | 
							
								    SemaphoreHandle_t sem;
							 | 
						||
| 
								 | 
							
								    const int gpios[TEST_GPIO_GROUP_SIZE];
							 | 
						||
| 
								 | 
							
								} test_dedic_task_context_t;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void test_dedic_gpio_on_specific_core(void *args)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    test_dedic_task_context_t *ctx = (test_dedic_task_context_t *)args;
							 | 
						||
| 
								 | 
							
								    uint32_t value = 0;
							 | 
						||
| 
								 | 
							
								    cpu_ll_write_dedic_gpio_all(0x0); // clear all out channels
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // configure a group of GPIOs, output only
							 | 
						||
| 
								 | 
							
								    const int bundleA_gpios[] = {ctx->gpios[0], ctx->gpios[1]};
							 | 
						||
| 
								 | 
							
								    gpio_config_t io_conf = {
							 | 
						||
| 
								 | 
							
								        .mode = GPIO_MODE_OUTPUT,
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								    for (int i = 0; i < sizeof(bundleA_gpios) / sizeof(bundleA_gpios[0]); i++) {
							 | 
						||
| 
								 | 
							
								        io_conf.pin_bit_mask = 1ULL << bundleA_gpios[i];
							 | 
						||
| 
								 | 
							
								        gpio_config(&io_conf);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    // Create bundleA, output only
							 | 
						||
| 
								 | 
							
								    dedic_gpio_bundle_handle_t bundleA = NULL;
							 | 
						||
| 
								 | 
							
								    dedic_gpio_bundle_config_t bundleA_config = {
							 | 
						||
| 
								 | 
							
								        .gpio_array = bundleA_gpios,
							 | 
						||
| 
								 | 
							
								        .array_size = sizeof(bundleA_gpios) / sizeof(bundleA_gpios[0]),
							 | 
						||
| 
								 | 
							
								        .flags = {
							 | 
						||
| 
								 | 
							
								            .out_en = 1,
							 | 
						||
| 
								 | 
							
								        },
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								    TEST_ESP_OK(dedic_gpio_new_bundle(&bundleA_config, &bundleA));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // configure another group of GPIOs, input and output
							 | 
						||
| 
								 | 
							
								    const int bundleB_gpios[] = {ctx->gpios[2], ctx->gpios[3]};
							 | 
						||
| 
								 | 
							
								    io_conf.mode = GPIO_MODE_INPUT_OUTPUT;
							 | 
						||
| 
								 | 
							
								    for (int i = 0; i < sizeof(bundleB_gpios) / sizeof(bundleB_gpios[0]); i++) {
							 | 
						||
| 
								 | 
							
								        io_conf.pin_bit_mask = 1ULL << bundleB_gpios[i];
							 | 
						||
| 
								 | 
							
								        gpio_config(&io_conf);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // GPIO bundleB, input and output
							 | 
						||
| 
								 | 
							
								    dedic_gpio_bundle_handle_t bundleB = NULL;
							 | 
						||
| 
								 | 
							
								    dedic_gpio_bundle_config_t bundleB_config = {
							 | 
						||
| 
								 | 
							
								        .gpio_array = bundleB_gpios,
							 | 
						||
| 
								 | 
							
								        .array_size = sizeof(bundleB_gpios) / sizeof(bundleB_gpios[0]),
							 | 
						||
| 
								 | 
							
								        .flags = {
							 | 
						||
| 
								 | 
							
								            .in_en = 1,
							 | 
						||
| 
								 | 
							
								            .out_en = 1,
							 | 
						||
| 
								 | 
							
								        },
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								    TEST_ESP_OK(dedic_gpio_new_bundle(&bundleB_config, &bundleB));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    dedic_gpio_bundle_write(bundleA, 0x01, 0x01);
							 | 
						||
| 
								 | 
							
								    dedic_gpio_bundle_write(bundleB, 0x03, 0x03);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    value = cpu_ll_read_dedic_gpio_out();
							 | 
						||
| 
								 | 
							
								    TEST_ASSERT_EQUAL(0x0D, value); // 1101
							 | 
						||
| 
								 | 
							
								    value = cpu_ll_read_dedic_gpio_in();
							 | 
						||
| 
								 | 
							
								    TEST_ASSERT_EQUAL(0x03, value); // 11
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    dedic_gpio_bundle_write(bundleB, 0x02, 0x0);
							 | 
						||
| 
								 | 
							
								    value = cpu_ll_read_dedic_gpio_out();
							 | 
						||
| 
								 | 
							
								    TEST_ASSERT_EQUAL(0x05, value); // 0101
							 | 
						||
| 
								 | 
							
								    value = cpu_ll_read_dedic_gpio_in();
							 | 
						||
| 
								 | 
							
								    TEST_ASSERT_EQUAL(0x01, value); // 01
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    cpu_ll_write_dedic_gpio_all(0x0F); // Set all out channels
							 | 
						||
| 
								 | 
							
								    value = cpu_ll_read_dedic_gpio_out();
							 | 
						||
| 
								 | 
							
								    TEST_ASSERT_EQUAL(0x0F, value);
							 | 
						||
| 
								 | 
							
								    value = cpu_ll_read_dedic_gpio_in();
							 | 
						||
| 
								 | 
							
								    TEST_ASSERT_EQUAL(0x03, value);                               // 11
							 | 
						||
| 
								 | 
							
								    TEST_ASSERT_EQUAL(0x03, dedic_gpio_bundle_read_out(bundleA)); // 11
							 | 
						||
| 
								 | 
							
								    TEST_ASSERT_EQUAL(0x00, dedic_gpio_bundle_read_in(bundleA));  // input is not enabled for bundleA
							 | 
						||
| 
								 | 
							
								    TEST_ASSERT_EQUAL(0x03, dedic_gpio_bundle_read_out(bundleB)); // 11
							 | 
						||
| 
								 | 
							
								    TEST_ASSERT_EQUAL(0x03, dedic_gpio_bundle_read_in(bundleB));  // 11
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    TEST_ESP_OK(dedic_gpio_del_bundle(bundleA));
							 | 
						||
| 
								 | 
							
								    TEST_ESP_OK(dedic_gpio_del_bundle(bundleB));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    xSemaphoreGive(ctx->sem);
							 | 
						||
| 
								 | 
							
								    vTaskDelete(NULL);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								TEST_CASE("Dedicated GPIO run on multiple CPU core", "[dedic_gpio]")
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    SemaphoreHandle_t sem = xSemaphoreCreateCounting(SOC_CPU_CORES_NUM, 0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for (int i = 0; i < SOC_CPU_CORES_NUM; i++) {
							 | 
						||
| 
								 | 
							
								        int start_gpio = i * TEST_GPIO_GROUP_SIZE;
							 | 
						||
| 
								 | 
							
								        test_dedic_task_context_t isr_ctx = {
							 | 
						||
| 
								 | 
							
								            .sem = sem,
							 | 
						||
| 
								 | 
							
								            .gpios = {start_gpio, start_gpio + 1, start_gpio + 2, start_gpio + 3}
							 | 
						||
| 
								 | 
							
								        };
							 | 
						||
| 
								 | 
							
								        xTaskCreatePinnedToCore(test_dedic_gpio_on_specific_core, "dedic_gpio_test_tsk", 4096, &isr_ctx, 1, NULL, i);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for (int i = 0; i < SOC_CPU_CORES_NUM; i++) {
							 | 
						||
| 
								 | 
							
								        xSemaphoreTake(sem, pdMS_TO_TICKS(1000));
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    vSemaphoreDelete(sem);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								IRAM_ATTR static void test_dedic_gpio_isr_callback(void *args)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    SemaphoreHandle_t sem = (SemaphoreHandle_t)args;
							 | 
						||
| 
								 | 
							
								    BaseType_t high_task_wakeup = pdFALSE;
							 | 
						||
| 
								 | 
							
								    esp_rom_printf("GPIO event\r\n");
							 | 
						||
| 
								 | 
							
								    xSemaphoreGiveFromISR(sem, &high_task_wakeup);
							 | 
						||
| 
								 | 
							
								    if (high_task_wakeup) {
							 | 
						||
| 
								 | 
							
								        esp_rom_printf("high priority task wake up\r\n");
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								TEST_CASE("Dedicated GPIO interrupt and callback", "[dedic_gpio]")
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    SemaphoreHandle_t sem = xSemaphoreCreateBinary();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // configure GPIO
							 | 
						||
| 
								 | 
							
								    const int bundle_gpios[] = {0, 1};
							 | 
						||
| 
								 | 
							
								    gpio_config_t io_conf = {
							 | 
						||
| 
								 | 
							
								        .mode = GPIO_MODE_INPUT_OUTPUT,
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								    for (int i = 0; i < sizeof(bundle_gpios) / sizeof(bundle_gpios[0]); i++) {
							 | 
						||
| 
								 | 
							
								        io_conf.pin_bit_mask = 1ULL << bundle_gpios[i];
							 | 
						||
| 
								 | 
							
								        gpio_config(&io_conf);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    dedic_gpio_bundle_handle_t bundle = NULL;
							 | 
						||
| 
								 | 
							
								    dedic_gpio_bundle_config_t bundle_config = {
							 | 
						||
| 
								 | 
							
								        .gpio_array = bundle_gpios,
							 | 
						||
| 
								 | 
							
								        .array_size = sizeof(bundle_gpios) / sizeof(bundle_gpios[0]),
							 | 
						||
| 
								 | 
							
								        .flags = {
							 | 
						||
| 
								 | 
							
								            .in_en = 1,
							 | 
						||
| 
								 | 
							
								            .out_en = 1,
							 | 
						||
| 
								 | 
							
								        },
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								    TEST_ESP_OK(dedic_gpio_new_bundle(&bundle_config, &bundle));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // enable interrupt on GPIO1
							 | 
						||
| 
								 | 
							
								    TEST_ESP_OK(gpio_set_intr_type(1, GPIO_INTR_POSEDGE));
							 | 
						||
| 
								 | 
							
								    // install gpio isr service
							 | 
						||
| 
								 | 
							
								    TEST_ESP_OK(gpio_install_isr_service(0));
							 | 
						||
| 
								 | 
							
								    // hook isr handler for specific gpio pin
							 | 
						||
| 
								 | 
							
								    TEST_ESP_OK(gpio_isr_handler_add(1, test_dedic_gpio_isr_callback, sem));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // trigger a posedge on GPIO1
							 | 
						||
| 
								 | 
							
								    dedic_gpio_bundle_write(bundle, BIT(1), 0x00);
							 | 
						||
| 
								 | 
							
								    dedic_gpio_bundle_write(bundle, BIT(1), 0xFF);
							 | 
						||
| 
								 | 
							
								    // wait for done semaphore
							 | 
						||
| 
								 | 
							
								    TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(sem, pdMS_TO_TICKS(1000)));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // remove isr handler for gpio number
							 | 
						||
| 
								 | 
							
								    TEST_ESP_OK(gpio_isr_handler_remove(1));
							 | 
						||
| 
								 | 
							
								    // uninstall GPIO interrupt service
							 | 
						||
| 
								 | 
							
								    gpio_uninstall_isr_service();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    TEST_ESP_OK(dedic_gpio_del_bundle(bundle));
							 | 
						||
| 
								 | 
							
								    vSemaphoreDelete(sem);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#endif // #if SOC_DEDICATED_GPIO_SUPPORTED
							 |