树莓派内核驱动配置

cat  /proc/cpu/nfo可查看cpu信息。pi3 pi4cpu型号不同,起始地址不同。pi3是BCM2835 PI4是BCM2711.

查看cpu起始物理地址的c文件。Pi4 pi3 起始地址不同。bcm_host.h头文件须链接库 

gcc addrBase.c -I /opt/vc/include -L /opt/vc/lib -lbcm_host

#include <stdio.h>
#include <bcm_host.h>

void main()
{
    unsigned t;
    t = bcm_host_get_peripheral_address();
    printf("baseadd = %x\n",t);
}

 

 

pi4基地址参考博文:https://blog.csdn.net/chenchengwudi/article/details/121902861

 

 

这是驱动框架

#include <linux/fs.h>         //file_operations声明
#include <linux/module.h>    //module_init  module_exit声明
#include <linux/init.h>      //__init  __exit 宏定义声明
#include <linux/device.h>     //class  devise声明
#include <linux/uaccess.h>   //copy_from_user 的头文件
#include <linux/types.h>     //设备号  dev_t 类型声明
#include <asm/io.h>          //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";   //模块名
 
//led_open函数
static int pin4_open(struct inode *inode,struct file *file)
{
    printk("pin4_open\n");  //内核的打印函数和printf类似
      
    return 0;
}
 
//led_write函数
static ssize_t pin4_write(struct file *file,const char __user *buf,size_t count, loff_t *ppos)
{
    printk("pin4_write\n");
    
    return 0;
}
 
static struct file_operations pin4_fops = {
    .owner = THIS_MODULE,
    .open  = pin4_open,
    .write = pin4_write,
};
 
int __init pin4_drv_init(void)   //真实驱动入口
{
    int ret;
    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);  //创建设备文件
    
    return 0;
}
 
void __exit pin4_drv_exit(void)
{
    device_destroy(pin4_class, devno);
    class_destroy(pin4_class);
    unregister_chrdev(major, module_name);  //卸载驱动
 
}
 
module_init(pin4_drv_init);  //入口,内核加载该驱动(insmod)的时候,这个宏被使用
module_exit(pin4_drv_exit);
MODULE_LICENSE("GPL v2");
 

ioremap函数原型:

  void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)

  void *ioremap(unsigned long phys_addr, unsigned long size)
  入口: phys_addr:要映射的起始的IO地址;
  size:要映射的空间的大小;
  flags:要映射的IO空间的和权限有关的标志;
  phys_addr:是要映射的物理地址
  size:是要映射的长度,单位是字节
  头文件:io.h
 
iounmap函数原型: 
  void iounmap (volatile void _iomem *addr)
 
copy_form_user函数原型:

  1. copy_from_user函数的目的是从用户空间拷贝数据到内核空间

  2. 解析原型:
  copy_from_user(void *to, const void __user *from, unsigned long n)
 
  1. @*to         将数据拷贝到内核的地址
  2. @*from    需要拷贝数据的地址
  3. @n     拷贝数据的长度(字节)
  3. 也就是将@form地址中的数据拷贝到@to地址中去,拷贝长度是n
  4. 使用示例
  int val;
  copy_from_user(&val, buf, count);
 
  @buf是调用应用程序中传入的
 
copy_to_user函数原型:
  unsigned long copy_to_user(void *to, const void __user *from, usigned long count);

 这是pi4亲测有效驱动pin21的程序:

#include <linux/fs.h>         //file_operations声明
#include <linux/module.h>    //module_init  module_exit声明
#include <linux/init.h>      //__init  __exit 宏定义声明
#include <linux/device.h>     //class  devise声明
#include <linux/uaccess.h>   //copy_from_user 的头文件
#include <linux/types.h>     //设备号  dev_t 类型声明
#include <asm/io.h>          //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 = "pin21";   //模块名
 
volatile unsigned int *GPFSEL2 = NULL;
volatile unsigned int *GPSET0 = NULL;
volatile unsigned int *GPCLR0 = NULL;
 
//led_open函数
static int pin4_open(struct inode *inode,struct file *file)
{
    printk("pin4_open\n");  //内核的打印函数和printf类似
        
        *GPFSEL2 &= ~(0x3 << 4);
        *GPFSEL2 |=  (0x1 << 3);
        
    return 0;
}
 
//led_write函数
static ssize_t pin4_write(struct file *file,const char __user *buf,size_t count, loff_t *ppos)
{
    int usrnum;
    printk("pin4_write\n");
    copy_from_user(&usrnum,buf,count);
    if(usrnum == 1){
        *GPSET0 |= (0x1 << 21);
    }else if(usrnum == 0){
        *GPCLR0 |= (0x1 << 21);
    }else{
        printk("ubdo\n");
    }
    
    return 0;
}
 
static struct file_operations pin4_fops = {
    .owner = THIS_MODULE,
    .open  = pin4_open,
    .write = pin4_write,
};
 
int __init pin4_drv_init(void)   //真实驱动入口
{
    int ret;
    printk("dp init\n");
    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);  //创建设备文件
    
    GPFSEL2 = (volatile unsigned int*)ioremap(0xFE200008,4);
    GPSET0  = (volatile unsigned int*)ioremap(0xFE20001C,4);
    GPCLR0  = (volatile unsigned int*)ioremap(0xFE200028,4);
    printk("%p\n",GPFSEL2);
    
    return 0;
}
 
void __exit pin4_drv_exit(void)
{
    iounmap(GPFSEL2);
    iounmap(GPSET0);
    iounmap(GPCLR0);
    
    device_destroy(pin4_class, devno);
    class_destroy(pin4_class);
    unregister_chrdev(major, module_name);  //卸载驱动
 
}
 
module_init(pin4_drv_init);  //入口,内核加载该驱动(insmod)的时候,这个宏被使用
module_exit(pin4_drv_exit);
MODULE_LICENSE("GPL v2");
 

 

driver.c cp 到linux/drivers/ach(或者drivers下其他文件夹,到哪个文件夹就改哪个文件夹下的Makefile)

vi Makefile  -m表示模块化编译   驱动文件名.o(这是模仿他这里面的文件写的)

 

 

ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7l make modules(此命令要在源码起始目录进行,不然报错no rules。)

得到.ko文件到树莓派。scp .... pi@192.168.0.23:/home/pi

 

 

sudo insmod qudong2.ko 加载内核驱动

ls /dev/pin4 -l查看有无驱动:

sudo chmod 666 /dev/pin4给权限

运行test.c

 

 

dmesg看驱动打印在内核的信息

sudo rmmod +驱动名(不需要写ko)将驱动卸载。

 

posted @ 2023-02-25 22:42  HxxxTENCTION  阅读(158)  评论(0)    收藏  举报