博客
关于我
【JokerのZYNQ7020】LINUX_EMIO_LED。
阅读量:298 次
发布时间:2019-03-03

本文共 6383 字,大约阅读时间需要 21 分钟。

软件环境:vivado 2017.4        硬件平台:XC7Z020


已经都快两个月没更新了,再不更新就要把最近搞得东西全都忘的一干二净了。说也搞笑,刚开始入行的时候,找到什么好东西,获得什么好的调试经验,都不愿意分享,想的都是些这是劳资辛辛苦苦搞出来的,凭啥,凭啥分享,写博客,写博客更是不可能中的不可能。现在就完全不一样了,做了什么都想写出来,都想记下来,要不然真的,过不了多久就全忘了,再多过阵子真就跟没干过一样了,可能因为年纪大了吧哈哈哈哈哈哈越来越记不住东西了,所以干脆想写了就写多点,不想写了就写少点,随时需要,随时能查,都是自己写的,稍微看下就能想起来,多好。

就先哔哔这么多,这篇主要想说下LINUX下EMIO怎么操作,也就是说在LINUX下,PL端的GPIO要怎么操作,以GPIO控制LED为例。


原理图是下面这样,因为后面会写EMIO中断也就是PL-PS在LINUX中断怎么搞,所以干脆模块就一起建了,后面中断也都是在这一个例子基础上写的程序。

这里控制PL端的GPIO用的是AXI_GPIO核,走的是AXI总线控制,所以每个模块都对应了一个总线地址。管脚约束完成以后生成bitstream,然后导入SDK生成fsbl和devicetree,基本操作就不啰嗦了,注意devicetree生成以后,有些地方要手动改一下,我的devicetree如下。

/* * CAUTION: This file is automatically generated by Xilinx. * Version:   * Today is: Thu Aug  8 10:09:43 2019 *// {	amba_pl: amba_pl {		#address-cells = <1>;		#size-cells = <1>;		compatible = "simple-bus";		ranges ;		axi_gpio_button: gpio@41210000 {			#gpio-cells = <2>;			#interrupt-cells = <2>;			clock-names = "s_axi_aclk";			clocks = <&clkc 15>;			compatible = "xlnx,xps-gpio-1.00.a";			gpio-controller ;			interrupt-controller ;			interrupt-names = "ip2intc_irpt";			interrupt-parent = <&intc>;			interrupts = <0 29 4>;			reg = <0x41210000 0x10000>;			xlnx,all-inputs = <0x0>;			xlnx,all-inputs-2 = <0x0>;			xlnx,all-outputs = <0x0>;			xlnx,all-outputs-2 = <0x0>;			xlnx,dout-default = <0x00000000>;			xlnx,dout-default-2 = <0x00000000>;			xlnx,gpio-width = <0x2>;			xlnx,gpio2-width = <0x20>;			xlnx,interrupt-present = <0x1>;			xlnx,is-dual = <0x0>;			xlnx,tri-default = <0xFFFFFFFF>;			xlnx,tri-default-2 = <0xFFFFFFFF>;		};		axi_gpio_led: gpio@41200000 {			#gpio-cells = <2>;			clock-names = "s_axi_aclk";			clocks = <&clkc 15>;			compatible = "xlnx,xps-gpio-1.00.a";			gpio-controller ;			reg = <0x41200000 0x10000>;			xlnx,all-inputs = <0x0>;			xlnx,all-inputs-2 = <0x0>;			xlnx,all-outputs = <0x1>;			xlnx,all-outputs-2 = <0x0>;			xlnx,dout-default = <0x00000000>;			xlnx,dout-default-2 = <0x00000000>;			xlnx,gpio-width = <0x4>;			xlnx,gpio2-width = <0x20>;			xlnx,interrupt-present = <0x0>;			xlnx,is-dual = <0x0>;			xlnx,tri-default = <0xFFFFFFFF>;			xlnx,tri-default-2 = <0xFFFFFFFF>;		};		gpio-leds {			compatible = "gpio-leds";                        #address-cells = <1>;                        #size-cells = <0>;                        led0 {                                label = "led0";                                gpios = <&axi_gpio_led 0 0>;                                linux,default-trigger = "none";                                default-state = "on";                        };                        led1 {                                label = "led1";                                gpios = <&axi_gpio_led 1 0>;                                linux,default-trigger = "none";                                default-state = "off";                        };                        led2 {                                label = "led2";                                gpios = <&axi_gpio_led 2 0>;                                linux,default-trigger = "none";                                default-state = "on";                        };                        led3 {                                label = "led3";                                gpios = <&axi_gpio_led 3 0>;                                linux,default-trigger = "none";                                default-state = "off";                        };                };		gpio-keys-polled {			compatible = "gpio-keys-polled";			#address-cells = <1>;			#size-cells = <0>;			poll-interval = <20>;			up {				label = "up";				gpios = <&axi_gpio_button 0 0>;				linux,code = <103>;			};			down {				label = "down";				gpios = <&axi_gpio_button 1 0>;				linux,code = <108>;			};		};	};};

需要说明一下,自动生成的devicetree拿来直接用会有问题的, 自动生成的devicetree中#gpio-cells =<3>需要改成#gpio-cells =<2>,下面的gpio-leds和gpio-keys-polled是手动添加的,因为后面会说好几种不同的控制方式。

gpio-leds这一块能不能不添,可以,不添的话,用mmap内存映射可以控制emio的leds,添了的话,可以分别通过/sys/class/leds来控制各个leds,从compatible = "gpio-leds"可以看到,这里主要用的是内核中现成的leds-gpio.c的驱动,在内核中的位置是/kernel/drivers/leds/leds-gpio.c,kernel在启动过程中会自动寻找与compatible相对应的驱动加载(设备树相互驱动对应),而后实现相关功能,关于自定义驱动实现led下一篇会介绍,本篇不提。

gpio-keys-polled这篇先不介绍,因为牵扯中断,后面会说。

SDK这块基本就没什么了,接下来说下linux内核编译过程中需要注意的,.config文件中下面三项需要使能。

CONFIG_GPIO_SYSFS=yCONFIG_SYSFS=yCONFIG_GPIO_ZYNQ=y

然后制作uboot、kernel、rootfs等等也不哔哔了,准备工作结束。


方法1.cd /sys/class/leds

如果devicetree那里手动添加的代码段部分添加都正确的情况下,进入这个目录后可以看见如下所示。

从led0~led3这4个led对我都是可见的,这里led的数量根据自己实际情况而定,有几个,就在devicetree上加几个分支。

led2 {                                label = "led2";                                gpios = <&axi_gpio_led 2 0>;                                linux,default-trigger = "none";                                default-state = "on";                        };

再详细哔哔下devicetree下面led2的那个写法,label就是名字标识,写什么就会在/sys/class/leds看到什么,gpios< >里的取地址符后面的名称需要与vivado中address editor下图红框这里严格对应,default-trigger是默认触发方式,这个怂管,default-state是默认初始化状态,如果是on,则开发板一上电进kernel时候,led就是点亮状态,off的话进kernel时候就是关闭状态。

 说下最简单的,直接手动控制。以led2为例,进入led2以后(下面所有的操作都是在进入led2路径后的操作,否则,echo后 >右侧的路径最好写全,只是我比较懒,就这么着吧)可以看到路径下有如下文件,说下主要用到的操作:

brightness用来点亮led,赋给brightness大于0的数,led就会亮,赋给brightness 0,led就会灭。

echo 1 > ./brightness  led就会亮echo 0 > ./brightness  led就会灭

max_brightness用来修改最大亮度。

cat ./max_brightness    用来查看当前最大亮度时对应的值

trigger用来使led闪烁。

echo timer > ./trigger    给led加入定时器

键入timer之后,路径下的文件会产生变化。

此时,修改delay_on的值,会改变led亮的时间(单位ms),改变delay_off的值,会改变led灭的时间(单位ms)。

echo 1000 > ./delay_on        使led亮持续1secho 1000 > ./delay_off       使led灭持续1s

键入如上命令后,可以看到led亮1s灭1s交替闪烁。


方法2.直接将上述操作写到代码里去(app)

直接对/sys/class/leds/ledx/brightness文件的open、write,都是对linux下文件的基本操作。添加代码led_test.c

#include 
#include
#include
#include
#include
#include
#define LED_0 "/sys/class/leds/led0/brightness"#define LED_1 "/sys/class/leds/led1/brightness"#define LED_2 "/sys/class/leds/led2/brightness"#define LED_3 "/sys/class/leds/led3/brightness" int main(){ int led0,led1,led2,led3; led0 = open(LED_0, O_WRONLY); led1 = open(LED_1, O_WRONLY); led2 = open(LED_2, O_WRONLY); led3 = open(LED_3, O_WRONLY); while(1) { write(led0, "1", 1); sleep(1); write(led0, "0", 1); sleep(1); write(led1, "1", 1); sleep(1); write(led1, "0", 1); sleep(1); write(led2, "1", 1); sleep(1); write(led2, "0", 1); sleep(1); write(led3, "1", 1); sleep(1); write(led3, "0", 1); sleep(1); } }

然后在linux下键入命令编译,将生成好的led_test拖到开发板执行。

arm-linux-gnueabihf-gcc -o led_test led_test.c

现象就是亮一秒,灭一秒然后换下一个led。

转载地址:http://rlrm.baihongyu.com/

你可能感兴趣的文章
MVC之修改
查看>>
struct 模块
查看>>
python之集合类型内置方法
查看>>
编程与编程语言分类
查看>>
【 UVA - 572 】 Oil Deposits (DFS水题)
查看>>
约瑟夫环问题
查看>>
CF #716 (Div. 2) B. AND 0, Sum Big(思维+数学)
查看>>
Java 設計模式 - 建造者模式
查看>>
ES6 JavaScript 重新認識 Promise
查看>>
2020-07-16:如何获得一个链表的倒数第n个元素?
查看>>
Imagination官方信息速递2021年光线追踪专刊
查看>>
webpack01 -- webpack安装和配置
查看>>
分享九款不同页面404源码html
查看>>
404页圈小猫游戏代码
查看>>
好看清新卡通人物404单页网站源码
查看>>
简洁仿t猫404页html源码
查看>>
Python九齿耙(Ninerake)数据采集大数据深度学习智能分析爬虫软件的正则表达式规则简介
查看>>
Kotlin实现冒泡排序
查看>>
NodeJS下TypeScript环境安装
查看>>
汽车后市场,小程序为何独占鳌头
查看>>