Arduino ESP8266 прямое/быстрое управление цифровыми контактами
Как управлять цифровым контактом напрямую, избегая медленной цифровой записи или цифрового чтения?
@qubit, 👍8
Обсуждение4 ответа
Лучший ответ:
После выходных поисков и попыток, вот что я искал:
Это немного отличается от чипов AVR. Существует один регистр для установки выводов на ВЫСОКИЙ, а другой-для установки выводов на низкий.
Установка контакта ВЫСОКО:
GPOS = (1 << PIN_OUT);
Установка НИЗКОГО значения вывода:
GPOC = (1 << PIN_OUT);
используя это, мне удалось ускорить свой код в три раза. Это не так драматично, как для чипов AVR, так как функция цифровой записи намного проще для ESP8266.
Это намного быстрее: digitalWrite() 910 секунд против GPO или GPO 88nsec !! (WS 1 февраля 2021 года)
В спецификации вы найдете подробную информацию о вашем устройстве, но в большинстве случаев это довольно просто.
Для управления ими будут использоваться глобальные переменные, каждая из которых будет управлять различными аспектами контактов.
Например, у вас будет регистр для управления вводом или выводом, регистр для управления выходным состоянием,... Еще раз прочитайте спецификацию вашего устройства, чтобы узнать, что есть что.
После настройки контакта инструкция по установке максимального значения пина выглядит следующим образом:
PORTA |= PINx_MASK;
где Pinx_MASK-битовая маска с одним битом, установленным в соответствии с контактом, который она представляет.
Чтобы установить низкий уровень контакта, это похоже:
PORTA &= ~PINx_MASK;
Чтобы установить несколько выводов на порту на разные значения, вы можете выполнить следующее:
PORTA = (PORTA & ~pinsMask) | pinValues;
где pinsMask-это битовая маска, в которой заданы все пины, которые вы хотите изменить, а значения PIN-это битовая маска, для которой пины должны быть установлены высоко.
Полезно знать, как манипулировать битами в битовых масках, но это выходит за рамки данного ответа.
SDK сам будет выполнять прямые манипуляции с портом, если вы будете следовать определениям, вы сможете это понять.
это похоже на код AVR, вы тестировали его на ESP?, @dandavis
Это работает для платформы с чипами Atmel AVR, такими как Arduino Uno, Nano,..., но это не работает для ESP8266. Я полностью осведомлен об этом трюке и хочу знать, существует ли он для ESP8266., @qubit
"Для управления ими будут использоваться глобальные переменные". Это не глобальные переменные, это регистры. Когда вы сделали это с переменной, pin не изменится., @Codebeat
процесс, описанный храповым уродом, является правильным.
по сути, на самом низком уровне вы устанавливаете или удаляете определенные биты, как показано ранее в посте ratchet freak.
однако то, как именно вы это делаете, зависит от вашего подхода или предпочтений.
например, если вы хотите получить прямой доступ к регистрам, используйте "eagle_soc.h" через "ets_sys.h".
если вы хотите использовать заранее определенные процедуры, используйте "gpio.h".
если вы хотите использовать oem-драйверы, используйте "gpio16.h".
если вы хотите использовать библиотеки других людей, следуйте их инструкциям.
если вы хотите прокатиться самостоятельно, что ж, небо-это предел.
по сути, вы должны решить, какой маршрут выбрать в первую очередь, а затем следовать конкретным инструкциям.
но суть та же, что и у ratchet freak ранее.
К сожалению, ответ Ratchet Freak специфичен для AVR и не соответствует тому, как работает ESP8266.
Похоже, что в ESP8266 действительно есть регистры для выполнения именно этого, которые позволят вам установить все 16 выводов GPIO (GPIO0-GPIO15, 16-это совсем другое дело) с помощью одной операции. Существует также регистр SET, который устанавливает контакты, соответствующие 1 биту, и игнорирует контакты, соответствующие 0 битам, и регистр CLEAR, который является обратным.
Кое-что, что я нашел на форуме, где говорилось, что пользователь переключился с ~800 кГц на ~5,7 МГц, переключая контакты с помощью этих прямых регистров, это звучит примерно так.
Одна из версий этого находится в eagle_soc.h
. Соответствующие фрагменты из заголовка, чтобы вы начали:
#define GPIO_REG_READ(reg) READ_PERI_REG(PERIPHS_GPIO_BASEADDR + reg)
#define GPIO_REG_WRITE(reg, val) WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + reg, val)
#define GPIO_OUT_ADDRESS 0x00
#define GPIO_OUT_W1TS_ADDRESS 0x04
#define GPIO_OUT_W1TC_ADDRESS 0x08
Итак, если я правильно понял это (и я не проводил никакого реального тестирования, просто удалился из спецификации, заголовка и сообщений в другом месте):
GPIO_REG_WRITE(GPIO_OUT_ADDRESS, 0xF0F0);
установил бы GPIO 4-7 и 12-15 на высокий, а 0-3 и 8-11 на низкий. За одну операцию. Но это еще не все! Посмотрите на эти названия W1TS
и W1TC
. Это установленные и четкие регистры. А это значит, что вам не нужно что-то скрывать. Вместо того, чтобы захватывать текущее значение, немного увеличивать или уменьшать его, а затем записывать обратно, вы можете использовать эти:
GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, 0x1);
Это установит значение GPIO0 высоким и не повлияет на какие-либо другие биты.
Это также предлагается в более чистой/простой (??) форме в esp8266_peri.h
, что упрощает его до:
GPOS = 0x1;
для настройки немного. Это то, что на самом деле называется digitalWrite библиотеки arduino (для контактов, отличных от GPIO16):
extern void ICACHE_RAM_ATTR __digitalWrite(uint8_t pin, uint8_t val) {
pwm_stop_pin(pin);
if(pin < 16){
if(val) GPOS = (1 << pin);
else GPOC = (1 << pin);
[...]
Но обязательно имейте в виду это, если вы делаете что-то быстро, потому что запись нескольких выводов с помощью одной операции будет намного быстрее, чем несколько вызовов функций. Без этого этот чип даже не может переключать биты так быстро, как Arduino с частотой 16 МГц.
- Как читать и записывать EEPROM в ESP8266
- Как сделать выводы Tx и Rx на ESP-8266-01 в выводах GPIO?
- Как навсегда изменить скорость передачи данных ESP8266 (12e)?
- Как заставить 5-вольтовое реле работать с NodeMCU
- Как исправить: Invalid conversion from 'const char*' to 'char*' [-fpermissive]
- ESP8266 не подключается к Wi-Fi
- AT-команда не отвечает на последовательный монитор
- Разница между этими двумя платами NodeMCU?
Один читает таблицу данных., @Majenko
каким образом это происходит медленно? ты ведь знаешь тактовую частоту экстрасенсорики, верно?, @dandavis
digitalWrite и digitalRead имеют много накладных расходов, так как входной контакт является переменной. Я только что попробовал следующий код void loop() { digitalWrite(D3,HIGH); digitalWrite(D3,LOW); } и он работает с частотой 160 кГц на Wemos D1 mini. Это очень медленно для микроконтроллера, работающего на частоте 80 МГц, @qubit
Ваш вопрос нуждается в более подробной информации., @sa_leinad
@sa_leinad - нет, в этом действительно не нужно больше подробностей - все и так совершенно ясно. Это довольно простой и обычный вопрос. Довольно хорошо известно, как сделать аналогичную вещь на ATmega, и имеет смысл задать вопрос о том, чтобы сделать это на ESP8266, если этот чип вообще будет рассматриваться в качестве цели для Arduino., @Chris Stratton