LPC23XX之I2C使用总结
--- 原野之狼写于2010年重阳节之时
近来由于项目需要,玩了玩LPC23XX系列的I2C,这么一个小小的东西费了我一周的时间,实在是令人崩溃!
首先要指出的是,原厂的LPC23XX的User Manual存在着严重的误导作用,另外给的Sample程序也存在着误导作用。很不幸,俺手头上拥有的正好是这两份资料,所以走了许多弯路。
关于I2C的官方Specification诸位最好先看看,我就提醒一点:I2C硬件上要求各I2C器件不管是作为Master还是作为Slave使用时都要采用OC或者OD模式作为IO接口,然后在外部用电阻上拉到电源,这样才能使得当总线冲突时高电平和低电平不会互相拼个你死我活。目前Internet上的一些关于I2C的参考程序一般都是采用IO模拟I2C协议来实现的,这当然是可以的,但是记得要把MCU的IO口配置成OC、OD或者弱上拉模式,不要弄成推挽输出哦。不过采用IO模拟方式比较占资源系统资源,本文描述的是采用MCU自带的I2C控制器来实现。
LPC23XX支持3个I2C接口,这三者并不是完全一样的,I2C0是严格遵守I2C协议的,而I2C1和I2C2并不严格遵守I2C协议,这体现在IO口的结构上,这点需要引起注意。
接下来说说User Manual的问题,我设置I2C控制器作为Master使用,并且是Single Master,外部挂了个RTC器件,因此本文的描述以此为前提条件。
User Manual关于I2C控制器的描述主要体现在这么一些资料:
资料1:状态迁移图Fig116和Fig117(P520~521)。
资料2:状态表Table451和Table452(P452~453)。
资料3:关于软件编写指导性的文字描述(P533)。
这三者本来应该是关联性很强并互为指导的的文档资料,但是我看了好几天都没有明白写的是啥子意思,无奈只好凭着感觉先把代码写完,然后一边调试程序一边对着资料看,旁边还架上示波器来看波形。
关于资料3,诸位看个大概就行了,如果你按照这个细节去做估计会死得很惨。
关于资料2,这个资料倒是没问题,但是得弄明白才行。
关于资料1,这个资料非常重要,但是很不好理解,要是没有按照它所指定的路线操作就会出莫名其妙的问题。
先解读一下资料1的Fig116,用以辅助理解,当然诸位首先得看看User Manual,要不然俺说了也是白说,解读如下:
1、 程序设置S位到相关寄存器,控制器会尝试着去获得I2C的操作权,获得特权后就会发送起始信号。
2、 成功完成起始信号的发送后控制器会产生中断并返回0X08(注意不要理解错了,此返回并不是指中断程序返回,而是指控制器的状态寄存器的信息,下同)。
3、 程序写入SLA+W信息到相关寄存器。
4、 发送成功后会产生中断并返回0X18。
5、 程序写入要发送的数据到到相关寄存器。
6、 发送成功后会产生中断并返回0X28。
7、 如果还要继续发送请回到5,否则写入P到相关寄存器。
8、 在7时,如果数据已经发送完但是并不想写P以停止I2C操作,而需要继续进行别的操作。举个例子,比如在读取RTC的时间信息时,先写入要访问的寄存器地址信息,然后在读出数据信息,这是一个连贯的动作,并不需要插入P操作的,具体请查看RTC数据手册。那么这个时候程序再次设置S位到相关寄存器,使得控制器发送起始信号。
9、 上一步再次发送S成功后会产生中断并返回0X10。此时程序写入SLA+R信息到相关寄存器。
10、 接下来就转到了Fig117了。
接下来,解读一下Fig117:
1、 程序设置S位到相关寄存器,控制器会尝试着发送起始信号。
2、 成功完成起始信号的发送后控制器会产生中断并返回0X08。
3、 程序写入SLA+R信息到相关寄存器。
4、 发送成功后会产生中断并返回0X40,注意Fig116第10条也就是这里的第4条。这个时候我们该做什么了呢,显然是需要读取数据。但是请注意,并不是现在就读取数据,因为本条的0X40仅仅表示了SLA+R发送完毕了,我们想要的其它数据还在后头呢,中断程序退出后控制器才会产生时钟去外部I2C器件那里取数据。
5、 如上所述,当读取数据成功后控制器会产生中断并返回0X50,这时就可以从控制器的数据寄存器拷贝数据了。根据I2C协议,此时主机还需要向从机提供应答信号,如果接下来还需要读取数据,那么应答ACK,否则应答NO ACK。如果应答ACK,请继续第5条,否则就是第6条的事情了。应答操作由程序完成。
6、 如果之前应答的是NO ACK,应答完后控制器会产生中断并返回0X58。写入P到相关寄存器完成此次I2C操作。
以上两篇解读仅以状态迁移图的主线为例,其它分支因为比较简单所以没有做解读,编程的时候需要考虑其它分支情况。
关于资料1就说这么多,一定要先把这个状态迁移图搞明白,要不然会死得不明不白。资料1理解透了,看资料2就轻松许多了,无非是一些细节嘛。记住一条就是了,该设置的位要设置,该清除的位要清除,不能多也不能少,会带来什么问题俺也不清楚,没有逐个测试,调试的过程发现不正确的设置会导致状态迁移不按规定的路径走。
在调试的过程中可以通过跟踪中断程序中读来的状态码来确定状态迁移路径,要是路径不对多半就是俺在上一个段落中提到的原因了。还有一点尤其注意,有些I2C器件存在超时的问题,就是说一次完整的I2C操作(从S开始算起,以P作为结束)需要在规定的时间内完成,所以诸位千万不要在中断程序里设置断点来观察寄存器信息,除非你能保证你眼睛够犀利手脚够麻利能够在超时时间之内完成想要做的事情。
OK,该打住了,就说这么多,不要向我要源代码,不是本狼不够OPEN,是因为俺自己都搞不到。
联系我:y_y_z_l 爱她 163.com
版权声明:欢迎转载,但请保留本文的完整性。
文章评论(0条评论)
登录后参与讨论