基于基本框架简单实现树莓派IO口驱动代码的编写

基于基本框架简单实现树莓派IO口驱动代码的编写,第1张

基于基本框架简单实现树莓派IO口驱动代码的编写

1. 驱动代码实现:

#include             //file_operations声明
#include     //module_init  module_exit声明
#include       //__init  __exit 宏定义声明
#include         //class  devise声明
#include    //copy_from_user 的头文件
#include      //设备号  dev_t 类型声明
#include           //ioremap iounmap的头文件


static struct class *pin4_class;
static struct device *pin4_class_dev;

static dev_t devno;                //设备号
static int major =231;             //主设备号
static int minor =0;               //次设备号
static char *module_name="pin4";   //模块名

volatile unsigned int *GPFSEL0 = NULL;      //volatile避免地址因编译器的优化而省略,同时也要求每次编译时在原始内存中读值,而不是寄存器中的备份数据,提高时效性
volatile unsigned int *GPSET0  = NULL;
volatile unsigned int *GPCLR0  = NULL;


//led_open函数
static int pin4_open(struct inode *inode,struct file *file)
{
        printk("pin4_openn");  //内核的打印函数和printf类似
        //配置pin4引脚为输出引脚,将bit 14,13,12配置为001
        *GPFSEL0 &= ~(0x6 << 12);  //将bit 14,13置为00, 这里包括下一步通过与或的操作是为了不影响其他位的设置
        *GPFSEL0 |= (0x1 << 12);   //将bit 12置1

        return 0;
}

//led_read函数
static int pin4_read(struct file *file, char __user *buf,size_t count, loff_t *ppos)
{
        printk("pin4_readn");

        return 0;
}

//led_write函数
static ssize_t pin4_write(struct file *file,const char __user *buf,size_t count, loff_t *ppos)
{
        int userCmd;
        printk("pin4_writen");
        //从上层获得write函数的值
        copy_from_user(&userCmd, buf, count);
        //根据获取到的上层写入值来设置IO口引脚高低电平
        printk("get datan");
        if (userCmd == 1){
                *GPSET0 |= (0x1 << 4);
                printk("pin4 sets 1n");
        }
        else if (userCmd == 0){
                *GPCLR0 |= (0x1 << 4);
                printk("pin4 sets 0n");
        }
        else {
                printk("set faliuern");
        }

        return 0;
}

static struct file_operations pin4_fops = {

        .owner = THIS_MODULE,
        .open  = pin4_open,
        .write = pin4_write,
        .read  = pin4_read,
};

int __init pin4_drv_init(void)
{
        int ret;
        printk("insmod driver pin4 successn");
        devno = MKDEV(major,minor);  //创建设备号
        ret   = register_chrdev(major, module_name,&pin4_fops);  //注册驱动  告诉内核,把这个驱动加入到内核驱动的链表中

        pin4_class=class_create(THIS_MODULE,"myfirstdemo");  //让代码在dev自动生成设备
        pin4_class_dev =device_create(pin4_class,NULL,devno,NULL,module_name);  //创建设备文件

        GPFSEL0 = (volatile unsigned int *)ioremap(0x3f200000, 4);  //用ioremap将物理地址转化为虚拟地址,将io口寄存器映射成普通内存单元进行访问
        GPSET0  = (volatile unsigned int *)ioremap(0x3f20001C, 4);
        GPCLR0  = (volatile unsigned int *)ioremap(0x3f200028, 4);

        return 0;
}

void __exit pin4_drv_exit(void)
{
        iounmap(GPFSEL0);
        iounmap(GPSET0);
        iounmap(GPCLR0);

        device_destroy(pin4_class,devno);
        class_destroy(pin4_class);
        unregister_chrdev(major, module_name);  //卸载驱动

}

module_init(pin4_drv_init);  //,注意这个不是函数调用,它是一个宏,是加载内核的入口,内核加载驱动的时候,这个宏会被调用,即pin4_drv_init()这个函数会被调用
module_exit(pin4_drv_exit);
MODULE_LICENSE("GPL v2");

2. 上层测试代码实现:

#include 
#include 
#include 
#include 

int main(int argc, char *argv[])
{
        int fd;
        int n_write;
        int cmd;

        fd = open("/dev/pin4", O_RDWR);
        if (fd == -1){
                printf("open /dev/pin4 failuern");
                perror("failuer reason");
        }
        else {
                printf("fd = %dn", fd);
                printf("open /dev/pin4 successn");
        }
        printf("Please input 1/0 to select high/low voltage in pin4n");
        scanf("%d", &cmd);
        if (cmd == 1){
                printf("cmd = %dn", cmd);
                n_write = write(fd, &cmd, 4);  //注意这里len=4不是1,因为cmd是int型占4个字节

        }
        else if (cmd == 0){
                printf("cmd = %dn", cmd);
                n_write = write(fd, &cmd, 4);

        }
        else {
                printf("Wrong Inputn");
        }

        return 0;
}
~    

3. 实现过程:
(1)对内核进行编译:

ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make -j4 modules

同样的将生成的pin4Driver2.ko驱动文件scp到树莓派上,树莓派上将先前的pin4Driver2驱动卸载了,即sudo rmmod pin4Driver2 ,再sudo insmod pin4Driver2.ko 加载驱动,最后也是很关键的一步,即sudo chmod 666 /dev/pin4 更改/dev/pin4访问权限后驱动才能运行成功。

(2)将上层测试文件交叉编译后scp到树莓派上,即arm-linux-gnueabihf-gcc pin4Test.c -o pin4Test ,scp pin4Test pi@172.20.10.6:/home/pi

(3)在树莓派上运行pin4Test,并打开树莓派gpio(gpio readall):
最后再通过dmesg查看内核打印信息:
当然,我们还可以实现上层read以及其它引脚电平的配置

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5651727.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-16
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存