基于Gpio的Linux字符型驱动设计--…
2014-01-26 16:01
218 查看
流水灯Linux驱动步骤
第一步:编写字符设备驱动
第二步:加载
第三步:编写应用程序测试设备驱动
第一步:编写流水灯Linux驱动
在/linux-3.2/driver/char/sep4020_char/
下面新建一个sep4020_flowled.c
内容如下:
#define KEY_MAJOR 249
#define LED_ON 1
#define LED_OFF 2
struct led_dev
{
struct cdev cdev;
unsigned char value;
};
struct led_dev *leddev;
打开和关闭操作
open和release函数会在设备打开和关闭时被调用,open的时候对设备进行初始化
static int sep4020_flowled _open(struct inode * inode, struct file
* filp)
{
sep4020_flowled_setup();
……
}
static int sep4020_flowled _release(struct inode * inode, struct
file * filp)
{
……
return
0;
}
写入和读出操作
static int sep4020_flowled _write(struct file *file, const char
* buffer,size_t count, loff_t *ppos)
{
return 0;
}
static int sep4020_flowled _read(struct file *file, const char *
buffer,size_t count, loff_t * ppos)
{
return 0;
}
设备操作
int sep4020_flowled_ioctl(struct inode *inode, struct file
*filp, unsigned int cmd, unsigned long arg)
{
struct
led_dev *dev = filp->private_data;
unsigned int
i,j;
switch
(cmd)
{
case LED_ON:
j=i;
if(j<6)
dev->value
|=1<<j;
else dev->value
>>=1;
*(volatile unsigned long*)GPIO_PORTE_DATA_V =
dev->value; //flow led is open;
i++;
break;
case LED_OFF:
dev->value = 0;
*(volatile unsigned long*)GPIO_PORTE_DATA_V = 0; //flow led is
close;
break;
default:
return -ENOTTY;
}
return 0;
}
设备初始化
static int __init sep4020_flowled _init(void)
{
//申请设备号
dev_t devno = MKDEV(KEY_MAJOR, 0);
if(KEY_MAJOR)
result = register_chrdev_region(devno, 1, "sep4020_flowled");
leddev = kmalloc(sizeof(struct led_dev),GFP_KERNEL);
if (!leddev)
{
result = -ENOMEM;
goto fail_malloc;
}
//硬件初始化,推荐在open中实现
//sep4020_flowled_setup();
//字符设备注册
cdev_init(&(leddev->cdev),
&sep4020_flowled_fops);
leddev->cdev.owner = THIS_MODULE;
err = cdev_add(&leddev->cdev, devno,
1);// 创建设备文件
return 0;
fail_malloc: unregister_chrdev_region(devno,1);
return result;
}
设备注销
static void __exit sep4020_flowled_exit(void)
{
//删除设备文件
cdev_del(&leddev->cdev);
kfree(leddev);
unregister_chrdev_region(MKDEV(KEY_MAJOR, 0),1);//注销设备
unregister_chrdev(Led_Major, DEVICE_NAME);
}
module_init(sep4020_flowled _init); //向Linux系统记录设备初始化的函数名称
module_exit(sep4020_flowled_exit); //向Linux系统记录设备退出的函数名称
修改Kconfig和Makefile
在相应的字符型驱动的目录顶部的Kconfig中添加如下语句:
config SEP4020_FLOWLED
tristate "sep4020 flowed led"
在相同目录底下的Makefile中添加如下语句:
obj-$(CONFIG_SEP4020_FLOWLED) += sep4020_flowled.o
第二步:驱动程序的加载
Linux内核有2种加载驱动程序的方法:
静态:
Linux系统启动时,通过代码自身加载模块.这种方式称为静态编译入内核, 驱动程序开发完毕后一般使用这种方式.
动态:
Linux系统启动后,通过insmod等命令加载模块.这种方式称为动态加载,驱动程序开发调试过程中一般使用这种方式.
方法1:驱动程序以驱动模块加载
打开终端,进入Linux根目录,输入命令make
menuconfig
进入device drivers->character
device->sep4020 char devices->sep4020
key driver
使用空格键将sep4020_flowed选择成M
运行make 命令,编译通过后当前目录下就生成名为sep4020_flowled.ko的驱动程序
模块动态加载
#insmod
sep4020_flowled.ko 驱动程序模块插入内核
#cat
/proc/devices
查看是否载入,如果载入成功会显示你的设备名称sep4020_flowled
#rmmod
sep4020_flowled.ko
从内核移除设备
动态加载在开发板端的具体操作如下:
(1)将开发板上电,并将sep4020_flowled.ko拷贝到网络文件系统/demo/目录下面
(2)在/dev/目录下创建一个设备节点flowled
/dev # mknod flowled c 249 0
(3)驱动程序模块插入内核
insmod sep4020_flowled.ko
(4)#cat /proc/devices
查看是否载入,如果载入成功会显示你的设备名称sep4020_flowled
方法2:静态编译进内核
打开终端,进入Linux根目录,输入命令make menuconfig
进入device drivers->character
device->sep4020 char devices->sep4020
key driver
使用空格键将sep4020_flowed选择成*
运行make 命令,编译通过后就将流水灯驱动编译进内核了
执行mkimage指令重新生成新的能被uboot引导的内核
静态编译开发板端的操作:
(1)将重新编译好的内核重新拷贝至tftp目录下,重新开发板上电
(2)在/dev/目录下创建一个设备节点flowled
# mknod /dev/flowled c 249 0
第三步:编译应用程序
#include
<stdio.h>
#define OPEN 1
#define CLOSE 2
int main(int argc,char **argv)
{
int fd;
int i,j;
fd = open("/dev/flowled",0);
if(fd == -1)
{
printf("wrong\r\n");
exit(-1);
}
for(j=0;
j<41; j++)
{
ioctl(fd,OPEN,0);
for(i=0; i<1000000; i++);
}
close(fd);
return 0;
}
利用arm-linux-gcc将其编译为可执行的二进制文件:
指令如下:arm-linux-gcc–o flowledflowled.c
将编译好的flowled文件拷贝至nfs文件夹下
第一步:编写字符设备驱动
第二步:加载
第三步:编写应用程序测试设备驱动
第一步:编写流水灯Linux驱动
在/linux-3.2/driver/char/sep4020_char/
下面新建一个sep4020_flowled.c
内容如下:
#define KEY_MAJOR 249
#define LED_ON 1
#define LED_OFF 2
struct led_dev
{
struct cdev cdev;
unsigned char value;
};
struct led_dev *leddev;
打开和关闭操作
open和release函数会在设备打开和关闭时被调用,open的时候对设备进行初始化
static int sep4020_flowled _open(struct inode * inode, struct file
* filp)
{
sep4020_flowled_setup();
……
}
static int sep4020_flowled _release(struct inode * inode, struct
file * filp)
{
……
return
0;
}
写入和读出操作
static int sep4020_flowled _write(struct file *file, const char
* buffer,size_t count, loff_t *ppos)
{
return 0;
}
static int sep4020_flowled _read(struct file *file, const char *
buffer,size_t count, loff_t * ppos)
{
return 0;
}
设备操作
int sep4020_flowled_ioctl(struct inode *inode, struct file
*filp, unsigned int cmd, unsigned long arg)
{
struct
led_dev *dev = filp->private_data;
unsigned int
i,j;
switch
(cmd)
{
case LED_ON:
j=i;
if(j<6)
dev->value
|=1<<j;
else dev->value
>>=1;
*(volatile unsigned long*)GPIO_PORTE_DATA_V =
dev->value; //flow led is open;
i++;
break;
case LED_OFF:
dev->value = 0;
*(volatile unsigned long*)GPIO_PORTE_DATA_V = 0; //flow led is
close;
break;
default:
return -ENOTTY;
}
return 0;
}
设备初始化
static int __init sep4020_flowled _init(void)
{
//申请设备号
dev_t devno = MKDEV(KEY_MAJOR, 0);
if(KEY_MAJOR)
result = register_chrdev_region(devno, 1, "sep4020_flowled");
leddev = kmalloc(sizeof(struct led_dev),GFP_KERNEL);
if (!leddev)
{
result = -ENOMEM;
goto fail_malloc;
}
//硬件初始化,推荐在open中实现
//sep4020_flowled_setup();
//字符设备注册
cdev_init(&(leddev->cdev),
&sep4020_flowled_fops);
leddev->cdev.owner = THIS_MODULE;
err = cdev_add(&leddev->cdev, devno,
1);// 创建设备文件
return 0;
fail_malloc: unregister_chrdev_region(devno,1);
return result;
}
设备注销
static void __exit sep4020_flowled_exit(void)
{
//删除设备文件
cdev_del(&leddev->cdev);
kfree(leddev);
unregister_chrdev_region(MKDEV(KEY_MAJOR, 0),1);//注销设备
unregister_chrdev(Led_Major, DEVICE_NAME);
}
module_init(sep4020_flowled _init); //向Linux系统记录设备初始化的函数名称
module_exit(sep4020_flowled_exit); //向Linux系统记录设备退出的函数名称
修改Kconfig和Makefile
在相应的字符型驱动的目录顶部的Kconfig中添加如下语句:
config SEP4020_FLOWLED
tristate "sep4020 flowed led"
在相同目录底下的Makefile中添加如下语句:
obj-$(CONFIG_SEP4020_FLOWLED) += sep4020_flowled.o
第二步:驱动程序的加载
Linux内核有2种加载驱动程序的方法:
静态:
Linux系统启动时,通过代码自身加载模块.这种方式称为静态编译入内核, 驱动程序开发完毕后一般使用这种方式.
动态:
Linux系统启动后,通过insmod等命令加载模块.这种方式称为动态加载,驱动程序开发调试过程中一般使用这种方式.
方法1:驱动程序以驱动模块加载
打开终端,进入Linux根目录,输入命令make
menuconfig
进入device drivers->character
device->sep4020 char devices->sep4020
key driver
使用空格键将sep4020_flowed选择成M
运行make 命令,编译通过后当前目录下就生成名为sep4020_flowled.ko的驱动程序
模块动态加载
#insmod
sep4020_flowled.ko 驱动程序模块插入内核
#cat
/proc/devices
查看是否载入,如果载入成功会显示你的设备名称sep4020_flowled
#rmmod
sep4020_flowled.ko
从内核移除设备
动态加载在开发板端的具体操作如下:
(1)将开发板上电,并将sep4020_flowled.ko拷贝到网络文件系统/demo/目录下面
(2)在/dev/目录下创建一个设备节点flowled
/dev # mknod flowled c 249 0
(3)驱动程序模块插入内核
insmod sep4020_flowled.ko
(4)#cat /proc/devices
查看是否载入,如果载入成功会显示你的设备名称sep4020_flowled
方法2:静态编译进内核
打开终端,进入Linux根目录,输入命令make menuconfig
进入device drivers->character
device->sep4020 char devices->sep4020
key driver
使用空格键将sep4020_flowed选择成*
运行make 命令,编译通过后就将流水灯驱动编译进内核了
执行mkimage指令重新生成新的能被uboot引导的内核
静态编译开发板端的操作:
(1)将重新编译好的内核重新拷贝至tftp目录下,重新开发板上电
(2)在/dev/目录下创建一个设备节点flowled
# mknod /dev/flowled c 249 0
第三步:编译应用程序
#include
<stdio.h>
#define OPEN 1
#define CLOSE 2
int main(int argc,char **argv)
{
int fd;
int i,j;
fd = open("/dev/flowled",0);
if(fd == -1)
{
printf("wrong\r\n");
exit(-1);
}
for(j=0;
j<41; j++)
{
ioctl(fd,OPEN,0);
for(i=0; i<1000000; i++);
}
close(fd);
return 0;
}
利用arm-linux-gcc将其编译为可执行的二进制文件:
指令如下:arm-linux-gcc–o flowledflowled.c
将编译好的flowled文件拷贝至nfs文件夹下
相关文章推荐
- 嵌入式Linux中基于 Qt/Embeded触摸屏驱动的设计
- 基于NanoPi2的Linux3.4内核GPIO驱动
- 《嵌入式设计及Linux驱动开发指南——基于ARM9处理器》读书笔记
- s3c2440基于linux的gpio led字符设备驱动
- 基于S3C2440和linux的多路步进电机驱动设计
- 基于OMAPL138的Linux字符驱动_GPIO驱动AD9833(二)之cdev与read、write
- s3c2440基于linux的gpio led字符设备驱动实践
- 分层设计的驱动程序 及gpio驱动(Linux驱动5)
- Linux芯片级移植与底层驱动(基于3.7.4内核)(GPIO&&pinctrl&&clk)
- ZYNQ7000基于linux3.0操作系统驱动分析——GPIO驱动
- Linux 平台上的usb驱动开发,主要有内核驱动的开发和基于libusb的无驱设计。
- 基于ARM+Linux 2.6内核的控制系统驱动设计
- zynq-7000系列基于zynq-zed的vivado初步设计之linux下控制PL扩展的GPIO
- Linux 平台上的usb驱动开发,主要有内核驱动的开发和基于libusb的无驱设计。
- 基于NanoPi2的Linux3.4内核GPIO驱动
- 基于mini6410的linux驱动学习总结(四 设计字符设备驱动程序)
- Linux设备驱动程序学习(基于2440的GPIO字符设备驱动)
- 基于OMAPL138的Linux字符驱动_GPIO驱动AD9833(一)之miscdevice和ioctl
- 基于嵌入式ARM-Linux无线ZigBee协调器驱动设计
- 嵌入式设计及Linux驱动开发指南——基于ARM9处理器