TA的每日心情 | 开心 2024-10-25 14:50 |
---|
签到天数: 1071 天 连续签到: 1 天 [LV.10]以坛为家III
|
本帖最后由 TLLED 于 2020-6-23 15:14 编辑
开始学习在米尔MYD-C8MMX开发板linux开发环境下编写驱动程序。开发板使用的linxu版本是linux4.14板,给予linux4版本下的驱动都是基于设备树结构进行驱动程序开发的。下面使用板卡上的LED灯,使用GPIO 来驱动LED。
一、硬件电路
开发板上的LED灯对应的端口,这次使用的端口是GPIO5_4,LED1指示灯,LED2用指示系统运行就不在改动LED2。
一、驱动程序
1.1、驱动测试的设备树文件在/MYIR-i.MX8MM-Linux/arch/arm64/boot/dts/freescale/下面,找到对应开发板的dts文件 myb-fsl-imx8mm-evk.dts 查找有关开发板上有关LED1的设备,厂家已经把LED灯端口都配置好了。
1.2、驱动程序源码
1.2.1、userled.c
- #include <linux/types.h>
- #include <linux/kernel.h>
- #include <linux/delay.h>
- #include <linux/ide.h>
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/errno.h>
- #include <linux/gpio.h>
- #include <linux/cdev.h>
- #include <linux/device.h>
- #include <linux/of.h>
- #include <linux/of_address.h>
- #include <linux/of_gpio.h>
- #include <asm/uaccess.h>
- #include <asm/io.h>
- #define GPIOLED_CNT 1
- #define GPIOLED_NAME "userled"
- #define LEDOFF 0
- #define LEDON 1
-
- struct userled_dev{
- dev_t devid;
- struct cdev cdev;
- struct class *class;
- struct device *device;
- int major;
- int minor;
- struct device_node *nd;
- int led_gpio;
- };
- struct userled_dev userled;
- //led open
- static int led_open(struct inode *inode, struct file *filp)
- {
- filp->private_data = &userled;
- return 0;
- }
- //led read
- static ssize_t led_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
- {
- return 0;
- }
- //led write
- static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
- {
- int retvalue;
- unsigned char databuf[1];
- unsigned char ledstat;
- struct userled_dev *dev = filp->private_data;
- retvalue = copy_from_user(databuf, buf, cnt);
- if(retvalue < 0)
- {
- printk("kernel write failed!\r\n");
- return -EFAULT;
- }
- ledstat = databuf[0];
- if(ledstat == LEDON)
- {
- gpio_set_value(dev->led_gpio, 0);
- }
- else if(ledstat == LEDOFF)
- {
- gpio_set_value(dev->led_gpio, 1);
- }
- return 0;
- }
- //led release
- static int led_release(struct inode *inode, struct file *filp)
- {
- return 0;
- }
- //fops
- static struct file_operations userled_fops = {
- .owner = THIS_MODULE,
- .open = led_open,
- .read = led_read,
- .write = led_write,
- .release = led_release,
- };
- //led init
- static int __init led_init(void)
- {
- int ret = 0;
- userled.nd = of_find_node_by_path("/leds/user");
- if(userled.nd == NULL)
- {
- printk("userled node not find!\r\n");
- return -EINVAL;
- } else
- {
- printk("userled node find!\r\n");
- }
- userled.led_gpio = of_get_named_gpio(userled.nd, "gpios", 0);
- if(userled.led_gpio < 0)
- {
- printk("can't get usergpio");
- return -EINVAL;
- }
- ret = gpio_direction_output(userled.led_gpio, 1);
- if(ret < 0)
- {
- printk("can't set usergpio!\r\n");
- }
- if (userled.major)
- {
- userled.devid = MKDEV(userled.major, 0);
- register_chrdev_region(userled.devid, GPIOLED_CNT, GPIOLED_NAME);
- } else
- {
- alloc_chrdev_region(&userled.devid, 0, GPIOLED_CNT, GPIOLED_NAME);
- userled.major = MAJOR(userled.devid);
- userled.minor = MINOR(userled.devid);
- }
- printk("userled major=%d,minor=%d\r\n",userled.major, userled.minor);
-
- userled.cdev.owner = THIS_MODULE;
- cdev_init(&userled.cdev, &userled_fops);
- cdev_add(&userled.cdev, userled.devid, GPIOLED_CNT);
- userled.class = class_create(THIS_MODULE, GPIOLED_NAME);
- if (IS_ERR(userled.class))
- {
- return PTR_ERR(userled.class);
- }
- userled.device = device_create(userled.class, NULL, userled.devid, NULL, GPIOLED_NAME);
- if (IS_ERR(userled.device))
- {
- return PTR_ERR(userled.device);
- }
- return 0;
- }
- //led exit
- static void __exit led_exit(void)
- {
- cdev_del(&userled.cdev);
- unregister_chrdev_region(userled.devid, GPIOLED_CNT);
- device_destroy(userled.class, userled.devid);
- class_destroy(userled.class);
- }
- module_init(led_init);
- module_exit(led_exit);
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("author");
复制代码
1.2.2、Makefile文件
- KERNELDIR := /opt/04-Sources/MYIR-i.MX8MM-Linux
- CURRENT_PATH := $(shell pwd)
- obj-m := userled.o
- build: kernel_modules
- kernel_modules:
- $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
- clean:
- $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
复制代码
1.2.3、编译程序
设置编译环境
>/opt/04-Sources/example/userled# source /opt/myir-imx-xwayland/4.14-sumo/environment-setup-aarch64-poky-linux
>/opt/04-Sources/example/userled# LDFLAGS="" CC="$CC"
>make
编译完成后,会生成userled.ko文件,
二、应用程序
通过应用测试来测试驱动程序的运行情况。
2.1、userledApp.c
- #include <stdio.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <stdlib.h>
- #include <string.h>
- #define LED_DELAY_US (200*1000) /* 200 ms */
- #define LEDOFF 0
- #define LEDON 1
- int main(int argc, char *argv[])
- {
- int fd, retvalue;
- char *filename;
- unsigned char databuf[1];
- unsigned char databuf1[1];
-
- if(argc != 3){
- printf("Error Usage!\r\n");
- return -1;
- }
- filename = argv[1];
- fd = open(filename, O_RDWR);
- if(fd < 0)
- {
- printf("file %s open failed!\r\n", argv[1]);
- return -1;
- }
- for(;;)
- {
- databuf[0] = 0x01;
- retvalue = write(fd, databuf, sizeof(databuf));
- usleep(LED_DELAY_US );
- databuf[0] = 0x00;
- retvalue = write(fd, databuf, sizeof(databuf));
- usleep(LED_DELAY_US );
- printf("LED Control test!\r\n");
- }
-
- retvalue = close(fd);
- if(retvalue < 0)
- {
- printf("file %s close failed!\r\n", argv[1]);
- return -1;
- }
- return 0;
- }
复制代码
2.2、Makefile
- include ../env.mk
- TARGET = userledApp
- SRC = $(TARGET).c
- OBJS = $(patsubst %.c ,%.o ,$(SRC))
- .PHONY: all
- all: $(TARGET)
- $(TARGET) : $(OBJS)
- $(CC) -o $@ $^
- %.o : %.c
- $(CC) -c [ DISCUZ_CODE_421 ]lt; -o $@
- clean:
- $(RM) *.o $(TARGET)
复制代码
2.3、编译程序
执行make命令生成文件。
三、测试程序
3.1、将上面生成的两个文件复制到开发板上
3.2、加载模块
3.3、运行测试程序
3.4、测试结果
蓝色的LED闪烁运行。
|
|