Zynq-7000系列之linux开发学习笔记:Linux下的MIO/EMIO GPIO驱动与操作(八)

开发板:Zynq7030数据采集板
PC平台:Ubuntu-18.04 + MobaXterm
开发环境:Xilinx Vivado + SDK -18.3
交叉编译工具:arm-linux-gnueabihf-
学习目标:通过Linux下GPIO驱动控制开发板上的LED灯

一、Zynq Linux的GPIO驱动

在前面文章:Zynq-7000系列之linux开发学习笔记:PS和PL端的GPIO使用(三)中分享了Zynq下GPIO的三种类型,由于使用的硬件关系,只分享EMIO和AXI_GPIO的具体配置流程。由于是在裸机的情况下进行的GPIO操作,需要在Vivado和SDK下对PS和PL端进行配置,还要在SDK里面编写程序,才能通过JTAG的方式下载到板子上运行。
但在Linux系统环境下,操作GPIO是非常方便的事情,一般都是通过驱动程序来进行操作。驱动程序可以通过自己编写来实现,也可以直接采用Linux下的驱动程序。

二、EMIO_GPIO

从前面几篇文章中可知:移植Linaro操作系统的流程中,生成FSBL阶段时配置了一个EMIO连接到PL端的PIN脚。
可以查看一下编译内核的时候,在 ./linux-xlnx-xilinx-v2018.3/arch/arm/configs 路径下的Xilinx Zynq官方配置文件 xilinx_zynq_defconfig ,是否使能了下面内容:

CONFIG_GPIO_SYSFS=y
CONFIG_SYSVIPC=y
CONFIG_GPIO_ZYNQ=y

  
  
  • 1
  • 2
  • 3

查看通过SDK生成的设备树文件,包含有下面GPIO内容:

		gpio@e000a000 {
			compatible = "xlnx,zynq-gpio-1.0";
			#gpio-cells = <0x2>;
			clocks = <0x1 0x2a>;
			gpio-controller;
			interrupt-controller;
			#interrupt-cells = <0x2>;
			interrupt-parent = <0x4>;
			interrupts = <0x0 0x14 0x4>;
			reg = <0xe000a000 0x1000>;
			emio-gpio-width = <0x1>;
			gpio-mask-high = <0x0>;
			gpio-mask-low = <0x5600>;
		};

  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

1、Linux下Sysfs方式直接操作GPIO

在多GPIO的系统下,需要确定要控制GPIO口的编号,一种方法就是通过查看./sys/class/gpio路径下的gpiochips编号,它反映了GPIO在系统中的地址。还有一种方法比较麻烦,就不提了0.0.0

root@linaro-ubuntu-desktop:~$ cd /sys/class/gpio/
root@linaro-ubuntu-desktop:/sys/class/gpio$ ls
export  gpiochip906  unexport
root@linaro-ubuntu-desktop:/sys/class/gpio$ cat gpiochip906/label
zynq_gpio

  
  
  • 1
  • 2
  • 3
  • 4
  • 5

上面内容表明第一个GPIO口编号为906,并以此编号开始计算后续GPIO编号。我们使用的EMIO是第一个EMIO,总共有54个MIO,所以我们需要设置的GPIO口编号为960。

/* Export a GPIO pin */
root@linaro-ubuntu-desktop:~$ echo 960 > /sys/class/gpio/export
root@linaro-ubuntu-desktop:~$ cd /sys/class/gpio/
root@linaro-ubuntu-desktop:/sys/class/gpio$ ls
export  gpio960  gpiochip906  unexport

/* Read the direction and value from the GPIO pin */
root@linaro-ubuntu-desktop:/sys/class/gpio$ ls gpio960
active_low device direction edge power subsystem uevent value
root@linaro-ubuntu-desktop:/sys/class/gpio$ cat gpio960/direction
in
root@linaro-ubuntu-desktop:/sys/class/gpio$ cat gpio960/value
0

/* Set the direction to an output and write a value 1 to GPIO pin */
root@linaro-ubuntu-desktop:/sys/class/gpio$ echo out > gpio960/direction
root@linaro-ubuntu-desktop:/sys/class/gpio$ cat gpio960/direction
out
root@linaro-ubuntu-desktop:/sys/class/gpio$ echo 1 > gpio960/value
root@linaro-ubuntu-desktop:/sys/class/gpio$ cat gpio960/value
1

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

可以看到开发板上的LED灯亮了!!!如下图所示。
在这里插入图片描述
对上面的一些操作进行下说明:
/sys/class/gpio/路径下相关文件说明:

FileDescription
export将GPIO节点导入到用户空间
unexport将GPIO节点移除用户空间
gpiochip*该目录下保存系统中GPIO寄存器信息:每个寄存器控制引脚的起始编号base,寄存器名称,引脚总数

/sys/class/gpio/gpio960/路径下相关文件说明:

FileDescription
direction配置GPIO口输方面,"in"为输入;"out"为输出
valueGPIO为输出时可设置GPIO口电平,"0"为低电平;"1"为高电平。
edge设置GPIO口输入时触发方式:“none”, “rising”, “falling”, or “both”
active_low按照官方的说法是翻转电平,输入非零的数即上升沿变为下降沿

2、GPIO用户空间APP方式

上面的方法是直接在系统里通过SYSFS操作GPIO口,也可以通过写APP的方式来操作GPIO。
首先在虚拟机Ubuntu下编写GPIO的.C程序 ,用Xilinx的交叉编译工具链来编译程序,操作如下:

claude1009@ubuntu:~/xc7030/gpio$ gedit emio_gpio.c 
claude1009@ubuntu:~/xc7030/gpio$ arm-linux-gnueabihf-gcc emio_gpio.c -o linux_gpio
emio_gpio.c: In function ‘main’:
emio_gpio.c:67:5: warning: implicit declaration of function ‘write’; did you mean ‘fwrite’? [-Wimplicit-function-declaration]
     write(exportfd, "960", 4);
     ^~~~~
     fwrite
emio_gpio.c:68:5: warning: implicit declaration of function ‘close’; did you mean ‘pclose’? [-Wimplicit-function-declaration]
     close(exportfd);
     ^~~~~
     pclose
emio_gpio.c:103:9: warning: implicit declaration of function ‘sleep’ [-Wimplicit-function-declaration]
         sleep(1);
         ^~~~~
claude1009@ubuntu:~/xc7030/gpio$ ls
emio_gpio.c  linux_gpio

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

具体程序如下:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>

// The specific GPIO being used must be setup and replaced thru
// this code. The GPIO of 897 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 gpio897 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,
// the GPIO can be toggled about every 1sec.
// 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 897 > /sys/class/gpio/export
// bash> echo out > /sys/class/gpio/gpio897/direction
// bash> echo 1 > /sys/class/gpio/gpio897/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/gpio897/value
// echo 0 > /sys/class/gpio/gpio897/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

int main()
{
int valuefd, exportfd, directionfd;

<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"GPIO test running...\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// The GPIO has to be exported to be able to see it</span>
<span class="token comment">// in sysfs</span>

exportfd <span class="token operator">=</span> <span class="token function">open</span><span class="token punctuation">(</span><span class="token string">"/sys/class/gpio/export"</span><span class="token punctuation">,</span> O_WRONLY<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>exportfd <span class="token operator">&lt;</span> <span class="token number">0</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"Cannot open GPIO to export it\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">exit</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token function">write</span><span class="token punctuation">(</span>exportfd<span class="token punctuation">,</span> <span class="token string">"960"</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">close</span><span class="token punctuation">(</span>exportfd<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"GPIO exported successfully\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Update the direction of the GPIO to be an output</span>

directionfd <span class="token operator">=</span> <span class="token function">open</span><span class="token punctuation">(</span><span class="token string">"/sys/class/gpio/gpio960/direction"</span><span class="token punctuation">,</span> O_RDWR<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>directionfd <span class="token operator">&lt;</span> <span class="token number">0</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"Cannot open GPIO direction it\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">exit</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token function">write</span><span class="token punctuation">(</span>directionfd<span class="token punctuation">,</span> <span class="token string">"out"</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">close</span><span class="token punctuation">(</span>directionfd<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"GPIO direction set as output successfully\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Get the GPIO value ready to be toggled</span>

valuefd <span class="token operator">=</span> <span class="token function">open</span><span class="token punctuation">(</span><span class="token string">"/sys/class/gpio/gpio960/value"</span><span class="token punctuation">,</span> O_RDWR<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>valuefd <span class="token operator">&lt;</span> <span class="token number">0</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"Cannot open GPIO value\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">exit</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">"GPIO value opened, now toggling...\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// toggle the GPIO as fast a possible forever, a control c is needed</span>
<span class="token comment">// to stop it</span>

<span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    <span class="token function">write</span><span class="token punctuation">(</span>valuefd<span class="token punctuation">,</span><span class="token string">"1"</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">write</span><span class="token punctuation">(</span>valuefd<span class="token punctuation">,</span><span class="token string">"0"</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>       
<span class="token punctuation">}</span>

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107

然后在开发板端,通过NFS挂载到虚拟机Ubuntu下,然后再运行程序即可:

root@linaro-ubuntu-desktop:~$ mount -t nfs -o nolock 192.168.3.100:/home/claude1009 /mnt
root@linaro-ubuntu-desktop:~$ cd /mnt
root@linaro-ubuntu-desktop:/mnt$ cd xc7030/gpio/
root@linaro-ubuntu-desktop:/mnt/xc7030/gpio$ ls
emio_gpio.c  linux_gpio
root@linaro-ubuntu-desktop:/mnt/xc7030/gpio$ ./linux_gpio
GPIO test running...
GPIO exported successfully
GPIO direction set as output successfully
GPIO value opened, now toggling...

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

此时就可看见开发板上的LED灯在不停地闪烁!!!

                                </div>
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值