字符设备驱动应用---LED设备驱动实现

本文介绍如何为iTop4412开发板上的LED灯编写Linux字符设备驱动程序,通过ioctl系统调用控制LED的状态。文章详细解释了从硬件资源分析到驱动代码实现的全过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目标

本次实验将为开发上的LED灯实现驱动代码,应用程序可以通过ioctl系统调用控制LED灯的亮灭。

硬件资源

处理器

本人使用的开发板是讯为科技的iTop4412开发板,CPU是三星的4412,属于A9系列。

原理图

这里写图片描述
这里写图片描述
在开发板的原理图中,可以看到LED是连到GPL2_0引脚的,因此我们要控制LED,就要控制这个引脚。

寄存器物理地址转化成虚拟地址

翻看4412的芯片手册,可以找到控制led的I/O口的相关寄存器,我们需要对其进行设置。
不像裸机代码里,控制某个寄存器可以使用物理地址,在Linux系统里,用户用到的所有地址内核都认为是虚拟地址。内核看到一个地址以后把它当成虚拟地址,当内核需要读写这些地址时,需要经过内存管理子系统翻译成物理地址再读写。因此我们想要控制I/O寄存器,需要将寄存器的地址转化成虚拟地址,然后再通过虚拟地址控制这些寄存器。
内核中提供了如下宏将物理地址转化成虚拟地址:

ioremap(physaddr,size);

physaddr 是待转化的物理地址,size是物理地址的长度,返回虚拟地址。
内核还提供了若干函数给相关虚拟地址写数据:

void writel(unsigend int data,volatile void _iomem *addr);

代码实现

根据字符设备驱动,可以编写基于字符设备驱动模型的LED设备驱动,代码如下:

驱动代码

#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/io.h>
/*设备描述符*/
struct cdev led_dev;

/*设备号*/
dev_t devno;

/*控制寄存器地址*/
#define LEDCON 0x11000100
#define LEDDAT 0x11000104

/*控制器转换后的虚拟地址*/
unsigned int *led_con;
unsigned int *led_dat; 

/*打开函数*/
int led_open(struct inode *inode,struct file *file){
    led_con = ioremap(LEDCON,4);
    led_dat = ioremap(lEDDAT,4);
    writel(0x00000001,led_con);
    return 0;
}
/*控制函数*/
long led_ioctl(struct file *file,unsigned int cmd,unsigned long arg){
    switch(cmd){
        //点亮led
        case 1: writel(0x01,led_dat);
                break;
        //熄灭led
        case 0: writel(0x00000000,led_dat);
                break;
        default:
                return -EINVAL;
    }
    return 0;

}
/*关闭函数*/
int led_close(struct inode *inode, struct file *file){
    return 0;

}
/*文件操作函数集合*/
struct file_operations led_ops = {
    .open = led_open,
    .unblocked_ioctl = led_ioctl,
    .release = led_close,
};
/*模块初始化*/
static int led_init(void){
    int ret;
    //初始化cdev
    cdev_init(&led_dev,&led_ops);

    //分配设备号
    alloc_chrdev_region(&devno,0,1,"myled");
    //注册驱动
    ret = cdev_add(&led_dev,devno,1);
    return ret;
}

/*模块注销*/
static void led_exit(void){
    //注销设备结构
    cdev_del(&led_dev);
    //注销设备号
    unregister_chrdev_region(&led_dev,2);
}

/*遵循协议声明*/
MODULE_LICENSE("GPL");

/*模块安装和卸载函数*/
module_init(led_init);
module_exit(led_exit);

应用代码

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <fcntl.h>
int main(int arg,char *argv[]){
    int fd;
    int i=0;
    if((fd=open("/dev/myled",O_RDWR))<0){
        printf("App open file failed!\n");
        return 0;
    }
    while(i++ < 4){
        ioctl(fd,0);
        sleep(1);
        ioctl(fd,1);
        sleep(1);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值