Chinaunix首页 | 论坛 | 博客
  • 博客访问: 974428
  • 博文数量: 238
  • 博客积分: 2842
  • 博客等级: 少校
  • 技术积分: 2765
  • 用 户 组: 普通用户
  • 注册时间: 2009-04-16 00:20
个人简介

stdlf

文章分类

全部博文(238)

文章存档

2013年(6)

2012年(13)

2011年(82)

2010年(89)

2009年(48)

我的朋友

分类:

2009-09-04 22:21:35

/*
I2C stuff    下面是关于IIC总线初始化,读写操作
*/

/*
* Initialization, must be called once on start up, may be called
* repeatedly to change the speed and slave addresses.初始化启动时必须调用一次,也可重复调用多次以改变速度和从地址
*/
void i2c_init(int speed, int slaveaddr)
{
/*
   setting up I2C support
*/
unsigned int save_F,save_PF,rIICCON,rPCONA,rPDATA,rPCONF,rPUPF;
//请对照hfrks3c44b0开发板的电路图,EEPROM使用IIC BUS ,它的SCL,SDA接在CPU的61与60脚,它是IICSCL,IICSDA与IO口F组复用端口
save_F = PCONF;
save_PF = PUPF;

rPCONF = ((save_F & ~(0xF))| 0xa);//端口F的配置寄存器PCONF=0xa=1010,即PF0=10,PF1=10,定义为IICSCL和IICSDA
rPUPF = (save_PF | 0x3); //上拉电阻配置寄存器PUPF对应的PF0,PF1=1,不允许上拉电阻连接到对应脚
PCONF = rPCONF; /*PF0:IICSCL, PF1:IICSDA */
PUPF = rPUPF; /* Disable pull-up   IICSCL,IICSDA引脚是开放的输出引脚,因此需要上拉电阻才能当作IO口,这里不需要,所以不要上拉电阻*/

/* Configuring pin for WC pin of EEprom 配置EEPROM的wc引脚*/
rPCONA = PCONA;
rPCONA &= ~(1<<9);    //PCONA第9位=0,下面PDATA第9位=0,PA9配置为输出口,对应脚的状态与该位值相同;
//当端口配置为功能引脚时,如果读该位的值,将是一个不确定的值。
PCONA = rPCONA;      

rPDATA = PDATA;
rPDATA &= ~(1<<9);
PDATA = rPDATA;

/*
   Enable ACK, IICCLK=MCLK/16, enable interrupt
   75Mhz/16/(12+1) = 390625 Hz
*/
rIICCON=(1<<7)|(0<<6)|(1<<5)|(0xC); /*多主IIC总线控制寄存器IICCON=1010 1100
[3:0]transmit clock value IIC总线发送时钟预分频值,发送时钟频率由4位预分频值决定。公式:Tx clock=IICCLK/(IICCON[3:0]+1)
[4]Interrupt pending flag IIC总线Tx/Rx中断挂起标志,写1是不可能的,当该位为1时,IICSCL为低,IIC停止;为了恢复操作,清除该位。
[5]Tx/Rx Interrupt Enable IIC总线Tx/Rx中断使能/禁止位 为1允许中断。
[6]Tx clock source selection IIC总线的源时钟预分频值选择位:0为IICCLK=MCLK频率/16   1为IICCLK=MCLK频率/512
IICCLK=75MHz/16    Tx clock=75MHZ/16/(12+1)=390625HZ
[7]应答允许位 1允许应答信号产生。在发送模式,IICSDA在ACK时释放;在接受模式,IICSDA在ACK时为低电平
*/
IICCON = rIICCON;

IICADD = slaveaddr; //IICADD多主IIC总线地址寄存器。[7:0]从地址:当IICSTAT中的输出使能位为0时,IICADD为写允许,IICADD的值可能在
//任何时候被读,而不管输出使能位的设置,从地址=[7:1],非映射位=[0]
}

/*
* Probe the given I2C chip address. Returns 0 if a chip responded,
* not 0 on failure.探测给定的IIC芯片地址,如果响应返回0,非0则失败
*/
int i2c_probe(uchar chip)
{
/*
   not implemented   代码未实现
*/

printf(__FUNCTION__ " chip %d\n", (int) chip);
return -1;
}
/*补充:s3c44b0x IIC 总线接口的一些操作
应答ACK信号传送:为了完成一个字节的传送,接收器应发送一个ACK位给发送器。ACK脉冲应出现在SCL线的第9个时钟脉冲上。一字节数据传送需要8个时钟。
传送ACK位需要主设备产生一个时钟脉冲。ACK位的传送功能可由软件(IICSTAT)激活或禁止。然而完成一字节数据传送操作时,在SCL第9个时钟上的ACK脉冲是必不可少的。
读写模式:在传送模式下,数据被传送后,IIC接口将处于等待状态。直到有一个新数据写入IICDS。在新数据写入之前,SCL线将保持低电平。新数据写入IICDS之后,
SCL线将被释放。s3c44b0x保持这个中断来确定当前数据传送的完成。CPU接受到中断请求后,将在写一个新数据到IICDS。
在接收模式下,数据被接收后,IIC接口将处于等待状态。直到IICDS寄存器被读。在新数据被读出之前,SCL线将保持低电平。新数据读出之后,
SCL线将被释放。s3c44b0x保持这个中断来确定当前数据接收的完成。CPU接受到中断请求后,将从IICDS中读出这个数据
*/
/*
* Read/Write interface: 读写接口
*   chip:    I2C chip address, range 0..127
*   addr:    Memory (register) address within the chip
*   alen:    Number of bytes to use for addr (typically 1, 2 for larger
*              memories, 0 for register type devices with only one
*              register)
*   buffer: Where to read/write the data
*   len:     How many bytes to read/write
*
*   Returns: 0 on success, not 0 on failure
*/

#define S3C44B0X_rIIC_INTPEND               (1<<4)   //IICCON位定义,便于操作
#define S3C44B0X_rIIC_LAST_RECEIV_BIT       (1<<0)   //IICSTAT
#define S3C44B0X_rIIC_INTERRUPT_ENABLE      (1<<5)
#define S3C44B0_IIC_TIMEOUT 100
//IIC读函数,参数定义解释在上面
int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
{

int k, j, temp;
u32 rIICSTAT;

/*
   send the device offset
*/

rIICSTAT = 0xD0;   /*IICSTAT多主IIC总线控制状态寄存器
[0]Last-Received Bit Status Flag IIC总线上一次接收到的状态标志位。0=最后接收位是0(ACK收到);1=最后接收位是1(ACK没收到)
[1]IIC总线地址为0状态标志:0=检测到START/STOP清除;1=接收到的从地址是00000000B
[2]IIC总线从地址状态标志位:0=检测到START/STOP清除;1=接收到的从地址匹配IICADD的值
[3]IIC总线仲裁过程状态标志位:0=成功;1=失败
[4]IIC总线串行数据输出使能/禁止位 0=禁止Rx/Tx;1=使能Rx/Tx
[5]IIC总线忙信号状态位 0=读时总线不忙,写时总线STOP;1=读时总线忙,写时总线START信号产生 IICDS上的数据自动传输在START信号后。
 [7:6]IIC总线主/从Tx/Rx模式选择位:00=从接收模式 01=从发送模式 10=主接收模式 11=主发送模式
*/
IICSTAT = rIICSTAT;   //配置为主发送模式

IICDS = chip; /* this is a write operation... 将地址写入IICDS*/
//IICDS多主IIC总线发送/接收数据移位寄存器 [7:0]当IICSTAT中的串行输出使能位=1时,IICDS为写使能,IICDS可在任何时候被读
rIICSTAT |= (1<<5);
IICSTAT = rIICSTAT; //写时总线START信号产生 将0xF0写入IICSTAT

for(k=0; k   temp = IICCON;   //若IICCON[4]=1,break ;
   if( (temp & S3C44B0X_rIIC_INTPEND) == S3C44B0X_rIIC_INTPEND)
   break;
   udelay(2000);
}
if (k==S3C44B0_IIC_TIMEOUT)
   return -1;

/* wait and check ACK 等待效验ACK */
temp = IICSTAT; //若IICSTAT[0]=1,return -1
if ((temp & S3C44B0X_rIIC_LAST_RECEIV_BIT) == S3C44B0X_rIIC_LAST_RECEIV_BIT )
   return -1;

IICDS = addr;   //使用芯片内部发送/接收数据移位寄存器
IICCON = IICCON & ~(S3C44B0X_rIIC_INTPEND); //清除该位,读时,没有中断

/* wait and check ACK */
for(k=0; k   temp = IICCON;
   if( (temp & S3C44B0X_rIIC_INTPEND) == S3C44B0X_rIIC_INTPEND)
   break;
   udelay(2000);
}
if (k==S3C44B0_IIC_TIMEOUT)
   return -1;

temp = IICSTAT;
if ((temp & S3C44B0X_rIIC_LAST_RECEIV_BIT) == S3C44B0X_rIIC_LAST_RECEIV_BIT )
   return -1;

/*
   now we can start with the read operation...现在开始进行读操作
*/

IICDS = chip | 0x01; /* this is a read operation... IICDS为写使能,IICDS可在任何时候被读*/

rIICSTAT = 0x90; /*master recv 主接收模式*/
rIICSTAT |= (1<<5);
IICSTAT = rIICSTAT;

IICCON = IICCON & ~(S3C44B0X_rIIC_INTPEND);//清中断挂起位

/* wait and check ACK */
for(k=0; k   temp = IICCON;
   if( (temp & S3C44B0X_rIIC_INTPEND) == S3C44B0X_rIIC_INTPEND)
   break;
   udelay(2000);
}
if (k==S3C44B0_IIC_TIMEOUT)
   return -1;

temp = IICSTAT;
if ((temp & S3C44B0X_rIIC_LAST_RECEIV_BIT) == S3C44B0X_rIIC_LAST_RECEIV_BIT )
   return -1;

for (j=0; j

/*clear pending bit to resume 清除挂起位以便重新开始,CPU接受到中断请求后,将从IICDS中读出这个数据。*/

temp = IICCON & ~(S3C44B0X_rIIC_INTPEND);
IICCON = temp;

/* wait and check ACK */
for(k=0; k   temp = IICCON;
   if( (temp & S3C44B0X_rIIC_INTPEND) == S3C44B0X_rIIC_INTPEND)
   break;
   udelay(2000);
}
if (k==S3C44B0_IIC_TIMEOUT)
   return -1;


   buffer[j] = IICDS; /*save readed data     从IICDS读出新数据 ,保存读出的数据到缓冲区,*/

    } /*end for(j)   */

/*
   reading the last data   
   unset ACK generation
*/
temp = IICCON & ~(S3C44B0X_rIIC_INTPEND | (1<<7));
IICCON = temp;

/* wait but NOT check ACK */
for(k=0; k   temp = IICCON;
   if( (temp & S3C44B0X_rIIC_INTPEND) == S3C44B0X_rIIC_INTPEND)
   break;
   udelay(2000);
}
if (k==S3C44B0_IIC_TIMEOUT)
   return -1;

buffer[j] = IICDS; /*save readed data*/

rIICSTAT = 0x90; /*master recv*/

/* Write operation Terminate sending STOP */
IICSTAT = rIICSTAT;
/*Clear Int Pending Bit to RESUME*/
temp = IICCON;
IICCON = temp & (~S3C44B0X_rIIC_INTPEND);

IICCON = IICCON | (1<<7); /*restore ACK generation 恢复应答位1允许应答信号产生*/

return 0;
}
//下面是写操作,参考上面的即可

这是主设备接收模式下的操作流程图,可能效果不是太好,请参考s3c44b0x的datasheet
阅读(890) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~