【JokerのZYNQ7020】LINUX_MIO_BUTTON(偷鸡)。
发布日期:2021-05-06 21:36:45 浏览次数:18 分类:技术文章

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

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


这个...标题既然这样起,完全是因为经过前几篇的测试,产生了个突发奇想,如果把ps侧的mio管脚类似于pl侧的emio操作方式,添加进设备树,那么,能不能像操作emio一样,操作mio。由于不是像linux下传统方式,调用gpio_request()和request_irq()等来操作gpio,所以说是一个偷鸡的方法,但是不得不说,居然还真的试成功了。

底图的话跟前几篇的没任何区别,主要是要仿照操作emio设备树的写法,把要操作的mio部分,单独的添加到设备树里,这里以mio50和mio51来说明,我的mio50接了个button,mio51外挂了一个LED,做出如下改写。

amba_pl: amba_pl {		#address-cells = <1>;		#size-cells = <1>;		compatible = "simple-bus";		ranges ; 		axi_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_led 0 0>;				linux,default-trigger = "none";				default-state = "off";			};			led1 {				label = "led1";				gpios = <&axi_led 1 0>;				linux,default-trigger = "none";				default-state = "off";			};			led2 {				label = "led2";				gpios = <&axi_led 2 0>;				linux,default-trigger = "none";				default-state = "off";			};			led3 {				label = "led3";				gpios = <&axi_led 3 0>;				linux,default-trigger = "none";				default-state = "off";			};			led-ps51 {				label = "led-ps51";				gpios = <&gpio0 51 0>	;				linux,default-trigger = "none";				default-state = "off";					};		};		gpio-keys {			compatible = "gpio-keys";			#address-cells = <1>;			#size-cells = <0>;			poll-interval = <20>;						key50{				label = "key50";				gpios = <&gpio0 50 0>;				linux,code = <103>;					};		};	};

需要注意的点自然是gpios = <&gpio0 50/51 0>,对于ps侧的mio来说,基址当然是在gpio0,那么这个gpio0又在哪里定义的,是在zynq-7000.dtsi这个ps侧设备树中定义的。

gpio0: gpio@e000a000 {			compatible = "xlnx,zynq-gpio-1.0";			#gpio-cells = <2>;			clocks = <&clkc 42>;			gpio-controller;			interrupt-controller;			#interrupt-cells = <2>;			interrupt-parent = <&intc>;			interrupts = <0 20 4>;			reg = <0xe000a000 0x1000>;		};

设备树添加没问题后,编译、启动系统,理所当然的在/sys/class/leds目录下能看到可操作的led-ps51,在/sys/class/input目录下也能看到可供操作的event0。

至于led-ps51和event0是否真的有用,真的建立成功,还需要写app来测试,测试是这样计划的,通过按mio50的button来调教mio51的led闪烁频率,这样,即验证了mio的外中断,又验证了mio的输出,测试代码如下。

#include 
#include
#include
#include
#include
#include
#include
#define MIO_LED_BRIGHTNESS "/sys/class/leds/led-ps51/brightness"#define MIO_LED_TRIGGER "/sys/class/leds/led-ps51/trigger"#define MIO_INPUT_EVENT "/dev/input/event0"#define LED_MAX_SPEED 10#define PERIOD_COEFF 16000 unsigned int led_speed_now;pthread_mutex_t lock; /* Blink LED */static void *LED_Flash(void *dummy){ unsigned int led_period; int tmp; tmp = open(MIO_LED_BRIGHTNESS, O_WRONLY); if (tmp < 0){ exit(1); } while (1) { pthread_mutex_lock(&lock); led_period = (LED_MAX_SPEED - led_speed_now) * PERIOD_COEFF; pthread_mutex_unlock(&lock); write(tmp, "1", 2); usleep(led_period); write(tmp, "0", 2); usleep(led_period); }} int main(){ pthread_t pth; struct input_event ev; int tmp; int key_code; int size = sizeof(ev); /* Configure MIO-LED */ led_speed_now = 5; tmp = open(MIO_LED_TRIGGER, O_WRONLY); if (tmp < 0) return 1; if (write(tmp, "default-on", 10) != 10) { printf("Error writing trigger"); return 1; } close(tmp); printf("Configured LED for use\n"); /* Create thread */ pthread_mutex_init(&lock, NULL); pthread_create(&pth, NULL, LED_Flash, "Blinking LED..."); /* Read event0 */ tmp = open(MIO_INPUT_EVENT, O_RDONLY); if (tmp < 0) { printf("\nOpen " MIO_INPUT_EVENT " failed!\n"); return 1; } /* Read and parse event, update global variable */ while (1) { if (read(tmp, &ev, size) < size) { printf("\nReading from " MIO_INPUT_EVENT " failed!\n"); return 1; } if (ev.value == 1 && ev.type == 1) { key_code = ev.code; if (key_code == KEY_UP) { pthread_mutex_lock(&lock); /* raise speed */ if (led_speed_now < 9) led_speed_now += 1; else led_speed_now -= 9; pthread_mutex_unlock(&lock); } printf("Speed: %i\n", led_speed_now); usleep(1000); } }}

主函数里像上一篇一样,通过不断监测ev.value和ev.type的值来判断当前是否有键来按下,如果有,就增加led闪烁的速度,当速度加到头时候将速度清0,在子线程里,根据led_speed_now值得改变,不断计算led闪烁的周期,通过usleep延时来达到控制的目的,注意在app编译的时候,因为程序使用了线程,需要把-pthread加上。

程序运行起来以后,就能看到随着按键的不断按下,闪烁频率不断的增加啦,当然,随着按钮的按下,控制台也一样能看到如下打印。

 因为做法比较偷鸡,但是确实是可行的,所以先在这里分享出来,后面会依旧测试传统的gpio_request()和request_irq()做法,有进展了会继续在这里分享给大家,么么哒(づ ̄ 3 ̄)づ。

上一篇:【JokerのZYNQ7020】QSPI启动。
下一篇:【JokerのZYNQ7020】LINUX_EMIO_BUTTON。

发表评论

最新留言

第一次来,支持一个
[***.219.124.196]2025年03月10日 17时19分41秒