新闻  |   论坛  |   博客  |   在线研讨会
Zynq7000 Linux 学习第一课 GPIO控制
lolo84 | 2017-07-20 16:01:08    阅读:30002   发布文章

Zynq7000 Linux 学习第一课

概述:学习zynq linux,完成第一个linux下的应用程序编写,本文主要针对linux如何控制gpio做详细的讲解;


1. 设备树

1.1 设备树概念概述

设备树是linux 内核版本v2.6.23 以后才开始支持的,为什么要引出设备树的概念,是因为linux操作系统支持多种CPU架构下运行,但是每个处理器厂家的cpu支持的接口各有不同,为了兼容各个平台,linux在内核中做了很多mach_xxx的工作,这使得linux的内核越来越庞大,为了改变这种局面,所以引出了设备树的概念,u-boot在启动的时候向内核传递处理器的详细信息,通过dtb来实现;这个就是以二进制形式呈现的cpu设备信息;需要说明的是每个版本对应的设备树描述方式会有所不同,对应的DTC执行方式也会不一样,所以生成设备树一定要选择跟edk tool相匹配的dtc BSP去生成dts文件;

1.2 zynq gpio类型分类

zynq有三种GPIO , a. MIO  b. EMID c.AXI-GPIO

MIO是PS直接下挂并引出的,EMIO也是PS直接下挂,但是引出使用需要在.xdc文件中做约束,占用PL的io管教

AXI-GPIO 是硬件逻辑生成的GPIO控制单元,通过AXI-lite总线下挂到PS端;

该例程描述的是AXI-gpio的控制 ;

1.3 AXI-gpio 设备树生成的范本

我使用的linux内核版本是 linux-xlnx-xilinx-v2016.3  , vivado sdk生成的AXI-GPIO的格式如下,


axi_gpio_0: gpio@41200000 {

#gpio-cells =;

compatible = "xlnx,xps-gpio-1.00.a";

gpio-controller ;

reg =;

xlnx,all-inputs =;

xlnx,all-inputs-2 =;

xlnx,all-outputs =;

xlnx,all-outputs-2 =;

xlnx,dout-default =;

xlnx,dout-default-2 =;

xlnx,gpio-width =;

xlnx,gpio2-width =;

xlnx,interrupt-present =;

xlnx,is-dual =;

xlnx,tri-default =;

xlnx,tri-default-2 =;

};

因为axi-gpio是通过axi-lite总线下挂到PS端的,所以其实这个设备树是下挂在amba_pl 设备下的,有关如何生成设备树的步骤会在其他文章中做详解;


2. 驱动加载

2.1 默认的内核选项中是没有开启对xilinx axi-gpio的支持的,需要在内核中打开对应的选项;

如下



参照上图,驱动的位置在 Device Drivers -> GPIO Support -> Memory mapped GPIO drivers

Xilinx GPIO support 选项在本例子中选择编程模块加载的方式,对应的选项为,

在内核根目录下运行  make modules ,会生成一个  gpio-xilinx.ko 的驱动模块文件,把这个文件copy到SD卡中,在板子进入系统后手动加载;

2.2 加载axi-gpio过程

a.挂载sd卡到系统目录 /mnt下面,命令 为  mount /dev/mmcblk0p1 /mnt/

b.打开/mnt目录,看到下面有按照2.1步骤生成的gpio-xilinx.ko 文件,运行 insmod gpio-xilinx.ko加载驱动

c.这个时候就会出现 XGpio: /amba_pl/gpio@41200000: registered, base is 902 代表axi-gpio被成功加载;

3.png

d. 打开/sys/class/gpio目录会看到gpiochip902 gpiochip906 这两个GPIO chip


4.png


2.3 gpiochip讲解

linux下对gpio是按照组来管理的,在这个例子中看到的gpiochip为gpiochip902 gpiochip906 , 这两个chip是怎么来的困扰了我好久,简单结说是按照驱动加载的顺序从上而下自动生成的,

linux-xlnx-xilinx-v2016.3 采用的内核版本为4.6.0 , 可以通过命令uname -a 来查看内核版本

5.png

这个内核版本默认是有1024个GPIO的,按照注册的先后自动生成gpiochip , zynq7000 PS端共有MIO EMIO共计118 个,所以这个906刚好是1024-118 = 906 ,906就是这么来的; 例程中的

axi-gpio共计有4个gpio ,所以gpiochip902 中的902 = 906-4 ;后续有增加会相应的增加gpiochip ;

这些信息可以在 /sys/class/gpio/gpiochipxxx 下面的ngpio看到,命令为 走到/sys/class/gpio/gpiochipxxx 目录下 cat ngpio  ;


6.png



3 命令行测试gpio是否正常工作

3.1 完成了设备树及驱动加载,接下来就可以通过简单的命令行来操作axi-gpio了 ;

3.2 打开 /sys/class/gpio ,输入命令 echo  902 > export ,这样就会看到路径下多出来一个gpio902 ,这个就是我们可以直接用来操作的gpio设备了,需要注意的是902 > export 中间都有空格,如果没有空格不能正确的生成gpio902 文件夹;

7.png

3.3 对于gpiochip902中一共管理着4个gpio , 你要操作哪一个gpio 就需要相应的输入命令

echo  902 > export ,echo  903 > export ,echo  904 > export ,echo  905 > export ,gpio number从chip的base开始,不能超出范围;

3.4 打开你需要控制的gpio会看到下面有value 、direction 等文件,直接操作这个文件就可以控制gpio了;

8.png

3.5 例程中的gpio是直接接到led灯上的,所以设置成输出控制高低就可以看到led的亮和灭,命令如下

echo out > direction

echo 1 > value

echo 0 > value


3.5.png




4. 完整的linux下应用程序代码


// The specific GPIO being used must be setup and replaced thru

// this code.  The GPIO of 240 is in the path of most the sys dirs

// and in the export write.

//

// Figuring out the exact GPIO was not totally obvious when there

// were multiple GPIOs in the system. One way to do is to go into

// the gpiochips in /sys/class/gpio and view the label as it should

// reflect the address of the GPIO in the system. The name of the

// the chip appears to be the 1st GPIO of the controller.

//

// The export causes the gpio240 dir to appear in /sys/class/gpio.

// Then the direction and value can be changed by writing to them.


// The performance of this is pretty good, using a nfs mount,

// running on open source linux, on the ML507 reference system,

// the GPIO can be toggled about every 4 usec.


// The following commands from the console setup the GPIO to be

// exported, set the direction of it to an output and write a 1

// to the GPIO.

//

// bash> echo 240 > /sys/class/gpio/export

// bash> echo out > /sys/class/gpio/gpio240/direction

// bash> echo 1 > /sys/class/gpio/gpio240/value


// if sysfs is not mounted on your system, the you need to mount it

// bash> mount -t sysfs sysfs /sys


// the following bash script to toggle the gpio is also handy for

// testing

//

// while [ 1 ]; do

//  echo 1 > /sys/class/gpio/gpio240/value

//  echo 0 > /sys/class/gpio/gpio240/value

// done


// to compile this, use the following command

// gcc gpio.c -o gpio


// The kernel needs the following configuration to make this work.

//

// CONFIG_GPIO_SYSFS=y

// CONFIG_SYSFS=y

// CONFIG_EXPERIMENTAL=y

// CONFIG_GPIO_XILINX=y



#include

#include

#include


int main()

{

int valuefd, exportfd;

int directionfd;

printf("GPIO test running...\n");

// The GPIO has to be exported to be able to see it

// in sysfs

exportfd = open("/sys/class/gpio/export", O_WRONLY);

if (exportfd < 0)

{

printf("Cannot open GPIO to export it\n");

exit(1);

}

write(exportfd, "902", 4);

write(exportfd, "903", 4);

write(exportfd, "904", 4);

write(exportfd, "905", 4);

close(exportfd);

printf("GPIO exported successfully\n");

// Update the direction of the GPIO to be an output

directionfd = open("/sys/class/gpio/gpio903/direction", O_RDWR);

if (directionfd < 0)

{

printf("Cannot open GPIO direction it\n");

exit(1);

}

write(directionfd, "out", 4);

close(directionfd);

printf("GPIO direction set as output successfully\n");

// Get the GPIO value ready to be toggled

valuefd = open("/sys/class/gpio/gpio903/value", O_RDWR);

if (valuefd < 0)

{

printf("Cannot open GPIO value\n");

exit(1);

}

printf("GPIO value opened, now toggling...\n");

// toggle the GPIO as fast a possible forever, a control c is needed

// to stop it

while (1)

{

write(valuefd,"1", 2);

sleep(1) ;

write(valuefd,"0", 2);

sleep(1) ;

}

}


5. 小结

按照如上步骤可以完成对gpio的控制,其实还有一个方法就是直接运用devmem命令来操作物理地址,以达到控制gpio的目的,这个方法最直接,无需加载驱动都可以完成;

example

# Read 32-bit register from physical address, match it to your AXI4-lite.

devmem 0x41200000


# Write 32-bit register with value

devmem 0x41200000 32 0x12345678

9.png


要想正确的操作gpio还需要参照axi-gpio的使用说明,找到对应的地址偏移寄存器的作用;

a.按照规格书里面将的地址偏移0x00000004 对应的是gpio的方向,初始值为0x0000000f,代表该axi-gpio的4个gpio全部被配置成了输入,往里面直接写0x00000000 将其配置成输出,命令如下

devmem 0x41200000 32 0x00000000 ;

b.地址偏移0x0是gpio的值,最后4bit分别对应1个gpio,用命令

devmem 0x41200000 32 0x0000000f 可以点亮4个led灯;


*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
lantu  2017-07-21 09:58:39 

赞一个

推荐文章
最近访客