ESP32 прямая манипуляция с портом - PullRequest
0 голосов
/ 16 сентября 2018

Уважаемые StackOverflowers,

Я пытаюсь использовать 3,5-дюймовый TFT HX8357D от Adafruit ( link ) с esp32. Драйвер TFT имеет два интерфейса: SPI и 8-битный параллельный.Предоставленная библиотека от Adafruit ( link ) поддерживает только SPI на esp32. Мне нужно иметь более высокие скорости отображения, поэтому я решил попробовать добавить поддержку esp32 сам. У меня совсем нет опытатакого рода программирование, но мне понравился вызов.

Я выяснил, как работает 8-битный интерфейс, перепроектировав поддержку Arduino Uno / Mega. Чтобы добавить поддержку esp32, мне нужен способ прямого манипулированиярегистры, управляющие портами gpio в esp32. Я посмотрел в интернете, но примеров того, как это сделать, очень мало. Техническое справочное руководство Espressif ( link ) содержит всю необходимую информацию, ноЯ не достаточно опытен, чтобы понять, как перевести это в код.

Для программирования esp32 я использую ядро ​​esp32 Arduino.его пример ( link ) показывает, как установить выводы gpio в качестве выходных и сделать их ВЫСОКИМИ и НИЗКИМИ непосредственно, используя регистры.Проблема в том, что мне нужно иметь возможность установить 8 выводов в качестве выходных данных, записать в них данные, сделать их ввод и затем прочитать данные из них, используя регистры вместо использования функций pinMode, digitalRead и digitalWrite.

Как это работает на Arduino Uno / Mega, мне ясно, есть три регистра, которые управляют портом:

  • DDR * для чтения / записи
  • PORT * для установкиgpio HIGH / LOW
  • PIN * для чтения HIGH / LOW, если gpio - INPUT.

Но как это работает на esp32 и как я могу использовать регистры длясоздать эту 8-битную параллельную связь?

Если есть кто-то, кто имеет больше знаний, чем я, по этой теме, я был бы очень благодарен за объяснение.Заранее спасибо.

Ответы [ 3 ]

0 голосов
/ 24 октября 2018

Чтобы минимизировать вычислительную нагрузку при работе с 8 выводами, вы хотите, чтобы эти выводы соответствовали последовательным номерам GPIO (например, от GPIO12 до GPIO19). Ниже приведена реализация, которая управляет несколькими входами / выходами параллельно и работает, если вышеуказанное требование (последовательные номера GPIO) выполнено и если все номера GPIO находятся в диапазоне 0-31; Я использовал GPIO12 для GPIO19 (GPIO12 соответствует биту 0 в 8-битных значениях ввода / вывода), которые удобно использовать, если у вас есть плата разработки ESP32 с модулем ESP-WROOM-32 или ESP32-WROVER. Поэтому я определил GPIO, соответствующий биту 0, как показано ниже:

#define PARALLEL_0  12

При инициализации вам необходимо настроить все 8 контактов GPIO, например, установив их все как входные данные:

void setup() {
  for (int i = 0; i < 8; i++) {
    pinMode(PARALLEL_0 + i, INPUT);
  }
}

После этого вы можете использовать следующие функции для установки 8 выводов в качестве входов или выходов, а также для считывания входных значений и записи выходных значений:

void parallel_set_inputs(void) {
  REG_WRITE(GPIO_ENABLE_W1TC_REG, 0xFF << PARALLEL_0);
}

void parallel_set_outputs(void) {
  REG_WRITE(GPIO_ENABLE_W1TS_REG, 0xFF << PARALLEL_0);
}

uint8_t parallel_read(void) {
  uint32_t input = REG_READ(GPIO_IN_REG);

  return (input >> PARALLEL_0);
}

void parallel_write(uint8_t value) {
  uint32_t output =
    (REG_READ(GPIO_OUT_REG) & ~(0xFF << PARALLEL_0)) | (((uint32_t)value) << PARALLEL_0);

  REG_WRITE(GPIO_OUT_REG, output);
}
0 голосов
/ 30 января 2019

Для параллельного вывода данных с высокой пропускной способностью вы, возможно, захотите изучить режим ЖК-дисплея периферийного устройства ESP32 I2S.

См. Раздел 12.5.1 в ESP32 TRM и главу 4 о подключении периферийных устройств к нужным контактам. Хорошая особенность этого подхода заключается в том, что вы можете отобразить до 24 бит выходного сигнала с периферийного устройства на выходной вывод.

Раздел 12.4.4 гласит:

Модуль ESP32 I2S выполняет операцию передачи данных [...] Синхронизирует данные последовательно или параллельно, как сконфигурировано пользователем

0 голосов
/ 16 сентября 2018

Есть много способов сделать это.Я часто делаю это по одному.

Один простой способ - создать собственный регистр, определив переменную.Если регистр имеет ширину 8 бит, определите байтовую переменную:

unsigned char disp_register;

Затем вы пишете в этот регистр, как если бы он существовал в оборудовании дисплея.Конечно, затем вы должны вывести этот регистр на выводы GPIO ESP32.Так как контакты все кончены, вы должны сделать это за булавкой.Определите ваши аппаратные выводы для удобства чтения:

/* OUTPUTS (numbers mean GPIO port) */
#define REGISTER_BIT7_ON_PIN        9
#define REGISTER_BIT6_ON_PIN        10
#define REGISTER_BIT5_ON_PIN        5
// continue with all the pins you need

Где-то в начале вашей программы, установите эти выводы как выходные и, возможно, установите их значение по умолчанию '0':

io_conf.intr_type = GPIO_PIN_INTR_DISABLE;
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
io_conf.pin_bit_mask =  ((1ULL<< REGISTER_BIT7_ON_PIN) | (1ULL<< REGISTER_BIT6_ON_PIN) | (1ULL<< REGISTER_BIT5_ON_PIN)); // of course, do like this all the pins
gpio_config(&io_conf);

gpio_set_level(REGISTER_BIT7_ON_PIN, 0); // do like this all the pins you need to set the boot-up value, pin-by-pin

Затем вам понадобится ваша функция, чтобы скопировать ваш регистр во внешний мир выводов GPIO:

/*
 * wrote this simply for ease of understanding, feel free to do this in a loop
 * or shifting bit by bit
 */
void copy_register_to_GPIO_pins(unsigned char disp_register)
{
    gpio_set_level(REGISTER_BIT7_ON_PIN, (disp_register & 0x80) >> 7);
    gpio_set_level(REGISTER_BIT6_ON_PIN, (disp_register & 0x40) >> 6);
    gpio_set_level(REGISTER_BIT5_ON_PIN, (disp_register & 0x20) >> 5);
    gpio_set_level(REGISTER_BIT4_ON_PIN, (disp_register & 0x10) >> 4);
    gpio_set_level(REGISTER_BIT3_ON_PIN, (disp_register & 0x08) >> 3);
    gpio_set_level(REGISTER_BIT2_ON_PIN, (disp_register & 0x04) >> 2);
    gpio_set_level(REGISTER_BIT1_ON_PIN, (disp_register & 0x02) >> 1);
    gpio_set_level(REGISTER_BIT0_ON_PIN, (disp_register & 0x01));
}

Затем, после того, как вы записали что-либо в свой регистр, вызовите свою функцию, чтобы вывести его:

disp_register = 0x2A; // example value you want to send to display
copy_register_to_GPIO_pins(disp_register);

// or, output byte WITHOUT using any register:
copy_register_to_GPIO_pins(0x2A);

Надеемся, что вы можете сделать обратное самостоятельно, чтение выводов выполняется другой функцией, где вы копируете каждое значение вывода GPIO и собираете его в байтовую переменную.Конечно, на этом этапе контакты должны быть установлены на входы.В принципе:

/*
 * wrote this simply for ease of understanding
 */
unsigned char copy_GPIO_pins_to_register(void)
{
    unsigned char retval = 0;

    retval |= gpio_get_level(REGISTER_BIT7_ON_PIN);
    retval = retval << 1;
    retval |= gpio_get_level(REGISTER_BIT6_ON_PIN);
    retval = retval << 1;
    retval |= gpio_get_level(REGISTER_BIT5_ON_PIN);
    retval = retval << 1;
    retval |= gpio_get_level(REGISTER_BIT4_ON_PIN);
    retval = retval << 1;
    retval |= gpio_get_level(REGISTER_BIT3_ON_PIN);
    retval = retval << 1;
    retval |= gpio_get_level(REGISTER_BIT2_ON_PIN);
    retval = retval << 1;
    retval |= gpio_get_level(REGISTER_BIT1_ON_PIN);
    retval = retval << 1;
    retval |= gpio_get_level(REGISTER_BIT0_ON_PIN);

    return retval;
}
...