IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 嵌入式Linux驱动开发的演进 -> 正文阅读

[嵌入式]嵌入式Linux驱动开发的演进

嵌入式Linux驱动开发的最终目的

从裸机开发经历来看

从C51到STM32开发的经历来看,最终都是操作寄存器以达到某些目的。

正点原子的嵌入式Linux教程也是从裸机开发开始的

汇编点灯

/********************************************************
描述	   : 裸机实验1 汇编点灯
		使用汇编来点亮开发板上的LED灯,学习和掌握如何用汇编语言来完成对I.MX6U处理器的GPIO初始化和控制。
********************************************************/

.global _start  /* 全局标号 */

/*
 * 描述:	_start函数,程序从此函数开始执行此函数完成时钟使能、
 *		  GPIO初始化、最终控制GPIO输出低电平来点亮LED灯。
 */
_start:
	/* 1、使能所有时钟 */
	ldr r0, =0X020C4068 	/* CCGR0 */
	ldr r1, =0XFFFFFFFF  
	str r1, [r0]
    /* 省略CCGR1~6 */

	/* 2、设置GPIO1_IO03复用为GPIO1_IO03 */
	ldr r0, =0X020E0068	/* 将寄存器SW_MUX_GPIO1_IO03_BASE加载到r0中 */
	ldr r1, =0X5
	str r1,[r0]

	/* 3、配置GPIO1_IO03的IO属性	
	 *bit 16:0 HYS关闭
	 *bit [15:14]: 00 默认下拉
     *bit [13]: 0 kepper功能
     *bit [12]: 1 pull/keeper使能
     *bit [11]: 0 关闭开路输出
     *bit [7:6]: 10 速度100Mhz
     *bit [5:3]: 110 R0/6驱动能力
     *bit [0]: 0 低转换率
     */
    ldr r0, =0X020E02F4	/*寄存器SW_PAD_GPIO1_IO03_BASE */
    ldr r1, =0X10B0
    str r1,[r0]

	/* 4、设置GPIO1_IO03为输出 */
    ldr r0, =0X0209C004	/*寄存器GPIO1_GDIR */
    ldr r1, =0X0000008		
    str r1,[r0]

	/* 5、打开LED0
	 * 设置GPIO1_IO03输出低电平
	 */
	ldr r0, =0X0209C000	/*寄存器GPIO1_DR */
   	ldr r1, =0		
   	str r1,[r0]

/*
 * 描述:	loop死循环
 */
loop:
	b loop 			

嵌入式Linux驱动的目的

从上面的裸机开发可以知道嵌入式Linux驱动开发的目的还是操作物理寄存器,只不过为什么叫驱动开发呢?我的理解有两个:

  1. 以前像C51和STM32之类单片机的开发,驱动和应用其实是没有分开的(没有驱动这个概念)。即一个工程甚至是一个文件里面即包括驱动(操作物理寄存器),也包括应用(实现实际的功能)。
  2. 而对于用Linux这样优秀的操作系统来做开发,应该做到分离和分层。这样可以很好的、很快的、很轻易的做到快速开发,以及分工合作。驱动就只管做好操作物理寄存器,并提供相应的API给应用程序(具体是给内核,内核再给用户),这就是驱动工程师该做的事情。应用程序就只管应用需求的开发,不用在意底层的实现,只管调用底层提供的API即可,这就是应用开发工程师该做的事情。

韦老师的教学路线

上面我们说了,嵌入式Linux开发分为两类:应用开发和驱动开发。

实现最基本的需求

主要分为应用程序部分和驱动部分。整体框架如下:
在这里插入图片描述

应用程序部分

直接调用open、read、write、close等函数。

驱动程序部分

实现chr_open、chr_read、chr_write、chr_close等函数供应用程序调用。而在这些函数中要实现其自己的功能,比如配置寄存器、操作寄存器等。

面向对象的思想

在驱动程序中的相应函数中直接操作寄存器会使程序移植、维护变得困难,可以将操作物理寄存器和驱动分开。即整体框架如下:

在这里插入图片描述

对于开发板上的led灯,可以抽象出一个led_opr结构体,其中包括对led的初始化和配置函数,并且将led_opr结构体提供给上层。

struct led_operations {
	int num;
	int (*init) (int which); /* 初始化LED, which-哪个LED */ 
	int (*ctl) (int which, char status); /* 控制LED, which-哪个LED, status:1-亮,0-灭 */
};

struct led_operations *get_board_led_opr(void);

主要有3个c文件,app.c, driver.c, led_opr.c。调用关系为: app.c调用相关函数,进入到driver.c驱动程序中,而在驱动程序中的open函数中调用led_opr.c提供的led_opr结构体中的init成员初始化led灯,在驱动程序中的write函数中调用led_opr.c提供的led_opr结构体中的ctrl成员控制led灯。

以后只需改变led_opr结构体中相应函数即可,不必理会driver.c文件。

面向对象更进一步

上面说了,如果led变了,那么就需要改变led_opr结构体中相应函数的具体实现。但是对于某些开发板来说,虽然它们板上的led所用的GPIO管脚不一样,但是用的芯片是一样的,而对于同一款芯片来说,GPIO的操作都是一样的。

所以我们可以把开发板和芯片分离,即针对某一款芯片编写一个c文件来初始化GPIO;对于开发板编写一个c文件来实现控制哪一个led(GPIO),即在这一个文件中说明led用的是哪一个GPIO资源。

主要有4个文件,app.c, driver.c, led_resource.c, chip_gpio.c。调用关系为:app.c调用相关函数,进入到driver.c驱动程序中,而在驱动程序中的open函数中调用chip_gpio.c提供的init函数(同上面的led_opr),在init函数中初始化相应的led管脚,具体是哪一个管脚呢?由led_resource.c指定。也可一这么说,在init函数中调用led_resource.c提供的led_pin;在驱动程序中的write函数中调用chip_gpio.c提供的ctrl函数(同上面的led_opr)操作相应的led管脚(led对应的gpio已经由init函数获得)。

更进一步/总线驱动

前面一直在说对led的操作,那么对于其它的呢?比如蜂鸣器、spi等。那么Linux内核抽象出了platform_device和platform_driver,一个定义资源,一个实现操作。

在这里插入图片描述

更具体的图:

在这里插入图片描述

和上面比,其实platform_device=led_resource.c,platform_driver=chip_gpio.c

在这里插入图片描述

chip_demo_gpio.cchip_gpio.c)相当于最开始的中根据platform_device指定的资源进行初始化和操作,该文件中有platform_driver结构体,其中有probe成员。

在这里插入图片描述

board_A_led.c(相当于最开始的led_resource.c)中根据platform_device指定需要操作对象,上图中的resource成员指定了2个gpio管脚。

文件有点多,说明一下它们之间的关系:

platform_device这个文件加载时,platform_driver结构体中的probe成员会自动执行(如果两者匹配成功的话),并且platform_device作为probe的参数,所以就可以在probe中获得platform_device指定的pin管脚资源。而platform_driver这个文件是操作物理寄存器的,所以它加载到内核时,首先把自己操作物理寄存器的init和ctrl方法告诉(写一个函数返回封装的led_opr)给它的上层驱动程序leddrv.c,而又由于platform_driver已经获得了具体的资源,所以init和ctrl都有了具体的操作对象。

设备树的引入

设备树的引入是为了解决platform_device的,因为每个设备都要写一个.c文件,这样的话会让Linux源码中充满着垃圾(.c文件),所以现在就用设备树代替.c文件中的platform_device。

即用设备树来描述开发板的情况,设备树中的每个结点都会被Linux内核解析成一个device_node结构体,然后某些device_node结构体会被解析成platform_device。

部分
设备树中的结点
device_node
platform_device

最终总结

应用+驱动

在应用中使用相应的函数,在驱动中实现相应的函数。并且在相应的函数中(如open、write等)直接操作物理寄存器。

所含文件:app.c、driver.c

特点:如果更换led灯的话,driver.c要重写。

应用+驱动框架+led_opr

在驱动相应的函数中不去操作物理寄存器,而是使用下层提供的led_opr结构体,其中包含init和write等成员,在下层中实现init、write等函数(操作寄存器)。

所含文件:app.c、driver.c、led_opr.c

特点:led灯更换后只需修改led_opr.c文件。

应用+驱动框架+led_resource+chip_gpio

正如上面所说,led灯更换后,led_opr需要修改。所以我们可以继续封装,led_resource.c中指明用到了那些设备/资源,chip_gpio.c中是对某款芯片所有的gpio的操作。这样我们在led_resource中指明所用的设备(led),在driver.c相应的函数中(open、write等)从led_resource中获取指定管脚,然后再调用chip_gpio提供的一些函数(如init、ctrl等)来操作指定管脚。

所含文件:app.c、driver.c、led_resource.c、chip_gpio.c

特点:led更换后只需修改led_resource.c文件。即led_resource指明led灯的管脚,chip_gpio实现某款芯片所有gpio的操作(init和ctrl),driver.c根据led_resource指明的引脚告诉chip_gpio操作那个引脚。

应用+驱动框架+platform_device+platform_driver

和上面一个一样的,只不过采用Linux内核提供的总线驱动框架来编写驱动程序。platform_device声明设备/led所用的资源,platform_driver实现对platform_device声明的设备进行操作(platform_driver可以写入到驱动框架中去)。

所含文件:app.c、driver.c、led_resource.c(platform_device)、chip_gpio.c(platform_driver)

应用+驱动框架+设备树+platform_driver

和上面一样,只不过platform_device写入到设备树中去了(前面说过,设备树中的结点会被内核解析成device_node,某些device_node被解析成platform_device)。然后platform_driver可以和驱动框架写一块。最终的文件只含:

所含文件:app.c、driver.c(platform_driver)、设备树.dts

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-03-21 21:07:25  更:2022-03-21 21:07:45 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 6:38:43-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码