You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
config AD9833_ADI
tristate "AD9833 DDS support."
depends on ARM
help
GPIO on OMAPL138 configuration is:
AD9833_FSY_IO -> GPIO[0,1]
AD9833_CLK_IO -> GPIO[0,5]
AD9833_DAT_IO -> GPIO[0,0]
基于OMAPL138的Linux字符驱动_GPIO驱动AD9833(一)之miscdevice和ioctl
0. 导语
在嵌入式的道路上寻寻觅觅很久,进入嵌入式这个行业也有几年的时间了,从2011年后半年开始,我清楚的记得当时拿着C51的板子闪烁了LED灯,从那时候开始,就进入到了嵌入式的大门里面。嵌入式的学习从来没有停止过,中间也有无数的插曲和机缘巧合学会C++和Java,做一些好玩的应用。无论是嵌入式DSP也好,还是如今的嵌入式ARM,7年之久从来没有停止过。技术最大的好处就是,**无论发展到什么境地,那种第一次点亮LED灯欣喜永远的可以伴随着你,只要你解决了一个卡了你很久的问题,这就是技术的魅力。**我也将开始大肆的从嵌入式DSP转入到嵌入式Linux,在研究生阶段,完成这个转型。
这个Demo意义重大,使用Linux也有四五年的时间了,Linux良好的基础和嵌入式基础让我在嵌入式inux道路上算的上是顺风顺水。**这个Demo将过去STM32,F28xx的DSP或者那些单片机桥接起来,将过去裸机上的程序全部编到内核里面,通过嵌入式的应用进行互联。 **
本DEMO依然使用AD9833作为例子,将用linux内核级的gpio对AD9833写时序,完成对于AD9833的驱动程序,在嵌入式Linux上生成/dev/目录节点,使用Linux命令行对AD9833产生波形进行控制。(只要有了/dev节点,使用Qt,C++,Python都可以控制了,这就是物联网最注重的。)
效果视频观看地址: https://v.youku.com/v_show/id_XMzY3NDUwNTMwOA==.html?spm=a2h3j.8428770.3416059.1
1. 开发驱动综述
本开发驱动基于Linux3.3内核版本,且内核必须编译正确,否则不能运行。
这个Demo可以归结为三个部分,一个部分为Linux字符驱动模板,第二部分为AD9833驱动程序,第三部分为通信协议。还附加一个配置文件。
本Demo就围绕这三点进行。
2. Linux字符驱动模板
* 函数ioctl
主要负责进行数据交互的。当设备生成字符设备驱动节点(/dev目录下),使用shell级命令cat或者编译一段C应用程序用open打开节点的时候,后面将参数就是通过ioctl函数进行传递。(在嵌入式Linux端定义一个ioctl的函数,在C语言的程序也有一个ioctl用来和其进行对应,这样就完成了数据参数传递。)
*结构体file_operations
ioctl函数不能独立的存在需要file_operations指针进行操作,ioctl为一个执行命令的清单,file_operations就是这个清单的执行者。下面就是file_operations的指针,里面的成员需要接收到ad9833_ioctl的函数地址,在内部运行的时候会调用该地址。
###* 结构体miscdevice
*miscdevice结构体为字符驱动的一级,字符驱动如同文献[3]所说的一样,非常的凌乱,到底里面使用了miscdevice还是cdev还是platform-device or platform-driver,这里暂时不进行理,这里使用miscdevice级的字符驱动设备向Linux内核进行设备的注册,后续有文章进行区分,类似的文献还有我的《Linux GPIO键盘驱动开发记录_OMAPL138》,这里使用的室platform-device进行。
可以看见,在miscdev里面指定了file指针的地址,miscdev主要的作用就是向内核注册该驱动。
*函数init
内核级的嵌入式Linux驱动给出的硬性要求进行init函数,并标识init函数为__init,而且还要在module_init中填写init函数的地址。
当我们运行insmod xxxx.ko的时候,此时运行的就是这个init函数,在这个函数中主要完成对于设备内存的请求和一些初始状态的注册。在本DEMO中对对于AD9833的结构体进行了注册,并对gpio进行申请。ret = misc_register( &ad9833_miscdev ); 重点室这句话。
*函数exit
除此之外内核也要求了exit函数,主要进行对init中内存申请的释放。
这是一个非常简单的字符驱动的模板,然后就需要我们添加AD9833的驱动了。
3. AD9833芯片级时序驱动
到此,基本上就是裸机嵌入式的知识了,对于芯片功能的描述,对于芯片时序的把握。作为本博客不在赘述,给出函数的列表,如果喜欢,本文将DEMO的源码放在后面,自行下载观看。
该设备使用链表进行描述。
3. 与驱动通信的ioctl函数
在参考文献[1]中,给出了Linux字符设备驱动开发重要的ioctl函数解析,写的很接地气,很朴实,也写的很明白,包括利用ioctl函数应用程序和驱动程序进行交互,ioctl函数使用MAGIC_number幻数对命令进行转换。
在ioctrl函数里面通常使用switch 和case进行执行,见上衣章的内容。
这里给出使用ioctl的应用程序,它和内核驱动进行通信:
在ioctl函数和嵌入式Linux驱动里面的ioctl函数就会对应,命令就传递过去了。
另外补充一个知识:
void main( int argc char *argv[] )
argv[1] 就是nihao, argv[2] 就是hello, argv[3] 就是1234
4. 将驱动程序编入Linux内核代码树
驱动开发完毕,就必须要将驱动编入Linux内核代码树,假如Linux内核代码在./linux-3.3目录,我们的驱动名字叫做ad9833.c,那么我们就要将ad9833.c文件放入./linux-3.3/drivers/char目录下,操作两件事情。
修改Kconfig文件
修改Kconfig文件,在menuconfig文件中会出现我们的内核配置选项。
修改该目录下的Makefile文件
在文末追加
obj-$(CONFIG_AD9833_ADI) += ad9833.o
这里CONFIG_后面接的必须和上面的Kconfig中 config字段一样 ad9833.o 的.o文件必须和放入该内核代码的ad9833.c名字字段一样。
编译内核
make CROSS_COMPILE=arm-none-linux-gnueabi- ARCH=arm menuconfig
然后,进入到drivers -> char.. device -> 找到你的驱动
以模块编译或者编译进内核。
make CROSS_COMPILE=arm-none-linux-gnueabi- ARCH=arm -j8
make CROSS_COMPILE=arm-none-linux-gnueabi- ARCH=arm uImage
可以重启运行了
insmod ad9833.ko
可以看到效果了:
源代码下载
链接: https://pan.baidu.com/s/1rfZymtf-mRnZNlhb41RpGA 密码: 4pxx
参考文献
[1] zqixiao_09, Linux 字符设备驱动开发基础(四)—— ioctl() 函数解析
, 2016-03-11
[2] 草根老师, 解决undefined reference to __aeabi_uidivmod和undefined reference to __aeabi_uidiv'错误, 2012-07-21 21:59:03
[3] 小C爱学习, 一步一步写miscdevice的驱动模块, 2013-07-24
[4] 宋宝华,Linux设备驱动开发详解:基于最新的Linux 4.0内核
The text was updated successfully, but these errors were encountered: