【JokerのZYNQ7020】LINUX_MIO_BUTTON(偷鸡)。

软件环境: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 <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <fcntl.h>
#include <signal.h>
#include <pthread.h>
#include <linux/input.h>
  
#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 ̄)づ。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值