嵌入式linux如何操作硬件

2019-07-12 16:08发布

拿到Beaglebone Black以后,我最先考虑的是如何用它控制硬件,包括ARM片上的硬件资源和外接的各种设备。通过我的前几篇日志也给出了若干硬件的使用方法,但是总感觉缺乏条理。因此查了一些资料,在此做一点总结。
我们知道Linux系统分为用户空间和内核空间,系统调用函数和Linux API(本质上也是在使用系统调用)是内核空间和用户空间之间的接口,设备驱动程序是内核空间和机器硬件之间的接口。我们在用户空间想要访问硬件,必须通过系统调用操作驱动程序来实现。因为Linux中一切皆文件,所以对硬件的操作等同于对设备文件的操作。在Beaglebone中通过使用capemgr加载device tree文件来加载设备,通常设备经过加载以后就会出现在 /dev 目录中,我们可以在c语言程序中使用open()、close()、read()、write()、ioctl()等系统调用函数对其进行操作。这些函数操作的具体实现,就是在相应的驱动程序中定义的了,一般需要查询相应驱动的说明或阅读驱动源码来得知。
通常所说的驱动程序是属于内核空间的程序,编写驱动程序比较复杂、调试不方便而且有一定危险。实际上,在用户空间也可以编写简单的驱动程序,方法是利用 /dev/mem 这个设备,将芯片的寄存器映射到用户空间中,然后我们就可以像操作单片机一样控制芯片的外设了。一个很好的例子是这位仁兄写的C语言操作Beaglebone的GPIO的函数库,就是用这个方法实现的。感兴趣的话可以到这里去看一看他的思路和源代码 www.element14.com/community/community/knode/single-board_computers/next-gen_beaglebone/blog/2013/10/10/bbb--beaglebone-black-io-library-for-c 必须了解的是,在用户空间的驱动程序有很多力不能及的地方,比如:无法使用中断、响应速度慢、很多设备不能在用户空间处理等等。
上面说的是在c程序中操作硬件的方法。但在shell中一般不能直接读写 /dev 目录下的设备文件,也不能进行ioctl()操作。如果我们想在shell中操作硬件怎么办?这就要用到 /sys 目录了。/sys 目录中存放着系统内核和驱动相关的内容,它是一个虚拟的文件系统,这个文件系统的目录结构实质上就是内核对象模型树。我们可以对这里的文件进行读写操作来实现对设备的操作。至于每个设备里都有哪些文件,操作哪些文件能产生什么效果,还是由设备驱动程序定义的了。(前提是设备驱动中设置了相应的sysfs,否则就没法在shell里访问了。)

以我之前的日志中对各种片上资源进行操作为例进行一下说明: 1、操作IO口是在shell中对/sys/class/gpio这个目录下的文件进行了一系列读写操作实现,因为gpio驱动是默认加载的,所以无需加载device tree就能实现操作; 2、使用ADC接口是在shell中对/sys/bus/iio/devices这个目录下的文件进行读写实现,操作之前先要加载相应的device tree; 3、操作UART比较特殊,直接对/dev/tty*进行写入来操作,之前同样需要先加载device tree; 4、使用I2C时利用了BMP085芯片的驱动,通过对/sys/bus/i2c/drivers/bmp085目录下的内容进行读取来操作,可能是因为这是一个比较早期的驱动,所以这里没有用到device tree; 5、操作SPI时先加载了device tree,然后在c程序中使用了ioctl()等系统调用实现功能。