#驱动开发

内核模块
字符设备驱动
中断、内核定时器

裸机开发和驱动开发的区别?

|-----|----------------|------------------|
| | 裸机开发 | 驱动开发(基于内核) |
| 相同点 | 都能够控制硬件(本质:操作寄存器) ||
| 不同点 | 用C语言给对应的地址里面写值 | 按照一定的框架格式往地址里面写值 |
| 不同点 | 单独编译单独执行 | 依赖内核编译、执行 |
| 不同点 | 同时只能执行一份代码 | 同时执行多份代码 |
| 不同点 | 只需要一个main函数 | 依赖内核的框架来操作硬件 |

STM32启动流程详解(超全,startup_stm32xx.s分析)_stm32启动过程详解-CSDN博客文章浏览阅读3.8k次,点赞32次,收藏84次。启动模式只决定程序烧录的位置,加载完程序之后会有一个重映射(映射到0x00000000地址位置);真正产生复位信号的时候,CPU还是从开始位置执行。值得注意的是STM32上电复位以后,代码区都是从0x00000000开始的,三种启动模式只是将各自存储空间的地址映射到0x00000000中。_stm32启动过程详解https://blog.csdn.net/m0_56694518/article/details/135032170?spm=1001.2014.3001.5501

驱动里面操作LED灯的寄存器

驱动模块是依赖内核框架执行代码

ARM裸机直接操作的是物理内存,直接拿到寄存器地址写值。

驱动是基于内核,操作的是虚拟内存,使用之前先映射实际物理内存。

Linux系统组成

硬件层:led 鼠标 键盘 lcd 触摸屏 摄像头 u盘 emmc 光猫 路由器 dm9000

0-3G的用户空间 是每个进程单独拥有0-3G的空间

系统调用(软中断swi) 应用层通过系统调用与底层交互,swi将应用层切换到内核层。

驱动代码就在内核空间(在3-4G内核空间, 共用空间)

注:1G的物理内存映射成0~4G的虚拟内存,每个进程都可以访问内核,0~3G是每个进程单独拥有的,3G~4G是所有的共有的。代码运行在物理内存上,向虚拟内存上面写值,其实是写在物理内存上面的

宏内核和微内核(了解)

宏内核:集中管理的架构,负责多种系统资源的调度和管理;

将进程、文件、网络、内存、设备等功能集成到一个内核中,具备直接操作硬件的能力。

优点:执行效率高,操作系统资源可以直接在内核中实现,减少了进程间通信带来的性能损失,提高了系统的执行速度。

缺点:内核的代码量非常大,不易拓展,且单个模块的崩溃可能会影响整个系统的运行。

eg:ubuntu、Android

微内核:更侧重于模块化和移植性,通过传递请求的方式实现不同模块之间的交互

将最基本的操作系统功能放到内核中,其他服务和程序在微内核之上构建,并在用户态下运行。(设计分界线不同)

优点:系统灵活性和可扩展性好,系统可靠性高

缺点:代码运行效率低->通过API接口让整个系统运行起来

eg:Window 、鸿蒙

驱动移植

步骤:

需要有对应的驱动代码(.c)

修改对应目录的Makefile - drivers-》char)-》obj-$(CONFIG_LED) +=led.o

修改对应目录里的Kconfig(tristate " ...... " )

make menuconfig-》配置自己的驱动为M(模块的)

make modules(在最顶层目录)

把编译产生的.ko结尾的驱动文件,放到nfs(/opt/6818/rootfs/rootfs)目录下使用

安装insmod led.ko

卸载rmmod led

静态编译:生成的执行文件不依赖于外部库文件,可以直接运行,且程序运行效率较高。

动态编译:可执行文件和库分开写,生成的可执行程序需要依赖于外部的库文件。

内部编译:在内核源码树中编译

外部编译:在内核源码树外编译

驱动模块

驱动的框架

入口(安装):资源申请
出口(卸载):资源释放

许可证:GPL(开源的---》Linux开源-----》GPL许可证)

Linux内核许可规则

Linux内核许可规则 --- The Linux Kernel documentation

驱动程序编写

复制代码
#include <linux/init.h>`
`#include <linux/module.h>`

`//申请资源`
`//static - 限定作用域,延长生命周期`
`//存储类型 数据类型 指定存放内存区域 函数名(形参)`
`static int __init hello_init(void)`
`{`
`    return 0;`
`}`

`//释放资源`
`static void __exit hello_exit(void)`
`{`
`}`

`module_init(hello_init);    //入口:申请资源   本质-回调一个自己写的函数`
`module_exit(hello_exit);    //出口:释放资源`
`MODULE_LICENSE("GPL");      //许可证:公共许可协议(开源协议)`

`

ctags的安装和使用

方法1

1.ctags

ctags工具是将指定目录以及子目录添加索引文件,可以实现快速搜索文件内容(宏定义、取别名以及结构体)

2.ctags创建索引文件

安装ctags:

sudo apt-get install ctags

在/usr/include目录下执行命令:

sudo ctags -R

执行完毕之后,会生成一个tags的索引文件

3、默认只能在/usr/include使用,所以需要设置为全局

打开家目录下的.vimrc文件,然后添加一句话:

set tags+=/usr/include/tags

5.3 ctags工具的使用

追代码:

vim -t 结构体名/宏定义名/取别名

vi -t 结构体名/宏定义名/取别名

如果要查看所有定义的位置:在底行模式下输入

tselect 结构体名/宏定义名/取别名

继续追指定的内容:

将光标放在这个内容的任意位置,然后点击快捷键ctrl ]

返回上一次的文件:

ctrl t

例如:追一下sockaddr_in结构体,查看结构体成员

继续查看这个结构体中成员的类型

查看完毕后返回到最开始的结构体

方法2

把ctags_set文件夹拷贝到Ubuntu里

cd ctags_set
sudo chmod 774 ctags_set.sh
sudo ./ctags_set.sh

验证:在~目录下

vi -t sockaddr_in

生成tags 文件 :在相应目录下 ctags -R

在代码中追变量: ctrl + ]

返回代码中 : ctrl + t

mv tags /home/hq/kernel/kernel-3.4.39

可以不执行:

==================================

在内核源码目录下 执行

make tags

========================

cd ~

sudo vim .vimrc

在.vimrc 最后添加

set set tags+=内核源码绝对路径/tags

例如set tags+=/home/hq/kernel/kernel-3.4.39/tags

驱动Makefile编写

复制代码
KERNELDIR = /home/hq/kernel/kernel-3.4.39	#开发板路径`
`#KERNELDIR = /lib/modules/$(shell uname -r)/build	#PC机`

`PWD = $(shell pwd)    #驱动文件的路径`

`all:`
`	make -C $(KERNELDIR) M=$(PWD) modules`
`	#基于内核框架将驱动代码编译生成驱动模块`
`	#需要在内核的顶层目录下执行 make modules`
`	#-C:指定到哪个路径下执行这个命令`
`	#M:赋值,要将哪个路径下的驱动文件编译生成驱动模块`
`    #注:进入内核目录下执行make modules这条命令,如果不指定 M=$(PWD) 会把内核目录下的.c文件编译生成.ko`

`.PHONY:clean`
`clean:`
`	make -C $(KERNELDIR) M=$(PWD) clean`
	
`obj-m += hello.o`

`

Source Insight工具

软件安装

激活码:SI3US-719473-71478

使用(配置工程)

配置信息:*.c;*.h;*.S;*.lds;*defconfig;*Makefile;*.mak;*.dts;*.dtsi

软件使用

ctrl+/ 可以搜索变量及函数

按住ctrl左击鼠标可以追变量或者函数

打印函数

在Linux中可以使用

复制代码
grep "printk" * -nR

搜索函数,搜到以后,在里面任意找到一个,看函数原形

复制代码
`	`printk` `(打印级别 "内容");`
	`printk(KERN_ERR "Fail%d",a);`
	`printk(KERN_ERR "%s:%s:%d\n",__FILE__,__func__,__LINE__);//(驱动在哪一个文件,哪一个函数,哪一行)`

`

内核打印级别

vi -t KERN_ERR(查看内核打印级别)//也可直接在SI中按住ctrl左击跳转进行查看

0 ------------------ 7

最高的 最低的

终端打印级别

复制代码
#define console_loglevel (console_printk[0])    //终端的级别`
`#define default_message_loglevel (console_printk[1])//消息的默认级别`
`#define minimum_console_loglevel (console_printk[2])//终端的最大级别`
`#define default_console_loglevel (console_printk[3])//终端的最小级别`
`

查看虚拟机终端级别

复制代码
cat /proc/sys/kernel/printk

只有当消息的级别大于终端级别,消息才会被显示

打印函数代码

复制代码
#include <linux/init.h>`
`#include <linux/module.h>`
`#include <linux/printk.h>`

`static int __init hello_init(void)`
`{`
`    printk("hello world\n");`
`    printk(KERN_CRIT "%s %s %d\n",__FILE__,__func__,__LINE__);`
`    printk(KERN_INFO "%s %s %d\n",__FILE__,__func__,__LINE__);`
`    return 0;`
`}`

`static void __exit hello_exit(void)`
`{`
`    printk("bai bai le nin lei\n");`
`    printk(KERN_CRIT "%s %s %d\n",__FILE__,__func__,__LINE__);`
`    printk(KERN_INFO "%s %s %d\n",__FILE__,__func__,__LINE__);`
`}`

`module_init(hello_init);    //入口:申请资源`
`module_exit(hello_exit);    //出口:释放资源`
`MODULE_LICENSE("GPL");      //许可证:公共许可协议(开源协议)`
`

但对与咱们的这个Ubuntu被开发者修改过,所有消息不会主动回显。

命令 使用

sudo insmod hello.ko 安装驱动模块

sudo rmmod hello 卸载驱动模块

lsmod 查看模块

dmesg 查看消息

sudo dmesg -C 直接清空消息不回显

sudo dmesg -c 回显后清空

修改系统的默认级别

su root

echo 4 3 1 7 > /proc/sys/kernel/printk

虚拟机的默认情况:

修改开发板的默认级别

查看开发板的默认级别

复制代码
cat /proc/sys/kernel/printk

如果想修改开发板对应的打印级别

vi etc/init.d/rcS
echo 5 5 1 7 > /proc/sys/kernel/printk

//当系统重新启动,rcS中的命令会全部重新执行一遍

在rootfs/etc/init.d/rcS里面添加上以后再起板子,板子的级别就为如下:

etc/init.d/rcS:一些启动虚拟机需要启动的东西都可以放在这个文件中,启动系统时同时启动。

echo 5 5 1 7 > /proc/sys/kernel/printk

放到板子跟文件系统对应这个文件中。

安装驱动和卸载驱动时,消息会打印。

相关推荐
hhhhhhh_hhhhhh_41 分钟前
rk3568制冷项目驱动开发流程汇总(只适用于部分模块CIF DVP等,自用)
驱动开发
icy、泡芙3 小时前
T527-----音频调试
linux·驱动开发·音视频
7yewh14 小时前
嵌入式Linux QT+OpenCV基于人脸识别的考勤系统 项目
linux·开发语言·arm开发·驱动开发·qt·opencv·嵌入式linux
疯狂飙车的蜗牛1 天前
从零玩转CanMV-K230(4)-小核Linux驱动开发参考
linux·运维·驱动开发
嵌入式进阶行者1 天前
【驱动开发初级】内核模块静态和动态添加功能的步骤
驱动开发
逝灮1 天前
【蓝桥杯——物联网设计与开发】拓展模块3 - 温度传感器模块
驱动开发·stm32·单片机·嵌入式硬件·物联网·蓝桥杯·温度传感器
__NULL__USER3 天前
petalinux-adi ---添加AD9361驱动(二)
linux·驱动开发
7yewh3 天前
嵌入式驱动RK3566 HDMI eDP MIPI 背光 屏幕选型与调试提升篇-eDP屏
linux·arm开发·驱动开发·嵌入式硬件·嵌入式linux·rk·edp
少年、潜行4 天前
树莓派3B+驱动开发(8)- i2c控制PCF8591
驱动开发·树莓派·3b+
千千道4 天前
深入理解 Linux 内核启动流程
linux·arm开发·驱动开发