Skip to content

GPIO revisited

Edgar K edited this page Mar 23, 2019 · 16 revisions

Автор: Эдгар Казиахмедов

Введение

В данной статье будет еще раз рассмотрен режим работы цифровой выход системы ввода-вывода, в частности будет сделан акцент на разнице между режимами OpenDrain и PushPull. Данная статья является дополнением к лекции по "GPIO".

Как было уже сказано, порты ввода-вывода в микроконтроллере STM32 поддерживают 4 основных режима работы: цифровой выход, цифровой вход, аналоговый вход и режим альтернативной функции (Рис. 1). Описание данной периферии находится на стр. 148 справочного описания периферии.

gpio-modes.png Рис. 1. Режимы работы портов ввода-вывода

Цифровой выход

Одним из наиболее используемых режимов работы портов ввода-вывода является режим цифрового выхода. В данном режиме можно управлять различными устройствами, подключенными к выводам портов. К примерам данных устройств можно отнести светодиоды, семисегментные индикаторы, двигатели и т.д. Для написания кода инициализации и работы к периферией будут использованы функции из главы по GPIO (стр. 829) библиотеки Low Layer.

Если вернуться к блок схеме, то модуль состоит из двух основных частей:

  • Регистры, отображающие текущее состояние порта:
    • ODR - текущее логическое состояние цифр. выхода;
    • BSRR - так называемый bit/reset регистр;
  • Физический драйвер, работа которого задается следующими конфигурационными регистрами:
    • OTYPER - режим работы выходного драйвера (Open-Drain, PushPull);
    • OSPEEDR - настройка скорости работы выходного драйвера;
    • PUPDR - включение/выключение резистора, подтягивающего к земле, либо к питанию;

Давайте для примера рассмотрим регистр MODER на стр. 157, с помощью которого можно будет сконфигурировать вывод в режим цифрового выхода (Рис. 2)

moder.png Рис. 2. Регистр MODER

Регистр состоит из групп по два бита для каждого вывода по отдельности. Стоит заметить, что все выводы по умолчанию находятся в состоянии цифрового входа, а значит по умолчанию активен триггер Шмидта, который будет переключаться из-за любой помехи на входе и, соответственно, потреблять энергию. Для переключения в состояние цифровой выход необходимо записать в соответствующую группу битов значение 01.

Конечно писать напрямую в регистр нежелательно, так как это приводит к плохой читабельности кода в будущем. По этой причине в курсе используется библиотека LL, при пролистывании которой можно увидеть функцию LL_GPIO_SetPinMode, которая как раз и позволяет выставить режим работы вывода путем обычной записи в тот самый регистр MODER. Для примера можно инициализировать седьмой вывод порта GPIOC (к которому подключен один из светодиодов на отладочной плате):

LL_GPIO_SetPinMode(GPIOC, LL_GPIO_PIN_8, LL_GPIO_MODE_OUTPUT);

ACHTUNG: перед работой с любой периферией необходимо подать на нее тактирование, а иначе ничего никогда не заработает, в данном случае (так как все порты ввода-вывода подключены к шине AHB, то для любого другого порта аргументом будет LL_AHB1_GRP1_PERIPH_GPIOx, где x - буква порта):

LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOC);

Теперь рассмотрим два режима работы выходного драйвера: PushPull (двухтактный), OpenDrain (с открытым стоком). На схеме устройства оба режима будут выглядеть следующим образом:

pushpull.png

Рис. 3. Режим PushPull

opendrain.png

Рис. 4. Режим OpenDrain

Как видно, разница лишь заключается в наличии транзистора в верхнем плече. В режиме PushPull при записи единицы выходной драйвер "подключит" выход к питанию, а при записи нуля к земле. То есть на выходе будет либо +3В, либо .

В режиме OpenDrain картина будет следующая: при записи единицы выход будет "висеть в воздухе", то есть никуда не подключен, а при записи нуля будет подключен к земле.

Возникает вопрос, а где вообще может пригодиться режим OpenDrain, когда есть PushPull, который, казалось бы, выполняет все необходимые функции?

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

mcu_35.png

Рис. 5. Подключение микроконтроллеров с разной логикой

В случае, если используется режим PushPull (представим схему без резистора), входной порт микроконтроллера с трехвольтовой логикой может выйти из строя из-за превышения напряжения на входе. Решением этой проблемы как раз и является использование режима OpenDrain. Проще говоря, теперь логическая единица для МК слева будет означать, что вывод никуда на подключен, поэтому он "подхватывается" подтягивающим резистором на питание +3В и попадает на вход правого МК, для которого такой входной потенциал уже является нормальным.

mcu_35_od.png

Рис. 6. Логическая единица OpenDrain

mcu_35_0.png

Рис. 7. Логический ноль OpenDrain

В следующем примере рассмотрим такую задачу: необходимо подключить несколько выходов с N микроконтроллеров и подать их на один вход N+1 микроконтроллера. Положим N=2:

od_2.png

Рис. 8. Подключение трех МК

Сначала положим, что резисторов нет и выводы сконфигурированы в режим PushPull. Представим такую ситуацию: два МК слева работают асинхронно и выставили в какой-то момент времени разные выходные состояния, верхний - единицу, нижний - нуль. В таком случае произойдет короткое замыкание, так как максимальный ток потечет от верхнего МК к нижнему (ограничительного резистора нет). В результате чего выводы могут выйти из строя, так как выгорят внутренние транзисторы (конечно существуют еще и ограничительные диоды, но в целом ситуация крайне опасная). Чтобы избежать такого состояния, переведем все выводы в режим OpenDrain и подключим на каждый вывод подтягивающий резистор. Теперь логическая единица на любом из выводом означает лишь подтягивание к питанию. Получился некий вариант реализации логического элемента "И". На вход третьего МК попадет единица, когда все МК выставят лог. единицу на выходе.

Третий пример касается такого интерфейса как I2C, где используются два вывода SDA (передача данных) и CLK (сигнал синхронизации). К этой шине подключаются участники сети, и для избежания электрических конфликтов, используется режим OpenDrain. В следующих лекциях при рассмотрении I2C, еще раз будет сделан акцент на данный режим при подключении микроконтроллера и дисплея.

Также в модуле ввода-вывода присутствуют внутренние подтягивающие резисторы, которые можно использовать для подтяжки в режиме OpenDrain, но нужно иметь ввиду, что они достаточно маломощные.

5V tolerance

На самом деле нет необходимости все время использовать OpenDrain для подключения двух МК с разной логикой, STM32 поддерживает вход практически для всех входов. Чтобы убедиться, что конкретный вход имеет поддержку входа на , необходимо открыть описание конкретного подсемейства микроконтроллеров на странице с распиновкой (стр. 31) и посмотреть какой I/O Structure у конкретного входа в таблице. Выходы, поддерживающие данную возможность имеет надпись FT (five-tolerant).

Скорость работы выводов

При рассмотрении мы упустила из виду еще один интересный регистр OSPEEDR, который задает скорость работы вывода. По умолчанию, все выходные драйверы находятся в низкоскоростном режиме, это позволяет уменьшить количество выскочастотных шумов при переключении сигнала. Высокочастотные шумы, в свою очередь, являются источниками помех для других устройств. Если скорость переключения будет низкая, то сигнал будет переключаться с более низкой скоростью нарастания (или с меньшей крутизной) (Рис. 9, вертикальная прямая становится прямой под наклоном) и излучать меньше шумов:

slew_rate.png

Рис. 9. Скорость нарастания сигнала

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

LL_GPIO_SetPinSpeed(GPIOx, LL_GPIO_PIN_x, 
                    LL_GPIO_SPEED_FREQ_{LOW|MEDIUM|HIGH})

Изменение регистра внутри микроконтроллера приводит к изменению параметров выходных драйверов, то есть меняется скорость нарастания сигнала: чем выше скорость работы, тем больше крутизна сигнала.