Amd gpio driver что это
Перейти к содержимому

Amd gpio driver что это

GPIO для чайников (часть 1)

Что делать, когда нечего делать? Попробовать что-нибудь новое!

Если вы приобрели Raspberry Pi просто ради любопытства, не отдавая себе отчёта в том, для чего он конкретно вам нужен, то наверняка с каждым днём вам становится всё труднее найти для него применение. Вы уже с ним вдоволь наигрались. Попробовали установку разных операционных систем, послушали музыку, посмотрели видео, попробовали поиграть и порисовать… И наверняка с огорчением для себя сделали вывод — «Всё ж таки Raspberry Pi мало годится для использования в качестве настольного компьютера». Слишком он уж медленный и задумчивый, по сравнению с обычным компьютером. И вроде бы ничего серьезного с ним сделать нельзя. Остаётся лишь найти ему применение в качестве либо медиацентра, либо простенького интернет-сервера, который не страшно оставлять включённым круглые сутки…

Но всё ж таки Raspberry Pi может делать одну вещь гораздо более эффективнее, чем любой домашний компьютер- он может управлять внешними устройствами. Устройства могут быть абсолютно любыми, от обычной лампочки, до беспилотного летательного аппарата. В данном случае, область применения Raspberry ограничена лишь вашей фантазией и знаниями. И если вы никогда и ничего подобного не делали, но это вас заинтересовало, то эта статья для вас. И так, начнём.

Чтобы общаться с любыми внешними устройствами и управлять ими, Raspberry Pi имеет на борту интерфейс, называемый GPIO. Это аббревиатура от General Purpose Input Output. А по-русски, это низкоуровневый интерфейс ввода-вывода прямого управления. На плате Raspberry он находится в углу, в виде гребёнки из 26 штырьков, рядом с видеовыходом. Т.е. через этот интерфейс Raspberry может слушать и отдавать команды любому внешнему устройству, например беспилотнику. Но сегодня мы беспилотник строить не будем, начнём с обычной лампочки, а точнее светодиода, который и исполнит роль подопытной лампочки. Наша задача — заставить светодиод, подключённый к Raspberry включаться и выключаться по его команде. Кроме того, дабы убедиться, что эти включения происходят вполне осознано и так, как мы этого хотим, а не благодаря каким-то глюкам в недрах процессора, мы привнесём в нашу программу элемент общения с нами. Т.е. отстроим чёткую иерархию- Raspberry управляет светодиодом, а самим Raspberry управляем мы. Теперь надо подготовиться и раздобыть где-то несколько вещей.

Во-первых, нужно найти светодиод:

Его можно достать из старой сломанной игрушки, из зажигалки с фонариком, попросить у знакомого радиоэлектронщика, в конце концов, просто купить.

Во-вторых, понадобятся проводочки любые и парочка коннекторов BLS:

Такие коннекторы можно вытащить из старого системного блока вместе с проводами, или попросить у знакомого компьютерщика, или тоже купить. Они прекрасно подходят для подключения к разъёму на Raspberry.

Начнём с планирования используемых портов. Порт- это грубо говоря штырёк на разъёме. Так, как штырьков там много (26), то и портов тоже много. А чтобы в них не запутаться, то каждому порту присвоен свой номер и обозначение. Следует заметить, что не все штырьки в этом разъёме являются портами. Некоторые штырьки подключены к источникам напряжения, а некоторые вообще никуда не подключены (По секрету, на самом деле они всё-же подключены, но ими пользоваться нельзя, можно убить свою Малинку. Поэтому лучше вобще их не трогайте).

Вот собственно как эти порты расположены на плате:

Чтобы светодиод зажёгся, нам нужно его подключить к источнику питания. Выбираем для питания светодиода Р1-01, верхний по рисунку штырёк, на котором присутствуетнапряжение 3,3в. Для управления светодиодом нам понадобится один порт GPIO. Можно выбрать любой. Но если у вас есть разъём BLS, то удобнее в данном случае использовать порт, который выведен на штырёк P1-03 и называется GPIO 0. В таком случае мы, воспользовавшись одним разъёмом, сможем подключить наш светодиод. И так, мы будем подключать светодиод между ножками разъёма P1-01 и Р1-03. С вывода Р1-01 мы берём +3,3в для питания светодиода, а вывод Р1-03 будет тем самым управляющим выводом порта GPIO. Все эти порты физически находятся внутри центрального процессора Raspberry Pi, который называется BCM2835. Этот процессор может подключать любой порт к источнику напряжения 3,3в, а может подключить порт к 0 питания (а может вообще никуда не подключать, но об этом позже). Эти переключения он делает в соответствии с поданной командой. Значит, когда порт будет подключён к напряжению +3,3в, наш светодиод гореть не будет, т.к. току некуда идти. А когда процессор подключит порт к 0, то наш светодиод загорится, т.к. ток побежит от +3,3в к 0 через светодиод. Значит наша программа должна будет отдавать соответствующие команды процессору в соответствии с нашим желанием.

Маленькое, но важное. На самом деле, мы не должны подключать светодиод напрямую между источником питания +3,3в и выводом порта. Это нельзя делать по двум причинам. Причина первая: любой светодиод нормально работает при определённом токе. Если через светодиод потечёт большой ток (а выход +3,3в способен отдать до 50мА), то светодиод сгорит. Если маленький ток, то светодиод будет гореть слишком слабо, либо вообще не будет светиться. Для большинства обычных светодиодов рабочий ток находится в пределах 10-20мА. Отсюда вытекает и вторая причина (хотя в данном случае она несущественна). Если мы пропустим большой ток через порт GPIO, то этим самым мы уничтожим процессор и Raspberry- умрёт. Поэтому, мы должны следить, чтобы через порт не протекал ток больше допустимого. Примем для себя ограничение в 16мА, так мы точно не сожжем процессор. Как этого добиться? Очень просто! Нам нужно последовательно со светодиодомвключить токоограничивающий резистор. И сейчас мы его рассчитаем.

Примем для светодиода рабочий ток в 10мА. Убеждаемся в том, что выбранный нами ток не превышает предельно допустимый ток для порта в 16мА. Теперь зная напряжение питания 3,3в и рабочий ток 10мА, мы можем по закону Ома рассчитать необходимое нам сопротивление. R=U/I=3,3/0,01=330Ом. Значит нам нужно найти резистор с сопротивлением 330Ом. А точнее- сопротивлением не менее 330Ом. Больше- можно. Светодиод будет заметно светиться и при сопротивлении 1000 Ом, или 1кОм. В общем наша задача- найти резистор с сопротивлением от 330 Ом до 1кОм. Если вы его нашли, то можно собрать вот такую схему:

Схему лучше собрать на макетной плате. Лично мне, для экспериментов, мой сын дал на прокат свой конструктор «Знаток».

Так выглядит схема в сборе:

Так мы подключаемся к Raspberry:

А вот общий план всей конструкции:

В крайнем случае, можно просто скрутить выводы элементов. Но в этом случае нужно следить за тем, чтобы оголённые ножки элементов случайно не попали на контактные площадки Raspberry. Это может убить его. Так же стоит обратить внимание на то, что светодиод должен подключаться Анодом к + источника питания, т.е. в нашем случае это Р1-01. Как найти на светодиоде Анод? Очень просто! Достаньте из любого ДУ батарейку на 1,5В и подключите к ней ваш светодиод. Если он не зажёгся, поменяйте выводы местами. Если зажёгся- то на + батарейки и будет Анод светодиода.

Если вы собрали схему, то отложите пока её в сторонку. Теперь мы займёмся второй частью задачи — написанием программы управления светодиодом. Писать эту программу мы будем на языке Си.

Почему на именно на Си? Просто по тому, что я других языков не знаю, а раз вы читаете эту статью, то скорее всего вы тоже немного знаете о программировании и радиоэлектронике, а значит, вам всё равно с какого языка начинать.

Обычно изучение языков программирования начинают с написания программы «Hello World!», но мы же круче «тех» чайников, поэтому мы начнём сразу с низкоуровневой работы с периферией. Тем более, что это не намного сложнее ХеллоуВорлда. 😉 Что для этого нужно? Нужен любой текстовый редактор, в котором мы будем набирать программу. В Raspbian есть отлично подходящий для этого редактор “nano”. Ещё нужен компилятор, это программа, которая осуществляет перевод написанной нами программы с человечески понятного языка на язык, понятный компьютеру. Т.е. делает из нашей программы исполняемый файл, который мы впоследствии и запустим на Raspberry. Эта штука тоже у нас есть, называется gcc. Этот компилятор поставляется в комплекте со всеми Линуксами и уже готов к работе.

Как видите,всё необходимое у нас уже есть. Хотя нет. Одной вещи все-таки у нас не хватает. Её мы возьмем из интернета. Речь идёт о библиотеке функций управления портами GPIO на Raspberry, специально написанно добрым человеком для того, чтобы наша программа по своей простоте могла бы соперничать с «Хеллоуворлдом» и нам самим бы не пришлось ломать голову, изучая техническую документацию на процессор и протоколы работы с его внутренностями. Сама библиотека состоит из заголовочного файла, в котором обозначены все имена функций со структурами переменных и файла библиотеки самих функций. Эту библиотеку нужно скачать и установить, чтобы компилятор мог с ней работать. Библиотека называется bcm2835-1.17. Последние цифры в названии библиотеки, обозначают её версию. А так, как библиотека постоянно обновляется автором, то версии будут меняться. на сегодняшний день доступна версия 1.17. Узнать о номере последней версии можно по адресу: http://www.open.com.au/mikem/bcm2835/index.html По этой же ссылке вы можете ознакомиться со всеми функциями, которые присутствуют в этой библиотеке.

Мы же пока установим версию 1.17. Запускаем окно терминала и вводим туда команду: wget http://www.open.com.au/mikem/bcm2835/bcm2835-1.17.tar.gz

Библиотека быстренько скачивается. Чтобы её установить, нужно сначала её разархивировать. Это делается следующей командой: tar zxvf bcm2835-1.17.tar.gz

Теперь перейдём в директорию, куда эта библиотека развернулась: cd bcm2835-1.17

Ну и инсталлируем её:

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

Тут можно создать папочку для наших экспериментов с любым именем, например myprog: mkdir myprog

Перейдём в эту папку: cd myprog

И начинаем писать нашу программу: nanoGPIO-test.c

Эта команда запускает текстовый редактор nano, который создаёт текстовый файл GPIO-test.c.Теперь можете набрать в нём следующую программу (можно просто скопировать и вставить):

Обратите внимание на строки #define. Их в программе 2 и одна из них закомментирована. Одна строка для ревизии RPi v1, вторая для RPi v2. Если у вас v1, то всё оставьте как есть. Если у вас RPi v2, то первую строку с #define удалите, а со второй уберите символ комментария //.В будущем, во всех остальных программах, просто добавляйте _V2_ между RPI и GPIO в определении портов, если ваша плата RPi v2.

Сохраняем нашу программу ctrl-o и выходим из текстового редактора ctrl-x. Теперь, если вы введёте команду ls, то увидите только что созданный файл GPIO-test.c. Чтобы этот файл превратился в работающую программу, его нужно скомпилировать. Пишем: gcc -o GPIO-test GPIO-test.c -lrt -lbcm2835 в этой строке: gcc- это имя компилятора; -o GPIO-test GPIO-test.c эта команда компилятору говорит о том, что требуется создать исполняемый файл с именем GPIO-test из текстового файла GPIO-test.c; -l (латинская л маленькая) bcm2835 говорит компилятору о том, что все неизвестные ему функции в нашей программе, он может найти в установленной библиотеке bcm2835. Если компилятор не выдал никаких сообщений, то значит, всё у нас получилось. Если сейчас дать команду ls, то мы увидим, что в директории появился ещё один файл GPIO-test, причём он отмечен зелёным цветом. Это говорит о том, что файл является исполняемой программой. Осталось нам его запустить, но перед этим ещё раз проверяем нашу схему со светодиодом, чтобы всё было собрано правильно и подключено к контактам Р1_01 и Р1_03 разъёма GPIO. Если ошибок не обнаружено, запускаем программу: sudo ./GPIO-test После этого светодиод должен загореться ровно на 1 секунду и погаснуть. Если всё так и произошло, то я вас поздравляю! Вы только что при помощи Raspberry Pi передали через порт GPIO команды светодиоду: включиться, гореть 1 секунду и выключиться.

Теперь о том, что делает каждая строка в нашей программе.

Все надписи после двойного слеша // являются коментариями и никак не влияют на выполнение программы.

#include <bcm2835.h> -эта строка говорит компилятору, что в программе используется заголовочный файл bcm2835.h. В этом файле находятся все описания функций и идентификаторы портов GPIO.

#define PIN RPI_GPIO_P1_03 — здесь мы говорим компилятору, что везде в программе, где он увидит идентификатор PIN, ему нужно выполнить замену его на идентификатор RPI_GPIO_P1_03 . Это сделано для того, чтобы мы могли при желании быстро изменить номер подключаемого порта. Для этого достаточно изменить только эту строку, а не выискивать по всей программе, где мы этот идентификатор использовали.

int main() это начало нашей программы, обозначение главной функции в Си.

if (!bcm2835_init()) — эта часть пытается инициализировать GPIO и если это не получилось,

return 1; то аварийно завершает программу и передаёт на выходе код 1.

bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_OUTP); — Эта функция устанавливает для нашего порта Р1_03 режим на вывод. Т.е. говорит процессору, что этот порт будет использован для управления внешним устройством.

bcm2835_gpio_write(PIN, LOW); — устанавливаем порт Р1_03 в низкое состояние, т.е. процессор его подключает к 0. После этого светодиод загорается.

bcm2835_delay(1000); — Эта функция просто ждёт 1000 милисекунд, или ровно 1 секунду. Всё это время у нас горит светодиод.

bcm2835_gpio_write(PIN, HIGH); — устанавливаем порт Р1_03 в высокое состояние, т.е. процессор его подключает к +3,3в. При этом светодиод гаснет.

b>return 0; — Выход из программы с кодом 0.

Т.е. алгоритм работы с портом GPIO в режиме записи, т.е. вывода, выглядит следующим образом:

1. Инициализируем GPIO;

2. Устанавливаем режим для выбранного порта на Вывод;

3. Теперь можем управлять этим портом, устанавливая его в высокое, или низкое состояние. Соответственно на этом порте будет пристутствовать либо +3,3В, либо 0В. Что соответствует логической 1 и логическому 0 соответственно.

На этом на сегодня закончим. В следующей части научим наш светодиод загораться более полезным образом, а так же научимся портами GPIO не только отдавать команды другим устройством, но и слушать их.А пока можете начинать изучать язык Си. А так же попробуйте изменить эту программу так, чтобы светдиод управлялся бы другим портом и испытайте её.

ARM. Учебный Курс. Порты GPIO

С железной части порты бывают двух видов стандартные и устойчивые к напряжению в 5 вольт. При том, что напряжение питания у STM32 максимум 3.3 вольта. Разница у портов в схемотехнике. А точнее в том, что у 5V tolerant входов защитные диоды видут на какую то особую шину питания Vdd_ft. Полагаю, что там стоит нечто вроде небольшого повышателя, накачивающего напругу до 5 вольт.


Вывод 5V Tolerant

Остальное все более менее стандартно. Сигнал на выход может вывалиться либо с периферии (стрелочка Alternate function Output) либо с выходного регистра. В который мы вольны записывать биты напрямую, либо же воспользоваться служебными регистрами установки/снятия битов.

Входной сигнал с ноги попадает в Data register и в Alternate Function Input. Причем селектора там нет, а значит можно по ходу дела считывать и глядеть что там творит периферия.

Т.к. RM0008 это общий документ, сразу на все семейство STM32F10x то распиновку выводов конткретного чипа в конкретном корпусе надо смотреть в конкретном даташите. Для STM32F103C8T6, что стоит на Pinboard II она выглядит следующим образом * :

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

Вот примерный кусок того, что вы должны найти* :

Разберем ее чуть подробней.

  • Pins — тут все просто. Это номера пинов в выбраном нами корпусе. Тут сразу все, от BGA до TQFP. Если в вашем чипе меньше выводов, то будут стоять прочерки. Т.е. в ядре то пин есть, но наружу не торчит. Печаль…
  • Pin Name — собственно имя GPIO по его основному назначению. То самое, что вы видели на картинке с распиновкой. Помогает ориентироваться.
  • Type — тип вывода. I — только вход, I/O вход-выход, как настроишь, S — supply, т.е. питание по нашенски. Через эти выводы контроллер получает разное ЖРАТ. Сюда входят разные питания (ядра, периферии, АЦП и мало ли еще чего) и земли.
  • I/O Level допустимый уровень напряжения на пине. Собственно бывает только обычный (т.е. 3.3V) и устойчивый к 5 вольтам. Пятивольтовые обозначаются как FT .
  • Main Function — главная функция, то как настроен вывод по дефолту, после сброса питания. Обратите внимание на то, что там не все выводы ведут себя как GPIO, хотя и большинство. Всякие JTAG/SWD любят быть включенными по дефолту. А также тактовые для разных дополнительных кварцев, вроде часовых.
  • Alternate Functions/Defaults — дополнительные периферийные функции. В отличии от тех же AVR, где стоило только включить какой-нибудь UART, так сразу же выводы под UART становились в нужные режимы, тут все по другому. Вывод переводится в режим управления от периферии ручками. Записью битов в регистры. И вот то каким он станет после включения альтернативного режима и указано в колонке Defaults
  • Alternate Functions/Remap —А еще там есть бит ремапа. Позволяющий взять и перебросить многие выводы периферии на другие ноги. Т.е. у того же UART1, например, вывод TX1 может быть либо на PA9 либо на PB6, в зависимости от бита ремапинга порта. Это удобно, легче разводить плату. Цепляешь вывод туда, где удобней, но изрядно взрывает мозг 🙂 Вот в этой колонке и указывается куда что ремапится при выставлении этого бита. Правда надо учитывать, что биты периферии ремапятся не по одному, а сразу все. Т.е. если это UART то сразу RX и TX. Врочем бывают исключения. Подробней надо смотреть в описании регистров ремапинга. Там портянка на три страницы с комбинациями куда что.*

Также настояяятельно рекомендую читать сноски и пояснения к этой таблице. Там много всяких уточнений.

Итак, портом управляют следующие регистры

Пара GPIOx_CRH:GPIOx_CRL
Т.к. порты в STM32 шестнадцати разрядные, а на конфигурацию одной ноги выделено аж четыре бита, то на 16 выводов надо 64 бита. Т.е. два регистра. В CRL хранятся конфиги выводов от 0 до 7, а в CRH с 8 до 15го.

Выглядит внутри так:


Красными блоками я выделил группы битов, отвечающих за одну ножку. Тут конфигурируются выводы от 0 до 7. Это CRL. В CRH то же самое, но настраиваются пины от 8го до 15го.

Все возможные состояния описываются в таблице 18 и 19 из User Manual

Тут стоит обратить внимание на скоростной режим порта. Т.е. с какой частотой он может дрыгать лапой. Полагаю сия настройка должна влиять на энергопотребление. Т.е. если жалко батарейку и не планируем дрыгать быстро, то имеет смысл поставить минимальную частоту.

Какой режим выставить зависит от того, что мы хотим получить. Если для ручного дрыганья портами все просто и ясно, то для периферии возможны затупы. Т.к. тут надо вручную выставлять нужные режимы портов для периферии. А кому какой? Ответ на это дает пачка таблиц с 20 по 31 из User Manual * Там таблицы такого вида:

Где сказано для какого режима периферии какой режим порта надо поставить. Так что курите документацию. Это вам не AVR, тут ее просто горы 🙂

  • Файл RM0008 STM32 User Manual. Раздел 8.3 Alternate function I/O and debug configuration (AFIO) стр. 161
  • Файл RM0008 STM32 User Manual. Раздел 8.4.2 AF remap and debug I/O configuration register (AFIO_MAPR) стр. 170 и далее.

Искать там просто — находишь нужную периферию в таблице в разделе 8.3 и смотришь куда ее можно перекинуть. Затем идешь в раздел 8.4.2 и смотришь какие биты для этого нужно записать в регистр AFIO_MAPR.

Структура регистра ODR проста — первые биты от 0 до 15 отвечают за соответствующий вывод, а старшие, от 16 и до 31го не используются вообще.

Все же, что на ноге появилось, вылезает во входном регистре GPIOx_IDR. Это аналог регистра PINx в AVR. Т.е. в каком логическом уровне находится вывод МК, такое значение в этом регистре. Даташит говорит, что данные считываются на каждом такте шины APB2.
Структура регистра GPIO_IDR похожая на ODR. Т.е. первые 16 бит отвечают за соответствующие выводы, а старшие не используются.

Также там есть регистры атомарных действий. Позволяющие менять значения битов в ODR без использования операций чтение-модификация-запись.

С BRR все просто. Его младшие 16 бит отвечают за сброс бита в ODR.

Т.е. надо тебе, например, сбросить бит 3 в ODR, не трогая остальные. Без BRR регистра, надо было бы сначала считать ODR, потом по маске загасить нужный бит, не трогая остальные, а потом вернуть его обратно в ODR в уже измененном виде. Как минимум тут будет три команды. Между которыми может вломиться прерывание и обгадить нам всю малину. C регистром сброса все упрощается до одной команды. Нам нужно только лишь записать «адын» в третий бит GPIOx_BRR и усе, бит 3 в ODR будет сброшен. На нули же никакой реакции не будет. Таким образом можно сбрасывать и несколько битов.

Регистр BSRR работает аналогично, только на установку. Т.е. записал ты единичку в третий разряд BSSR и она автоматом выставилась в ODR.

Разница лишь в том, что в BRR старшие биты (т.е. 16 до 31) не влияют ни на что, а в BSSR они активны и сбрасывают бит. Записал в бит 0 BSRR единичку — бит 0 в ODR выставился. Записал в бит 16 BSRR единичку — бит 0 в ODR сбросился. Потому то он и зовется Bit Set/Reset Register.

Каждый бит регистра LCKR отвечает за один бит порта. А 16й бит регистра LCKR (LCKK) служит ключиком. Для того, чтобы заблочить порт нужно:

Выставить в регистре GPIO_LCKR биты выводов которые мы хотим заблокировать.

  • Записать в бит LCKK 1
  • Записать в бит LCKK 0
  • Записать в бит LCKK 1
  • Считать из LCKK 0
  • Считать из LCKK 1 (этот шаг опциональный, но считывание 1 будет означать, что блокировка установилась)

В процессе записи ключевой последовательности нельзя модфицировать биты регистра LCKR кроме 16го, ключевого. Иначе замок не сработает.

Тактирование портов

Порты GPIO сидят на шине APB2 и тактируются оттуда. По умолчанию тактирование ВЫКЛЮЧЕНО! сделано это скорей ради экономии энергии. Нет тактов — нет потребления. Вообще вся периферия изначально отключена от тактирования. Поэтому то часто возникают непонятки — порты все настроил, а нифига не работает.

Как видишь, тут каждой периферийной шняге, что висит на шине APB2 присвоен битик. Каждому из портов (от А до G) тоже. Также отдельный бит присвоен альтернативному использованию портов. Бит AFIO. Вот выставляешь эти битики и поехало.

Подведем итог. Что нам надо сделать, чтобы помигать таки этим чертовым диодиком?

  • Выставить тактирование нужного порта на APB2
  • Сконфигурировать порты в CRH:CRL регистрах на выход «тяни-толкай»
  • Записать/стереть нужный бит в ODR или воспользоваться регистрами BRR или BSRR.

Просто как раз-два-три! И чего я тут распинаюсь 😉

CMSIS
Теперь поглядим на представление наших портов через призму CMSIS и попробуем написать кусочек кода для мигания. Мигать будем битом на B05.

// Выставляем тактирование в APB2 RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; // Конфигурируем CRL регистры. GPIOB->CRL &=

GPIO_CRL_CNF5; // Сбрасываем биты CNF для бита 5. Режим 00 — Push-Pull GPIOB->CRL |= GPIO_CRL_MODE5_0; // Выставляем бит MODE0 для пятого пина. Режим MODE01 = Max Speed 10MHz GPIOB->BSRR = GPIO_BSRR_BR5; // Сбросили бит. GPIOB->BSRR = GPIO_BSRR_BS5; // Установили бит.

Сброс и запись мы делаем через один и тот же регистр BSRR. А записываем в него разное число.

GPIO_BSRR_BR5 = 0x00200000
GPIO_BSRR_BS5 = 0x00000020

Разница лишь в половине в которую идет запись бита. Также можно и напрямую пинать данные в ODR.

Набросал простенький примерчик в Keil и запустил на Pinboard II
Видео уж прикладывать не буду. Что вы, в самом деле, мигающий диод не видели? 😉 Уж, надеюсь, поверите мне на слово 🙂

  • Пример в Keil
  • RM0008 User Manual
  • Даташит STM32F103

to do… тут надо дописать ту же самую портянку, но про LPC1343… когда нибудь.

Спасибо. Вы потрясающие! Всего за месяц мы собрали нужную сумму в 500000 на хоккейную коробку для детского дома Аистенок. Из которых 125000+ было от вас, читателей EasyElectronics. Были даже переводы на 25000+ и просто поток платежей на 251 рубль. Это невероятно круто. Сейчас идет заключение договора и подготовка к строительству!

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

108 thoughts on “ARM. Учебный Курс. Порты GPIO”

Ох, такую статью бы, да две недели назад.. Было бы здорово 🙂
Сейчас я почти со всем уже разобрался сам, уткнувшись в даташиты.

Очередной хит от автора блога ! Жаль, что статьи выходят не часто…

А в режиме «открытый коллектор» можно рулить напряжением большим чем 5вольт

Лучше не стоит. Защитные диоды никуда не денутся, а по ним лишняя напруга уйдет в шину питания со всеми нехорошими последствиями.

а нафига тогда этот режим. чем он отличается от обычного нуля на выходе. тот же открытый нижний транзистор, и закрытый верхний.
или может защитные диоды все же как то отрубаются от пина, и там настоящий ОК выходит )))

Тем что когда в ODR=1 выход в Hi-Z. Тут верхний всегда закрыт.

DI напиши статью о работе с I2C и SPI на этих контроллерах.

Напишу… в этом или следующем году 🙂

А что за режим push-pull? не совсем понятно

Два транзистора. Верхний и нижний. Между ними вывод. Верхний ведет на шину питания, нижний на землю. Открываем верхний — вывод жестко прижимается к питанию. Открываем нижний — к земле.

А, все понял) спасибки DI)

Нормально push-pull называется двухтактным выходом, что в цифровой, что в аналоговой (усилители) технике. А тяни-толкай это, как пошутил аффтар, из доктора Айболита

ооо… давно не было статьей.

А для чего блокировка нужна? Кроме теоретического сферического STM32 в вакууме?

Ну чтобы в результате сбоя, например в результате срыва стека, порты не изменили свою конфигурацию и не устроили ядерный взрыв раньше времени. Полезная фича так то.

То есть в случае необходимости блокируем пин, а если нужно его поменять программно перезагружаем контроллер?

Да, например так.

Спасибо, очень познавательная статья!

А как насчет bit-band?
Есть там такая фраза в даташите как «These bits can be read and written by software and can be accessed in Word mode only.», под описанием регистра ODR. Однако гугление показало что народ вроде как делал и оно работало. Еще пытался найти набор удобных дефайнов для всех пинов(вида PORTA8, например), но не нашел, впрочем тут можно заморочится и самому сенерить, посмотрев по каким адресам там чего лежит.

Кстати, получается атомарно инвертировать бит нельзя? Жалко, например у xmega если память не изменяет есть такая функция(спец регистр типа BSRR). Интересен самый простоый и/или быстрый способ инвертировать бит в регистре.

Есть. У STM32 с этим все в порядке. ЕМНИП инверснуть можно через битбанд, там вроде как регистр на set, clear и invert, но надо уточнить.

Битбанда нет в LPC младших версий.

У LPC1343 есть битовый доступ через MASKED_ACCESS. Причем это не отдельная команда, область в адресном пространстве (массив по сути). Более того доступ ко всему порту идет через эту же область (где маска == все выводы).

Написано как всегда легко и понятно. Только вот ее бы год или месяцев 9 назад, что бы не тупить в талмуды даташитов…

DI, а можешь поделиться планами, что по армам планируешь рассматривать?

Да я сам не знаю. 🙂

Ну еще хорошо бы добавить что на Remap тоже такты давать надо.

Что имеется в виду в вопросе про Bit-Band? если руление битами через область памяти в которой каждый байт соответствует своему биту — то да, оно работает, во всяком случае на STM32. Разве что несколько геморно высчитывать адреса.

А про дефайны типа AVR-овских PORTA, PORTB — каждый порт дефайнится ала GPIOx, а бит этого порта дефайнится как GPIO_Pin_х , где x — буква порта в первом случае и номер пина во втором. Это при использовании CMSIS.

На ремап в смысле на тот GPIO куда сремапилось? Думаю это очевидно. Нет?

Или там еще куда то надо загнать?

Немного неправильно выразился. Там врубаются такты на регистры управления альтернативными функциями, регистр ремапа тоже относится к этой группе.
У меня для ремапа SPI1 в коде идут 2 команды:

// alternative func enable
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
AFIO->MAPR |= AFIO_MAPR_SWJ_CFG_JTAGDISABLE; // disable JTAG

// remap SPI1 to port B
AFIO->MAPR |= AFIO_MAPR_SPI1_REMAP;

Ну и отрубание JTAGа тут докучи

Ага, т.е. вот это:
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
Обязательно при ремапе.

А нет готовых дефайнов всех GPIO_Pin_х с высчитанными адресами?
В CMSIS этого не нашел.

Все, не надо, написал простую программку, сам сгенерил 🙂

http://tmp.avr.net.ru/bit.zip
Нате.
Там два файла, один с дефайнами для F100 (для F10x тоже скорее всего подойдет, не смотрел даташит, пока что 100RBT6 ковыряю). Вид дефайнов
PORTx_y (пример PORTA_12) и PINx_y (пример PINA_12). Это соответственно биты регистра ODR и IDR.

Второй файлик — программа для генерации первого. Написана на коленке за 5 минут, лишь бы генерило. Изменять под свой вкус. Вообще было бы круто написать такое для всех битов всей переферии, но это придется повозиться.

Вообще на мой взгляд бит-банд во много раз удобнее использования битовых масок и уж точно нагляднее.
А уж если хочется помигать светодиодиком, то вообще сказка 🙂
PORTC_9 = !PORTC_9;

Было бы интересно найти/сгенерить для всех регистров переферии(а они в стм32 как я понял ВСЕ попадают в зону битбанда). Тогда можно будет
GPIOA->CRH |= GPIO_CRH_MODE9_0 | GPIO_CRH_MODE9_1;
Заменить на
GPIOA_MODE9_0 = 1;
GPIOA_MODE9_1 = 1;
Как по мне, так вторая запись нагляднее и удобнее

Так это, у периферии есть базовый адрес, остальные смещения. Думаю можно сделать макрос которому подсовываешь базовый адрес, имя бита и опа…

Есть в СooCox IDE в
#include «stm32f10x_gpio.h»

#define GPIO_Pin_0 ((uint16_t)0x0001) /*!< Pin 0 selected */
#define GPIO_Pin_1 ((uint16_t)0x0002) /*!< Pin 1 selected */
#define GPIO_Pin_2 ((uint16_t)0x0004) /*!< Pin 2 selected */
#define GPIO_Pin_3 ((uint16_t)0x0008) /*!< Pin 3 selected */
#define GPIO_Pin_4 ((uint16_t)0x0010) /*!< Pin 4 selected */
#define GPIO_Pin_5 ((uint16_t)0x0020) /*!< Pin 5 selected */
#define GPIO_Pin_6 ((uint16_t)0x0040) /*!< Pin 6 selected */
#define GPIO_Pin_7 ((uint16_t)0x0080) /*!< Pin 7 selected */
#define GPIO_Pin_8 ((uint16_t)0x0100) /*!< Pin 8 selected */
#define GPIO_Pin_9 ((uint16_t)0x0200) /*!< Pin 9 selected */
#define GPIO_Pin_10 ((uint16_t)0x0400) /*!< Pin 10 selected */
#define GPIO_Pin_11 ((uint16_t)0x0800) /*!< Pin 11 selected */
#define GPIO_Pin_12 ((uint16_t)0x1000) /*!< Pin 12 selected */
#define GPIO_Pin_13 ((uint16_t)0x2000) /*!< Pin 13 selected */
#define GPIO_Pin_14 ((uint16_t)0x4000) /*!< Pin 14 selected */
#define GPIO_Pin_15 ((uint16_t)0x8000) /*!< Pin 15 selected */
#define GPIO_Pin_All ((uint16_t)0xFFFF) /*!< All pins selected */

И ёще много итересного…

на асме зажечь светики на STM32 value line discovery

.syntax unified .cpu cortex-m3 .fpu softvfp .thumb .section .isr_vector,"a",%progbits .type Vectors, %object .size Vectors, .-Vectors Vectors: .word _eram @ Вершина Стека .word main @ Reset main: .include "macros.s" @ стандартные макросы .include "st32f100rbt6b.s" @ настройки и имена для контроллера MOV R10, 0 @ для bitbang MOV R11, 1 @ для bitbang # подключаем тактирование к порту С MOV32 R0 , RCC_APB2ENR MOV32 R1 , RCC_APB2ENR_IOPCEN STR R1 , [R0] # конфигурируем пины 8 и 9 порта С (на них сидят диоды) MOV32 R0 , GPIOC+GPIO_CRH MOV R1 , GPIO_CRH_MODE8 + GPIO_CRH_MODE9 STR R1 , [R0] # зажигаем оба диода (пины 8 и 9 устанавливаем в 1) SET_BIT_IO GPIOC, GPIO_ODR, 8 SET_BIT_IO GPIOC, GPIO_ODR, 9 loop: b loop

последние (SET_BIT_IO GPIOC, GPIO_ODR, 8 и SET_BIT_IO GPIOC, GPIO_ODR, 9) как раз макрос битбанда

@ макрос установки бита в периферии при помощи bitbang @ использование: @ SET_BIT_IO GPIOA, GPIO_CRL , 0 /* установка нулевого бита GPIOA_CRL */ @ .macro SET_BIT_IO base, reg, bit MOV32 R0 , (0x42000000 + (base + reg — 0x40000000) * 32 + bit * 4) STR r11 , [r0] .endm

Интересно, почему все настойчиво думают, что на вордпрессе работают ББ коды форума и что они тут вообще есть 🙂

нет, не думаем.. — мы надеемся .

а кнопки «редактировать» ответ нет 🙁

а там внизу, под окном в котором печатаешь сообщение, мелким шрифтом чего-то про коды сказано. Я глянул мельком, в тексте присутствовало, я его и воткнул 😀

P.S. Во: Можно использовать следующие HTML-теги и атрибуты: \ \ \ \ \

Гадость… Она таки сожрала все тэги. И кстати почему-то сечас тэг code показало как надо, а в прошлых комментах его проигнорировало…

</pre>
Язык можно выбирать разный.

Биты CNF[1:0] изначально выставлены в единицы? Просто в АРМах новичок и не совсем понятны операции &=

. По отдельности норм. В мануале ничего не нашел. Или просто не там ищу. Хотелось бы узнать что к чему. И еще вопрос? Как определяется битовая маска? В даташнике где то?

Не помню, сбрасываю для верности, чтобы битмаски сразу накладывать по OR. Обращай внимание на звездочки в конце предложений. Наведешь на них — увидишь сноску на конкретную страницу даташита или юзермануала.

Битмаски все прописаны в CMSIS читай описание библиотеки CMSIS

За звездочки спасибо. По аналогии с подсвеченными пунктами мануала нахожу одноименные у себя. А вот с библиотекой сложнее. Пишу в ИАРе. Зашел в дереве проекта в библиотеку CMSIS там куча .h файлов. Подскажите как бит маски там описываются? Пробовал по поиску ничего определенного нет.

В курсе ARM есть статья по CMSIS там подробно расписано, что как и где искать.

Хорошо. После прочтенного (смотрю пример в статье Keil+CMSIS):
1. Выражение GPIOA->CRL &=

GPIO_CRL_CNF3;
Бит маска GPIO_CRL_CNF3 согласно хидеру 0x0000C000.
2. После операции

она становится 0хFFFF3FFF.
3. Т.к. 3 бит надо обнулить выполняем операцию 0хFFFF3FFF & 0x00000000.
Может я что то упустил?

в пункте 3 вы выполняете операцию (GPIOA->CRL & 0хFFFF3FFF)

получается битмаска умножается на ее инверсию? 0x0000C000 & 0хFFFF3FFF и получаем сброс, т.е. обнуленные биты CNF3?

Битмаска помноженная на ее инверсию Всегда даст ноль 🙂

кстати обнуляться два бита группы 3 и 4. (3= 0b0011)

Так, давайте разберемся по порядку, чтобы не было вопросов.

GPIO_CRL_CNF3;
Это эквивалентно
GPIOA->CRL = GPIOA->CRL & (

GPIO_CRL_CNF3); (написание выше используется для сокращения).
Дальше, подставляем значение битмаски
GPIOA->CRL = GPIOA->CRL & (

0x0000C000);
Теперь побитово инвертируем и получаем фактически это:
GPIOA->CRL = GPIOA->CRL & 0хFFFF3FFF;

Таким образом, что мы имеем — в регистр CRL порта А записывается он же, помноженный на 0хFFFF3FFF. Так как умножение Х на 1 дает Х, то везде где в полученном числе стоят 1 — останется то значение которое до этого было в регистре. Так как умножение Х на 0 дает 0, то везде где в полученном числе стоят 0 — получится 0.

Тоесть этим действием мы обнуляем в регистре CRL те биты, которые соответствуют 1 в изначальной маске GPIO_CRL_CNF, при этом все остальные биты остаются в таком же состоянии, в каком и были до этого.

Вот теперь понятно откуда «биты» растут!:) И с последовательностью операторов все норм теперь. Спасибо.

Вот теперь понятно откуда «биты» растут!:) Спасибо.

di halt, это конечно интересно, но хотелось бы почитать статьи для полных новичков, — например как работает кварц, подробный разбор небольших схем с транзистором, как куда идет сигнал и тп.

DI HALT, посоветуйте транзистор для электронного ключа (лучше импортный, рос. не смогу достать, никогда ничего не паял, появилась потребность сделать тросик к фотоаппарату, управляемый с платы), сигнал с вывода STM32l152 на плате STM32L-discovery. Вывод как понимаю нужно переводить в режим тяни-толкай?

Но вам лучше применить оптореле. CPC1035N, например. Будет куда проще и надежней.

спасибо за ответ, есть ли какие нибудь аналоги с корпусом не SMD?

Доброго времени суток, вот собрался разбираться с данным семейством, однако, руки не доходили до знакомства с ним, до сегодняшнего дня, пока не предложили преобрести отладочный комплект STM32VLDISCOVERY. И по сему возник вопрос, могу ли я с данным комплектом в основе, которого мк STM32F100RBT6B, пользоваться данными уроками , где, как я понял, рассматривается 103 серия ( и вообще есть ли существенная разница между этими сериями). Прошу сильно не бить за столь глупый вопрос, т.к. семейство абсолютно не знакомое и новое для меня и времени на раздумья 1 — 2 дня, нет времени разбираться. И прошу прощения если вопрос не туда адресован и если гдето уже был задан подобный вопрос

вопрос цены, возможностей и целей, для многих задач этой платы «за глаза»

раньше в авр начинали с меги8 или 16 — так вот F100RB быстрее обоих, флеша больше (128 кб), озу больше и так далее..
более чем достаточно чтобы начать! да и продолжить тоже 🙂

Можешь, но смотри на отличия между МК. Отдельно я их оговаривать не буду.

DI HALT, добрый день. Знаю что вы работали с модулями Radiocrafts RC1240, прочитал вашу статью, но т.к. там последний коммент датируется 2010 годом, решил написать сюда, в надежде на вашу помощь)

Не подскажете, в чем может быть проблема — три модуля закупил (из одной партии, явно, даже в одной ленте были), подключаю по даташиту — никакого отклика, даже тестового меандра с 20го пина нет.

Соединял как в даташите — Vcc — 3.3В (пробовал также и с 5.0В), все пины GND, понятное дело, на землю, CTS, RTS, CONFIG — подключены к пину Vdd. On/Off пин подключен к Vcc.
Reset — висит в воздухе, пробовал также коснуться им Gnd и потом бросить в воздухе, а также — коснуться им Gnd и потом подключить к Vdd.
Антену пока не паял.
На выходе Vdd присутствуют искомые 2.7В, замеры потребляемого модулем тока соответствуют даташитовским — после включения показывает 20.5 мА, когда On/Off подключаю к земле — 0 мА, когда CTS, RTS на землю — 9 мА. Но меандра нет. И уарт молчит. Никаких реакций на
CONFIG->LOW нет.
Уже все перепробовал, даже с оф. дистрибютерами связался — те почесали голову и сказали «свяжемся позже».

Сброс бит в ODR можно выполнить посредством 2 регистров — это разряды 15-0 BRR и разряды 31-16 BSRR? Я правильно понял, у них одинаковое предназначение?

Пустяшное дело: подключение к Discovery (VL) четарех разрядного семисегментного LCD, вылилось в познавательную прогулку по даташиту. При 16ти разрядных портах можно, одной посылкой в порт, подавать код сегмента и знакомест, в которых эти сегменты встречаються. О целесообразности такого подхода можно поспорить, основным мотивом был тот , что в этом случае, нагрузкой на пин будут не боле 4х сегментов (традиционно — 8). Итого нужно 8 пин (с учетом запятой) и 4 пина под знакоместа. Смотрим на Discover и видим что порт «А» создан для поставленной цели, там подряд разведены по 8 младшие и старшие разряды этого порта. Под сегменты берем РА8-РА15, под знакоместа: РА0-РА3. Индикатор таков , что для зажигания сегмента требуеться плюс не знако место и корпус на сегмент. Отсюда: РА8-РА15 ставим в режим OD (Open-drin), а РА0-РА3 в РР.
С портами оказалось понятней без структур. Инициализация выглядит так:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);
GPIOA->CRL=0x33333333;// Режим РР,Выход, 50МГц порт А младший байт
GPIOA->CRH=0x77777777;//Режим OD,Выход, 50МГц порт «А» старший байт
Начинаешь играться с сегментами, запуская вариации : GPIOA->ODR=0xEFFF; // Здесь горит один сегмент во всех знакоместах.
ОДНАКО сегменты на РА13 РА14 горят постоянно.Находим в мануалах табицу 5(так она звучит в обсуждаемой статье) и видим ,что на этих пирах висит отладчик, и действительно,стоит снять джамперы отладчика -сегменты гаснут. Гаснут но зажечь то их не удаётся.Читаем. Похоже по умолчанию это и не порты вовсе, и надо покурить,чтобы они стали таковыми. Ultrin в этом форуме от 7го февраля, оказывается очень кстати. Пишем инициализацию.
RCC->APB2ENR|=RCC_APB2ENR_AFIOEN;// Remapingu это надо
AFIO->MAPR|=AFIO_MAPR_SWJ_CFG_DISABLE;//Глушим JTAG и SW,
GPIOA->CRL=0x33333333;// Режим РР,Выход, 50МГц порт А младший байт
GPIOA->CRH=0x77777777;//Режим OD,Выход, 50МГц порт «А» старший байт,
Снимаем перемычки программатора,иначе сегменты на РА13,РА14 не гаснут.Заработало.
Небольшой стресс, Отключив JTAG и SW залить следующую программу не удастся, если не держать кнопку RESET пока не начнет мигать диод заливки. Такой вот экскурс.
while (1)
GPIOA->ODR=0xF7F1;
Delay(0x00FFF);
GPIOA->ODR=0xBFF2;
Delay(0x00FFF);
GPIOA->ODR=0xDFF4;
Delay(0x00FFF);
GPIOA->ODR=0xEFF8;
Delay(0x00FFF);
>
Горят четыре разных сегмента, по одному в знакоместе….

Извиняюсь за офтоп, но как в IAR посмотреть сколько памяти (flash, RAM и EEPROM) используется микроконтроллером?

Добрый вечер всем! Возник вопрос про 7 сегментный индикатор. На индикацию ничего не выводит, прошиваю — тишина (точнее «темнота») хотя JTAGом смотрю все биты в порядке. Может в коде что не так.
#include «stm32f10x.h»
#define SYSCLK_FREQ_72MHz 72000000

void Delay_ms(unsigned long takt)
unsigned long clk=(SYSCLK_FREQ_72MHz/1000000)*takt;

GPIOE->CRH |= GPIO_CRH_MODE8_0;
GPIOE->CRH |= GPIO_CRH_MODE9_0;
GPIOE->CRH |= GPIO_CRH_MODE10_0;
GPIOE->CRH |= GPIO_CRH_MODE11_0;
GPIOE->CRH |= GPIO_CRH_MODE12_0;
GPIOE->CRH |= GPIO_CRH_MODE13_0;
GPIOE->CRH |= GPIO_CRH_MODE14_0;
GPIOE->CRH |= GPIO_CRH_MODE15_0;

GPIOE->ODR = chisla[schet];
schet++;

if (schet == 10) schet=0;

Чтот меня смущает строчка активации порта. Ты точно на порт такты подал?

Как я понял вы про нее RCC->APB2ENR |= RCC_APB2ENR_IOPEEN ( с армами недавно работаю). Да, как положено. JTAG показывает APB2ENR 0х00000040. по даташиту сходится 6 бит в единицу.

В коде все ок, вроде бы. А взять мой пример и переписать его на твой порт?

А где его найти можно? не встречал 7 сегментник к СТМ32

Отличная статья! Спасибо ! Еще бы нарыть библиотеки для работы с строчными LCD (2*16 или больше)!…мож кто встречал?

ПРивет! Вопрос следующий. Как обратно ремапнуть порты в состояние дефолта? Камень stm32f107. Выводы РС10 и РС11 настроены как ТХ и RX USART3. Почитал даташит — думаю это делается с помощью регистра Event control register (AFIO_EVCR). Нужно уточнение правильно ли или нет. Спасибо!

А не подскажите как бы замапить порты, скажем для выдачи 32 бит разом для stm32F4 ?
Скажем есть переменная (x) 32 бит (uint32_t) с каким-либо значением, допустим 0x11111111
И нужно одной командой типа PORTx = x выдать значение в порт. Возможно это сделать ?

Одной командой не получится. Т.к. порты 16ти разрядные. Но думаю можно будет накорячить через указатели и привязать разные половинки к одному значению. Порты то замаплены в память.

Никак нельзя… порты 16ти битные, следовательно, даже на асме будет 2 команды вывода значений в 2 порта по 16 бит..

или я не правильно задачу понял ?

А как заставить порт работать на те вот 50 мгц на STM32F10xxx, пробовал через библиотеки, пробовал писать в сам регистр. Все равно максимум что получилось, это 84 нано сек(10Мгц где то). Сильно не копался в системе тактирования, но может там есть что то такое. Или эти порты могут работать только на вход ? с такой частотой.

А никто 50 мгц и не обещал !
про 50 мгц говориться только в ракурсе крутизны фронта\спада сигнала на выводе…

Подскажите, пожалуйста, только начал тут разбираться с программированием STMок несколлько раз перечитал раздел статьи о GPIOx_LCKR (блокировкой порта) и так толком не понял зачем он нужен, я думал бит LCKK блокирует весь порт от изменений а нифига! 🙂
Вот кусок кода (STM32F103C8):
http://easyelectronics.ru/repository.php?act=view&id=99

PS:
1) хотелось бы поподробней про этот момент.
2) Почему приходится делать столько телодвижений для блокировки? Не проще ли просто записать 1 в бит LCKK?

А у тебя вообще блокировка включилась? Может ты из таймингов выбился? Бит установился в реале?

Так сделано, чтобы случайно не включилась блокировка. Например, при срыве стека. Это очень серьезная фича, потом через такой форватер прогоняется.

Зачем регистр BSRR и записывает и сбрасывает порты? Если сразу запишу в него вот это значение BSRR=0x00010001, что с выходом произойдет? И раз такой уж универсальный регистр этот BSRR, то зачем тогда еще один BRR который только сбрасывает биты? Может какие-то особенности его применения есть?

Вот уж не знаю, надо спросить у разработчиков. Он либо сбросится либо вставится. По моему там сброс более приоритетный. Но не помню, в ДШ было написано, что там приоритетней.

Никаких особенностей я не заметил. Вообще складывается ощущение, что имея такое огромное адресное пространство разработчики изголялись кто во что горазд. Мол а я и так могу и так могу и этак могу.

Доброго времени суток! Помогите разобраться с GPIO у процессора Ambarella тема тут http://3ppc.net/forum/showthread.php?p=521399#post521399
Не могу понять что за режимы SW и HW? Может подскажите?

Растолкуйте пожалуйста такую вещь:
Есть ли разница между режимами входа с подтяжкой к питанию и с подтяжкой к земле? При наличии входного сигнала результат все равно одинаков. У меня только такое объяснение: при отсутствии входного сигнала в одном случае на входе будет +Uп а в другом 0, другого смысла не вижу.
И в чем смысл выхода с открытым стоком, с физической точки зрения? Какое применение этого режима?

Именно так, разное поведение при отсутствии сигнала. А открытый сток это выход позволяющий коротить сигнал на землю и только так. Полезен при работе на шину с подтяжкой. Вроде i2c или 1-wire.

Нигде не нашел информации о нагрузочной способности портов ввода вывода. Какой ток могут выдавать обычные пины и толерантные к 5в? На PB2 если я подключу к линейке светодиодов, ничего не попалю? Там 200 Ом резисторы, т.е. ток

amd gpio driver что это такое

obuv shnurki chb sepiya nastroenie 25685 1280x720

Что значит

990x.top

Простой компьютерный блог для души)

AMD GPIO Driver — что это за драйвер? (AMD GPIO Controller)

200804152525Драйвер интерфейса ввода/вывода (чипсет).

Простыми словами — нужен для корректной работы чипсета (набор логики) на материнской плате.

Без драйвера скорее всего тоже все будет работать, но функции будут только базовые, дополнительные — работать не будут. Всякие технологии, заложенные в чипсет, в том числе которые теоретически могут ускорить работу Windows — будут работать только после установки этого драйвера. Например регулировка частоты в Windows (в настройках Электропитания), автоматическое ее снижение в простое — не будет работать без этого драйвера. Также могут не работать порты USB 3.0/3.1 (точнее работать будут, но как версия 2.0) или некоторые технологии ускорения передачи данных по USB.

Также вы можете встретить драйвер с названием AMD GPIO Driver Promontory — это просто версия для чипсетов серии 300, 400 и X570.

Сам драйвер входит в состав пакета AMD Chipset Drivers. Поэтому можно сделать вывод, что он точно нужен для чипсета. Также в пакет входят и другие — AMD PCI driver, PSP driver, AMD SMbus, Promonotory GPIO Driver. И еще — после установки пакета можно перейти в эту папку (в нее распаковываются дрова):

И установить оттуда схему электропитания Ryzen balanced PowerPlan, которая тоже оптимизирует работу ПК.

После корректной установки драйверов у вас в диспетчере появится устройство AMD GPIO Controller:

200804152154Кстати, выше еще видим AMD PSP Device — это специальное устройство, которое участвует в защите софта AMD, а также используется в работе антивирусов, защищает некоторые компоненты Windows от вирусов. Аналог Intel Management Engine. PS: быстрый способ открыть диспетчер устройств: зажмите Win + R > введите команду devmgmt.msc > нажмите ОК.

Надеюсь информация оказалась полезной. Удачи и добра, до новых встреч друзья!

Amd gpio driver что это такое

AMD опубликовала обновленные версии драйверов для чипсетов AMD «Promontory» серии 300, 400 и X570. Новые драйверы версии 2.04.04.111 теперь поставляются с совершенно новым интерфейсом, перенесенным с Radeon Software Adrenalin 2020. AMD удалила несколько устаревших идентификаторов устройств IDs из IOV и встроенных драйверов контроллера USB 3.0, а также произвела «general system stability improvements».

реклама

Благодаря новому установщику драйверы больше не сталкиваются с кодом «Ошибка 1720» во время установки. Исправлена ошибка из-за которой драйверы не устанавливались в папку отличную от C-drive, ошибка поворота экрана на некоторых мобильных процессорах AMD и редкая ошибка остановки системы с некоторыми процессорами A-серии 7-го поколения (Сокет AM4).

Основные моменты релиза:

Удалены устаревшие идентификаторы устройств из драйвера IOV.

Удалены устаревшие идентификаторы устройств из драйвера USB 3.0.

Общие улучшения стабильности системы.

Установщик может зависнуть во время процесса установки.

Установщик может прервать работу с кодом «Ошибка 1720».

Установка не будет установлена в папку, отличную от C: \.

Устранена проблема с поворотом экрана в некоторых мобильных процессорах AMD.

Редкая остановка системы на APU 7-го поколения AMD A-серии.

Во время установки может появиться всплывающее сообщение установщика Windows.

Перемещение окна установщика во время процесса установки может вызвать мерцание / перемещение окна установщика по экрану.

Не удается открыть файл журнала установки после завершения.

Установщик не может обновить подпакет до последней версии.

AMD Chipset Drivers

dl 260dl 210dl 220

Разработчик: Advanced Micro Devices (США)
Лицензия: Бесплатно
Версия: 3.10.08.506 (Windows 10/11, 64-bit) / 2.17.25.506 (Windows 7, 64-bit) / 18.10.0830 (32-bit)
Обновлено: 2021-10-21
Системы: Windows 11 / 10 / 8.1 / 8 / 7 / Vista / XP (32/64-bit)
Интерфейс: русский / английский
Рейтинг: 5
Ваша оценка:
О программе
Что нового

Новое в версии 3.10.08.506 (21.10.2021):

Новое в версии 2.17.25.506 (02.06.2021):

Исправлены проблемы:

Известные проблемы:

Новое в версии 2.04.28.626 (Windows 7, 64-bit):

Системные требования

AMD Ryzen Chipset Drivers 2.10.13.408

AMD Ryzen Chipset Drivers 2.04.28.626

AMD Chipset Drivers 18.10.0830

Полезные ссылки
Подробное описание

Установка новейшей версии драйвера необходима для правильной работы всех компонентов компьютера, таких как контроллеры PCI Express, SATA и USB, а также для правильного управления питанием и энергосбережением.

Новейший драйвер AMD Chipset Drivers включает следующие компоненты:

Для Windows 11 и 10:

Для Windows 11, 10 и 7:

Для Windows 7:

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

Драйвер виртуальных GPIO с контроллером прерываний на базе QEMU ivshmem для Linux

77860c29e6024e7e818a102b55319904

Трудно недооценить роль GPIO, особенно в мире встраиваемых систем ARM. Помимо того, что это крайне популярный материал для всех руководств для начинающих, GPIO обеспечивают способ для управления многими периферийными устройствами, выступают в качестве источника ценных прерываний, или даже могут быть единственным доступным способом общения с миром для SOC.

Основываясь на собственном скромном опыте, могу сказать, что прерывания далеко не самая освященная тема в сообществе Linux. Из-за своих особенностей, а так же сильной привязки к аппаратной части, все обучающие материалы посвященные прерываниям лишены реального и легко воспроизводимого примера. Данный факт мешает пониманию того, что очень часто прерывания и GPIO неразделимы, особенно в области встраиваемого Linux. Многие начинают верить, что GPIO это очень простая и скучная вещь (которая кстати и стала таковой благодаря подсистеме sysfs).

Даже в примере приведенном в LDD3 (драйвер snull) прерывания эмитируются явным вызовом функции парного устройства. Так же имеются примеры в курсах USFCA (http://cs.usfca.edu/

cruse/cs686s08/), но они используют чужое прерывание, тесно связаны с архитектурой x86 и сильно устарели.

Предлагаемое решение способно решить данные проблемы. С точки зрения пространства пользователя и, во многом, во внутренней реализации драйвер неотличим от большинства «реальных», предоставляющих прерывания портов входов/выходов общего назначения. На данный момент драйвер поддерживает прерывания по переднему или заднему фронту и может быть использован как источник прерываний для других устройств.

ivshmem — разделяемая память Inter-VM

Разработано для совместного использования разделяемой памяти (выделенной на хост-платформе через механизм POSIX shared memory API) множественными процессами QEMU с различными гостевыми платформами. Для того чтобы все гостевые платформы имели доступ к области разделяемой памяти, ivshmem моделирует PCI устройство предоставляя доступ к памяти как PCI BAR.

и проанализировал быстродействие в целом.

В настоящей момент, официально, сопровождение ivshmem никто не осуществляет, тем не менее большой вклад в развитие ivshmem вносят сотрудники Red Hat.

ivshmem может послужить основой для симуляции и отладки многих классов устройств.
В данной статье мы рассматриваем виртуальную pci плату ввода/вывода общего назначения (general-purpose input/output, GPIO), которая так же является источником прерываний, и соответствующий драйвер с предоставлением доступа и управления посредством механизма sysfs.

Для разработки и тестирования использовалась виртуальная плата qemu versatilepb (system ARM).

g>> — команды или вывод выполняемые на гостевой системе.
h>> — на основной.

Пример и оригинальный код

Для начала продемонстрируем оригинальный код, основанный на оригинальном коде ( https://github.com/henning-schild/ivshmem-guest-code ), и модифицированном, в последствии, Siro Mugabi.

В принципе этого вполне достаточно для эмуляции GPIO уже в таком виде. И во многих случаях так и поступали, когда достаточно простого состояния входа или записи в выход, использование sysfs и прерываний предполагают небольшую надстройку на I/O mem.

Реализация

Заметим, что /dev/ivshmem0 и ne_ivshmem_shm_guest_usr.c нам более не нужны, вся работа с устройством со стороны гостевой машины из пространства пользователя (user-space) будет осуществляться средствами интерфейса sysfs.

Прежде чем разметить наше устройство в памяти, хотелось бы отметить, что мы просто дублируем схему применяемую в большинстве gpio драйверов.

Во-первых все входа/выхода gpio разделены на порты, как правило по 8, 16, 32 входа. Каждый порт имеет, как минимум, регистр состояния входов (GPIO_DATA), регистр направления, если переключение in/out поддерживается (GPIO_OUTPUT). Далее (если есть поддержка в самом устройстве), регистр состояния прерываний, регистры прерывания по переднему фронту (rising) и заднему фронту (falling) и по уровню (high и low). Аппаратное прерывание, поставляемое главным контроллером прерываний, как правило, одно на весь порт и делится между всеми входами порта.

Примеры существующих реализаций с комментариями

Sitara am335x

более известна в составе платы beaglebone

Разработчик: Texas Instruments
Документация: AM335x Sitara Processors Technical Reference Manual (page 4865)
Соответствующий ему драйвер gpio: linux/drivers/gpio/gpio-omap.c
Соответствующий заголовок: linux/include/linux/platform_data/gpio-omap.h
Количество входов/выходов: 128 (4 gpio порта — по 32 контакта каждый)

Имя регистра Смещение Имя в драйвере Комментарий
GPIO_IRQSTATUS_0 0x02С OMAP4_GPIO_IRQSTATUS_0 Состояние прерывания для заданного входа
GPIO_IRQSTATUS_1 0x030 OMAP4_GPIO_IRQSTATUS_1 Состояние прерывания для заданного входа
GPIO_IRQSTATUS_SET_0 0x034 OMAP4_GPIO_IRQSTATUS_SET_0 Включает прерывания по заданному входу
GPIO_IRQSTATUS_SET_1 0x038 OMAP4_GPIO_IRQSTATUS_SET_1 Включает прерывания по заданному входу
GPIO_IRQSTATUS_CLR_0 0x03С OMAP4_GPIO_IRQSTATUS_CLR_0 Выключает прерывания по заданному входу
GPIO_IRQSTATUS_CLR_1 0x040 OMAP4_GPIO_IRQSTATUS_CLR_1 Выключает прерывания по заданному входу
GPIO_OE 0x134 OMAP4_GPIO_OE Контролирует состояние вход/выход (in/out)
GPIO_DATAIN 0x138 OMAP4_GPIO_DATAIN Состояние входа/выхода
GPIO_DATAOUT 0x13C OMAP4_GPIO_DATAOUT Задание состояния для выходов (low/high)
GPIO_LEVELDETECT0 0x140 OMAP4_GPIO_LEVELDETECT0 Включение/выключения прерывания для входа по низкому уровню сигнала
GPIO_LEVELDETECT1 0x144 OMAP4_GPIO_LEVELDETECT1 Включение/выключения прерывания для входа по высокому уровню сигнала
GPIO_RISINGDETECT 0x148 OMAP4_GPIO_RISINGDETECT Включение/выключения прерывания для входа по переднему фронту
GPIO_FALLINGDETECT 0x14С OMAP4_GPIO_FALLINGDETECT Включение/выключения прерывания для входа по заднему фронту
GPIO_CLEARDATAOUT 0x190 OMAP4_GPIO_CLEARDATAOUT Переключает соответствующий вход в состояние low
GPIO_SETDATAOUT 0x194 OMAP4_GPIO_SETDATAOUT Переключает соответствующий вход в состояние high

Примечание: GPIO_IRQSTATUS_N также используется для IRQ ACK. Управление дребезгом, а так же питанием выходит за рамки данной статьи.

ep9301

Разработчик: Cirrus Logic
Документация: EP9301 User’s Guide (page 523)
Соответствующий ему драйвер gpio: linux/drivers/gpio/gpio-ep93xx.c
Соответствующий заголовок: linux/arch/arm/mach-ep93xx/include/mach/gpio-ep93xx.h
Количество входов/выходов: 56 (7 портов gpio — по 8 контактов каждый)

Имя регистра Смещение Имя в драйвере Описание
PADR 0x00 EP93XX_GPIO_REG(0x0) Регистр состояние входов/выходов доступен для чтения записи
PADDR 0x10 EP93XX_GPIO_REG(0x10) Контролирует состояние вход/выход (in/out)
GPIOAIntEn 0x9C int_en_register_offset[0] Включает прерывания по заданному входу
GPIOAIntType1 0x90 int_type1_register_offset[0] Задает тип прерывания level/edge
GPIOAIntType2 0x94 int_type2_register_offset[0] Задает high/rising или low/fallingв зависимости от выбранного типа прерываний
GPIOAEOI 0x98 eoi_register_offset[0] Регистр для оповещения об обработанном прерывании
IntStsA 0xA0 EP93XX_GPIO_A_INT_STATUS Регистр состояние прерывания

Примечание:
Из них для доступны 7 портов по 8, 8, 1, 2, 3, 2, 4 входов/выходов причем регистрами прерываний обладают только первый, второй и пятый порты.
В таблице рассмотрен только порт A.
Одной из особенностей ep9301, является то что тип прерываний both на аппаратном уровне не поддерживается, в драйвере происходит переключение в момент срабатывания прерывания. Другая интересная особенность — на порту F каждый контакт имеет свое собственное прерывание.

Bt848

Последний пример: pci плата Bt848, с gpio.

Разработчик: Intel
Документация: Bt848/848A/849A (page 68)
Соответствующий драйвер gpio: linux/drivers/gpio/gpio-bt8xx.c
Соответствующий заголовок: linux/drivers/media/pci/bt8xx/bt848.h
Количество входов/выходов: 24

Bt848 является платой видеозахвата.

Имя регистра Смещение Имя в драйвере Описание
BT848_GPIO_OUT_EN 0x118 BT848_GPIO_OUT_EN Регистр состояние входов/выходов доступен для чтения и записи
BT848_GPIO_DATA 0x200 BT848_GPIO_DATA Контролирует состояние вход/выход (in/out)

Поддержки прерываний нет. Всего два регистра — состояние и настройка in/out.

Размечаем в памяти наше устройство

Для начала выделим место под данные и управление состоянием.

Пусть устройство обладает 8 входами/выходами общего назначения, тогда:

Имя регистра Смещение Имя в драйвере Описание
DATA 0x00 VIRTUAL_GPIO_DATA Регистр состояние входов/выходов доступен для чтения и записи
OUTPUTEN 0x01 VIRTUAL_GPIO_OUT_EN Контролирует состояние вход/выход (in/out)

Краткая справка по интерфейсу gpio

Состояние выхода при переключении

Необходимо отметить параметр int value в функции direction_output, которая обслуживает файл /sys/class/gpio/gpioN/direction, принимающий значение не только “in”/”out”, но так же и “high”/“low”, значения которых передаются как параметр value (этот простой факт, по какой-то причине, редко упоминается в руководствах для начинающих).

Динамическое присвоение int base и наследие ARCH_NR_GPIOS

Исторически, количество GPIO в ядре было ограничено параметром ARCH_NR_GPIOS, по умолчанию равном 256 и, впоследствии увеличенном до 512 (версия 3.18).

Его смысл достаточно прост, в ядре не может быть больше GPIO чем значение параметра, если планируемое количество было больше чем значение по умолчанию, он переопределялся в соответствующем заголовочном файле платформы.

Причиной такого поведения было определение таблицы описаний GPIO как статической и максимальная величина смещения для каждого порта была ограничена:

Порты GPIO и их смещения были жестко определены в файлах описывающих аппаратную часть конкретного SOC, например:

Начиная с версии 3.19 статический массив был заменен на динамические для каждого порта GPIO, выделяемого в фукнции gpiochip_add().

Тем не менее ARCH_NR_GPIOS все еще здесь (на момент версии 4.7) и используется для поиска смещения при динамическом присваивании base.

Определим следующие функции нашего драйвера

Задать соответствующий контакт как вход:

Чтение текущего состояния контакта:

Задать соответствующий контакт как выход:

Задать состояние выхода:

Функция регистрации нашего драйвера как устройства gpio_chip:

vgread и vgwrite это просто обертки для функций iowrite8 и ioread8:

Передача значения gpiobase в качестве параметра при динамической загрузки модуля

Загрузка и тестирования модуля

DATA выставлен, OUTPUTEN выставлен.

Добавляем прерывания

Разметка регистров прерываний и базовая обработка прерывания

Примечание: В виртуальном драйвере рассматриваются только EDGEDETECT_RISE и EDGEDETECT_FALL.

Добавляем следующие регистры:

Имя регистра Смещение Имя в драйвере Описание
INTERRUPT_EN 0x01 VIRTUAL_GPIO_INT_EN Включает прерывания по заданному входу
INTERRUPT_ST 0x02 VIRTUAL_GPIO_INT_ST Регистр состояния прерывания
INTERRUPT_EOI 0x03 VIRTUAL_GPIO_INT_EOI Регистр для оповещения об обработанном прерывании
EDGEDETECT_RISE 0x04 VIRTUAL_GPIO_RISING Включение/выключения прерывания для входа по переднему фронту
EDGEDETECT_FALL 0x05 VIRTUAL_GPIO_FALLING Включение/выключения прерывания для входа по заднему фронту
LEVELDETECT_HIGH NC NOT CONNECTED
LEVELDETECT_LOW NC NOT CONNECTED

За обработку прерывания от pci шины отвечает следующая функция, на данный момент её роль заключается всего лишь в уведомлении об обработанном прерывании:

irq_chip и концепция chained_interrupt

На данный момент для нас является главным тот факт, что порты GPIO предоставляющие прерывания каскадируемые от родительского контроллера прерываний обычная практика в дни современного линукса.

Вот почему часть драйвера GPIO отвечающего за прерывания использует irq_chip. Другими словами такой драйвер использует две подсистемы одновременно: gpio_chip и irq_chip.

Беглый взгляд на подсистему irq дает нам следующую картину:

High-Level Interrupt Service Routines (ISRs) — Выполняет всю необходимую работу по обслуживанию прерывания на драйвере устройства. Например, если прерывание используется для индикации доступных для чтения новых данных, работа ISR будет заключаться в копировании данных в соответствующее место.

Interrupt Flow Handling — Данная подсистема отвечает за особенности в реализации обработок прерываний, таких как срабатывание по уровню сигнала (level) или по фронту (edge).

Срабатывание по фронту (Edge-triggering) происходит при определении, что на линии произошло изменение потенциала. Срабатывание по уровню (Level-triggering), определяется как определенное значение потенциала, при этом изменение потенциала не играет роли.

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

Chip-Level Hardware Encapsulation — Используется для инкапсуляции особенностей реализации работы с аппаратной частью. Данную подсистему можно рассматривать как разновидность “драйвера устройства” для контроллеров прерываний.

Как мы видим ядро берет на себя управление обработкой цепочки прерывания и разницу в реализации типов (по фронту и по уровню), если предоставить соответствующую инфраструктуру.

IRQ Domains

Подсистема IRQ Domain появившееся в патче irq: add irq_domain translation infrastructure позволила отделить локальные для контроллера номера прерываний от номеров прерываний в ядре, предоставив общий массив номеров прерываний. Цитируя официальную документацию: «Сегодня номер IRQ, это просто номер».

До данного обновления аппаратные номера отображались на номерами ядра как 1:1, а каскадирование не поддерживалось. Под аппаратными номерами, понимается локальные для контроллера номера прерывания, которые в нашем случае совпадают с локальными номерами GPIO.

Поскольку наш вектор прерываний достаточно мал, и у нас точно нет интереса в «No map» отображении, наше отображение линейно, фактически номера сопоставляются 1:1 со смещением, разница со старым подходом состоит в том что за присвоение номеров irq и за вычисление смещения отвечает ядро, при этом гарантируется непрерывность выделяемого диапазона.

В каждую функцию интерфейса irq_chip передается указатель на структуру struct irq_data, где irq_data->irq это номер прерывания в ядре linux, a irq_data->hwirq это наш локальный номер прерывания в рамках драйвера. Так же в struct irq_data передается указатель на нашу структуру struct virtual_gpio, что неудивительно.

Связывание irq_chip и gpio_chip

Если бы мы ориентировались на более младшие версии ядра, нам пришлось бы воспользоваться функцией irq_domain_add_simple для отображения наших номер, но с версии 3.15 в патче gpio: add IRQ chip helpers in gpiolib patch нет необходимости напрямую использовать интерфейс IRQ Domain.

Поэтому вместо прямого использования интерфейса IRQ Domain и предоставления инфраструктуры для отображения локальных номеров на глобальные (.map() ops), мы воспользуемся функциями gpiochip_irqchip_add и gpiochip_set_chained_irqchip (зависят от параметра GPIOLIB_IRQCHIP Kconfig).

Прекрасным примером использования и простоты в применении, является драйвер gpio-pl061.

Привязываем наш irq_chip к уже существующему gpio_chip:

handle_edge_irq — это один из встроенных обработчиков потока, который берет на себя управление цепочкой прерывания по фронтам.

Примечание: прерывания по фронтам является наиболее распространенным. Главное отличие от прерываний по уровню заключается как раз в управлении цепочкой, прерывание по уровню маскируется в ядре сразу после получения.

Вызовом функции gpiochip_set_chained_irqchip мы сообщаем ядру, что наш irq_chip использует прерывание от PCI шины и наши прерывания каскадируются от pdev->irq.

Доработаем наш обработчик, чтобы он генерировал прерывания в зависимости от состояния VIRTUAL_GPIO_INT_ST:

irq_find_mapping — вспомогательная функция для трансляции локального номера входа в глобальный номер прерывания.

Собираем все вместе

Прежде всего, отметим, что интерфейс irq_chip нашего драйвера, выглядит следующим образом:

Функция ack() всегда тесна связана с аппаратной спецификой контроллера. Некоторым устройствам, например требуется подтверждение обработки запроса прерывания, прежде чем могут быть обслужены последующие запросы.

В нашем случае в программе vg_get_set – используется достаточно грубая эмуляция регистра eoi. После выставления флага статуса прерывания, в цикле постоянно опрашивается eoi регистр. Когда бит входа уведомления о прерывании выставляется драйвером, происходит обнуление регистра eoi и снятие бита статуса прерывания на входе.

Маскирование и демаскирование производится записью соответствующего значения в регистр INTERRUPT_EN.

irq_type позволяет задать тип триггера — на текущий момент в ядре определены следующие типы:
IRQ_TYPE_NONE — тип не задан
IRQ_TYPE_EDGE_RISING — по переднему фронту
IRQ_TYPE_EDGE_FALLING — по заднему фронту
IRQ_TYPE_EDGE_BOTH — по переднему и заднему фронту
IRQ_TYPE_LEVEL_HIGH — по высокому уровню
IRQ_TYPE_LEVEL_LOW — по низкому уровню

Тестирование и результаты

Для тестирования передачи информации о прерываниях в user space, воспользуемся специально написанной утилитой vg_guest_client. Согласно документации по gpio_sysfs, “Если вы используете select для отслеживания событий, задайте файловый дескриптор (входа) в exceptfds”.

Подготавливаем входы к работе при помощи sysfs:

Примечание: gpio на подавляющем большинстве устройств по умолчанию инициализируются как входы.

Цепочка вызовов от нашего обработчика прерывания к уведомлению pselect:

Заключение

Данная статья подразумевалась мной, как базовая для материала, который сложно, или даже невозможно, представить без какого-либо общего вступления. Qemu в паре с ivshmem послужили отличным и понятным базисом для этой цели. Причиной выбора этой конкретной связки является наличие вменяемой документации и прозрачности использования.

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

Сам драйвер, несмотря на безусловную образовательную ценность, далек от идеала в контексте современного ядра. Для подобного простого драйвера стоит использовать generic-gpio драйвер, созданный, чтобы избежать похожего, повторяющегося кода для mmio gpio драйверов, использование которого, правда, не так очевидно. Обработку прерываний можно было бы сделать более элегантной, а значения смещений регистров лучше хранить в структуре драйвера.

Так же нельзя упускать из виду последние изменения в gpiolibsysfs gpio теперь является устаревшей. Новый основанный на ioctl интерфейс для gpiolib на пути становления как новый стандарт для общения с GPIO. Но младшие версии еще долго будут использоваться, к тому же никто не собирается на данный момент убирать из ядра старый интерфейс. У меня например до сих пор есть устройства успешно работающие на версии ядра 2.6.34.

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

Ваш адрес email не будет опубликован.