LuckFox Pico GPIO |
![]() |
Добавил(а) microsin |
В этой статье (перевод документации [1]) описывается, как использовать файловую систему sysfs для получения доступа и управления портами GPIO (General-Purpose Input/Output). [GPIO Subsystem] GPIO это тип универсального вывода, который может управляться программно микроконтроллером (MCU) или CPU. Такой порт может выполнять различные функции ввода/вывода, включая детектирование уровней логического сигнала (при работе в режиме входа) или управления цифровыми устройствами (при работе в режиме вывода. На Linux выводы GPIO могут экспортироваться на рабочее пространство пользователя (user space) и управляться через файловую систему sysfs, благодаря чему выводы GPIO можно использовать для различных целей, таких как последовательный обмен данными, I2C, сетевые коммуникации, детектирование напряжения и других функций. В Linux есть выделенная подсистема драйвера GPIO (GPIO subsystem driver framework) для работы с устройствами GPIO. Через эту подсистему можно просто работать с выводами GPIO через программирование CPU. Этот фреймворк драйвера поддерживает использование выводов для базовых функций ввода и вывода, а также поддерживает детектирование прерываний. Более детальную информацию о подсистеме GPIO можно найти в директории < Linux Kernel Source>/Documentation/gpio. [GPIO Control (Shell)] При экспортировании выводов GPIO в user space обычно нужны номера выводов. Эти номера можно определить по диаграммам интерфейса соответствующих плат. Например, имя вывода 4 платы будет GPIO1_C7_d, и соответствующий номер вывода 55. Цоколевка выводов LuckFox Pico: Цоколевка выводов LuckFox Pico Mini A/B: Цоколевка выводов LuckFox Pico Plus: Цоколевка выводов LuckFox Pico Pro/Max: Цоколевка выводов LuckFox Pico Ultra/Ultra W: Вычисление номеров выводов. Номера выводов соответствующих портов GPIO помечены на картинках выше, и вы можете либо их использовать напрямую, либо вычислять их номера следующим образом: • GPIO поделены на 5 банков: GPIO0 .. GPIO4, и у каждого банка есть 4 группы. В результате получается 32 вывода: A0 .. A7, B0 .. B7, C0 .. C7, D0 .. D7. • GPIO именуются в формате GPIO{bank}_{group}{X}, как показано ниже: GPIO0_A0 .. GPIO0_A7 GPIO1_A0 .. GPIO0_A7 GPIO1_D0 .. GPIO0_D7 • Номер вывода GPIO можно вычислить по следующей формуле: pin = bank * 32 + number Номер группы GPIO: number = group * 8 + X Таким образом: pin = bank * 32 + (group * 8 + X) В качестве примера рассмотрим GPIO1_C7_d, где: bank: 1 Таким образом, номер порта GPIO1_C7_d будет: 1 x 32 + (2 x 8 + 7) = 55. Директория устройства GPIO. В директории /sys/class/gpio каждое устройство GPIO имеет собственную папку. Имена папок содержат gpio (или gpiochip), за которым идет номер. Например, /sys/class/gpio/gpio55 представляет вывод номер 55, который именуется как GPIO1_C7_d. Для проверки вы можете использовать команду: [root@luckfox ]# ls /sys/class/gpio
export gpiochip0 gpiochip128 gpiochip32 gpiochip96 unexport
Атрибуты устройства GPIO. В этих директориях устройств вы можете найти файлы управления, связанные выводами GPIO, включая направление (direction), значение (value) и прерывания, вместе с другими файлами. Каждая директория устройства GPIO содержит набор файлов атрибута, используемых для конфигурирования и управления выводами GPIO. Вы можете использовать следующие команды в директории устройства GPIO. 1. Просмотр файлов атрибута устройства GPIO 55: # cd /sys/class/gpio
# echo 55 > /sys/class/gpio/export
# cd gpio55
# ls
value power subsystem active_low
uevent edge device direction
2. Файлы атрибутов. Используя файлы атрибутов, вы можете просто конфигурировать и управлять выводами GPIO, чтобы адаптировать их к различным сценариям применения и их требованиям. Некоторые ключевые атрибуты включают: • Направление (direction): in для порта, сконфигурированного на вход, out для порта, сконфигурированного на выход. Управление уровнями GPIO. Файлы атрибутов устройства работают как интерфейс для управления функциональными параметрами. Для каждой операции записи в файл /sys/class/gpio/gpio55/value происходит запуск кода драйвера, который модифицирует уровень на выходе GPIO pin 55 в соответствие со значением, записываемы в качестве параметра. При каждой операции чтения файла /sys/class/gpio/gpio55/value произойдет запуск кода драйвера для обновления текущего уровня GPIO pin 55 в соответствие с содержимым файла. 1. Экспорт GPIO 55 в user space: # echo 55 > /sys/class/gpio/export
2. Чтение уровня GPIO1_C7_d: # echo 55 > /sys/class/gpio/export
# echo in > /sys/class/gpio/gpio55/direction
# cat /sys/class/gpio/gpio55/value
3. Управление уровнем GPIO1_C7_d: # echo out > /sys/class/gpio/gpio55/direction
# echo 1 > /sys/class/gpio/gpio55/value
# echo 0 > /sys/class/gpio/gpio55/value
4. Отмена экспорта GPIO 55 из user space: # echo 55 > /sys/class/gpio/unexport
[Управление GPIO программой Python] Следующая программа разрешает управление уровнями выводов GPIO и чтение их уровней. from periphery import GPIO Конфигурирование направления GPIO. Следующий фрагмент кода использует библиотеку periphery, чтобы открыть два вывода GPIO в программе Python. Write_GPIO используется для вывода, и Read_GPIO для ввода. Write_GPIO = GPIO(Write_Pin, "out") Read_GPIO = GPIO(Read_Pin, "in") Управление уровнем на выходе. Следующий фрагмент кода использует объект Write_GPIO для записи логического значения True в вывод GPIO, чтобы его выход перешел на уровень лог. 1. Запись логического значения False в вывод GPIO установит уровень на выходе в лог. 0. Write_GPIO.write(True) Чтение уровня вывода. Следующий код считывает и состояние вывода объекта Read_GPIO и печатает его. Read_GPIO.read() возвратит состояние вывода (True для лог. 1, False для лог. 0). pin_state = Read_GPIO.read() Для редактирования кода программы используйте редактор vi или nano. # nano gpio.py
Скопируйте код в буфер обмена, вставьте в редакторе и сохраните файл. Запустите программу командой: # python3 gpio.py
[Управление GPIO программой C] В предыдущих секциях было продемонстрировано управление GPIO с помощью команды echo и программы Python. Как обычно, вы можете использовать редактор vi или nano для модификации файлов, однако нужно обращать внимание на права пользователя при внесении изменений. Кроме того, мы можем использовать библиотечные C-функции или системные вызовы, чтобы читать и записывать файлы устройств для управления устройствами. Обратите внимание, что для запуска программ на определенных встраиваемых системах часто необходимо использовать инструменты кросс-компиляции, чтобы скомпилировать код и сгенерировать исполняемые файлы, которые можно запустить на определенной целевой плате. Давайте вместе рассмотрим определенные шаги по реализации. 1. Следующая программа может управлять выводами ножек портов GPIO. #include < stdio.h> Рассмотрим эту программу подробнее. Экспорт вывода в User Space. Следующий фрагмент кода считает введенный пользователем номер вывода, откроет файл /sys/class/gpio/export и запишет в него это число, благодаря чему произойдет операция экспорта для вывода GPIO. printf("Please enter the GPIO pin number: "); scanf("%d", &gpio_pin); Конфигурирование направления GPIO. Следующий фрагмент кода откроет файл /sys/class/gpio/gpiox/direction и запишет в него "out", чтобы установить этот вывод GPIO в режим выхода. Если вы хотите сконфигурировать его как вход, то нужно записать вместо этого "in". char direction_path[50]; snprintf(direction_path, sizeof(direction_path), Управление уровнем выхода GPIO. Этот код используется для управления выходным уровнем логики вывода GPIO. Сначала вам нужно открыть файл /sys/class/gpio/gpiox/value, который используется для установки уровня на выводе GPIO. В цикле мы управляем выходом, записывая в этот файл последовательно "1" и "0". Затем мы используем команду cat для проверки, что значение, сохраненное в файл, было успешно записано. Обратите внимание, что стандартная библиотека C обычно использует буферы для повышения эффективности операций с файлами, вместо того, чтобы немедленно записывать данные в файл при каждой операции записи. Это значит, что даже если вы используете fprintf для записи данных, то на самом деле данные могут просто попадать в буфер вместо того, чтобы немедленно записываться в файл. Если вы хотите, чтобы эти данные были немедленно записаны в файл, то можете использовать функцию fflush для "слива" буфера, что заставит данные буфера записаться в файл, либо можете использовать способ последовательных операций fopen -> fprintf -> fclose для каждой записи. char value_path[50]; Отмена экспорта вывода. Следующий код откроет файл /sys/class/gpio/unexport и запишет в него номер порта, чем достигается отмена операции экспорта для этого вывода GPIO. FILE *unexport_file = fopen("/sys/class/gpio/unexport", "w"); [Кросс-компиляция программы C] 1. Укажите Cross-Compilation Tool. Сначала вам нужно добавить путь до утилит кросс-компиляции (cross-compilation) в системную переменную PATH, чтобы можно было запускать утилиты кросс-компиляции из любого места. Для этого вы можете добавить следующую строку в свой файл конфигурации шелла (обычно это файл ~/.bashrc, или ~/.bash_profile, или ~/.zshrc, в зависимости от вашего шелла). Обратите внимание, что путь после PATH= должен указывать на директорию, где находится исполняемый файл кросс-компилятора arm-rockchip830-linux-uclibcgnueabihf-gcc. Этот файл должен находиться в следующей папке: < директория SDK>/tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf/bin/ Откройте в редакторе текста конфигурационный файл шелла: $ vi ~/.bashrc
Добавьте путь до утилиты кросс-компилятора в системную переменную PATH так, чтобы он был первым, сразу после знака равно. При этом замените < SDK Directory> на реальный путь вашего SDK, такой как /home/luckfox/luckfox-pico/. export PATH=< SDK Directory>/tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf/bin:$PATH Перезагрузите файл конфигурации для применения изменений: $ source ~/.bashrc
2. Скомпилируйте программу с помощью кросс-компилятора: $ arm-rockchip830-linux-uclibcgnueabihf-gcc gpio.c -o gpio
3. После успешной компиляции в текущей директории появится файл gpio, который может быть запущен на целевой плате. $ ls
gpio gpio.c
4. Чтобы можно было запустить скомпилированную программу на целевой плате, необходимо её скопировать в файловую систему платы. Для этого можно использовать SCP, TFTP или ADB. Вот так это можно сделать с помощью ADB. Следующая команда копирует исполняемый файл gpio в каталог /oem/gpiotest на целевой системе: $ adb push gpio /oem/gpiotest
5. Для запуска программы запустите шелл платы, например с помощью ADB: $ adb shell
[root@luckfox ~]# cd /oem/gpiotest
[root@luckfox gpiotest]# ls
gpio
Измените права доступа на файл gpio, чтобы он стал исполняемым: [root@luckfox gpiotest]# chmod +x gpio
Следующая команда запустит нашу тестовую программу: [root@luckfox gpiotest]# ./gpio
Please enter the GPIO pin number: 55
1
0
1
0
1
[Модификация Device Tree] Выводы 55 и 54 в программе можно использовать напрямую без модификации device tree. Если нам нужно сконфигурировать другие выводы как general-purpose IO, то нужно изменить device tree. 1. Модификация файла Device Tree. Файлы конфигурации *.mk устройств разных поддерживаемых плат SDK находятся в папке < SDK directory>/project/cfg/BoardConfig_IPC: luckfox-pico$ ls -1 project/cfg/BoardConfig_IPC
Эти файлы содержат главным образом конфигурационные параметры разных моделей плат Luckfox Pico, настраивая такие их аспекты, как целевая архитектура (target architecture), загрузочный носитель (boot medium), конфигурации загрузчика (Uboot) и ядра (kernel), настройки разделов (partition settings). Структура директорий SDK следующая: ├── build.sh -> project/build.sh ---- скрипт компиляции SDK Экспортируемая переменная окружения RK_KERNEL_DTS указывает файл исходника для дерева устройств (Device Tree Source, DTS), который использует ядро (kernel). Если взять в качестве примера плату Luckfox Pico и открыть её файл конфигурации BoardConfig-EMMC-NONE-RV1103_Luckfox_Pico-IPC.mk, то мы можем увидеть, что переменная окружения RK_KERNEL_DTS указывает на файл rv1103g-luckfox-pico.dts (находится в каталоге sysdrv/source/kernel/arch/arm/boot/dts корня SDK). 2. Определение GPIO. Обычно определение GPIO требует добавления двух секций кода. Обратите внимание, что кнопка опрашивается по активному уровню лог. 0, и вход должен иметь подтяжку к верхнему уровню (pull-up). Ниже показан пример, как добавить определение вывода GPIO1_C7_d в device tree. Добавляемые куски кода: /{ 3. Комментирование функции вывода периферийного устройства. Запрет функции периферийного устройства вывода достигается комментированием соответствующего узла конфигурации в файле device tree. Ниже показан пример, как запретить функцию ШИМ (PWM) на выводе GPIO1_C7_d. 4. Компиляция ядра. SDK компилируется путем выбора ветвей для LuckFox Pico, LuckFox Pico Mini A, LuckFox Pico Mini B, LuckFox Pico Plus и LuckFox Pico Pro/Max. Выполните команду, и в ответ на запрос выбора платы введите её номер в меню: ~/luckfox-pico$ ./build.sh lunch
5. Рекомпиляция ядра: ~/luckfox-pico$ ./build.sh kernel
[Повторная прошивка firmware] 1. После успешной компиляции kernel сгенерированные файлы можно найти в директории < SDK directory>/output/image. $ ls output/image/
boot.img download.bin env.img idblock.img oem.img rootfs.img sd_update.txt
tftp_update.txt uboot.img update.img userdata.img
2. Для загрузки с карты заново создайте карту SD. Для загрузки из SPI NAND FLASH используйте команду прошивки: $ cd output/image/
$ sudo upgrade_tool uf update.img
[Ссылки] 1. LuckFox Pico GPIO site:wiki.luckfox.com. |