Программирование ARM ESP32-C3 Dedicated GPIO Fri, March 29 2024  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.

ESP32-C3 Dedicated GPIO Печать
Добавил(а) microsin   

Dedicated GPIO были разработаны для взаимодействия CPU с матрицей портов ввода/вывода (GPIO matrix) и мультиплексором ввода/вывода (IO MUX). К любому порту GPIO, который сконфигурирован как "dedicated", имеется прямой доступ для инструкций CPU, что упрощает достижение высокой скорости переключения ножек порта и симулирование последовательного/параллельного интерфейса путем программного управления выводами (bit-banging). Поскольку переключение GPIO таким способом работает как "CPU Dedicated", так что достигается небольшими накладными расходами, то это хорошо походит для измерения производительности кода с помощью осциллографа.

[Создание/удаление GPIO Bundle]

Термином "GPIO Bundle" обозначают группу GPIO, которой можно манипулировать одновременно в 1 такте CPU. Максимальное количество портов, которое может содержаться в такой группе, ограничено для каждого CPU. Более того, GPIO bundle значительно влияет на CPU, для которого был создан. Любые операции на GPIO bundle должны быть помещены в задачу, работающую на том же ядре CPU, которой принадлежит GPIO bundle (имеет значение только для двухядерных CPU, например ESP32; к ESP32-C3 это не относится). Подобнмым образом, работать с GPIO bundle могут только те ISR, которые запускаются тем же самым ядром CPU, которому приналежит этот GPIO bundle.

Примечание: Dedicated GPIO это более чем периферийное устройство CPU, поскольку представляет сильную взаимосвязь с ядром CPU. Настоятельно рекомендуется инсталлировать GPIO bundle и работать с ним в задаче, привязанной к ядру (pin-to-core task). Например, если GPIOA подключен к ядру CPU0, и инструкция dedicated GPIO выполнена ядром CPU1, то она не может управлять GPIOA.

Для инсталляции GPIO bundle нужно вызвать dedic_gpio_new_bundle(), чтобы выделить программные ресурсы и соединить dedicated-каналы с выбранными пользователем ножками GPIO. Конфигурация для GPIO bundle находится в структуре dedic_gpio_bundle_config_t (находится в заголовочном файле components/driver/include/driver/dedic_gpio.h):

typedef struct
{
   const int *gpio_array; /*!< Массив номеров GPIO numbers, gpio_array[0] ~ gpio_array[size-1],
                               т. е. low_dedic_channel_num ~ high_dedic_channel_num */
   size_t array_size;     /*!< Количество ножек GPIO в gpio_array */
   struct
   {
      unsigned int in_en: 1;      /*!< Разрешение входа */
      unsigned int in_invert: 1;  /*!< Инверсия входного сигнала */
      unsigned int out_en: 1;     /*!< Разрешение выхода */
      unsigned int out_invert: 1; /*!< Инверсия выходного сигнала */
   } flags; /*!< Флаги, управляющие специальным поведением GPIO bundle */
} dedic_gpio_bundle_config_t;

В следующем фрагменте кода показано, как инсталлировать GPIO bundle только для вывода:

// Конфигурирование GPIO:
const int bundleA_gpios[] = {0, 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);
}
 
// Создание bundleA, только для вывода:
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,
   },
};
ESP_ERROR_CHECK(dedic_gpio_new_bundle(&bundleA_config, &bundleA));

Для деинсталляции GPIO bundle нужно вызвать dedic_gpio_del_bundle().

Примечание: dedic_gpio_new_bundle() не покрывает все возможные конфигурации ножки GPIO, т. е. верхняя или нижняя подтяжка (pull up/pull down), нагрузочная способность (drive ability), разрешение выхода/входа (output/input enable), так что перед инсталляцией dedicated GPIO bundle нужно сконфигурировать GPIO отдельно соответствующими API-функциями драйвера GPIO (например gpio_config()). Для дополнительной информации см. описание API драйвера GPIO [2].

[Операции GPIO Bundle]

Функция операции Описание
dedic_gpio_bundle_write Запись в порты GPIO bundle по маске.
dedic_gpio_bundle_read_out Чтение выходных значений, которые были выведены в указанный GPIO bundle.
dedic_gpio_bundle_read_in Чтение входных значений, поступающих в указанный GPIO bundle.

Использование перечисленных выше функций может не обеспечить высокую скорость переключения GPIO из-за накладных расходов на вызовы функций и внутренних битовых операций. Для уменьшения этих накладных расходов можно написать код на языке ассемблера (см. далее), однако следует уделить особое внимание безопасности выполнения потоков в приложении ESP-IDF (thread safety).

Манипулирование ножками GPIO из кода на ассемблере. Продвинутые пользователи всегда могут написать критичный по времени исполнения код на ассемблере, или использовать CPU Low Level API (CPU LL API). Для этого обычно применяется следующая процедура:

1. Выделяется GPIO bundle: dedic_gpio_new_bundle().

2. Запрос маски, занимаемой этим GPIO bundle: dedic_gpio_get_out_mask() и/или dedic_gpio_get_in_mask().

3. Вызов CPU LL API (например dedic_gpio_cpu_ll_write_mask), или написание для этого кода на ассемблере, который будет записывать нужную маску.

Самый быстрый способ для переключения IO это использование специальных инструкций "set/clear":

· Установка бит GPIO: csrrsi rd, csr, imm[4:0].
· Очистка бит GPIO: csrrci rd, csr, imm[4:0].

Примечание: можно управлять только самыми младшими 4 каналами GPIO.

Примеры кода для манипуляции dedicated GPIO из ассемблера предоставлены в директории peripherals/dedicated_gpio среди примеров кода ESP-IDF (каталог examples). Эти примеры показывают, как можно таким способом эмулировать UART, и I2C и SPI.

Для подробностей по инструкциям dedicated GPIO см. PDF-документ "ESP32-C3 Technical Reference Manual", раздел "ESP-RISC-V CPU".

Для некоторых инструкций dedicated CPU предоставляются вспомогательные обертки в виде inline-функций (находятся в заголовочном файле hal/dedic_gpio_cpu_ll.h).

Замечание: написание кода на ассемблере создает трудности для портирования проектов между разными процессорами, потому что наличие этих специальных инструкций может не гарантироваться на для определенных target.

[Справочник по API]

Заголовочный файл components/driver/gpio/include/driver/dedic_gpio.h. Ниже в таблице приведено общее описание API-функций. Подробное описание параметров этих функций, возвращаемых из них значений, макросов, структур и типов данных см. в документации [1].

Функция Описание
dedic_gpio_get_out_mask, dedic_gpio_get_in_mask Извлечет выделенную маску каналов. У каждого GPIO bundle должна быть как минимум одна маска (in и/или out), задаваемая конфигурацией dedic_gpio_bundle_config_t. С возвращенной маской пользователь может напрямую вызывать LL-функцию наподобие dedic_gpio_cpu_ll_write_mask, или использовать dedicated GPIO инструкции ассемблера, чтобы достичь наилучшей производительности в манипуляции GPIO.
dedic_gpio_get_out_offset, dedic_gpio_get_in_offset Извлечет смещение канала GPIO bundle. GPIO bundle отображает выводы портов GPIO определенного направления (in/out) в последовательный набор каналов в пределе определенного банка GPIO определенного ядра CPU (относится к двухядерным CPU, таким как ESP32; у ESP32-C3 только одно ядро). Эта функция вернет смещение на первый канал GPIO bundle  определенного направления внутри банка.
dedic_gpio_new_bundle Создаст GPIO bundle и возвратит его дескриптор (handle). В параметре config необходимо включить как минимум входной или выходной режим.
dedic_gpio_del_bundle Удалит GPIO bundle.
dedic_gpio_bundle_write Запишет значение в GPIO bundle. Здесь mask указывается с точки зрения GPIO bundle. Например, если bundleA содержит GPIO10, GPIO12, GPIO17, то для установки только GPIO17 надо указать mask 0x04.(*)
dedic_gpio_bundle_read_out Прочитает значение, которое было выведено из указанного GPIO bundle.(*)
dedic_gpio_bundle_read_in Прочитает значение, которое пришло на вход указанного GPIO bundle.(*)

Примечание (*): из соображений максимальной производительности функция не проверяет корректность параметров, и размещается в IRAM [3].

[Ссылки]

1. ESP32-C3 Dedicated GPIO site:docs.espressif.com.
2. ESP32-C3: GPIO и RTC GPIO.
3. ESP32-C3: оптимизация скорости работы.

 

Добавить комментарий


Защитный код
Обновить

Top of Page