/****************************************************************************** 版权所有: 文件名称: e2prom_24lc.c 文件版本: 01.01 创建作者: sunxi 创建日期: 2008-08-06 功能说明: MICROCHIP 24LC系列的E2PROM驱动程序。 其它说明: 在I2C总线频率357k(周期2.8us)的情况下,写256bytes需要22206us,读256bytes 需要6836us。 修改记录: */ /*------------------------------- 头文件 -------------------------------------- */ #include "bspconfig.h" #include "i2c.h" #include "ustimer.h" #include "gpio.h" #include "e2prom.h" #if 0 /*------------------------------- 宏定义 -------------------------------------- */ #if CFG_BSP_DEBUG #define _DEBUG_E2PROM #endif #define E2PROM_I2C_ID 0XA0 /*------------------------------ 全局变量 ------------------------------------- */ /*------------------------------ 函数声明 ------------------------------------- */ int _ac_e2prom_write(unsigned char addr,uint32_t offset,unsigned char * buffer,uint32_t length); /*------------------------------ 外部函数 ------------------------------------- */ /****************************************************************************** 函数名称: ac_e2prom_init 函数版本: 01.01 创建作者: sunxi 创建日期: 2008-08-06 函数说明: ac_e2prom初始化。 参数说明: 无 返回值: 成功返回0. 修改记录: */ int ac_e2prom_init(void) { return 0; } /****************************************************************************** 函数名称: ac_e2prom_read 函数版本: 01.01 创建作者: sunxi 创建日期: 2008-08-06 函数说明: 从E2PROM中读出数据。 参数说明: offset(in):需要读的数据在E2PROM中的偏移量,和length之和不能大于 CFG_E2PROM_SIZE. buffer(out):读出数据的buffer。 length(in): 需要读出数据的长度,和offset之和不能大于CFG_E2PROM_SIZE。 返回值: 成功返回0. 修改记录: */ int ac_e2prom_read(unsigned char addr,uint32_t offset,unsigned char * buffer,uint32_t length) { unsigned char c; int h_i2c,ret; //检查参数 if(addr >= 8) { return -11; } if(buffer == 0 || (offset + length) > CFG_E2PROM_SIZE) { return -1; } if(length == 0) { return 0; } h_i2c = i2c_open(I2C_ID_E2PROM); if(h_i2c < 0) { return -1; } ret = -2; //等待总线释放 I2C_WAIT_BUS_IDLE(); //发送模式 MCF_I2CR |= MCF_I2C_I2CR_MTX; //发送START信号 MCF_I2CR |= MCF_I2C_I2CR_MSTA; //发送控制字节 MCF_I2DR = E2PROM_I2C_ID | (addr<<1); I2C_WAIT_COMPLETION(); I2C_CHECK_ACK(); //发送地址0 MCF_I2DR = (unsigned char)(offset>>8); I2C_WAIT_COMPLETION(); I2C_CHECK_ACK(); //发送地址1 MCF_I2DR = (unsigned char)(offset); I2C_WAIT_COMPLETION(); I2C_CHECK_ACK(); //发送重开始信号,方向改为读 MCF_I2CR |= MCF_I2C_I2CR_RSTA; MCF_I2DR = E2PROM_I2C_ID | (addr<<1) | 0x01; I2C_WAIT_COMPLETION(); I2C_CHECK_ACK(); //接收模式 MCF_I2CR &= ~MCF_I2C_I2CR_MTX; //接收数据,最后一个字节不发ACK. if(length == 1) { MCF_I2CR |= MCF_I2C_I2CR_TXAK; //不发ACK c = MCF_I2DR; //空读,启动下一个字节的读 I2C_WAIT_COMPLETION(); *buffer++ = MCF_I2DR; I2C_WAIT_COMPLETION(); } else { //循环接收length个字节。 MCF_I2CR &= ~MCF_I2C_I2CR_TXAK; //发送ACK c = MCF_I2DR; //空读,启动下一个字节的读 I2C_WAIT_COMPLETION(); while(length--) { if(length == 1) { MCF_I2CR |= MCF_I2C_I2CR_TXAK; //不发ACK } *buffer++ = MCF_I2DR; //读数据,并启动下一个字节的读。 I2C_WAIT_COMPLETION(); } } ret = 0; LABEL_END: //发送STOP信号 MCF_I2CR &= ~MCF_I2C_I2CR_MSTA; i2c_close(h_i2c); return ret; } /****************************************************************************** 函数名称: ac_e2prom_write 函数版本: 01.01 创建作者: sunxi 创建日期: 2008-08-06 函数说明: 将数据写入E2PROM中。注意:E2PROM按页写的速度比按字节写的速度快, 所以如果应用程序将要写入的数据组织成 参数说明: offset(in):需要写入的数据在E2PROM中的偏移量,和length之和不能大于 CFG_E2PROM_SIZE. buffer(in):写入数据的buffer。 length(in): 需要写入数据的长度,和offset之和不能大于CFG_E2PROM_SIZE。 返回值: 成功返回0. 修改记录: */ int ac_e2prom_write(unsigned char addr,uint32_t offset,unsigned char * buffer,uint32_t length) { int ret; uint32_t length_once,length_spare; //检查参数 if(addr >= 8) { return -11; } if(buffer == 0 || (offset + length) > CFG_E2PROM_SIZE) { return -1; } if(length == 0) { return 0; } //初始化length_spare length_spare = length; //写起始不完整页 length_once = CFG_E2PROM_PAGE_SIZE - (offset&(CFG_E2PROM_PAGE_SIZE - 1)); if(length_once > length_spare) { length_once = length_spare; } if(length_once) { ret = _ac_e2prom_write(addr,offset,buffer,length_once); if(ret != 0) { return ret; } offset += length_once; buffer += length_once; length_spare -= length_once; } //循环写完整页。 length_once = CFG_E2PROM_PAGE_SIZE; while(length_spare > CFG_E2PROM_PAGE_SIZE) { ret = _ac_e2prom_write(addr,offset,buffer,length_once); if(ret != 0) { return ret; } offset += length_once; buffer += length_once; length_spare -= length_once; } //写末尾不完整页。 length_once = length_spare; if(length_once) { ret = _ac_e2prom_write(addr,offset,buffer,length_once); if(ret != 0) { return ret; } } return 0; } /*------------------------------ 内部函数 ------------------------------------- */ /****************************************************************************** 函数名称: _ac_e2prom_write 函数版本: 01.01 创建作者: sunxi 创建日期: 2008-08-06 函数说明: 内部函数,将数据写入E2PROM中。 参数说明: offset(in):需要写入的数据在E2PROM中的偏移量,和length之和不能大于CFG_E2PROM_SIZE. buffer(in):写入数据的buffer。 length(in): 需要写入数据的长度,和offset之和不能大于CFG_E2PROM_PAGE_SIZE。 返回值: 成功返回0. 修改记录: */ int _ac_e2prom_write(unsigned char addr,uint32_t offset,unsigned char * buffer,uint32_t length) { int h_i2c,ret; unsigned long us0,us; //打开总线 h_i2c = i2c_open(I2C_ID_E2PROM); if(h_i2c < 0) { return -1; } //打开写保护. //GPIO_WP_E2PROM_LOW(); ret = -2; //等待总线释放 I2C_WAIT_BUS_IDLE(); //发送模式 MCF_I2CR |= MCF_I2C_I2CR_MTX; //发送START信号 MCF_I2CR |= MCF_I2C_I2CR_MSTA; //发送控制字节 MCF_I2DR = E2PROM_I2C_ID | (addr<<1); I2C_WAIT_COMPLETION(); I2C_CHECK_ACK(); //发送地址0 MCF_I2DR = (unsigned char)(offset>>8); I2C_WAIT_COMPLETION(); I2C_CHECK_ACK(); //发送地址1 MCF_I2DR = (unsigned char)(offset); I2C_WAIT_COMPLETION(); I2C_CHECK_ACK(); //发送数据 while(length--) { MCF_I2DR = *buffer++; I2C_WAIT_COMPLETION(); I2C_CHECK_ACK(); } //发送STOP信号,启动E2PROM内部写 MCF_I2CR &= ~MCF_I2C_I2CR_MSTA; //等待总线释放 I2C_WAIT_BUS_IDLE(); //等待完成 //发送START信号 MCF_I2CR |= MCF_I2C_I2CR_MSTA; us0= ustimer_get_origin(); while(1) { // 得到超时值 us = ustimer_get_duration(us0); //发送控制字节 MCF_I2DR = E2PROM_I2C_ID | (addr<<1); I2C_WAIT_COMPLETION(); //如果有ACK,内部写已经完成,退出。 if((MCF_I2SR & MCF_I2C_I2SR_RXAK) == 0) { ret = 0; break; } //最大写时间为5ms. if(us > 5*USTIMER_MS) { ret = -3; break; } //发送重开始信号 MCF_I2CR |= MCF_I2C_I2CR_RSTA; } LABEL_END: //发送STOP信号 MCF_I2CR &= ~MCF_I2C_I2CR_MSTA; //关闭写保护 //GPIO_WP_E2PROM_HIGH(); //关闭总线 i2c_close(h_i2c); return ret; } /*------------------------------ 测试函数 ------------------------------------- */ #ifdef _DEBUG_E2PROM #include "rt.h" #define E2PROM_TEST_SIZE 1002 //必须是偶数 //#define E2PROM_TEST_SUM CFG_E2PROM_SIZE #define E2PROM_TEST_SUM 4096 int ac_e2prom_test(void) { int ret; unsigned long us0,us; unsigned long i,offset,length; unsigned short buffer[E2PROM_TEST_SIZE/2]; unsigned char addr; rt_printf("ac_e2prom_test start...\r\n"); addr = 0; for(addr=0; addr<4; addr++) { rt_printf("addr=%d.\r\n",addr); offset = 0; while(offset < E2PROM_TEST_SUM) { //写 length = (E2PROM_TEST_SUM - offset) > E2PROM_TEST_SIZE ? E2PROM_TEST_SIZE : (E2PROM_TEST_SUM - offset); for(i=0;i E2PROM_TEST_SIZE ? E2PROM_TEST_SIZE : (E2PROM_TEST_SUM - offset); memset(buffer,0,E2PROM_TEST_SIZE); us0 = ustimer_get_origin(); ret = ac_e2prom_read(addr,offset,(unsigned char *)buffer,length); us = ustimer_get_duration(us0); rt_printf("ac_e2prom_read:(offset=%d,ret=%d,us=%d)\r\n",offset,ret,us); if(ret != 0) { break; } //比较 for(i=0;i