Управление портами GPIO процессора ARM11 из Linux

При использовании микроконтроллеров (далее МК), то и делаешь, что дергаешь его ножки и проверяешь регистры. Понятное дело, нет никаких файлов, тем более операционной системы (прим.: хотя недавно парень из штатов, запустил Linux на микроконтроллере припаяв к нему ОЗУ и sdcard; но это скорее исключение из правил). Но при использовании современной аппаратуры, во встраиваемых системах уже не обходится без операционной системы. И как показывает практика в современной аппаратуре это чаще всего Linux. Сам Linux вещь замечательная, так как работает практически под всё и везде. Поэтому очень часто есть соблазн взять более новый и навороченный образ от другой похожей платы и закатать к себе.

Тут и кроется некоторая изюминка, которую так сразу и не заметишь. А появляется она, как показывает практика, в самый неожиданный и очень не нужный момент. Под изюминкой, здесь я подразумеваю конфликт/отличие подключения ножек МК на разную периферию схожих между собой отладочных либо иных плат (например idea6410 и mini6410). В моём случае  оказались не туда подключены светодиоды и ШИМ. Поэтому светодиоды всегда светились, а динамик пищал… На самом деле, замечательно, что система запускается и правильно работает, выполняет основные функции. Но эти мелкие огрехи надо было исправлять.

Один из подходов это — разбираться с драйверами, копаться в исходниках в поисках того, как сделать так, чтобы все работало, потом пересобирать ядро, заливать все в плату и наблюдать процедуру запуска, ожидая, что сейчас всё заработает. Но зачем всё усложнять, если можно сделать проще. Я не спроста упомянул о микроконтроллерах в самом начале. Другой подход состоит в том, чтобы управлять отдельными ножками из самой операционной системы. К примеру, чтобы зажечь светодиод или погасить его, надо перевести ножку в выход и установить её значение либо в единицу либо в ноль. Всё также как в МК. Но тут же Linux, как быть? А точно также. Принцип Linux — всё есть файл. И отдельная ножка GPIO из сотни на процессоре/контроллере, на котором он работает, тоже является файлом.

Так как в данной статье рассматривается пример управления светодиодом через GPIO из Linux, то необходимо выяснить, какая ножка в текущей плате идет на светодиод.  Выяснять разницу между платами естественно надо по документации. Данный пример, это запуск ОС от платы mini6410 на плате idea6410. Так как проблемы возникают на idea6410, то смотрю документацию по ней и ищю на какие ножки подключены светодиоды. В моем случае, GPIO под названием «GPM0» идет на первый из четырех светодиодов. Соответственно, по той же документации, остальные светодиоды идут на GPIO «GPM1» — «CPM3». Посмотреть соответствие ножкам на светодиоды можно в схеме, которая представлена на рисунке. Приведу пример управления первым светодиодом. Для остальных управление ничем не отличается.

Пример подключения светодиодов на плате к определенным GPIO

Правда, скорее всего потребуется также пересобрать ядро. Но это потребуется сделать один раз, в отличие от подхода с переписыванием драйверов (хотя если они будут подгружаться как модули…, но всё равно потребуется компиляция и отладка). Итак, для того чтобы включить доступ к портам необходимо включить их поддержку в ядре. Доступ осуществляется с помощью sysfs располагающая в каталоге /sys. Содержит всю структуру платы, все подключенные устройства, которые удалось определить. Все доступные GPIO располагаются в каталоге /sys/class/gpio/. Но для того, чтобы они там появились, надо в ядрt включить их поддержку в «Device Drivers — GPIO Support» пункт «/sys/class/gpio/… (sysfs interface)». Для наглядности всё подробно ниже на скриншотах — включение поддержки и сборка:

gpio1 gpio2 gpio3 gpio4 gpio5 gpio6 gpio7

Теперь об управление отдельными GPIO. Загрузившись с новым ядром, в котором включена поддержка GPIO как файлов, получаем директорию «/sys/class/gpio/» содержащею файлы export, unexport и множество каталогов «gpiochipN», где N-любое число. Посмотрев информацию об этом каталоге можно заметить, что все каталоги на самом деле являются ссылками.

 gpio8

Те кто работал , например, с микроконтроллерами фирмы Atmel, представляют как управлять отдельно взятой ножкой.  Управление идет через код на С\С++ либо ассемблер. Но в Linux, как говорилось выше, подход совершенно иной — всё есть файл. Поэтому даже ножка мобильного процессора (так описывают samsung s3c6410 в интернете) тоже становится файлом. Как правило несколько ножек объединяются в какой-то порт, так например в МК Atmel они именуются как PortA, PortB, PortC и т.д. В современных процессорах/контроллерах именование немного другое.  Вместо Port идут две буквы GP затем буква порта. Так например в S3C6410 они именуются как GPO, GPM, GPQ, GPP и т.п. и количество ножек в одном порту у каждого своё. Посмотреть наименования порта достаточно просто. Как видно на скриншоте ниже, обычная команда cat файла «gpiochipN/label». Далее по тексту предполагается что мы уже находимся в каталоге «/sys/class/gpio/».

 gpio9

Данный каталог описывает весь порт. Поэтому предоставляет информацию только по названию порта и количеству его ножек, и не дает возможность управления конкретной ножкой МК. Для изменения состояния ножки необходимо её определить. Затем можно задавать направление и логический уровень. Если вкратце описать алгоритм, то он будет следующий:

  1. Найти необходимое название порта (Если ножка называется GPM2, то название порта  — GPM);
  2. Определить какой индекс у требуемой ножки в системе (Индексы норжек не начинаются заново у каждого порта, они последовательные. Нет ножек с одинаковым индексом);
  3. Определить ножку в системе (Появится новая папочка «gpioN» в том же каталоге);
  4. Задать направление ножки;
  5. Если задали ножку как вывод, то задать её логический уровень.

Таким образом, для управления определенной ножкой, которая может быть в использована в режиме ввода или вывода, требуется всего лишь 4-5 шага. А если известен индекс ножки в системе, то вообще получается 2-3 (с 3 по 5).

В моем случае необходим порт GPM.  Он соответствует папочки «gpiochip137», соответственно индексы ножек начинаются с 137. Для определения начального индекса порта пришлось просматривать файл label из папок «gpiochipN» пока не нашел нужный. Следовательно, для ножки GPM0 индекс равен 137, GPM1 — 138, GPM2 — 139 и для GPM3 — 140.  Пункты 1 и 2 выполнены. Вроде как с портами разобрались, и даже определили индексы ножек, но остался вопрос: Как все таки управлять ножками из Linux? Осталось сделать одно действие — определить ножку в системе. После чего появится еще одна папочка с названием «gpioN», где N — индекс ножки. Делается это простой командой. Надо всего лишь записать индекс в файл export:

echo 137 > export

И вот она заветная папочка для управления ножкой. Посмотрим её содержание:

ls -la gpio137/

Как видно на рисунке, содержание отличается от папок портов. Получается папка какого-либо порта — gpiochipN, папка ножки порта — gpioM, где N — первоначальный индекс порта, M — индекс ножки порта. В папке конкретной ножки есть очень необходимые файлы: direction — направление ножки ввод или вывод и value — значение логического уровня ножки. Value в случае, если ножка настроена как вход, показывает входной логический уровень, а если как выход, то показывает и задает логический уровень на ней.

 gpio10 gpio11

Наконец-то итог. С помощью вышеописанных файлов direction и value просматриваются и устанавливаются параметры ножек. Так для GPM0 (то есть первый светодиод) настройки по умолчанию — направление вход, значение приходящее в пин — 1. Судя по схеме подключения светодиодов, а именно через транзизтор npn все работает правильно. Вход подтягивается к единице, соответственно есть напряжение на базе и транзистор открывается. Для проверки меняем направление вывода — светодиод продолжает гореть. Дальше меняем значение уровня на выходе пина на нулевой — светодиод погас! Миссия выполнена, переходим на следующий уровень! =)

gpio12 gpio13 gpio15 gpioShemIDEALedGPM_transistor

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

Запись опубликована в рубрике программирование, цифровая электроника с метками , , , , . Добавьте в закладки постоянную ссылку.

2 комментария на «Управление портами GPIO процессора ARM11 из Linux»

  1. Илья говорит:

    Подскажите пожалуйста, интересно ваше мнение.

    У меня свое приложение, которое взаимодействует с внешним устройством через RS232. 9600,8,n,1 Задействованы только RX и TX, т.е. нет CTS, RTS и т.п. У внешнего устройства изначально интерфейс TTL, соответственно используется конвертер уровней для работы через RS232.

    Ко всему прочему перешли с Intel платформы на ARM, соответственно имеет смысл перейти с RS232 на GPIO.

    Но не могу врубиться, как работать с устройством вместо RS232 на GPIO? Смотрел примеры использования GPIO они в основном о миганиях диодов, чтобы реализовать прием/передачу данных — не нашел ничего интересного.

    • alexei говорит:

      Не пойму зачем уходить от RS232? Как бы это самый распространенный интерфейс для обмена данными, особенно при отладке. Думаю реализовать через GPIO интерфейс 232 придется через какую-нибудь микросхему,… которая сама будет обмениваться через 232, а на другой стороне надо по стробам считывать все биты по GPIO, а затем превращать их в байты…

Добавить комментарий для alexei Отменить ответ

Ваш адрес email не будет опубликован. Обязательные поля помечены *

*