最近几年国产化芯片的使用如火如荼,部分国产手册说明杂且描述不清,尤其是一些映射关系使用文字描述非常不直观。博主在使用GPIO功能输出的时候反复看了几遍再去尝试控制耗费了不少时间。现结合相关文档总结GPIO映射表格,方便读者使用。
1、 GPIO引脚确定方法
GPIO 引脚编号 = 控制器对应的基值 + 控制引脚偏移值
对于 FMQL 来说, PS 的 4 个 GPIO 控制器对应信息如下
GPIO A 控制 MIO 引脚[31:0],对应基地址 0xE0003000
GPIO B 控制 MIO 引脚[53:32] ,对应基地址 0xE0003100
GPIO C 控制 EMIO 引脚信号[31:0] ,对应基地址 0xE0003200
GPIO D 控制 EMIO 引脚信号[63:32] ,对应基地址 0xE0003400
从上图可以直观看出基址对应的号。
基址 | 对应管脚号 | GPIO组 |
0xE0003000 | 480 | GPIO A |
0xE0003100 | 458 | GPIO B |
0xE0003200 | 426 | GPIO C |
0xE0003400 | 394 | GPIO D |
根据算法可直接列出MIO和EMIO映射关系。
MIO | 对应管脚号 | GPIO组 |
0~31 | 480+(0-31) | GPIO A |
32-53 | 458+(0-21) | GPIO B |
EMIO | 对应管脚号 | GPIO组 |
0~31 | 426+(0-31) | GPIO C |
32-63 | 394+(0-31) | GPIO D |
2、 GPIO 的使用方法
从上面知道了 linux 内核 gpio 编号后,就可以把对应 gpio 接口导出到 linux 用户空间,然后
在 linux 的用户空间使用命令或者在应用程序中使用文件操作的方式操作 gpio 了。
ls -l /sys/class/gpio/, 可以发现其中包含有两个文件 export、 unexport 和若干
gpiochipN 类型文件夹。
export :用于将指定编号的引脚导出,作为 GPIO 使用
unexport :用于将导出的 GPIO 删除掉
gpiochipN :当前芯片中包含的 GPIO 控制器
举例说明:
1、添加设备接口 gpio500(使用MIO20,得出对应管脚编号为480+20=500)
输入如下命令, 可以发现,目录下出现了 gpio500。
echo 500 > /sys/class/gpio/export
direction: 设置输出还是输入模式
设置为输入: echo “in” > direction
设置为输出: echo “out” > direction
value : 输出时,控制高低电平;输入时,获取高低电平
高电平: echo 1 > value
低电平: echo 0 > value
edge : 控制中断触发模式,引脚被配置为中断后可以使用 poll() 函数监听引脚
非中断引脚: echo “none” > edge
上升沿触发: echo “rising” > edge
下降沿触发: echo “falling” > edge
边沿触发: echo “both” > edge
2、 删除 gpio500, 输入如下命令:
echo 500 > /sys/class/gpio/unexport
3、 用户态使用文件操作的方式操作 gpio
例如: 监控 gpio500 的电平变化步骤如下
(1)、 shell 中输入如下命令
echo “in” > /sys/class/gpio/gpio500/direction
echo “both” > /sys/class/gpio/gpio500/ edge
(2)、在应用程序中对”/sys/class/gpio/gpio500/value”执行 select/poll 操作,代码如下:
#include <stdio.h>
#include <fcntl.h>
#include <poll.h>
#include <unistd.h>
int main()
{
struct pollfd fds[1];
char buffer[16];
int len;
int fd=open("/sys/class/gpio/gpio500/value",O_RDONLY);
if(fd<0)
{
perror("open '/sys/class/gpio/gpio500/value' failed!\n");
return -1;
}
fds[0].fd=fd;
fds[0].events=POLLPRI;
while(1)
{
if(poll(fds,1,0)==-1)
{
perror("poll failed!\n");
return -1;
}
if(fds[0].revents&POLLPRI)
{
if(lseek(fd,0,SEEK_SET)==-1)
{
perror("lseek failed!\n");
return -1;
}
if((len=read(fd,buffer,sizeof(buffer)))==-1)
{
perror("read failed!\n");
return -1;
}
buffer[len]=0;
printf("%s",buffer);
}
}
return 0;
}
欢迎大家指正!若描述有误,请私信或留言告知!