Linux树莓派4B 驱动学习 驱动开发(GPIO)

驱动认知

  • 为什么需要驱动?
    • 在了解了Linux内核结构之后,我们知道Linux内核大致由用户层、内核层和硬件层组成,当我们希望驱动某个硬件的时候要经过用户层到内核层再到硬件层,而内核层往往都有驱动文件对应相应的硬件(Linux一切皆文件),可以理解为从内核层到硬件层驱动文件是"必经之路",这就显得驱动文件的重要性。
  • 为什么要学习驱动开发?
    • 对于树莓派来说有wiringPi这样的库来支持对应的硬件驱动,但是别的平台不一定有wiringPi库的支持,所以学习驱动开发为了能适应更多的平台

驱动开发

  • 驱动开发是什么?
    • Linux一切皆文件,驱动开发一般指设备驱动开发,而设备在Linux系统下可以看成是"文件"(树莓派根目录底下的/dev文件下对应的都是些设备文件),对于驱动开发可以当做文件开发(我们所用c库在用户层进行文件操作无非是open,read,write)。
  • 设备都有对应的驱动,驱动又是从哪里来?
    • 驱动当然是人为开发了,驱动文件做好后需要在内核中添加,这样才能使用内核层sys_open访问驱动文件(使用别人的库自然是把这一切都做好了)
  • 当用户层调用open的时候怎么找到相应的驱动文件?(两种方式)
    • 文件名(初级的驱动框架使用的方法)
    • 设备号(在/dev文件下使用ls -l 可以查看驱动文件的设备号和次设备号)
      • 主设备号用来区分不同种类的设备,而次设备号用来区分同一类的多个设备
        • 简而言之就是如:苹果手机是主设备号,苹果手机的不同型号(ipthon14,ipthon13)是次设备号
    • 总结
      • 内核当中有驱动链表去管理驱动文件
        • 添加:编写完驱动程序,加载到内核
        • 查找:调用驱动程序(用户层open)
        • 驱动插入链表的顺序由设备号检索
  • 总结驱动开发大致两个步骤:添加驱动,调用驱动
    • 添加驱动
      • 基于linux底层内核驱动框架(参考别的驱动代码)进行开发,遵循驱动框架,使代码能进行驱动链表添加
    • 调用驱动过程
      1. 用户层open(“驱动文件路径”,权限)->产生软中断进入内核层
      2. 内核层调用sys_call(根据设备名找到设备号)->虚拟文件系统(VFS)调用sys_open(调用设备号对应的驱动文件里的open:寄存器操作)

GPIO驱动开发(树莓派4B)

  • 开发前的准备:内核源码获取、源码配置、内核编译、内核替换

  • 根据数据手册(4B芯片是BCM2711)找到想要配置的寄存器地址

    通过寄存器配置树莓派GPIO所操作的是寄存器的虚拟地址,芯片手册上的是物理地址,操作前要先得到物理地址和虚拟地址的关系( 在linux系统中,所有操作的地址都是虚拟地址,都是由linux内核去管理,所以需要将物理地址转换成内核可识别的虚拟地址。)

    • 使用 cat /proc/iomem指令查看地址映射

    • 指令找到的映射地址0xfe200000

    • GPIO相关寄存器解读

      • GPFDEL(x):端口功能选择寄存器(可针对于该端口下的某一个具体的GPIO进行选择输入还是输出功能配置),GPFDEL0端口可用于控制GPIO(0-9)

        • 以控制GPIO4为例,在手册中找到FSEL4,它属于GPFDEL0控制
        • 手册中例举了GPIO9的操作方法:29:27三个位配置GPIO9,那么GPIO4是用14:12三个位配置(000是输入模式,001是输出模式,默认值是000也就是输入模式)
        • GPFDEL0是32位寄存器,由虚拟基地址进行偏移(偏移量直接看手册加上去就行)得到的该寄存器地址:0xfe200000+0x00
          • volatile unsigend int *GPFSEL0 = NULL;//定义一个无符号整型的指针,volatile是C语言关键字后面会补充
          • GPFSEL0 = (volatile unsigned int*) ioremap(0xfe200000,4);//指针指向ioremap返回的空类型地址(需要进行数据类型转换),ioremap函数后面会补充
          • 按位操作(配置GPIO4为输出模式)
            • *GPFSEL0 &= ~(0x6 << 12);
            • *GPFSEL0 |= (0x1 << 12);
      • GPSET(x):GPIO输出控制寄存器,GPSET0可配置GPIO(0-31),GPSET1可配置GPIO(32-57)。置0无效输出低电平,置1有效输出高电平

        • GPSET0是32位寄存器,由虚拟基地址进行偏移(偏移量直接看手册加上去就行)得到的该寄存器地址:0xfe200000+0x1c

          • volatile unsigend int *GPSET0 = NULL;

          • GPSET0 = (volatile unsigned int*) ioremap(0xfe20001c,4);

          • 按位操作(配置GPIO4为输出高电平)

            • *GPSET0 |= 0x01 << 4;
      • GPCLR(x):GPIO清除寄存器,GPCLR0可配置GPIO(0-31),GPCLR1可配置GPIO(32-57)。置0无效,置1有效清除指定GPIO状态

        • GPCLR0是32位寄存器,由虚拟基地址进行偏移(偏移量直接看手册加上去就行)得到的该寄存器地址:0xfe200000+0x28
          • volatile unsigend int *GPCLR0 = NULL;

          • GPCLR0 = (volatile unsigned int*) ioremap(0xfe200028,4);

          • 按位操作(清除GPIO4的输出状态)

            • *GPCLR0 |= 0x01 << 4;
    • 补充

  • 基于驱动框架编写驱动代码

  • 上层调试代码
    在这里插入图片描述

  • 编译编写好的驱动代码

    • 将驱动代码拷贝到内核源码目录底下的drivers/char目录下:
    • 修改Makefile
      • sudo vi Makefile
      • 添加一段(我的驱动代码名字是:pin4driver2.c):
        • -m是编译成模块,加载模块也是添加驱动的一种方式
    • 编译模块
      • 成功生成
        • 运行命令:modinfo pin4driver2.ko
          • 编译出来的驱动模块的内核版本一定要与树莓派内核版本一致,不然无法在树莓派上装载:这就体现了驱动开发前内核替换的重要性
    • 将生成的驱动模块pin4driver.ko传送到树莓派上
      • scp pin4driver2.ko theone@192.168.x.x:/home/theone/Desktop
    • 交叉编译调试代码或是在树莓派上编译也可以
      • scp pin4driver1.o theone@192.168.x.x:/home/theone/Desktop
  • 装载内核驱动模块

    • sudo insmod pin4driver2.ko
      • 成功后树莓派的/dev目录下可以找到名为pin4的驱动,而且主设备号和次设备号以及文件名都能与驱动代码里设置的对应上
      • lsmod可以查看当前已经装载的驱动
    • 修改驱动文件权限,使驱动能被访问:
    • 运行调试程序并打印内核信息
    • 卸载驱动:sudo rmmod pin4driver2(这里就没有.ko了)
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Trt_ToHoldOn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值