写一个点LED的驱动分为下面几个步骤:
1.框架
2.完善硬件的操作
a.看原理图
b.看6410手册
c.写代码:
单片机:操作物理地址
测试代码:
1.框架
2.完善硬件的操作
a.看原理图
b.看6410手册
c.写代码:
单片机:操作物理地址
驱动:操作虚拟地址:ioremap来进行映射。
查看6410原理图LED SCH如下:
从上图可以看到,要使得LED点亮,需要使得nLEDx输出的电平为低电平,继续查看SCH,可以看到nLEDx连接到主核心板的GPM 引脚,如下所示:
所以要操作的工作有:
1.设置GPM0 - GPM3为输出引脚
2.点灯或者灭灯,对GPMDAT 进行操作即可。
3.使用ioremap和iounmap对物理地址进行映射和取消映射。
具体代码如下:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <linux/device.h>
#include <asm/io.h>
struct class *first_dev_class;
struct device *first_dev;
volatile unsigned long *gpmcon = NULL;
volatile unsigned long *gpmdat = NULL;
static int first_drv_open(struct inode *inode, struct file *file) //设备节点的相关操作函数
{
printk("first_drv_open!!\n");
//设置gpio为输出引脚
*gpmcon &= ~(0x3 | 0x3 << 4 | 0x3 << 8 | 0x3 << 12);
*gpmcon |= (0x1 | 0x1 << 4 | 0x1 << 8 | 0x1 << 12);
return 0;
}
static int first_drv_read(struct file *filp, char __user *buff,
size_t count, loff_t *offp)
{
printk("first_drv_read!!\n");
return 0;
}
ssize_t first_drv_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
{
printk("first_drv_write!!\n");
int val;
copy_from_user(&val,buf,len);
if(val == 1){
//点灯
*gpmdat &= ~(1 << 0 | 1 << 1 | 1 << 2 | 1 << 3);
}else if(val == 0){
//灭灯
*gpmdat |= (1 << 0 | 1 << 1 | 1 << 2 | 1 << 3);
}
return sizeof(buf);
}
static struct file_operations first_drv_fops = { //填充file_operations结构体
.owner = THIS_MODULE,
.open = first_drv_open,
.read = first_drv_read,
.write = first_drv_write,
};
int major;
static int __init first_drv_init(void)//入口函数
{
printk("first_drv_init\n");
major = register_chrdev(0,"first_drv",&first_drv_fops);//告诉内核设备的操作,将first_drv_fops挂接到主设备为123的索引节点上从而让app可以找到
first_dev_class = class_create(THIS_MODULE,"first_class");
first_dev = device_create(first_dev_class,NULL,MKDEV(major,0),NULL,"shanl");
gpmcon = (volatile unsigned long *)ioremap(0x7F008820, 16);//地理地址转换为虚拟地址
gpmdat = gpmcon + 1;
return 0;
}
static void __exit first_drv_exit(void)
{
printk("first_drv_exit\n");
device_destroy(first_dev_class,MKDEV(major,0));
class_destroy(first_dev_class);
unregister_chrdev(major,"first_drv");
iounmap(0x7F008820);
}
module_init(first_drv_init);//入口修饰函数
module_exit(first_drv_exit);
MODULE_LICENSE("GPL"); //证书
测试代码:
#include <stdio.h>
#include <fcntl.h>
int main(int argc , char **argv)
{
int fd ;
int val;
if(argc < 2){
printf("Usage : %s <on/off> \n",argv[0]);
return -1;
}
if(!strcmp(argv[1],"on")){
val = 1;
}else if(!strcmp(argv[1],"off")){
val = 0;
}
fd = open("/dev/shanl",O_RDWR); //打开设备节点/dev/shanl
if(fd < 0){
printf("Can not open devices\n");
return -1;
}
write(fd,&val,4);//向设备节点做写操作
return 0;
}