EEPROM(electrically erasable and programmable read-only memory),就是一个可以读写数据的存储器件,断电后数据还保存着,一般用来存储一些用户设置的参数,摄像头模组上也会用它保存OTP的数据。
以AT24C08为例,如下代码通过GPIO产生IIC通信信号,进行读写。
代码示例iic.h
#ifndef _IIC_H_
#define _IIC_H_
#include "def.h"
#define AT24C08_ADDRDRESS 0xa0
#define true 1
#define false 0
#define PAGE1 0xa0
#define PAGE2 0xa2
#define PAGE3 0xa4
#define PAGE4 0xa6
#define IIC_CLOCK_HIGH rGPEDAT |= (1<<14)
#define IIC_CLOCK_LOW rGPEDAT &= ~(1<<14)
#define IIC_DATA_HIGH rGPEDAT |= (1<<15)
#define IIC_DATA_LOW rGPEDAT &= ~(1<<15)
#define SET_IIC_DATA_INPUT rGPECON &= ~(3<<30)
#define SET_IIC_DATA_OUTPUT rGPECON |= (1<<30)
void iic_init(void);
U8 i2c_write(U8 device_address, U8 memory_address , U8 data);
U8 i2c_read(U8 device_address, U8 memory_address, U8 *data);
U8 i2c_page_read(U8 device_address, U8 memory_address, U8 *destination,U32 size);
U8 i2c_page_write(U8 device_address, U8 memory_address , U8 *source,U32 size);
U8 i2c_largepage_write(U8 device_address, U8 memory_address , U8 *source,U32 size);
void i2c_test(void);
#endif
iic.c
#include "2440addr.h"
#include "def.h"
#include "uart.h"
#include "iic.h"
//#include "timer.h"
#define DELAY_DECIMUS_MS 100
void delayus( U32 time)
{
U32 i,j;
for ( i=0; i<time; i++)
{
for(j=0;j<DELAY_DECIMUS_MS;j++)
{
}
}
}
void iic_init(void)
{
/* config GPE14, GPE15 as output*/
rGPECON &=(~((3<<30)|(3<<28)));
rGPECON |=(1<<30)|(1<<28);
/* SDA,SCL 默认为高电平 */
rGPEDAT |= ((1<<15)|(1<<14));
rGPEUP |= ((1<<15)|(1<<14));
delayus(1);
}
void i2c_start(void)
{
IIC_DATA_HIGH;
delayus(1);
IIC_CLOCK_HIGH;
delayus(1);
IIC_DATA_LOW;
delayus(1);
IIC_CLOCK_LOW;
}
void i2c_stop(void)
{
SET_IIC_DATA_OUTPUT;
delayus(1);
IIC_DATA_LOW;
delayus(1);
IIC_CLOCK_HIGH;
delayus(1);
IIC_DATA_HIGH;
delayus(1);
}
U8 check_ack(void)
{
/* ack */
U8 ret;
U8 ucErrTime=0;
SET_IIC_DATA_INPUT;
delayus(1);
IIC_CLOCK_HIGH; //negative edge clock data out of each device
delayus(1);
while(rGPEDAT&(1<<15))
{
ucErrTime++; //时间累加
ret = false;
if(ucErrTime>250) //如果时间大于250
{
i2c_stop(); //调用IIC停止子函数
return ret; //程序返回值0
}
}
ret = true;
IIC_CLOCK_LOW;
delayus(1);
SET_IIC_DATA_OUTPUT;
delayus(1);
return ret;
}
void send_no_ack(void)
{
delayus(1);
IIC_CLOCK_LOW; //positive edge clock data into eachEEPROM
delayus(1);
SET_IIC_DATA_OUTPUT;//发送数据时与上升沿同步
IIC_DATA_HIGH; /* 发送高电平no ack */
delayus(2);
IIC_CLOCK_HIGH;
delayus(1);
IIC_CLOCK_LOW;
delayus(1);
}
void data_write(U8 data)
{
U8 i;
SET_IIC_DATA_OUTPUT;
delayus(1);
/* data transmit */
for (i = 0; i< 8; i++)
{
if(data&(1<<(7-i)))//发送数据时与上升沿同步
{
IIC_DATA_HIGH;
}
else
{
IC_DATA_LOW;
}
delayus(1);
IIC_CLOCK_HIGH ;
delayus(1);
IIC_CLOCK_LOW ;
delayus(1);
}
IIC_DATA_HIGH;
delayus(1);
// UartPuts(" data write over!\n");
}
void data_read(U8 *data )
{
U8 i;
IIC_DATA_HIGH;
delayus(1);
SET_IIC_DATA_INPUT;
delayus(1);
/* data reas */
for (i = 0 ; i< 8; i++)
{
IIC_CLOCK_LOW;
delayus(1);
IIC_CLOCK_HIGH;
delayus(1);
if(rGPEDAT&(1<<15))//接收数据时与下降沿同步
{
(*data) |=(1<<(7-i)) ;
}
else
{
(*data) &=~(1<<(7-i)) ;
}
}
IIC_CLOCK_LOW;
delayus(1);
SET_IIC_DATA_OUTPUT;
// Uart_Printf("---- %4x \n",*data);
}
U8 i2c_write(U8 device_address, U8 memory_address , U8 data)
{
U8 write_addr;
U8 ack_flag;
U8 ret;
/* start */
i2c_start();
/* write address transmit */
data_write(device_address);
/* ack */
ack_flag = check_ack();
//ack_flag = 0;
if(!ack_flag)
{
ret = false;
UartPuts(" write i2c device address no ack!\n");
goto i2c_stop;
}
/* write address transmit */
data_write(memory_address);
/* ack */
ack_flag = check_ack();
if(!ack_flag)
{
ret = false;
UartPuts(" write memory address no ack!\n");
while(1);
goto i2c_stop;
}
/* write data transmit */
data_write(data);
/* ack */
ack_flag = check_ack();
if(!ack_flag)
{
ret = false;
UartPuts(" write data no ack!\n");
goto i2c_stop;
}
else
{
ret = true;
}
i2c_stop:
i2c_stop();
delayus(1000); //延时等待STOP信号生效(10ms)
return ret;
}
U8 i2c_dummy_write(U8 device_address, U8 memory_address )
{
U8 write_addr;
U8 ack_flag;
U8 ret;
/* start */
i2c_start();
/* write address transmit */
data_write(device_address);
/* ack */
ack_flag = check_ack();
if(!ack_flag)
{
ret = false;
UartPuts(" dummy write i2c device address no ack!\n");
goto i2c_stop;
}
/* write address transmit */
data_write(memory_address);
/* ack */
ack_flag = check_ack();
if(!ack_flag)
{
ret = false;
UartPuts(" dummy write memory address no ack!\n");
goto i2c_stop;
}
/* write data transmit */
else
{
ret = true;
return ret;
}
i2c_stop:
i2c_stop();
return ret;
}
U8 i2c_read(U8 device_address, U8 memory_address, U8 *data)
{
U8 read_addr;
U8 ack_flag;
U8 ret;
ret = i2c_dummy_write( device_address , memory_address);
if(!ret)
{
ret = false;
return ret;
}
i2c_start();
read_addr = device_address |1;
data_write(read_addr);
ack_flag = check_ack();
if(!ack_flag)
{
ret = false;
UartPuts(" i2c_read write i2c device address no ack!\n");
goto i2c_read_stop;
}
data_read(data);
send_no_ack();
ret = true;
i2c_read_stop:
i2c_stop();
return ret;
}
U8 i2c_page_read(U8 device_address, U8 memory_address, U8 *destination,U32 size)
{
int i;
for(i=0;i<size;i++)
i2c_read(device_address,memory_address+i,destination+i);
}
U8 i2c_page_write(U8 device_address, U8 memory_address , U8 *source,U32 size)
{
int i;
for(i=0;i<size;i++)
{
i2c_write(device_address,memory_address+i,source[i]);
//Uart_Printf("write %d\n",i);
}
}
U8 i2c_largepage_write(U8 device_address, U8 memory_address , U8 *source,U32 size)
{
int i;
int n,m;
if(size>256)
Uart_Printf("Size illegal\n");
//assert(size<=256);//判断参数合法性
n=size/16; //写入的小页数
m=size%16; //写入小页后剩余的个数
for(i=0;i<n;i++)
i2c_page_write(device_address,(memory_address+16*i),(source+16*i),16);
for(i=0;i<m;i++)
i2c_write(device_address,(memory_address+16*n+i),*(source+16*n+i));
}
void i2c_test(void)
{
U8 flag;
U8 write_data;
U8 read_data;
U8 i,j;
i=1;
j=1;
#if 0
UartPuts(" Begin to write!\n");
for(i=1;i<10;i++,j++)
{
flag = i2c_write(AT24C02_ADDRDRESS,i,j);
if(flag)
UartPuts(" write i2c ok!\n");
else
UartPuts(" write i2c failed!\n");
Delay_DMS(1000);
flag = i2c_read(AT24C02_ADDRDRESS,i,&read_data);
if(flag)
{
Uart_Printf(" read i2c ok! %4x \n",read_data);
//UartPutch(0x30+read_data);
//UartPuts(" \n");
//Uart_Printf("%4x",read_data);
}
else
{
UartPuts(" read i2c failed!\n");
}
Delay_DMS(500);
}
#endif
flag = i2c_read(AT24C08_ADDRDRESS,1,&read_data);
if(flag)
{
Uart_Printf("---- read i2c ok! %4x \n",read_data);
}
else
{
UartPuts(" read i2c failed!\n");
}
delay1us(500);
}