已经有很久没有管理自己的blog了,很久都没有总结自己的了。人生总是有那么多的插曲,无奈~~~
用spi接口来采样AD7888的数据,这个驱动写了太久了,仍然没有什么进展,还是总结一下写驱动的过程中遇到的一些问题吧。
在S3C2440中有两个通用的spi接口,S3C2440和S3C2410没有什么区别,所以在内核中很多函数、寄存器以及位掩码等都是以2410为基础来定义的(都有S3C2410字样),S3C2440比S3C2410多了一个GPJ接口,这个接口是13位的宽度,是一个摄像头的接口,寄存器的定义会有一些不一样,但是使用的函数还是S3C2410的函数来操作,还有一个音频接口。在我的这个程序中用到了GPJ12这一个口来做为AD的CS线。
本来在最新的内核中(2.6.32)已经有了SPI的驱动程序,有两种方案的,一种是基于了spi真实硬件的接口,另一种是用普通的IO口来模拟spi的时序从而得到的接口,而且这两种方案都编写成了子系统的形式,没有一定的内核基础的人是很难把里面的struct啊,指针搞得明白的,所以我的驱动程序没有用到子系统(本人水平有限)。而是把它当成了普通的字符设备来写。这样的话会简单很多,其实这也不简单。
我采用了两种方法去注册设备驱动:
第一种:当做杂项设备来做,所谓的杂项设备就是主设备号为10的设备,在内核中把很多的设备都当做了杂项设备,而这些设备是通过次设备号来区分不同的设备的。而这个杂项设备一般在系统起动的时候就被加载了,所以在加载完.ko的模块后不用在/dev目录下面建立设备节点,因为加载模块完成后自动会在dev目录下面有了设备节点了,这样做有两个好处:
1、节省了主设备号,因为主设备号可是稀有的资源;
2、不用mknod了,直接可以运行测试或是应用程序了。但是有一个不好的地方就是不能把这个模块给卸了(当发现模块编写不对的时候当然是要把它卸载的),也就是说rmmod是个废。是不是有什么其它的方法,我还没有找到。我想肯定是会有方法的,我选择了最SB的方法——reboot。
使用miscdevice注册的这种方法在mini2440的开发板中有很多的体现。
第二种,把它当做普通的字符设备来做,我采用的是LDD3里提供的方法。这也是最新的内核里提供的方法,新的内核不应该用旧的方法。这里一波三折。出现了很多的bug。我把容易出错的地方总结一下:
1、在写spi的驱动时,一定要先检测一下,主clk的寄存器中spi的clk位有没有开启(第18位),不然是不能设置spi的相关的寄存器的(写入不了)。
2、定义了spi的设备结构体的时候 ,一定要为这个cdev分配内存,不然会出现 Oops的错误。
3、在把物理地址映射到内核空间(虚拟地址)的时候一定要用rmmap()这个函数,把物理地址映射到虚拟地址,因为在内核空间里只能访问虚拟地址。在这里最好不要使用跑裸机的方法去映射地址(volatile的方法),rmmap就是内核提供的接口函数,不用白不用,用了还安全。问访的时候尽量采用基址+偏移的方法去操作寄存器。 例如:
ioread8(addr_base+S3C2410_SPPRE);
iowirte8(0xf,addr_base+S3C2410_SPPRE);
还有一点要提一下的是ARM使用的IO内存,也就是说,把对外设的访问当做访问内存一样。X86的体系结构用的IO端口,用不同的指令访问内存和外设(貌似只有这个体系用这种方法)。
而这种方法的注册ldd3上有说明,而且在宋宝华的书上也有说明,也有很多的例子。就是看了宋宝华的书(书上第一个例子)才想到自己的那个cdev没有分配内存的。
错误的代码列出在这个链接里了。
以上是一些小bug,不过把我的进度给耽误了很久,现在这个驱动还同有写好,估计是时序的问题了,慢慢改吧,哦还有一个问题:到电子城去买元器件的时候一定要先看一下官方的报价(重要的元件AD/DA),别成了SB,买了旧的或是假货,就YY 了。我这个AD7888还不知道是不是真的,前一个估计是假的。
痛苦~~~~
阅读(3193) | 评论(0) | 转发(0) |