e2prom_24lc.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. /******************************************************************************
  2. 版权所有:
  3. 文件名称: e2prom_24lc.c
  4. 文件版本: 01.01
  5. 创建作者: sunxi
  6. 创建日期: 2008-08-06
  7. 功能说明: MICROCHIP 24LC系列的E2PROM驱动程序。
  8. 其它说明: 在I2C总线频率357k(周期2.8us)的情况下,写256bytes需要22206us,读256bytes
  9. 需要6836us。
  10. 修改记录:
  11. */
  12. /*------------------------------- 头文件 --------------------------------------
  13. */
  14. #include "bspconfig.h"
  15. #include "i2c.h"
  16. #include "ustimer.h"
  17. #include "gpio.h"
  18. #include "e2prom.h"
  19. #if 0
  20. /*------------------------------- 宏定义 --------------------------------------
  21. */
  22. #if CFG_BSP_DEBUG
  23. #define _DEBUG_E2PROM
  24. #endif
  25. #define E2PROM_I2C_ID 0XA0
  26. /*------------------------------ 全局变量 -------------------------------------
  27. */
  28. /*------------------------------ 函数声明 -------------------------------------
  29. */
  30. int _ac_e2prom_write(unsigned char addr,uint32_t offset,unsigned char * buffer,uint32_t length);
  31. /*------------------------------ 外部函数 -------------------------------------
  32. */
  33. /******************************************************************************
  34. 函数名称: ac_e2prom_init
  35. 函数版本: 01.01
  36. 创建作者: sunxi
  37. 创建日期: 2008-08-06
  38. 函数说明: ac_e2prom初始化。
  39. 参数说明: 无
  40. 返回值: 成功返回0.
  41. 修改记录:
  42. */
  43. int ac_e2prom_init(void)
  44. {
  45. return 0;
  46. }
  47. /******************************************************************************
  48. 函数名称: ac_e2prom_read
  49. 函数版本: 01.01
  50. 创建作者: sunxi
  51. 创建日期: 2008-08-06
  52. 函数说明: 从E2PROM中读出数据。
  53. 参数说明:
  54. offset(in):需要读的数据在E2PROM中的偏移量,和length之和不能大于
  55. CFG_E2PROM_SIZE.
  56. buffer(out):读出数据的buffer。
  57. length(in): 需要读出数据的长度,和offset之和不能大于CFG_E2PROM_SIZE。
  58. 返回值: 成功返回0.
  59. 修改记录:
  60. */
  61. int ac_e2prom_read(unsigned char addr,uint32_t offset,unsigned char * buffer,uint32_t length)
  62. {
  63. unsigned char c;
  64. int h_i2c,ret;
  65. //检查参数
  66. if(addr >= 8)
  67. {
  68. return -11;
  69. }
  70. if(buffer == 0 || (offset + length) > CFG_E2PROM_SIZE)
  71. {
  72. return -1;
  73. }
  74. if(length == 0)
  75. {
  76. return 0;
  77. }
  78. h_i2c = i2c_open(I2C_ID_E2PROM);
  79. if(h_i2c < 0)
  80. {
  81. return -1;
  82. }
  83. ret = -2;
  84. //等待总线释放
  85. I2C_WAIT_BUS_IDLE();
  86. //发送模式
  87. MCF_I2CR |= MCF_I2C_I2CR_MTX;
  88. //发送START信号
  89. MCF_I2CR |= MCF_I2C_I2CR_MSTA;
  90. //发送控制字节
  91. MCF_I2DR = E2PROM_I2C_ID | (addr<<1);
  92. I2C_WAIT_COMPLETION();
  93. I2C_CHECK_ACK();
  94. //发送地址0
  95. MCF_I2DR = (unsigned char)(offset>>8);
  96. I2C_WAIT_COMPLETION();
  97. I2C_CHECK_ACK();
  98. //发送地址1
  99. MCF_I2DR = (unsigned char)(offset);
  100. I2C_WAIT_COMPLETION();
  101. I2C_CHECK_ACK();
  102. //发送重开始信号,方向改为读
  103. MCF_I2CR |= MCF_I2C_I2CR_RSTA;
  104. MCF_I2DR = E2PROM_I2C_ID | (addr<<1) | 0x01;
  105. I2C_WAIT_COMPLETION();
  106. I2C_CHECK_ACK();
  107. //接收模式
  108. MCF_I2CR &= ~MCF_I2C_I2CR_MTX;
  109. //接收数据,最后一个字节不发ACK.
  110. if(length == 1)
  111. {
  112. MCF_I2CR |= MCF_I2C_I2CR_TXAK; //不发ACK
  113. c = MCF_I2DR; //空读,启动下一个字节的读
  114. I2C_WAIT_COMPLETION();
  115. *buffer++ = MCF_I2DR;
  116. I2C_WAIT_COMPLETION();
  117. }
  118. else
  119. {
  120. //循环接收length个字节。
  121. MCF_I2CR &= ~MCF_I2C_I2CR_TXAK; //发送ACK
  122. c = MCF_I2DR; //空读,启动下一个字节的读
  123. I2C_WAIT_COMPLETION();
  124. while(length--)
  125. {
  126. if(length == 1)
  127. {
  128. MCF_I2CR |= MCF_I2C_I2CR_TXAK; //不发ACK
  129. }
  130. *buffer++ = MCF_I2DR; //读数据,并启动下一个字节的读。
  131. I2C_WAIT_COMPLETION();
  132. }
  133. }
  134. ret = 0;
  135. LABEL_END:
  136. //发送STOP信号
  137. MCF_I2CR &= ~MCF_I2C_I2CR_MSTA;
  138. i2c_close(h_i2c);
  139. return ret;
  140. }
  141. /******************************************************************************
  142. 函数名称: ac_e2prom_write
  143. 函数版本: 01.01
  144. 创建作者: sunxi
  145. 创建日期: 2008-08-06
  146. 函数说明: 将数据写入E2PROM中。注意:E2PROM按页写的速度比按字节写的速度快,
  147. 所以如果应用程序将要写入的数据组织成
  148. 参数说明:
  149. offset(in):需要写入的数据在E2PROM中的偏移量,和length之和不能大于
  150. CFG_E2PROM_SIZE.
  151. buffer(in):写入数据的buffer。
  152. length(in): 需要写入数据的长度,和offset之和不能大于CFG_E2PROM_SIZE。
  153. 返回值: 成功返回0.
  154. 修改记录:
  155. */
  156. int ac_e2prom_write(unsigned char addr,uint32_t offset,unsigned char * buffer,uint32_t length)
  157. {
  158. int ret;
  159. uint32_t length_once,length_spare;
  160. //检查参数
  161. if(addr >= 8)
  162. {
  163. return -11;
  164. }
  165. if(buffer == 0 || (offset + length) > CFG_E2PROM_SIZE)
  166. {
  167. return -1;
  168. }
  169. if(length == 0)
  170. {
  171. return 0;
  172. }
  173. //初始化length_spare
  174. length_spare = length;
  175. //写起始不完整页
  176. length_once = CFG_E2PROM_PAGE_SIZE - (offset&(CFG_E2PROM_PAGE_SIZE - 1));
  177. if(length_once > length_spare)
  178. {
  179. length_once = length_spare;
  180. }
  181. if(length_once)
  182. {
  183. ret = _ac_e2prom_write(addr,offset,buffer,length_once);
  184. if(ret != 0)
  185. {
  186. return ret;
  187. }
  188. offset += length_once;
  189. buffer += length_once;
  190. length_spare -= length_once;
  191. }
  192. //循环写完整页。
  193. length_once = CFG_E2PROM_PAGE_SIZE;
  194. while(length_spare > CFG_E2PROM_PAGE_SIZE)
  195. {
  196. ret = _ac_e2prom_write(addr,offset,buffer,length_once);
  197. if(ret != 0)
  198. {
  199. return ret;
  200. }
  201. offset += length_once;
  202. buffer += length_once;
  203. length_spare -= length_once;
  204. }
  205. //写末尾不完整页。
  206. length_once = length_spare;
  207. if(length_once)
  208. {
  209. ret = _ac_e2prom_write(addr,offset,buffer,length_once);
  210. if(ret != 0)
  211. {
  212. return ret;
  213. }
  214. }
  215. return 0;
  216. }
  217. /*------------------------------ 内部函数 -------------------------------------
  218. */
  219. /******************************************************************************
  220. 函数名称: _ac_e2prom_write
  221. 函数版本: 01.01
  222. 创建作者: sunxi
  223. 创建日期: 2008-08-06
  224. 函数说明: 内部函数,将数据写入E2PROM中。
  225. 参数说明:
  226. offset(in):需要写入的数据在E2PROM中的偏移量,和length之和不能大于CFG_E2PROM_SIZE.
  227. buffer(in):写入数据的buffer。
  228. length(in): 需要写入数据的长度,和offset之和不能大于CFG_E2PROM_PAGE_SIZE。
  229. 返回值: 成功返回0.
  230. 修改记录:
  231. */
  232. int _ac_e2prom_write(unsigned char addr,uint32_t offset,unsigned char * buffer,uint32_t length)
  233. {
  234. int h_i2c,ret;
  235. unsigned long us0,us;
  236. //打开总线
  237. h_i2c = i2c_open(I2C_ID_E2PROM);
  238. if(h_i2c < 0)
  239. {
  240. return -1;
  241. }
  242. //打开写保护.
  243. //GPIO_WP_E2PROM_LOW();
  244. ret = -2;
  245. //等待总线释放
  246. I2C_WAIT_BUS_IDLE();
  247. //发送模式
  248. MCF_I2CR |= MCF_I2C_I2CR_MTX;
  249. //发送START信号
  250. MCF_I2CR |= MCF_I2C_I2CR_MSTA;
  251. //发送控制字节
  252. MCF_I2DR = E2PROM_I2C_ID | (addr<<1);
  253. I2C_WAIT_COMPLETION();
  254. I2C_CHECK_ACK();
  255. //发送地址0
  256. MCF_I2DR = (unsigned char)(offset>>8);
  257. I2C_WAIT_COMPLETION();
  258. I2C_CHECK_ACK();
  259. //发送地址1
  260. MCF_I2DR = (unsigned char)(offset);
  261. I2C_WAIT_COMPLETION();
  262. I2C_CHECK_ACK();
  263. //发送数据
  264. while(length--)
  265. {
  266. MCF_I2DR = *buffer++;
  267. I2C_WAIT_COMPLETION();
  268. I2C_CHECK_ACK();
  269. }
  270. //发送STOP信号,启动E2PROM内部写
  271. MCF_I2CR &= ~MCF_I2C_I2CR_MSTA;
  272. //等待总线释放
  273. I2C_WAIT_BUS_IDLE();
  274. //等待完成
  275. //发送START信号
  276. MCF_I2CR |= MCF_I2C_I2CR_MSTA;
  277. us0= ustimer_get_origin();
  278. while(1)
  279. {
  280. // 得到超时值
  281. us = ustimer_get_duration(us0);
  282. //发送控制字节
  283. MCF_I2DR = E2PROM_I2C_ID | (addr<<1);
  284. I2C_WAIT_COMPLETION();
  285. //如果有ACK,内部写已经完成,退出。
  286. if((MCF_I2SR & MCF_I2C_I2SR_RXAK) == 0)
  287. {
  288. ret = 0;
  289. break;
  290. }
  291. //最大写时间为5ms.
  292. if(us > 5*USTIMER_MS)
  293. {
  294. ret = -3;
  295. break;
  296. }
  297. //发送重开始信号
  298. MCF_I2CR |= MCF_I2C_I2CR_RSTA;
  299. }
  300. LABEL_END:
  301. //发送STOP信号
  302. MCF_I2CR &= ~MCF_I2C_I2CR_MSTA;
  303. //关闭写保护
  304. //GPIO_WP_E2PROM_HIGH();
  305. //关闭总线
  306. i2c_close(h_i2c);
  307. return ret;
  308. }
  309. /*------------------------------ 测试函数 -------------------------------------
  310. */
  311. #ifdef _DEBUG_E2PROM
  312. #include "rt.h"
  313. #define E2PROM_TEST_SIZE 1002 //必须是偶数
  314. //#define E2PROM_TEST_SUM CFG_E2PROM_SIZE
  315. #define E2PROM_TEST_SUM 4096
  316. int ac_e2prom_test(void)
  317. {
  318. int ret;
  319. unsigned long us0,us;
  320. unsigned long i,offset,length;
  321. unsigned short buffer[E2PROM_TEST_SIZE/2];
  322. unsigned char addr;
  323. rt_printf("ac_e2prom_test start...\r\n");
  324. addr = 0;
  325. for(addr=0; addr<4; addr++)
  326. {
  327. rt_printf("addr=%d.\r\n",addr);
  328. offset = 0;
  329. while(offset < E2PROM_TEST_SUM)
  330. {
  331. //写
  332. length = (E2PROM_TEST_SUM - offset) > E2PROM_TEST_SIZE ? E2PROM_TEST_SIZE : (E2PROM_TEST_SUM - offset);
  333. for(i=0;i<length/2;i++)
  334. {
  335. buffer[i] = (unsigned short)(offset + i + 0x5555);
  336. }
  337. us0 = ustimer_get_origin();
  338. ret = ac_e2prom_write(addr,offset,(unsigned char *)buffer,length);
  339. us = ustimer_get_duration(us0);
  340. rt_printf("ac_e2prom_write:(offset=%d,ret=%d,us=%d)\r\n",offset,ret,us);
  341. if(ret != 0)
  342. {
  343. break;
  344. }
  345. offset += length;
  346. }
  347. offset = 0;
  348. memset(buffer,0,sizeof(buffer));
  349. while(offset < E2PROM_TEST_SUM)
  350. {
  351. //读
  352. length = (E2PROM_TEST_SUM - offset) > E2PROM_TEST_SIZE ? E2PROM_TEST_SIZE : (E2PROM_TEST_SUM - offset);
  353. memset(buffer,0,E2PROM_TEST_SIZE);
  354. us0 = ustimer_get_origin();
  355. ret = ac_e2prom_read(addr,offset,(unsigned char *)buffer,length);
  356. us = ustimer_get_duration(us0);
  357. rt_printf("ac_e2prom_read:(offset=%d,ret=%d,us=%d)\r\n",offset,ret,us);
  358. if(ret != 0)
  359. {
  360. break;
  361. }
  362. //比较
  363. for(i=0;i<length/2;i++)
  364. {
  365. if(buffer[i] != (unsigned short)(offset + i + 0x5555))
  366. {
  367. break;
  368. }
  369. }
  370. if(i== length/2)
  371. {
  372. rt_printf("compare ok(offset=%d,i=%d)!\r\n",offset,i);
  373. }
  374. else
  375. {
  376. rt_printf("compare error(offset=%d,i=%d)!\r\n",offset,i);
  377. break;
  378. }
  379. offset += length;
  380. }
  381. if(offset == E2PROM_TEST_SUM)
  382. {
  383. rt_printf("ac_e2prom_test ok!\r\n\n");
  384. }
  385. else
  386. {
  387. rt_printf("ac_e2prom_test fail!\r\n\n");
  388. }
  389. }
  390. return 0;
  391. }
  392. #endif
  393. #endif
  394. /*------------------------------ 文件结束 -------------------------------------
  395. */