stdlf
分类:
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
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
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
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); /* wait and check ACK */ } /*end for(j) */ /* /* wait but NOT check ACK */ buffer[j] = IICDS; /*save readed data*/ rIICSTAT = 0x90; /*master recv*/ /* Write operation Terminate sending STOP */ IICCON = IICCON | (1<<7); /*restore ACK generation 恢复应答位1允许应答信号产生*/ return 0;
IICCON = temp;
for(k=0; k
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读出新数据 ,保存读出的数据到缓冲区,*/
reading the last data
unset ACK generation
*/
temp = IICCON & ~(S3C44B0X_rIIC_INTPEND | (1<<7));
IICCON = temp;
for(k=0; k
if( (temp & S3C44B0X_rIIC_INTPEND) == S3C44B0X_rIIC_INTPEND)
break;
udelay(2000);
}
if (k==S3C44B0_IIC_TIMEOUT)
return -1;
IICSTAT = rIICSTAT;
/*Clear Int Pending Bit to RESUME*/
temp = IICCON;
IICCON = temp & (~S3C44B0X_rIIC_INTPEND);
}
//下面是写操作,参考上面的即可