SPI是当前用的比较多的硬件总线,结构很简单,一共只要4根线就可以了。 其中两根是数据线,名字等会说,一根时钟线,叫SCK; 一根是片选线(CS)。4根线的连接见下面:
SPI的典型应用中,通信的双方一个是主(Master),一个是从(slave)。区别是由主设备提供通信时钟信号SCK给从设备,此外主设备还需要提供一个引脚来驱动Slave的片选信号CS。 主从设备的SO和SI是交叉连接的, 主的SO是数据输出口要接在从设备的SI上,反之依然。根据这样的设计, 能做SPI的设备往往是单片机, ARM芯片或者更强一些的CPU什么,而flash, 网络芯片或者声音A/D 和D/A转换芯片就扮演从设备的角色。主设备提供片选信号来选中从设备和连续时钟信号来驱动双方设备的读写过程。
由于从设备往往都是厂家设计好的, 主要的用户工作是如何在主设备上把从设备驱动起来。 这是把我搞的灰头土脸的地方。以我要驱动Flash为例, 根据看的文档,我直觉上知道应该把片选信号先拉低(选中flash),然后在SO上发出控制指令,最后等数据到来。结果我的程序是这样写的:
1、初始化SPI控制器,包括波特率设置
2、驱动CS为低电平选中flash
3、发送控制命令
4、接受数据
结果我收到的数据只有一个字节,内容为0. 忙了一个早上还是这个结果,搞的我极其郁闷,严重怀疑自己的RP,然后开始怀疑单片机是不是坏的,flash是不是坏的。一圈下来继续怀疑RP。 最后实在郁闷,就扛来示波器测波形。 因为这个玩也不熟悉,因此不敢轻易动,弄坏了把自己卖了才赔的起了(10G的哦)。结果发现430单片机的片选CS信号正常,在数据发送的时候SO口的确有波形输出,说明输出是对的。 但是。。。。为什么SCK没有连续时钟信号输出 ???? 我立刻理直气壮认为 单片机烧了,告诉师兄, 结果师兄暴汗.... :SPI主设备如果不连续输出数据,就不维护时钟了。顿时觉得自己长的好白阿。 正确的做法应该在主设备上送完指令后不停的送无用数据让spi控制器继续输出时钟并且读取发回来的数据。由于SPI控制器是同步读取数据的,因此我在发送的同时也读取数据,因此我送出去一个字节的数据,所以读回来一个数据,当然这个数据是无用的。
知道问题了,午饭后我把程序改成中断模式的, 所有的数据发送和接受全部采用中断。 发送寄存器一空 430就会发一个发送就绪中断,我在中断程序中把数组中的命令字发出去,等发完之后就一直发0x00,维护时钟,直到发送出去的字节数等于期望收到的数据量。另外一方面当数据收到后430就触发接收中断得到数据。 中断程序把数据读出来扔到接收数组里面。 等发送完后要检查是不是移位寄存器为空,防止还有数据没出去, 等空了就拉高片选信号断开flash. 完成这些后,检查接收数组,可以看到如果发送命令为n字节,则前面n字节的数据都是废的,所以要从n+1的位置来找收到的数据。 圆满大结局。(其实后面还碰到了波特率不对,结果丢数据的问题,但是很快解决了加上现在写的手酸,就略过拉)