flash.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. /* ========================================================================
  2. * [PROJECT] SIR
  3. * [MODULE] Flash
  4. * [TITLE] Routines for Atmel AT45 serial dataflash memory chips.
  5. * [FILE] flash.c
  6. * [VSN] 1.0
  7. * [CREATED] 11042007
  8. * [LASTCHNGD] 11042007
  9. * [COPYRIGHT] Copyright (C) STREAMIT BV 2010
  10. * [PURPOSE] contains all interface- and low-level routines to
  11. * read/write/delete blocks in the serial DataFlash (AT45DBXX)
  12. * ======================================================================== */
  13. #define LOG_MODULE LOG_FLASH_MODULE
  14. //#include <stdio.h>
  15. #include <cfg/os.h>
  16. #include <cfg/memory.h>
  17. #include <sys/timer.h>
  18. #include <string.h>
  19. #include <stdlib.h>
  20. #include "typedefs.h"
  21. #include "flash.h"
  22. #include "portio.h"
  23. #include "log.h"
  24. #include "spidrv.h"
  25. /*-------------------------------------------------------------------------*/
  26. /* local defines */
  27. /*-------------------------------------------------------------------------*/
  28. #ifndef MAX_AT45_CMDLEN
  29. #define MAX_AT45_CMDLEN 8
  30. #endif
  31. #ifndef AT45_ERASE_WAIT
  32. #define AT45_ERASE_WAIT 3000
  33. #endif
  34. #ifndef AT45_CHIP_ERASE_WAIT
  35. #define AT45_CHIP_ERASE_WAIT 50000
  36. #endif
  37. #ifndef AT45_WRITE_POLLS
  38. #define AT45_WRITE_POLLS 1000
  39. #endif
  40. #define DFCMD_READ_PAGE 0xD2 /* Read main memory page. */
  41. #define DFCMD_READ_STATUS 0xD7 /* Read status register. */
  42. #define DFCMD_CONT_READ 0xE8 /* Continuos read. */
  43. #define DFCMD_PAGE_ERASE 0x81 /* Page erase. */
  44. #define DFCMD_BUF1_WRITE 0x84 /* Buffer 1 write. */
  45. #define DFCMD_BUF1_FLASH 0x83 /* Buffer 1 flash with page erase. */
  46. /*
  47. * \brief last page of flash (264 bytes) can be dedicated for parameter storage
  48. * Special routines are provided for that goal but can be disabled here to save
  49. * codespace (about 360 bytes of code for GCC)
  50. */
  51. //#define USE_FLASH_PARAM_PAGE
  52. /*-------------------------------------------------------------------------*/
  53. /* typedefs & structs */
  54. /*-------------------------------------------------------------------------*/
  55. /*!
  56. * \brief Known device type entry.
  57. */
  58. typedef struct _AT45_DEVTAB
  59. {
  60. u_long devt_pages;
  61. u_int devt_pagsiz;
  62. u_int devt_offs;
  63. u_char devt_srmsk;
  64. u_char devt_srval;
  65. } AT45_DEVTAB;
  66. /*!
  67. * \brief Active device entry.
  68. */
  69. typedef struct _AT45DB_DCB
  70. {
  71. AT45_DEVTAB *dcb_devt;
  72. u_char dcb_cmdbuf[MAX_AT45_CMDLEN];
  73. } AT45DB_DCB;
  74. /*!
  75. * \brief Table of known Dataflash types.
  76. */
  77. AT45_DEVTAB at45_devt[] = {
  78. {512, 264, 9, 0x3C, 0x0C}, // AT45DB011B - 128kB
  79. {1025, 264, 9, 0x3C, 0x14}, // AT45DB021B - 256kB
  80. {2048, 264, 9, 0x3C, 0x1C}, // AT45DB041B - 512kB
  81. {4096, 264, 9, 0x3C, 0x24}, // AT45DB081B - 1MB
  82. {4096, 528, 10, 0x3C, 0x2C}, // AT45DB0161B - 2MB
  83. {8192, 528, 10, 0x3C, 0x34}, // AT45DB0321B - 4MB
  84. {8192, 1056, 11, 0x38, 0x38}, // AT45DB0642 - 8MB
  85. {0, 0, 0, 0, 0} // End of table
  86. };
  87. /*-------------------------------------------------------------------------*/
  88. /* local variable definitions */
  89. /*-------------------------------------------------------------------------*/
  90. /*!
  91. * \brief Table of active devices.
  92. */
  93. static AT45DB_DCB dcbtab;
  94. /*-------------------------------------------------------------------------*/
  95. /* local routines (prototyping) */
  96. /*-------------------------------------------------------------------------*/
  97. static int At45dbTransfer(CONST void *txbuf, void *rxbuf, int xlen, CONST void *txnbuf, void *rxnbuf, int xnlen);
  98. /*!
  99. * \addtogroup SerialFlash
  100. */
  101. /*@{*/
  102. /*-------------------------------------------------------------------------*/
  103. /* start of code */
  104. /*-------------------------------------------------------------------------*/
  105. /*!
  106. * \brief mid-level SPI-interface routine
  107. *
  108. * This routine handles sending a command an reading back the reply in one routine
  109. * It will perform 'xlen' + 'xnlen' SPI-byte cycles. During the 'xlen' cycles, data in 'txbuf'
  110. * is sent using the SPI, and each resulting byte is stored in 'rxbuf'. Then it starts with
  111. * the 'xnlen' cycles whereby the contents of the 'txnbuf' are sent using the SPI.
  112. * Each resulting byte then is stored in 'rxnbuf'
  113. */
  114. // cb, cb, len, tdata, rdata, datalen
  115. static int At45dbTransfer(CONST void *txbuf, void *rxbuf, int xlen, CONST void *txnbuf, void *rxnbuf, int xnlen)
  116. { int i;
  117. u_char *ptTxbuf, *ptRxbuf;
  118. SPIselect(SPI_DEV_FLASH);
  119. ptTxbuf=(u_char*)txbuf;
  120. ptRxbuf=(u_char*)rxbuf;
  121. /*
  122. * send command, store the bytes that were read the same time
  123. */
  124. for (i=0; i<xlen; ++i)
  125. {
  126. *ptRxbuf++=SPItransferByte(*ptTxbuf++);
  127. }
  128. ptTxbuf=(u_char*)txnbuf;
  129. ptRxbuf=(u_char*)rxnbuf;
  130. /*
  131. * send dummy data, store the bytes that were read the same time
  132. */
  133. for (i=0; i<xnlen; ++i)
  134. {
  135. *ptRxbuf++=SPItransferByte(*ptTxbuf++);
  136. }
  137. SPIdeselect();
  138. return(0); // always...
  139. }
  140. /*!
  141. * \brief send a command to the AT45dbXX
  142. *
  143. */
  144. int At45dbSendCmd(u_char op, u_long parm, int len, CONST void *tdata, void *rdata, int datalen)
  145. {
  146. u_char *cb = dcbtab.dcb_cmdbuf;
  147. if (len > MAX_AT45_CMDLEN)
  148. {
  149. return (-1);
  150. }
  151. memset(cb, 0, len);
  152. cb[0] = op;
  153. if (parm)
  154. {
  155. cb[1] = (u_char) (parm >> 16);
  156. cb[2] = (u_char) (parm >> 8);
  157. cb[3] = (u_char) parm;
  158. }
  159. return (At45dbTransfer(cb, cb, len, tdata, rdata, datalen));
  160. }
  161. /*!
  162. * \brief read status
  163. *
  164. */
  165. u_char At45dbGetStatus()
  166. {
  167. u_char buf[2] = { DFCMD_READ_STATUS, 0xFF};
  168. if (At45dbTransfer(buf, buf, 2, NULL, NULL, 0))
  169. {
  170. return(u_char) - 1;
  171. }
  172. return (buf[1]);
  173. }
  174. /*!
  175. * \brief Wait until flash memory cycle finished.
  176. *
  177. * \return 0 on success or -1 in case of an error.
  178. */
  179. int At45dbWaitReady(u_long tmo, int poll)
  180. {
  181. u_char sr;
  182. while (((sr = At45dbGetStatus()) & 0x80) == 0)
  183. {
  184. if (!poll)
  185. {
  186. NutSleep(1);
  187. }
  188. if (tmo-- == 0)
  189. {
  190. return (-1);
  191. }
  192. }
  193. return (0);
  194. }
  195. /*!
  196. * \brief runtime detection of serial flash device
  197. */
  198. int At45dbInit()
  199. {
  200. u_char sr;
  201. u_char i;
  202. At45dbGetStatus();
  203. sr = At45dbGetStatus();
  204. for (i=0; at45_devt[i].devt_pages; i++)
  205. {
  206. if ((sr & at45_devt[i].devt_srmsk) == at45_devt[i].devt_srval)
  207. {
  208. dcbtab.dcb_devt = &at45_devt[i];
  209. break;
  210. }
  211. }
  212. return (i);
  213. }
  214. /*!
  215. * \brief Erase sector at the specified offset.
  216. */
  217. int At45dbPageErase(u_int pgn)
  218. {
  219. return (At45dbSendCmd(DFCMD_PAGE_ERASE, pgn, 4, NULL, NULL, 0));
  220. }
  221. /*!
  222. * \brief Erase entire flash memory chip.
  223. */
  224. int At45dbChipErase(void)
  225. {
  226. return (-1);
  227. }
  228. /*!
  229. * \brief Read data from flash memory.
  230. *
  231. * \param pgn Page number to read, starting at 0.
  232. * \param data Points to a buffer that receives the data.
  233. * \param len Number of bytes to read.
  234. *
  235. * \return 0 on success or -1 in case of an error.
  236. */
  237. int At45dbPageRead(u_long pgn, void *data, u_int len)
  238. {
  239. pgn <<= dcbtab.dcb_devt->devt_offs;
  240. return (At45dbSendCmd(DFCMD_CONT_READ, pgn, 8, data, data, len));
  241. }
  242. /*!
  243. * \brief Write data into flash memory.
  244. *
  245. * The related sector must have been erased before calling this function.
  246. *
  247. * \param pgn Start location within the chip, starting at 0.
  248. * \param data Points to a buffer that contains the bytes to be written.
  249. * \param len Number of bytes to write.
  250. *
  251. * \return 0 on success or -1 in case of an error.
  252. */
  253. int At45dbPageWrite(u_long pgn, CONST void *data, u_int len)
  254. {
  255. int rc = -1;
  256. void *rp;
  257. if ((rp = malloc(len)) != NULL)
  258. {
  259. /* Copy data to dataflash RAM buffer. */
  260. if (At45dbSendCmd(DFCMD_BUF1_WRITE, 0, 4, data, rp, len) == 0)
  261. {
  262. /* Flash RAM buffer. */
  263. pgn <<= dcbtab.dcb_devt->devt_offs;
  264. if (At45dbSendCmd(DFCMD_BUF1_FLASH, pgn, 4, NULL, NULL, 0) == 0)
  265. {
  266. rc = At45dbWaitReady(AT45_WRITE_POLLS, 1);
  267. }
  268. }
  269. free(rp);
  270. }
  271. return (rc);
  272. }
  273. #ifdef USE_FLASH_PARAM_PAGE
  274. u_long At45dbParamPage(void)
  275. {
  276. #ifdef AT45_CONF_PAGE
  277. return (AT45_CONF_PAGE);
  278. #else
  279. return (dcbtab.dcb_devt->devt_pages - 1);
  280. #endif
  281. }
  282. int At45dbParamSize(void)
  283. {
  284. int rc;
  285. #ifdef AT45_CONF_SIZE
  286. rc = AT45_CONF_SIZE;
  287. #else
  288. rc = dcbtab.dcb_devt->devt_pagsiz;
  289. #endif
  290. return (rc);
  291. }
  292. /*!
  293. * \brief Load configuration parameters from flash memory.
  294. *
  295. * \param pos Start location within configuration sector.
  296. * \param data Points to a buffer that receives the contents.
  297. * \param len Number of bytes to read.
  298. *
  299. * \return Always 0.
  300. */
  301. int At45dbParamRead(u_int pos, void *data, u_int len)
  302. {
  303. int rc = -1;
  304. u_char *buff;
  305. int csize = At45dbParamSize();
  306. u_long cpage = At45dbParamPage();
  307. /* Load the complete configuration area. */
  308. if (csize > len && (buff = malloc(csize)) != NULL)
  309. {
  310. rc = At45dbPageRead(cpage, buff, csize);
  311. /* Copy requested contents to caller's buffer. */
  312. memcpy(data, buff + pos, len);
  313. free(buff);
  314. }
  315. return (rc);
  316. }
  317. /*!
  318. * \brief Store configuration parameters in flash memory.
  319. *
  320. * \param pos Start location within configuration sector.
  321. * \param data Points to a buffer that contains the bytes to store.
  322. * \param len Number of bytes to store.
  323. *
  324. * \return 0 on success or -1 in case of an error.
  325. */
  326. int At45dbParamWrite(u_int pos, CONST void *data, u_int len)
  327. {
  328. int rc = -1;
  329. u_char *buff;
  330. int csize = At45dbParamSize();
  331. u_long cpage = At45dbParamPage();
  332. /* Load the complete configuration area. */
  333. if (csize > len && (buff = malloc(csize)) != NULL)
  334. {
  335. rc = At45dbPageRead(cpage, buff, csize);
  336. /* Compare old with new contents. */
  337. if (memcmp(buff + pos, data, len))
  338. {
  339. /* New contents differs. Copy it into the sector buffer. */
  340. memcpy(buff + pos, data, len);
  341. /* Erase sector and write new data. */
  342. rc = At45dbPageWrite(cpage, buff, csize);
  343. }
  344. free(buff);
  345. }
  346. return (rc);
  347. }
  348. #endif // USE_FLASH_PARAM_PAGE