基于正点原子IMX6UL开发板的笔记
{ "configurations": [ { "name": "Linux", "includePath": [ "${workspaceFolder}/**", "/home/yinliang/linux/kernel/nxp_linux/include","/home/yinliang/linux/kernel/nxp_linux/arch/arm/include","/home/yinliang/linux/kernel/nxp_linux/arch/arm/include/generated"], "defines": [], "compilerPath": "/usr/bin/gcc", "cStandard": "c11", "cppStandard": "c++17", "intelliSenseMode": "clang-x64" } ], "version": 4
}
#include
#include
#include
#include
#include
#include
/***************************************************************
文件名 : chrdevbase.c
作者 : junluoyu
版本 : V1.0
描述 : chrdevbase驱动文件。
其他 : 无
日志 : 初版 V1.0 2022/11/28
***************************************************************/#define CHRDEVBASE_MAJOR 200 /* 主设备号 */
#define CHRDEVBASE_NAME "chrdevbase" /* 设备名 */static char readbuf[100]; /* 读缓存 */
static char writebuf[100]; /* 写缓存 */
static char kerneldata[] = {"kernel data!"};/** @description : 打开设备* @param - inode :传递给驱动的inode * @param - filp :设备文件,file结构体有给叫做private_data的成员变量* ,一般再open的时候将private_data指向设备的结构体 * @return :0成功;其他失败*/static int chrdevbase_open(struct inode *inode, struct file *filp){printk("chrdevbase open!\r\n");return 0;}/** @description : 从设备读取数据* @param - buf :返回给用户空间的数据缓冲区* @param - filp :要打开的设备文件(文件描述符)* @param - cnt :要读取的数据长度* @param - offt :相对于文件首地址的偏移* @return :读取的字节数,负值表示读取失败*/static ssize_t chrdevbase_read(struct file *filp, char __user *buf,size_t cnt, loff_t *offt){int retvalue = 0;/*向用户空间发送数据 */memcpy(readbuf, kerneldata, sizeof(kerneldata));retvalue = copy_to_user(buf, readbuf, cnt);if(retvalue == 0) {printk("kernel senddata ok!\r\n");}else{printk("kernel senddata failed!\r\n");}//printk("chrdevbase read!\r\n");return 0;}/** @description : 从设备写数据* @param - buf :要写给设备写入的数据* @param - filp :设备文件,表示打开的文件描述符* @param - cnt :要写入的数据长度* @param - offt :相对于文件首地址的偏移* @return :写入的字节数,负值表示读取失败*/static ssize_t chrdevbase_write(struct file *filp, const char __user *buf,size_t cnt, loff_t *offt){int retvalue = 0;/*接收用户空间传递给内核的数据并打印出来*/retvalue = copy_from_user(writebuf, buf, cnt);if(retvalue == 0) {printk("kernel recvdata: %s\r\n", writebuf);}else{printk("kernel recvdata failed!\r\n");}//printk("chrdevbase write!\r\n");return 0;}/** @description : 关闭、释放设备* @param - filp :要关闭的设备文件* @return :0成功;其他 失败*/static int chrdevbase_release(struct inode *inode, struct file *filp){// printk("chrdevbase release! \r\n");return 0;}/** 设备操作结构体*/
static struct file_operations chrdevbase_fops = {.owner = THIS_MODULE,.open = chrdevbase_open,.read = chrdevbase_read,.write = chrdevbase_write,.release = chrdevbase_release,
};/** @description : 驱动入口函数* @param - filp :无* @return :0成功; 其他 失败*/static int __init chrdevbase_init(void){int retvalue = 0;/* 注册字符设备驱动 */retvalue = register_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME,&chrdevbase_fops);if (retvalue < 0){printk("chrdevbase driver register failed\r\n");}printk("chrdevbase_init()\r\n"); return 0;}/** @description : 驱动出口函数* @param - filp :无* @return :无*/void __exit chrdevbase_exit(void){/* 注销字符设备驱动 */unregister_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME);printk("chrdevbase_exit()\r\n"); }/** 将上面两个函数指定为驱动的入口和出口函数*/module_init(chrdevbase_init);module_exit(chrdevbase_exit);/** LICENSE和作者信息*/MODULE_LICENSE("GPL");MODULE_AUTHOR("junluoyu");
#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include
/***************************************************************
文件名 : chrdevbaseApp.c
作者 : junluoyu
版本 : V1.0
描述 : chrdevbase驱动测试APP
其他 : 无
日志 : 初版 V1.0 2022/11/28
其他 : ./chrdevbaseApp /dev/chrdevbase 1(读文件)|2(写文件)
***************************************************************/
static char usrdata[] = {"usr data!"};/** @description : main主程序* @param -argc :argv数组元素长度* @param -argv :具体参数*/
int main(int argc, char *argv[])
{int fd, retvalue;char *filename;char readbuf[100], writebuf[100];if (argc != 3) {printf("Error Usage!\r\n");return -1;}filename = argv[1];/* 打开驱动文件 */fd = open(filename, O_RDWR);if (fd < 0) {printf("Can't open file %s \r\n", filename);return -1;}if (atoi(argv[2]) == 1) { /* 从驱动文件读取数据 */retvalue = read(fd, readbuf, 50);if (retvalue < 0) {printf("read file %s failed!\r\n", filename);} else {/* 读取成功,打印出读取成功的数据*/printf("read data:%s \r\n", readbuf);}}if (atoi(argv[2]) == 2) { /* 向驱动文件写数据 */memcpy(writebuf, usrdata, sizeof(usrdata));retvalue = write(fd, writebuf, 50);if (retvalue < 0) {printf("write file %s failed!\r\n", filename);} }/* 关闭设备 */retvalue = close(fd);if (retvalue < 0) {printf("Can't close file %s failed!\r\n", filename);return -1;} return 0;
}
KERNELDIR := /home/yinliang/linux/kernel/nxp_linux
CURERENT_PATH := $(shell pwd)
obj-m := chrdevbase.obuild: kernel_modulskernel_moduls:$(MAKE) -C $(KERNELDIR) M=$(CURERENT_PATH) modules
clean:$(MAKE) -C $(KERNELDIR) M=$(CURERENT_PATH) clean
arm-linux-gnueabihf-gcc chrdevbaseApp.c -o chrdevbaseApp
file chrdevbaseApp
sudo cp chrdevbase.ko chrdevbaseApp /home/yinliang/linux/nfs/rootfs/lib/modules/4.1.15/ -f
cd /lib/modules/4.1.151.安装驱动模块
insmod chrdevbase.ko modprobe chrdevbase.ko #会安装依赖文件2.挂载
cat /proc/devices #看有没有设备mknod /dev/chrdevbase c 200 0 #mknod创建节点命令,/dev/chrdevbase是创建的节点文件,c表示是字符设备,200是主设备号,0表示设备的次设备号ls /dev/chrdevbase -l3.测试
chmod 777 /dev/chrdevbase./chrdevbaseApp /dev/chedevbase 1./chrdevbaseApp /dev/chedevbase 24.卸载驱动模块
rmmod chrdevbase.ko modprobe -r chrdevbase.ko #会卸载依赖文件
IMX6U_CCM_CCGR1 = ioremap(CCM_CCGR1_BASE ,4);
// 物理地址映射到虚拟地址 4代表4个字节
iounmap(IMX6U_CCM_CCGR1 );
// 取消映射关系
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include /***************************************************************
文件名 : led.c
作者 : junluoyu
版本 : V1.0
描述 : led驱动文件。
其他 : 无
日志 : 初版 V1.0 2022/11/20
***************************************************************//* 寄存器物理地址 */
#define CCM_CCGR1_BASE (0X020C406C)
#define SW_MUX_GPIO1_IO03_BASE (0X020E0068)
#define SW_PAD_GPIO1_IO03_BASE (0X020E02F4)
#define GPIO1_DR_BASE (0X0209C000)
#define GPIO1_GDIR_BASE (0X0209C004)/* 映射后的寄存器虚拟地址指针 */
static void __iomem *IMX6U_CCM_CCGR1;
static void __iomem *SW_PAD_GPIO1_IO03;
static void __iomem *SW_MUX_GPIO1_IO03;
static void __iomem *GPIO1_DR;
static void __iomem *GPIO1_GDIR;#define LED_MAJOR 200 /* 主设备号 */
#define LED_NAME "led" /* 设备名 */#define LEDOFF 0 //关灯
#define LEDON 1 //开灯/** @description : led打开/关闭* @param - sta :LED0N 0 打开LED LEDOFF 1 关闭LED* @return :无*/void led_switch(u8 sta){u32 val = 0;if(sta == LEDON) {val = readl(GPIO1_DR);val &= ~(1<<3);writel(val,GPIO1_DR);} else if (sta == LEDOFF) {val = readl(GPIO1_DR);val |= (1<<3);writel(val,GPIO1_DR);}}/** @description : 打开设备* @param - inode :传递给驱动的inode * @param - filp :设备文件,file结构体有给叫做private_data的成员变量* ,一般再open的时候将private_data指向设备的结构体 * @return :0成功;其他失败*/static int led_open(struct inode *inode, struct file *filp){return 0;}/** @description : 从设备读取数据* @param - buf :返回给用户空间的数据缓冲区* @param - filp :要打开的设备文件(文件描述符)* @param - cnt :要读取的数据长度* @param - offt :相对于文件首地址的偏移* @return :读取的字节数,负值表示读取失败*/static ssize_t led_read(struct file *filp, char __user *buf,size_t cnt, loff_t *offt){return 0;}/** @description : 从设备写数据* @param - buf :要写给设备写入的数据* @param - filp :设备文件,表示打开的文件描述符* @param - cnt :要写入的数据长度* @param - offt :相对于文件首地址的偏移* @return :写入的字节数,负值表示读取失败*/static ssize_t led_write(struct file *filp, const char __user *buf,size_t cnt, loff_t *offt){int retvalue = 0;unsigned char databuf[1];unsigned char ledstat;/*接收用户空间传递给内核的数据并打印出来*/retvalue = copy_from_user(databuf, buf, cnt);if(retvalue < 0) {printk("kernel write failed: \r\n");return -EFAULT;}ledstat = databuf[0]; //读取状态值if(ledstat == LEDON) {led_switch(LEDON); //打开LED灯}else if(ledstat == LEDOFF) {led_switch(LEDOFF); //关闭LED灯}return 0;}/** @description : 关闭、释放设备* @param - filp :要关闭的设备文件* @return :0成功;其他 失败*/static int led_release(struct inode *inode, struct file *filp){// printk("led release! \r\n");return 0;}/** 设备操作结构体*/
static struct file_operations led_fops = {.owner = THIS_MODULE,.open = led_open,.read = led_read,.write = led_write,.release = led_release,
};/** @description : 驱动入口函数* @param - filp :无* @return :0成功; 其他 失败*/static int __init led_init(void){int retvalue = 0;u32 val = 0;/* 初始化LED *//* 1.寄存器地址映射 */IMX6U_CCM_CCGR1 = ioremap(CCM_CCGR1_BASE ,4);SW_MUX_GPIO1_IO03 = ioremap(SW_MUX_GPIO1_IO03_BASE ,4);SW_PAD_GPIO1_IO03 = ioremap(SW_PAD_GPIO1_IO03_BASE ,4);GPIO1_DR = ioremap(GPIO1_DR_BASE ,4);GPIO1_GDIR = ioremap(GPIO1_GDIR_BASE ,4);/* 2.使能GPIO1时钟 */val = readl(IMX6U_CCM_CCGR1);val &= ~(3<<26); /* 清除以前的设置 */val |= (3<<26); /* 设置新值 */writel(val, IMX6U_CCM_CCGR1);/* 3.设置GPIO1_IO03的复用功能,将其复用为GPIO01_IO03,最后设置IO属性 */writel(5, SW_MUX_GPIO1_IO03); //mux复用功能为5writel(0X10B0, SW_PAD_GPIO1_IO03); //PAD设置IO属性/* 4.设置GPIO1_IO03为输出功能*/val = readl(GPIO1_GDIR);val &= ~(1<<3); /* 清除以前的设置 */val |= (1<<3); /* 设置为输出 */writel(val,GPIO1_GDIR);/* 5.默认关闭LED*/val = readl(GPIO1_DR);val |= (1<<3); //默认为关,1电平writel(val, GPIO1_DR);/* 6.注册字符设备驱动 */retvalue = register_chrdev(LED_MAJOR, LED_NAME,&led_fops);if (retvalue < 0){printk("register led failed\r\n");return -EIO;}return 0;}/** @description : 驱动出口函数* @param - filp :无* @return :无*/void __exit led_exit(void){/* 取消映射 */iounmap(IMX6U_CCM_CCGR1 );iounmap(SW_PAD_GPIO1_IO03 ); iounmap(SW_MUX_GPIO1_IO03 ); iounmap(GPIO1_DR ); iounmap(GPIO1_GDIR ); /* 注销字符设备驱动 */unregister_chrdev(LED_MAJOR,LED_NAME);}/** 将上面两个函数指定为驱动的入口和出口函数*/module_init(led_init);module_exit(led_exit);/** LICENSE和作者信息*/MODULE_LICENSE("GPL");MODULE_AUTHOR("junluoyu");
#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
/***************************************************************
文件名 : ledApp.c
作者 : junluoyu
版本 : V1.0
描述 : led驱动测试APP
其他 : 无
日志 : 初版 V1.0 2022/11/28
其他 : ./ledApp /dev/led 1(打开LED)|0(关闭LED)
***************************************************************/
#define LEDOFF 0 //关灯
#define LEDON 1 //开灯/** @description : main主程序* @param -argc :argv数组元素长度* @param -argv :具体参数*/
int main(int argc, char *argv[])
{int fd, retvalue;char *filename;unsigned char databuf[1];if (argc != 3) {printf("Error Usage!\r\n");return -1;}filename = argv[1];/* 打开驱动文件 */fd = open(filename, O_RDWR);if (fd < 0) {printf("Can't open file %s \r\n", filename);return -1;}databuf[0] = atoi(argv[2]);/* 向/dev/led文件写入数据 */retvalue = write(fd, databuf,sizeof(databuf));if (retvalue < 0) {printf("led control failed!\r\n");close(fd);return -1;} /* 关闭led设备 */retvalue = close(fd);if (retvalue < 0) {printf("file %s close failed!\r\n", argv[1]);return -1;} return 0;
}
KERNELDIR := /home/yinliang/linux/kernel/nxp_linux
CURERENT_PATH := $(shell pwd)
obj-m := led.obuild: kernel_modulskernel_moduls:$(MAKE) -C $(KERNELDIR) M=$(CURERENT_PATH) modules
clean:$(MAKE) -C $(KERNELDIR) M=$(CURERENT_PATH) clean
make -j16
arm-linux-gnueabihf-gcc led.c -o ledApp
file chrdevbaseApp
sudo cp led.ko ledApp /home/yinliang/linux/nfs/rootfs/lib/modules/4.1.15/ -f
cd /lib/modules/4.1.151.安装驱动模块 第一次加载先使用depmod
insmod led.ko modprobe led.ko #会安装依赖文件2.挂载
cat /proc/devices #看有没有设备mknod /dev/led c 200 0 #mknod创建节点命令,/dev/led是创建的节点文件,c表示是字符设备,200是主设备号,0表示设备的次设备号ls /dev/led -l3.测试
chmod 777 /dev/led./ledApp /dev/led 1 //开灯./ledApp /dev/led 2 //关灯4.卸载驱动模块
rmmod ledbase.ko modprobe -r ledbase.ko #会卸载依赖文件
上一篇:内部购买破解版是什么意思
下一篇:初三语文25课五首诗