IMX6ULL-LED点灯

实验内容

实验目的

点亮IMX6ULL开发板LED2,通过输入 on/off控制LED亮灭以及查看灯状态

引脚原理图

LED2

IMX6ULL-LED点灯_第1张图片

查看引脚编号

cat /sys/kernel/debug/gpio 

GPIO5_3
IMX6ULL-LED点灯_第2张图片得出引脚编号131

实验代码

驱动程序

#include "asm-generic/errno-base.h"
#include "asm-generic/gpio.h"
#include "asm/uaccess.h"
#include 
#include 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

struct gpio_desc{
	int gpio;
	int irq;
    char *name;
    int key;
	struct timer_list key_timer;
} ;

static struct gpio_desc gpios[2] = {
    {131, 0, "led0", },
    //{132, 0, "led1", },
};

/* 主设备号                                                                 */
static int major = 0;
static struct class *gpio_class;


/* 实现对应的open/read/write等函数,填入file_operations结构体                   */
static ssize_t gpio_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
	char tmp_buf[2];
	int err;
    int count = sizeof(gpios)/sizeof(gpios[0]);

	if (size != 2)
		return -EINVAL;

	//buf用户空间buf
	//从用户空间拷贝数数据
	err = copy_from_user(tmp_buf, buf, 1);

	if (tmp_buf[0] >= count)
		return -EINVAL;

	tmp_buf[1] = gpio_get_value(gpios[tmp_buf[0]].gpio);

	//拷贝数据到用户空间
	err = copy_to_user(buf, tmp_buf, 2);
	
	return 2;
}

static ssize_t gpio_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
    unsigned char ker_buf[2];
    int err;

    if (size != 2)
        return -EINVAL;

    err = copy_from_user(ker_buf, buf, size);
    
    if (ker_buf[0] >= sizeof(gpios)/sizeof(gpios[0]))
        return -EINVAL;

    gpio_set_value(gpios[ker_buf[0]].gpio, ker_buf[1]);
    return 2;    
}



/* 定义自己的file_operations结构体                                              */
static struct file_operations gpio_key_drv = {
	.owner	 = THIS_MODULE,
	.read    = gpio_drv_read,
	.write   = gpio_drv_write,
};


/* 在入口函数 */
static int __init gpio_drv_init(void)
{
    int err;
    int i;
    int count = sizeof(gpios)/sizeof(gpios[0]);
    
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	
	for (i = 0; i < count; i++)
	{		
		/* set pin as output */
		//申请GPIO
		err = gpio_request(gpios[i].gpio, gpios[i].name);
		if (err < 0) {
			printk("can not request gpio %s %d\n", gpios[i].name, gpios[i].gpio);
			return -ENODEV;
		}
		//输出模式
		gpio_direction_output(gpios[i].gpio, 1);
	}

	/* 注册file_operations 	*/
	major = register_chrdev(0, "100ask_led", &gpio_key_drv);  /* /dev/gpio_desc */

	//创建类
	gpio_class = class_create(THIS_MODULE, "100ask_led_class");
	if (IS_ERR(gpio_class)) {
		printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
		unregister_chrdev(major, "100ask_led_class");
		return PTR_ERR(gpio_class);
	}

	//创建设备名
	device_create(gpio_class, NULL, MKDEV(major, 0), NULL, "100ask_led"); /* /dev/100ask_gpio */
	
	return err;
}

/* 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数
 */
static void __exit gpio_drv_exit(void)
{
    int i;
    int count = sizeof(gpios)/sizeof(gpios[0]);
    
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

	device_destroy(gpio_class, MKDEV(major, 0));
	class_destroy(gpio_class);
	unregister_chrdev(major, "100ask_led");

	for (i = 0; i < count; i++)
	{
		gpio_free(gpios[i].gpio);		
	}
}


/* 7. 其他完善:提供设备信息,自动创建设备节点                                     */

module_init(gpio_drv_init);
module_exit(gpio_drv_exit);

MODULE_LICENSE("GPL");



应用程序


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

static int fd;


//int led_on(int which);
//int led_off(int which);
//int led_status(int which);

/*
 * ./led_test <0|1|2|..>  on 
 * ./led_test <0|1|2|..>  off
 * ./led_test <0|1|2|..>
 */
int main(int argc, char **argv)
{
	int ret;
	char buf[2];

	int i;
	
	/* 1. 判断参数 */
	if (argc < 2) 
	{
		printf("Usage: %s <0|1|2|...> [on | off]\n", argv[0]);
		return -1;
	}


	/* 2. 打开文件 */
	fd = open("/dev/100ask_led", O_RDWR);
	if (fd == -1)
	{
		printf("can not open file /dev/100ask_led\n");
		return -1;
	}

	//argc参数个数
	if (argc == 3)
	{
		/* write */
		//将argv[1]转为整形
		buf[0] = strtol(argv[1], NULL, 0);

		if (strcmp(argv[2], "on") == 0)
			buf[1] = 0;
		else
			buf[1] = 1;
		
		ret = write(fd, buf, 2);
	}
	else
	{
		buf[0] = strtol(argv[1], NULL, 0);
		ret = read(fd, buf, 2);
		if (ret == 2)
		{
			printf("led %d status is %s\n", buf[0], buf[1] == 0 ? "on" : "off");
		}
	}
	
	close(fd);
	
	return 0;
}



makefile

KERN_DIR =  /home/book/100ask_imx6ull-sdk/Linux-4.9.88 # 板子所用内核源码的目录

all:
	make -C $(KERN_DIR) M=`pwd` modules 
	$(CROSS_COMPILE)gcc -o led_test led_test.c
clean:
	make -C $(KERN_DIR) M=`pwd` modules clean
	rm -rf modules.order  led_test

# 参考内核源码drivers/char/ipmi/Makefile
# 要想把a.c, b.c编译成ab.ko, 可以这样指定:
# ab-y := a.o b.o
# obj-m += ab.o



obj-m += led_drv.o

实验结果

编译程序

在驱动目录下执行make指令,得出如下文件
IMX6ULL-LED点灯_第3张图片

挂载文件到开发板

mount -t nfs -o nolock,vers=3 192.168.5.11:/home/book/nfs_rootfs /mnt

找到驱动文件目录
IMX6ULL-LED点灯_第4张图片

装载驱动

insmod led_drv.ko 

在这里插入图片描述

查看设备节点

ls /dev/100ask_led

在这里插入图片描述

执行程序

开LED

0:第0个灯,灯序号 on点亮 off熄灭

./led_test 0 on 

IMX6ULL-LED点灯_第5张图片

关LED

0:第0个灯,灯序号 on点亮 off熄灭

./led_test 0 off

IMX6ULL-LED点灯_第6张图片

查看LED状态

0:第0个灯,灯序号 on点亮 off熄灭
(on/ off不输入则检测当前灯状态)

./led_test 0

IMX6ULL-LED点灯_第7张图片

你可能感兴趣的:(IMX6ULL,单片机,linux,嵌入式硬件,mcu)