IIC

   

   s3c2440内部有一个IIC总线接口。它具有四种操作模式:主设备发送模式、主设备接收模式、从设备发送模式和从设备接收模式。

IIC的具体时序:

 

由此可知SCL为高位时SDA从高位跃迁到低位时表示开始、SCL为高位时SDA从低位跃迁到高位时表示结束。我们可以设置IICSTAT寄存器来发送开始或结束信号。在第九个时钟时主设备或从设备拉低SDA,表示应答ACK。应答后产出中断,此时可以将数据写入IICDS或读出,然后清除中断标志位IICCON[4]恢复操作

 

 主设备发送模式流程:首先配置IIC模式,然后把从设备地址写入接收发送数据移位寄存器IICDS中,再把0xF0写入控制状态寄存器IICSTAT中,这时等待从设备发送应答信号,如果想要继续发送数据,那么在接收到应答信号后,再把待发送的数据写入寄存器IICDS中,清除中断标志后,再次等待应答信号;如果不想再发送数据了,那么把0x90写入寄存器IICSTAT中,清除中断标志并等待停止条件后,即完成了一次主设备的发送。

 主设备接收模式流程:首先配置IIC模式,然后把从设备地址写入接收发送数据移位寄存器IICDS中,再把0xF0写入控制状态寄存器IICSTAT中,这时等待从设备发送应答信号,如果想要接收数据,那么在应答信号后,读取寄存器IICDS,清除中断标志;如果不想接收数据了,那么就向寄存器IICSTAT写入0x90,清除中断标志并等待停止条件后,即完成了一次主设备的接收。

 IICCON:[7]设置是否发出应答信号
             [6]设置IIC的时钟频率

                     [5]用于是否使能发送和接收中断

                     [4]用于中断的标志,当接收或发送数据后一定要对该位进行清零,以清除中断标志。

        IICSTAT:[7:6]用于设置是哪种操作模式

                     [5]写0或写1时,则表示结束IIC或开始IIC通讯

                     [4]用于是否使能接收/发送数据。

      寄存器IICCON的第6位和低4位用于设置IIC的时钟频率,因为IIC的时钟线SCL都是由主设备提供的。s3c2440的IIC时钟源为PCLK,当系统的PCLK为50MHz,而从设备最高需要100kHz时,可以将IICCON的第6位置1,IICCON的低4位全为0即可。

在这里,从设备是EEPROM——AT24C08A,要想让s3c2440能够正确地对AT24C08A读写,就必须让s3c2440的时序完全按照AT24C08A的时序。 

AT24C08A的写操作有两种模式:字节写和页写。字节写是先接收带有写命令的设备地址信息,如果符合就应答,再接收设备内存地址信息,发出应答后,再接收要写入的数据,这样就完成了字节写过程。页写与字节写的区别就是,页写可以一次写多个数据,而字节写只能一次写一个数据。但由于AT24C08A的一页才8个字节,所以页写也最多写8个数据,而且只能在该页内写,不会发生一次页写同时写两页的情况。

AT24C08A的读操作有三种模式:当前地址读、随机读和序列读。当前地址读是只能读取当前地址内的数据,它的时序是先接收带有读命令的设备地址信息,如果符合就应答,然后发送当前地址内的数据,在没有接收从主设备发来的应答信号的情况下终止该次操作。随机读的时序是,连续接收带有写命令的设备地址信息和设备内存地址信息,然后主设备重新开启IIC通信,AT24C08A再次接收到带有读命令的设备地址信息,在发出应答信号以后,发送该内存地址的数据,在没有接收到任何应答信号的情况下结束该次通信。当前地址读和随机读一次都只能读取一个数据,而序列读一次可以读取若干个数据,它的时序就是在当前地址读或随机读发出数据后,接收到了应答信号,那么AT24C08A会把下一个内存地址中的数据送出,除非AT24C08A接收不到任何应答信号,否则它会一直把下一个内存地址中的数据送出。序列读没有一页8个字节的限制。

 I2C设备并不只有一个设备地址。这一点往往被忽略,一般情况下认为在I2C启动信号之后的字节为I2C从机地址(7位)。对于AT24C04而言,内部具有4Kb存储位,合计512字节。若需要访问512字节内容,总共需要9根地址线(8位宽度),那么上图中的存储地址(8位长度)显然还差了一位,那么就需要从设备地址中“借”1位,这就使得AT24C04具有两个I2C地址,例如0x50和0x51

⑴清IIC中断标志语句rIICCON &= ~0x10;一定要在读写寄存器IICDS的后面,不能放到它的前面;

⑵在等待应答的死循环while内,一定要加上延时的程序;

⑶在读取AT24C02A数据时,当读到最后一个数据时,一定不能让s3c2440发送应答信号,否则以后会无法再读取AT24C02A数据,除非关电重启;

⑷在真正对AT24C02A进行读取数据时,在发送带有读命令的从设备地址后,AT24C02A会再返回一个从设备地址信息或从设备内存地址信息作为应答,所以一定要把该字节读取后抛弃,因为它不是我们所要读取的信息;

⑸按照AT24C02A的时序,在发送从设备地址字节时,它的最低位是0表示写,1表示读。但对于s3c2440来说,不用人为设置这一位,即是01都无所谓,因为这一位是由s3c2440根据是主设备发送模式还是主设备接收模式来自动设

读写是站在主机的立场上定义的.

""是主机接收从机数据,""是主机发送数据给从机

7I2C总线可以挂接127个不同地址的I2C设备,0"设备"作为群呼地址.

10I2C总线可以挂接更多的10I2C设备

常用IIC接口通用器件的器件地址是由种类型号,及寻址码组成的,共7位。
如格式如下: 
  D7 D6 D5 D4 D3 D2 D1 D0
1-
器件类型由:D7-D4 4位决定的。这是由半导公司生产时就已固定此类型的了,也就是说这4位已是固定的。

2-
用户自定义地址码:D3-D13位。这是由用户自己设置的,通常的作法如EEPROM这些器件是由外部IC3个引脚所组合电平决定的(用常用的名字如A0,A1,A2)。这也就是寻址码。

所以为什么同一IIC总线上同一型号的IC只能最多共挂8片同种类芯片的原因了。

3-最低一位就是R/W位。

 

 

mini2440-256M上面用的eeprom的型号为AT24C08B,这个eeprom的大小为1024*8(8k),这是什么意思呢?
    存储器芯片容量=存储单元数*数据位数
用AT24C08B来具体解释就是,AT24C08B共有1024个存储单元,每个存储单元的大小事8位(bits),而我们知道8位为一个字节,所以mini2440开发板的eeprom的大小为1024个字节,即1K大小,那么括弧里面的8K是什么意思的,8K的意思是总共有8*1024个位,不要混淆了哦。所以mini2440用户手册上说eeprom的大小是256字节是错误的,256字节那是AT24C0A的大小。

查数据手册可以其地址为0xa0或0xa1。最低位为读写标志。在s3c2440中根据IIC模式自动选择,所以地址我们只需填写0xa0即可。

值得注意的是EEPROM读写速度不是很快,所以每次读写一个字节都要加一定延时,这点十分关键。这往往是程序读写失败的原因。当然我们也需要设置好SCL的频率。在IICCON里设置这里不多说。

在接收模式下最后一个字节数据不发送ACK这点也需要注意。

测试代码中我们采用将数据写入EEPROM中然后读取出来输出到串口来检验,程序可以采用中断或轮询,代码如下:

mian.c部分

  1. #define  GLOBAL_CLK 1  
  2.  
  3. #include "def.h"  
  4. #include "option.h"  
  5. #include "2440addr.h"  
  6. #include "profile.h"  
  7. #include "mmu.h"  
  8.   
  9. typedef unsigned char uchar;  
  10. typedef unsigned int uint;  
  11.   
  12. extern void AT24C08_wirte(uchar waddr, uchar *dat,  int num);  
  13. extern void AT24C08_read(uchar waddr, uchar *rev,  int num);  
  14. extern void IIC_init(void);  
  15. extern void delay(int time);  
  16.   
  17. uchar dat[]={"0123456789abcdef"};  
  18. uchar rev[50]={0};  
  19.   
  20. void Main(void)  
  21. {  
  22.   
  23.     rGPBCON=(1<<0);//关闭蜂鸣器  
  24.     rGPBDAT=0x00;  
  25.       
  26.     IIC_init();  
  27.   
  28.     AT24C08_wirte(0x00, dat, 16);  
  29.     Uart_Printf(" ");  
  30.     AT24C08_read(0x00, rev, 10);  
  31.       
  32.     Uart_Printf(" %s ",rev);  

 IIC.c部分

  1. #include "def.h"  
  2. #include "option.h"  
  3. #include "2440addr.h"  
  4. #include "profile.h"  
  5. #include "mmu.h"  
  6.   
  7. typedef unsigned char uchar;  
  8. typedef unsigned int uint;  
  9. void __irq IIC_INT(void);  
  10.   
  11. int flag=1;//中断标志  
  12.   
  13. void delay(int time)  
  14. {  
  15.     int i,j,k;  
  16.     for(i=0;i<100;++i)  
  17.         for(k=0;k<100;++k)  
  18.             for(j=0;j<time;j++);  
  19. }  
  20.   
  21. //IIC初始化  
  22. void IIC_init(void)  
  23. {  
  24.     //设置GPE15、GPE14为SDA、SCL  
  25.     rGPECON |= (0x0a<<28);  
  26.       
  27.     //允许ACK、允许中断、发送频率Khz  
  28.     rINTMSK &= ~(1<<27);  
  29.     rIICCON |= (1<<7 | 0<<6 | 1<<5 | 0xf);  
  30.     rIICSTAT |= 1<<4;//IICDS可写  
  31.       
  32.     MMU_Init();//映射地址  
  33.     pISR_IIC = (unsigned)IIC_INT;//中断入口  
  34. }  
  35.   
  36. //AT24C08页写  
  37. void AT24C08_wirte(uchar waddr, uchar *dat, int num)  
  38. {  
  39.     int i=0;  
  40.   
  41.     rIICDS = 0xa0;//AT24C08地址  
  42.     rIICSTAT =0xf0;//发送模式、发送开始信号  
  43.     while(flag == 1)  
  44.         delay(100);//等待中断  (等待ACK应答发出的中断信号)
  45.     flag = 1;  
  46.       
  47.     rIICDS = waddr;//起始地址  
  48.     rIICCON = 0xaf;//清除中断标志位  
  49.     while(flag == 1)  
  50.         delay(100);//等待中断  
  51.     flag = 1;  
  52.           
  53.     for(i=0;i<num;++i){  
  54.         rIICDS = *(dat + i);  
  55.         rIICCON = 0xaf;//清除中断标志位  
  56.         while(flag == 1)  
  57.             delay(100);//等待中断  
  58.         flag = 1;  
  59.     }  
  60.       
  61.     rIICSTAT =0xd0;//发送停止位  
  62.     rIICCON = 0xaf;//清除中断标志位  
  63.     delay(100);  
  64. }  
  65.   
  66. //AT24C08连续读          
  67. void AT24C08_read(uchar waddr, uchar *rev, int num)  
  68. {  
  69.     int i=0;  
  70.       
  71.     rIICDS = 0xa0;  
  72.     rIICSTAT =0xf0;//发送从机地址  
  73.     while(flag == 1)  
  74.         delay(100);//等待中断  
  75.     flag = 1;  
  76.       
  77.     rIICDS = waddr;//初始地址  
  78.     rIICCON = 0xaf;//清除中断标志位  
  79.     while(flag == 1)  
  80.         delay(100);//等待中断  
  81.     flag = 1;  
  82.       
  83.     rIICDS = 0xa0;  
  84.     rIICSTAT =0xb0;//接收模式  
  85.     rIICCON = 0xaf;//清除中断标志位  
  86.     while(flag == 1)  
  87.         delay(100);//等待中断  
  88.     flag = 1;  
  89.       
  90.     for(i=0;i<num;++i){  
  91.         if(i == (num-1)) rIICCON = 0x2f;  
  92.         else rIICCON = 0xaf;  
  93.         while(flag == 1)  
  94.             delay(100);//等待中断  
  95.         flag = 1;  
  96.         *(rev + i) = rIICDS;  
  97.         delay(100);  
  98.     }  
  99.       
  100.     rIICSTAT =0x90;//发送停止位  
  101.     rIICCON = 0xaf;//清除中断标志位  
  102.     delay(100);  
  103. }  
  104.   
  105. //中断服务函数  
  106. void __irq IIC_INT(void)  
  107. {  
  108.     flag = 0;  
  109.     rSRCPND |= 1<<27;//先清除SRCPND  
  110.     rINTPND |= 1<<27;  
  111. }  
  112.   
  113.   
  114. /* 
  115. #include "2440addr.h" 
  116.  
  117. typedef unsigned char uchar; 
  118. typedef unsigned int uint; 
  119.  
  120. void delay(int time) 
  121. { 
  122.     int i,j,k; 
  123.     for(i=0;i<100;++i) 
  124.         for(k=0;k<100;++k) 
  125.             for(j=0;j<time;j++); 
  126. } 
  127.  
  128. //IIC初始化 
  129. void IIC_init(void) 
  130. { 
  131.     //设置GPE15、GPE14为SDA、SCL 
  132.     rGPECON |=  (0x0a<<28); 
  133.     //允许ACK、允许中断、发送频率Khz 
  134.     rIICCON |= (1<<7 | 0<<6 | 1<<5 | 0xf); 
  135.     rIICSTAT |= (1<<4);//IICDS可写 
  136. } 
  137.  
  138. //AT24C08页写 
  139. void AT24C08_wirte(uchar waddr, uchar *dat, int num) 
  140. { 
  141.     int i=0; 
  142.  
  143.     rIICDS = 0xa0;//AT24C08地址 
  144.     rIICSTAT =0xf0;//发送模式、发送开始信号 
  145.     while(!(rIICCON & 0x10)) 
  146.         delay(100);//等待中断 
  147.  
  148.     rIICDS = waddr;//起始地址 
  149.     rIICCON &= ~(1<<4);//清除中断标志位 
  150.     while(!(rIICCON & 0x10)) 
  151.         delay(100);//等待中断 
  152.      
  153.     for(i=0;i<num;++i){ 
  154.         rIICDS = *(dat + i); 
  155.         rIICCON &= ~(1<<4);//清除中断标志位 
  156.         while(!(rIICCON & 0x10)) 
  157.             delay(100);//等待中断 
  158.     } 
  159.      
  160.     rIICSTAT =0xd0;//发送停止位 
  161.     rIICCON &= ~(1<<4);//清除中断标志位 
  162.     delay(100); 
  163. } 
  164.  
  165. //AT24C08连续读         
  166. void AT24C08_read(uchar waddr, uchar *rev, int num) 
  167. { 
  168.     int i=0; 
  169.  
  170.     rIICDS = 0xa0; 
  171.     rIICSTAT =0xf0;//发送EEPROM地址 
  172.     while(!(rIICCON & 0x10)) 
  173.         delay(100);//等待中断 
  174.      
  175.     rIICDS = waddr;//初始地址 
  176.     rIICCON &= ~(1<<4);//清除中断标志位 
  177.     while(!(rIICCON & 0x10)) 
  178.         delay(100);//等待中断 
  179.          
  180.     rIICDS = 0xa0; 
  181.     rIICSTAT =0xb0;//接收模式 
  182.     rIICCON &= ~(1<<4);//清除中断标志位 
  183.     while(!(rIICCON & 0x10)) 
  184.             delay(100);//等待中断 
  185.      
  186.     for(i=0;i<num;++i){ 
  187.         if(i == (num-1)) rIICCON &= ~(1<<7 | 1<<4);//不发送ACK 
  188.         else rIICCON &= ~(1<<4);//清除中断标志位 
  189.         while(!(rIICCON & 0x10)) 
  190.             delay(100);//等待中断 
  191.         *(rev+i) = rIICDS; 
  192.         delay(100); 
  193.     } 
  194.  
  195.     rIICSTAT =0x90;//发送停止位 
  196.     rIICCON &= ~(1<<4);//清除中断标志位 
  197.     delay(100); 
  198. } 
  199. */
原文地址:https://www.cnblogs.com/liuchengchuxiao/p/4204516.html