第2章:计算机基础回顾:CPU、内存、外设工作原理,操作系统与驱动的关系
说实话,很多刚入行的朋友找我聊,上来就问驱动怎么写。我通常会反问一句:你知道CPU拿到你写的代码后,是怎么一步步让硬件动起来的吗?
这个问题要是答不上来,写驱动就跟闭着眼开车差不多。今天咱们就把这层窗户纸捅破。
2.1 CPU:它到底在忙什么?
CPU说白了就是个执行机器。它从内存里取指令,然后解码、执行,再写回结果。这个过程叫指令周期。
我当年刚接触ARM Cortex-M3时,一直搞不懂“取指”和“执行”为什么能重叠。后来看了流水线原理图才明白——CPU其实是个流水线工厂。
核心要点:CPU不关心你写的是C语言还是汇编,它只认二进制指令。驱动代码最终会被编译成机器码,一条条喂给CPU。
举个例子,你写了一句:
*(volatile uint32_t *)0x40021000 = 0x01;
这行代码在CPU眼里就是:把数值0x01写入地址0x40021000。至于这个地址对应的是GPIO寄存器还是UART,CPU不管。它只负责执行。
我的经验:调试驱动时,如果硬件没反应,先别怀疑外设。用逻辑分析仪抓一下地址线的波形,看看CPU是不是真的发出了你期望的地址和数据。我踩过这个坑,整整查了两天。
2.2 内存:不只是存数据那么简单
内存分两种:RAM和ROM。驱动开发中,我们打交道最多的是RAM。
但这里有个关键概念——内存映射。什么意思呢?就是CPU把外设的寄存器也映射到了内存地址空间里。
你想想看,CPU访问内存是0x20000000到0x200FFFFF,访问外设寄存器是0x40000000到0x400FFFFF。对CPU来说,这两件事本质上是一样的——都是读写某个地址。
| 地址范围 | 用途 | 访问速度 |
|---|---|---|
| 0x00000000 - 0x1FFFFFFF | 代码区(Flash/ROM) | 较快 |
| 0x20000000 - 0x3FFFFFFF | SRAM(数据区) | 最快 |
| 0x40000000 - 0x5FFFFFFF | 外设寄存器 | 取决于总线 |
注意:外设寄存器的访问通常要求使用volatile关键字。我曾经因为忘了加volatile,编译器把寄存器读操作优化掉了,结果外设死活不工作。嗯,这种错误犯一次就够了。
2.3 外设:CPU的“手脚”和“感官”
外设就是CPU与外界交互的桥梁。GPIO是手,UART是嘴,ADC是耳朵,定时器是心跳。
每个外设内部都有一组控制寄存器。驱动的工作,说白了就是往这些寄存器里写正确的值。
举个例子,你想让GPIO输出高电平:
// 假设GPIOA的BSRR寄存器地址是0x40020018
// 设置第0位为1,输出高电平
*(volatile uint32_t *)0x40020018 = (1 << 0);
就这么简单?对,硬件层面就这么简单。但实际项目中,你还要考虑时钟使能、引脚复用、上下拉配置等等。这些细节才是驱动开发的难点。
避坑指南:我曾经在STM32上配置UART时,忘了使能外设时钟。结果寄存器怎么写都没反应。后来查手册才发现,外设时钟默认是关闭的。这个坑,新手十有八九会踩。
2.4 操作系统与驱动:谁指挥谁?
很多人以为驱动是直接操作硬件的。其实在带操作系统的环境下,驱动是夹在操作系统和硬件之间的。
操作系统提供了一套抽象接口,比如Linux里的file_operations结构体。驱动开发者只需要实现这些接口:
struct file_operations my_driver_fops = {
.open = my_driver_open,
.read = my_driver_read,
.write = my_driver_write,
.release = my_driver_release,
};
用户程序调用open()、read()、write()时,操作系统会通过VFS(虚拟文件系统)找到对应的驱动函数,然后执行。
说白了,操作系统就是个中间人。它不关心你的硬件怎么工作,它只负责把用户的请求转交给驱动。
核心关系:
- 用户程序 → 系统调用 → 操作系统内核 → 驱动 → 硬件
- 驱动是操作系统和硬件之间的“翻译官”
- 操作系统提供框架,驱动填充细节
2.5 一张图看懂整体架构
下面这张图是我自己画的,把CPU、内存、外设、操作系统和驱动的关系串起来了:
从这张图可以看得很清楚:驱动是操作系统和硬件之间的桥梁。没有驱动,操作系统就是个空壳子,指挥不动任何硬件。
2.6 小结:驱动开发到底在做什么?
总结一下今天的内容:
- CPU:执行指令,不关心指令含义
- 内存:存储数据和代码,外设寄存器也被映射到内存空间
- 外设:通过寄存器与CPU交互,驱动就是配置这些寄存器
- 操作系统:提供统一接口,驱动负责实现这些接口
我个人觉得,理解这些基础概念比背一百个API都重要。因为驱动开发的本质,就是用软件去控制硬件。你不懂硬件怎么工作,写出来的驱动就是空中楼阁。
一句话总结:驱动开发 = 理解硬件手册 + 掌握操作系统框架 + 会写C语言。三者缺一不可。
好了,这一章就到这里。下一章我们开始搭建实际的开发环境,到时候我会手把手带大家配置工具链。嗯,那才是真正动手的时候。
可可精品资料库