前言
這是前3篇:
Linux 中的三大類驅動:字符設備驅動、塊設備驅動和網絡設備驅動. LED, GPIO屬於字符設備, 驅動在買的板子上一般廠家都已改好, 當然如果擴展或者自己畫新板子的話可以改設備樹. 本篇介紹下GPIO, 以LED, GPIO子系統爲例, 採用板子出廠配置的系統, 暫不涉及設備樹的改動.
LED
終端
# 查看LED
root@mys6ull14x14:~# ls /sys/class/leds
cpu mmc0:: user
# 米爾的MYS-6ULX板子上有3顆LED, 分別命名爲cpu, mmc0::, user
# user是閒置的LED, 用這個
# 查看LED設備屬性
root@mys6ull14x14:~# ls /sys/class/leds/user
brightness max_brightness subsystem uevent
device power trigger
# 這裏主要用brightness, 取值範圍0~brightness
# 如果不支持多級亮度, brightness取0燈滅, 非0燈亮(如1, 255)
# 點亮LED, 對應米爾MYS-6ULX板子上的D12
root@mys6ull14x14:~# echo 1 > /sys/class/leds/user/brightness
# 熄滅LED
root@mys6ull14x14:~# echo 0 > /sys/class/leds/user/brightness
腳本
此處可有腳本gpio_led.sh:
#!/bin/bash
echo "GPIO LED Test"
LED=/sys/class/leds/user/brightness
while (true)
do
echo 1 > $LED
sleep 1
echo 0 > $LED
sleep 1
done
加權限sudo chmod 777 gpio_led.sh
, 執行./gpio_led.sh
, 可以看到板子上LED間隔1s閃爍.
C語言
直接用系統調用的方式, 新建文件main.c:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#define USER_LED_DEV_PATH "/sys/class/leds/user/brightness"
int main()
{
int led_fd;
char cmd[128] = {0};
printf("user led demo\r\n");
led_fd = open(USER_LED_DEV_PATH, O_WRONLY);
if (led_fd < 0)
{
printf("Fail to open %s device\n", USER_LED_DEV_PATH);
exit(1);
}
while (1)
{
sprintf(cmd, "echo 1 > %s", USER_LED_DEV_PATH);
system(cmd);
sleep(1);
sprintf(cmd, "echo 0 > %s", USER_LED_DEV_PATH);
system(cmd);
usleep(1000 * 300);
}
close(led_fd);
return 0;
}
交叉編譯arm-linux-gnueabihf-gcc -o led1 led1.c
, 執行./led1
, 可以看到板子user LED亮1s滅300ms循環…
while中也可以改成write的方式:
while (1)
{
write(led_fd, "255", 3); //3: 3個字節
sleep(1);
write(led_fd, "0", 1);
usleep(1000 * 300);
}
交叉編譯執行, 效果是一樣的.
GPIO子系統
與LED子系統類似,Linux提供了GPIO子系統驅動框架,使用該驅動框架可以把CPU的GPIO引腳導出到用戶空間,用戶通過訪問/sys文件系統進行控制,GPIO子系統支持把引腳用於基本的輸入輸出功能,其中輸入功能還支持中斷檢測。
米爾的MYS-6ULX板子上留出了兩個gpio, gpio5和gpio9:
這裏以37引腳的GPIO_9爲例, 接上萬用表:
root@mys6ull14x14:~# ls /sys/class/gpio
export gpiochip0 gpiochip32 gpiochip96
gpio131 gpiochip128 gpiochip64 unexport
# 向export文件寫入GPIO編號可以向內核申請將該編號的GPIO導出到用戶空間
# 注意: 板子復位後設置無效
# 反操作是unexport
root@mys6ull14x14:~# echo 9 > /sys/class/gpio/export
# 查看導出的gpio, 發現多了gpio9
root@mys6ull14x14:~# ls /sys/class/gpio
export gpio9 gpiochip128 gpiochip64 unexport
gpio131 gpiochip0 gpiochip32 gpiochip96
# 查看gpio9屬性
root@mys6ull14x14:~# ls /sys/class/gpio/gpio9
active_low direction power uevent
device edge subsystem value
# 使用GPIO子系統的設備則可以在用戶空間靈活配置作爲輸入、輸出或中斷模式
# 查看gpio9的方向, 下面顯示是輸入
root@mys6ull14x14:~# cat /sys/class/gpio/gpio9/direction
in
# 設置gpio9爲輸出
root@mys6ull14x14:~# echo out > /sys/class/gpio/gpio9/direction
# gpio9輸出高電平, 可用萬用表檢測米爾MYS-6ULX板子J2的37引腳, 應爲3.3V
root@mys6ull14x14:~# echo 1 > /sys/class/gpio/gpio9/value
# gpio9輸出低電平
root@mys6ull14x14:~# echo 0 > /sys/class/gpio/gpio9/value
# 取消gpio9的導出
root@mys6ull14x14:~# echo 9 > /sys/class/gpio/unexport
再回頭看下米爾MYS-6ULX板子GPIO_9的定義, 實際引腳是GPIO1_IO09:
引用下 控制蜂鳴器(GPIO子系統)中的介紹:
i.MX6ULL芯片GPIO引腳名格式通常爲GPIOn_IOx,如GPIO1_IO09,其 中n是端口號,x爲該組端口的引腳號,開發板採用的芯片有1-5組端口,每組端口包含的引腳從0-31不等。
export文件使用的編號index與GPIO引腳名的轉換關係:index = GPIOn_IOx = (n-1)*32 + x
, 所以GPIO1_IO09對應的index是(1-1)*32+9 = 9
, 直接在原理圖中命名爲GPIO_9.
用C語言編寫文件gpio.c:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#define GPIO_INDEX "9"
int main()
{
int fd;
//echo 9 > /sys/class/gpio/export
fd = open("/sys/class/gpio/export", O_WRONLY);
if (fd < 0)
{
return 1;
}
write(fd, GPIO_INDEX, strlen(GPIO_INDEX));
close(fd);
//echo out > /sys/class/gpio/gpio9/direction
fd = open("/sys/class/gpio/gpio" GPIO_INDEX "/direction", O_WRONLY);
if (fd < 0)
{
return 2;
}
write(fd, "out", strlen("out"));
close(fd);
fd = open("/sys/class/gpio/gpio" GPIO_INDEX "/value", O_WRONLY);
if (fd < 0)
{
return 3;
}
while (1)
{
write(fd, "1", 1);
sleep(2);
write(fd, "0", 1);
sleep(2);
}
close(fd);
return 0;
}
交叉編譯: arm-linux-gnueabihf-gcc -o gpio1 gpio.c
, 嵌入式板子上執行./gpio1
, 可以看到萬用表3.3V和0V之間以2s間隔切換.
微信公衆號
歡迎掃描關注我的微信公衆號, 及時獲取最新文章: