ARM——I2C

  S5PC100的RISC微处理器支持多主机I2C总线串行接口。一个专用的串行数据线(SDA)和一个串行时钟线(SCL)在总线主机和连接到I2C总线的外围设备之间传递信息。SDA和SCL线是双向的。


  在多主机i2c总线模式中,多个微处理器发送到从机设备或从从机设备接收。主机S5PC100启动和终止一个在I2C总线上的数据传输。S5PC100上的I2C总线使用标准总线仲裁程序。

  为了控制多主机I2C总线操作,值必须写到一下寄存器:

  多主机I2C控制寄存器 I2CCON

  多主机I2C控制/状态寄存器 I2CSTAT

  多主机I2C发送/接收转换寄存器 I2CDS

  多主机I2C地址寄存器 I2CADD

  如果I2C总线空闲,SDA和SCL线应该均为高电平。当SCL线稳定在高电平时,SDA线电平由高到低转换将发起开始条件,SDA线电平由低到高转换将发起停止条件。

  主机设备总是产生开始条件和停止条件。当开始条件发起后,被放到总线上第一数据字节的7位地址值能够决定总线主机设备选择的从机设备。第8位决定传输方向(读/写)。

  每一个被放到SDA线上的数据字节应该是总共八位。总线传输期间发送或接收的数据字节数没有限制。数据总是首先从最高有效位MSB发送,每一字节后紧跟应答位ACK。

 

  S5PC100 I2C总线接口有四种操作模式:

  主机发送模式;主机接收模式;从机发送模式;从机接收模式

这些操作模式功能关系:

开始和停止条件

  如果I2C总线接口未启动,通常是从机模式。换句话说,接口在检测到SDA线上开始条件(当SCL线时钟信号高电平时SDA线电平由高到低转换发起开始条件)之前应该是从机模式。如果接口状态转换到主机模式,SDA线上数据传输可以被发起,SCL信号产生。

  通过SDA线开始条件传输一字节串行数据,停止条件终止数据传输。当SCL线时钟信号高电平时SDA线电平由低到高发起停止条件。主机产生开始和停止条件。如果开始条件产生,I2C总线将变为忙状态。停止条件释放I2C总线。如果主机发起开始条件,应该发送一个从机地址来通知从机设备,一个字节的地址域包含一个7位地址值和一个1位传输方向指示值(写或读)。如果第8位是0,则表示写操作(发送操作);如果第8位是1,则表示读数据请求(接收操作)。

  主机发送停止条件来完成传输操作,如果主机箱继续总线数据的发送,应该产生另一个开始条件和从机地址。这样,可以进行各种格式的读写操作。

 

 

数据传输格式 

SDA线上的每一字节应该长度为8位,每次传输发送的字节数没有限制。跟随开始条件的第一字节应该包含地址域。如果I2C总线操作在主机模式下,主机发送地址域。每一字节后应该紧跟一个应答位ACK。串行数据和地址的最高有效位MSB应该首先被发送。

应答信号发送

为了完成一字节传输操作,接收方发送应答位ACK到发送方。应答脉冲在SCL线的第9时钟周期产生。一字节数据传输使用了八个时钟。主机发送应答位ACK要产生时钟脉冲。

 

发送方如果接收到应答位ACK则通过使SDA线置高来释放SDA线。接收方在应答位ACK时钟脉冲期间驱使SDA线置低以使在SCL线第9脉冲周期间保持SDA线置低。

软件(I2CSTAT)使能或禁用应答位ACK发送功能。然而,在SCL线第9脉冲周期应答位ACK脉冲被请求来完成一字节数据传输操作。

 

 读/写操作

在发送模式下,如果数据被传输,I2C总线接口等待直到I2C总线数据转换寄存器(I2CDS)接收到一个新的数据。在新数据写到寄存器之前,SCL线保持低电平,然后写完之后释放。S5PC100获得中断来识别当前数据发送是否完成。CPU接收中断请求之后,再写一个新数据到I2CDS寄存器。

在接收模式下,如果数据被接收,I2C总线接口等待直到I2C总线数据转换寄存器(I2CDS)被读到。在新数据被读出之前,SCL线保持低电平,然后读完释放。S5PC100获得中断来识别当前数据接收是否完成。CPU接收中断请求之后,再从I2CDS寄存器读数据。

总线仲裁程序

仲裁发生在SDA线上来阻止总线上两主机冲突,如果一个SDA线高电平的主机检测到另一个SDA线低电平的主机,它将不发起数据传输,因为总线上的当前电平不能对应到他自己,仲裁程序延迟直到SDA线电平变高。

如果主机同时降低SDA线电平,没一个主机评估是否主控权在它自身。为了评估每一个主机检测地址位。当每一主机产生从机地址时,检测SDA线上的地址位,因为SDA线很可能获得低电平而不是保持高电平。假设一个主机产生低电平作为地址第一位,而另一个主机维持在高电平,这种情况,两主机检测到总线上低电平,因为低电平状态优于高电平状态。如果发生,产生低电平(作为地址第一位)的主机获得主控权而产生高电平(作为地址第一位)的主机撤出主控权。如果量主机产生低电平作为地址第一位,再对第二地址位仲裁。这种仲裁持续到地址位结束。

 

中止条件

如果从机接收方不能应答从机地址的确认,将保持SDA线高电平。这种情况,主机产生停止条件然后中止传输。

如果主机接收方忙于中止的传输,则通过在从机接收完最后的数据字节后取消产生应答位ACK来发信号中止从机发送。从机发送方释放SDA线来允许主机产生停止条件。

 

配置I2C总线

  

 为了控制串行总线时钟SCL的频率,4位预分频值被写进I2CCON寄存器。I2C总线接口地址保存在I2C总线地址(I2CADD)寄存器(默认情况下I2C总线接口地址有一个未知值)。

每个模式下的操作流程图

下面的步骤在每一个I2C发送/接收操作中都被执行

1如果需要,自己的从机地址到I2CADD寄存器

2设置I2CCON寄存器

  a使能中断

  b定义SCL周期

3设置I2CSTAT为使能串口输出

#include "s5pc100.h"

void putc(const char data)
{
 while(!(UART0.UTRSTAT0 & 0X2));
 UART0.UTXH0 = data;
 if(data == '\n')
  putc('\r');
}
void puts(const  char  *pstr)
{
 while(*pstr != '\0')
  putc(*pstr++);
}

void uart0_init(void)
{
 GPA0.GPA0CON = (GPA0.GPA0CON & ~(0xff)) | 0X22;//enable GPA0.0 GPA0.1 pin function mode // RXD0 TXD0
    UART0.UFCON0 = 0X00; //disable  fifo
 UART0.UMCON0 = 0X00; //disable AFC
 UART0.ULCON0 = 0X03; //data length 8 bit
 UART0.UCON0  = 0X305; //
 UART0.UBRDIV0 = 0X23; // Baud rate divisior register 115200   UBRDIV0 = (PCLK / (bps x 16 ) ) 
 UART0.UDIVSLOT0 = 0xDDD5;   //set  SLOT  register  generate more accurate baud rate
    printf("open uart device ok !\n");
}

 

 #include "s5pc100.h"
#include "uart.h"

/****
 * functioal : Reading the value of the internal lm75 register
 * param:  address register of the internal lm75 register
 * return: value of the internal lm75 register
 */
int set_pointer_and_read_temperature(void)

 int delay;
 int low, high;
 I2C0.I2CDS0 = 0x90;       /*LM75 SLAVE ADDRESS */
 I2C0.I2CCON0 = 0xe0;       /*ENABLE ACK BIT, PRESCALER:512 ,RX/TX INTERRUPT ENABLE ,*/
 I2C0.I2CSTAT0 =0xf0;       /*Master Trans mode ,START ,ENABLE RX/TX ,*/
 while(!(I2C0.I2CCON0&(1<<4)));  /*The end of the waiting to be sent  */
 
 I2C0.I2CDS0 = 0x0;        /*pointer register Temperature(read only) send address of SFR in the lm75*/
 I2C0.I2CCON0 &= ~(1<<4);        /* Clear pending condition & Resume the operation */
 while(!(I2C0.I2CCON0&(1<<4)));  /*The end of the waiting to be sent  */
 
 I2C0.I2CDS0 = 0x90;            /*Again to send LM75 salve address*/
 I2C0.I2CSTAT0 =0xb0;     /*Master receive mode ,START ,ENABLE RX/TX ,*/
 I2C0.I2CCON0  &= ~(1<<4);    /* Clear pending condition & Resume the operation */
 while(!(I2C0.I2CCON0&(1<<4))); /*The end of the waiting to be sent  */

 I2C0.I2CCON0 &= ~(1<<4);        /* Clear pending condition & Resume the operation */
 for(delay=0; delay<0xffff; delay++);
 high = I2C0.I2CDS0;             /*read temperature of high 8 bit */

 

 I2C0.I2CCON0 &= ~(1<<4);       /* Clear pending condition & Resume the operation */
 for(delay=0; delay<0xffff; delay++); 
 low = I2C0.I2CDS0;    /*read temperature of low 1 bit */

 I2C0.I2CSTAT0 &= ~(1<<5);   /*STOP signal generation,free bus */
 I2C0.I2CCON0 &= ~(1<<4);  /*clean interrup pending bit  */
 return ((high << 8) | low);
}

int main()
{
 int temp;
    int low, high;
    uart0_init();
    GPD.GPDCON = (GPD.GPDCON & ~(0X0F << 12)) | (0X2 << 12);  /*SDA  set gpd[3] functional mode*/
    GPD.GPDCON = (GPD.GPDCON & ~(0X0F << 16)) | (0X2 << 16);  /*SCL  set gpd[4] functional mode*/

 while (1){
  temp = set_pointer_and_read_temperature();
  high = temp >> 8;
  low = temp & 0xff;
     printf("TEMP is : %d.%d\n", high, (((low>>7)==0) ? 0 : 5)); 
 }
 return 0;
}

posted @ 2013-01-18 16:24  雪中飞  阅读(2937)  评论(0编辑  收藏  举报