at25df.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. /*
  2. * Copyright (C) 2006 by egnite Software GmbH. All rights reserved.
  3. * Copyright (C) 2008 by egnite GmbH. All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. Neither the name of the copyright holders nor the names of
  15. * contributors may be used to endorse or promote products derived
  16. * from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  21. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  22. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  23. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  24. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  25. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  26. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  27. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  28. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  29. * SUCH DAMAGE.
  30. *
  31. * For additional information see http://www.ethernut.de/
  32. *
  33. */
  34. /*!
  35. * \file dev/at25db.c
  36. * \brief Routines for Adesto/Atmel AT25 serial dataflash memory chips.
  37. *
  38. * \verbatim
  39. *
  40. * $Log$
  41. * Revision 1.9 2009/02/06 15:53:42 haraldkipp
  42. * Corrected a bug with non-negated chip selects.
  43. *
  44. * Revision 1.8 2009/01/17 11:26:46 haraldkipp
  45. * Getting rid of two remaining BSD types in favor of stdint.
  46. * Replaced 'u_int' by 'unsinged int' and 'uptr_t' by 'uintptr_t'.
  47. *
  48. * Revision 1.7 2008/12/15 19:18:49 haraldkipp
  49. * Enable DataFlash support for EIR board.
  50. *
  51. * Revision 1.6 2008/08/11 06:59:41 haraldkipp
  52. * BSD types replaced by stdint types (feature request #1282721).
  53. *
  54. * Revision 1.5 2008/08/06 12:51:09 haraldkipp
  55. * Added support for Ethernut 5 (AT91SAM9XE reference design).
  56. *
  57. * Revision 1.4 2008/02/15 17:10:43 haraldkipp
  58. * At25dbPageErase selected the wrong bank. Fixed. Parameter pgn (page number)
  59. * of At25dbPageWrite() changed from unsigned int to unsigned long.
  60. * New routines At25dbPages() and At25dbPageSize() allow to determine the
  61. * chip's layout.
  62. *
  63. * Revision 1.3 2007/08/17 10:45:21 haraldkipp
  64. * Enhanced documentation.
  65. *
  66. * Revision 1.2 2006/10/08 16:48:09 haraldkipp
  67. * Documentation fixed
  68. *
  69. * Revision 1.1 2006/09/29 12:41:55 haraldkipp
  70. * Added support for AT25 serial DataFlash memory chips. Currently limited
  71. * to AT91 builds.
  72. *
  73. *
  74. * \endverbatim
  75. */
  76. #include <cfg/os.h>
  77. #include <cfg/memory.h>
  78. #include <sys/timer.h>
  79. #include <string.h>
  80. #include <stdlib.h>
  81. //#include <dev/at91_spi.h>
  82. #include <dev/at25df.h>
  83. #include <dev/blockdev.h>
  84. #include <dev/spibus.h>
  85. #include <sys/nutdebug.h>
  86. #define MAX_AT25_CMDLEN 6
  87. #define AT25_ERASE_WAIT 3000
  88. #define AT25_CHIP_ERASE_WAIT 50000
  89. #define AT25_WRITE_POLLS 1000
  90. /*!
  91. * \name AT25 DataFlash Commands
  92. */
  93. /*@{*/
  94. /*! \brief Continuos read (high frequency).
  95. *
  96. * Reads a continous stream in high speed mode.
  97. */
  98. #define DFCMD_READ_PAGE 0x0B
  99. /*! \brief Block erase 4k.
  100. */
  101. #define DFCMD_BLOCK_ERASE_4K 0x20
  102. /*! \brief Block erase 32k.
  103. */
  104. #define DFCMD_BLOCK_ERASE_32K 0x52
  105. /*! \brief Block erase 64k.
  106. */
  107. #define DFCMD_BLOCK_ERASE_64K 0xd8
  108. /*! \brief Chip erase
  109. */
  110. #define DFCMD_CHIP_ERASE 0xC7
  111. /*! \brief Write bytes/page.
  112. */
  113. #define DFCMD_WRITE 0x02
  114. /*! \brief Read status register.
  115. */
  116. #define DFCMD_READ_STATUS 0x05
  117. #define DFCMD_READ_DEVICEID 0x9F
  118. #define DFCMD_WRITE_ENABLE 0x06
  119. #define DFCMD_WRITE_DISABLE 0x04
  120. /*@}*/
  121. #define MOUNT_OFFSET_AT45D0 0
  122. #define MOUNT_TOP_RESERVE_AT45D0 0
  123. /*! \brief Parameter table of known DataFlash types. */
  124. AT25D_INFO at25d_info[] = {
  125. {12, 2048, 4096, 0x48}, /* AT25DF641 - 8MB */
  126. };
  127. /*! \brief Number of known Dataflash types. */
  128. uint_fast8_t at25d_known_types = sizeof(at25d_info) / sizeof(AT25D_INFO);
  129. /*!
  130. * \brief Send DataFlash command.
  131. *
  132. * \param node Specifies the SPI node.
  133. * \param op Command operation code.
  134. * \param parm Optional command parameter.
  135. * \param oplen Command length.
  136. * \param txbuf Pointer to the transmit data buffer, may be set to NULL.
  137. * \param rxbuf Pointer to the receive data buffer, may be set to NULL.
  138. * \param xlen Number of byte to receive and/or transmit.
  139. */
  140. static int At25dCommand(NUTSPINODE * node, uint8_t op, uint32_t parm, int oplen, const void *txbuf, void *rxbuf, int xlen)
  141. {
  142. int rc = -1;
  143. NUTSPIBUS *bus;
  144. uint8_t cmd[8];
  145. NUTASSERT(node != NULL);
  146. bus = (NUTSPIBUS *) node->node_bus;
  147. NUTASSERT(bus != NULL);
  148. NUTASSERT(bus->bus_alloc != NULL);
  149. NUTASSERT(bus->bus_transfer != NULL);
  150. NUTASSERT(bus->bus_release != NULL);
  151. NUTASSERT(oplen <= 8);
  152. memset(cmd, 0, oplen);
  153. cmd[0] = op;
  154. if (parm) {
  155. cmd[1] = (uint8_t) (parm >> 16);
  156. cmd[2] = (uint8_t) (parm >> 8);
  157. cmd[3] = (uint8_t) parm;
  158. }
  159. rc = (*bus->bus_alloc) (node, 1000);
  160. if (rc == 0) {
  161. rc = (*bus->bus_transfer) (node, cmd, NULL, oplen);
  162. if (rc == 0 && xlen) {
  163. rc = (*bus->bus_transfer) (node, txbuf, rxbuf, xlen);
  164. }
  165. (*bus->bus_release) (node);
  166. }
  167. return rc;
  168. };
  169. /*!
  170. * \brief Query the device ID of the DataFlash.
  171. *
  172. * \param node Specifies the SPI node.
  173. *
  174. * \return 0 on success or -1 in case of an error.
  175. */
  176. static uint8_t At25dDeviceID(NUTSPINODE * node)
  177. {
  178. int rc;
  179. uint8_t cmd[5] = { DFCMD_READ_DEVICEID, 0xFF, 0xFF, 0xFF, 0xFF };
  180. NUTSPIBUS *bus;
  181. NUTASSERT(node != NULL);
  182. NUTASSERT(node->node_bus != NULL);
  183. bus = (NUTSPIBUS *) node->node_bus;
  184. NUTASSERT(bus->bus_alloc != NULL);
  185. NUTASSERT(bus->bus_transfer != NULL);
  186. NUTASSERT(bus->bus_wait != NULL);
  187. NUTASSERT(bus->bus_release != NULL);
  188. rc = (*bus->bus_alloc) (node, 1000);
  189. if (rc == 0) {
  190. rc = (*bus->bus_transfer) (node, cmd, cmd, 3);
  191. if (rc == 0) {
  192. (*bus->bus_wait) (node, NUT_WAIT_INFINITE);
  193. rc = cmd[2];
  194. }
  195. (*bus->bus_release) (node);
  196. }
  197. return (uint8_t) rc;
  198. }
  199. /*!
  200. * \brief Wait until DataFlash memory cycle finished.
  201. *
  202. * \param node Specifies the SPI node.
  203. *
  204. * \return 0 on success or -1 in case of an error.
  205. */
  206. static int At25dWaitReady(NUTSPINODE * node, uint32_t tmo, int poll)
  207. {
  208. uint8_t sr;
  209. while (((sr = At25dStatus(node)) & 0x01) == 0) {
  210. if (!poll) {
  211. NutSleep(1);
  212. }
  213. if (tmo-- == 0) {
  214. return -1;
  215. }
  216. }
  217. return 0;
  218. }
  219. /*!
  220. * \brief Query the status of the DataFlash.
  221. *
  222. * \param node Specifies the SPI node.
  223. *
  224. * \return 0 on success or -1 in case of an error.
  225. */
  226. static uint8_t At25dStatus(NUTSPINODE * node)
  227. {
  228. int rc;
  229. uint8_t cmd[3] = { DFCMD_READ_STATUS, 0xFF, 0xFF };
  230. NUTSPIBUS *bus;
  231. NUTASSERT(node != NULL);
  232. NUTASSERT(node->node_bus != NULL);
  233. bus = (NUTSPIBUS *) node->node_bus;
  234. NUTASSERT(bus->bus_alloc != NULL);
  235. NUTASSERT(bus->bus_transfer != NULL);
  236. NUTASSERT(bus->bus_wait != NULL);
  237. NUTASSERT(bus->bus_release != NULL);
  238. rc = (*bus->bus_alloc) (node, 1000);
  239. if (rc == 0) {
  240. rc = (*bus->bus_transfer) (node, cmd, cmd, 3);
  241. if (rc == 0) {
  242. (*bus->bus_wait) (node, NUT_WAIT_INFINITE);
  243. rc = cmd[1];
  244. }
  245. (*bus->bus_release) (node);
  246. }
  247. return (uint8_t) rc;
  248. }
  249. /*!
  250. * \brief Initialize dataflash at specified interface and chip select.
  251. *
  252. * \param spibas Interface base address. For ARM MCUs this may be the
  253. * I/O base address of the hardware SPI.
  254. * \param spipcs Device chip select.
  255. *
  256. * \return Device descriptor or -1 in case of an error.
  257. */
  258. int At25dfInit(NUTDEVICE* dev)
  259. {
  260. NUTBLOCKIO *blkio;
  261. NUTSPINODE *node;
  262. uint8_t sr;
  263. int_fast8_t i;
  264. NUTASSERT(dev != NULL);
  265. NUTASSERT(dev->dev_dcb != NULL);
  266. NUTASSERT(dev->dev_icb != NULL);
  267. blkio = dev->dev_dcb;
  268. node = dev->dev_icb;
  269. /* Read the status byte and locate the related table entry. */
  270. sr = At25dDeviceID(node);
  271. // sr &= AT45D_STATUS_DENSITY | AT45D_STATUS_PAGE_SIZE;
  272. for (i = at25d_known_types; --i >= 0;) {
  273. if (sr == at25d_info[i].at25d_srval) {
  274. /* Known DataFlash type. */
  275. blkio->blkio_info = &at25d_info[i];
  276. blkio->blkio_blk_cnt = at25d_info[i].at25d_pages;
  277. blkio->blkio_blk_siz = at25d_info[i].at25d_psize;
  278. return 0;
  279. }
  280. }
  281. /* Unknown DataFlash type. */
  282. return -1;
  283. }
  284. int SpiAt25PageRead (NUTDEVICE * dev, uint32_t pgn, void * data, int len){//Should work TODO: check
  285. NUTBLOCKIO *blkio;
  286. AT25D_INFO *info;
  287. NUTASSERT(dev != NULL);
  288. NUTASSERT(dev->dev_dcb != NULL);
  289. blkio = dev->dev_dcb;
  290. info = (AT25D_INFO *) blkio->blkio_info;
  291. NUTASSERT(blkio->blkio_info != NULL);
  292. if (pgn >= info->at25d_pages) {
  293. return -1;
  294. }
  295. pgn <<= info->at25d_pshft;
  296. if (At25dCommand((NUTSPINODE *) dev->dev_icb, DFCMD_READ_PAGE, pgn, 5, NULL, data, len)) {
  297. return -1;
  298. }
  299. return len;
  300. };
  301. int SpiAt25PageWrite (NUTDEVICE * dev, uint32_t pgn, const void *data, int len){//FIXME: fix for at25
  302. int rc = -1;
  303. uint8_t *dp = (uint8_t *) data;
  304. int step;
  305. uint_fast8_t pshft;
  306. uint32_t limit;
  307. int sector;
  308. NUTBLOCKIO *blkio;
  309. NUTSPINODE *node;
  310. /* Sanity check. */
  311. if (len == 0) {
  312. return 0;
  313. }
  314. NUTASSERT(data != NULL);
  315. NUTASSERT(dev != NULL);
  316. NUTASSERT(dev->dev_dcb != NULL);
  317. NUTASSERT(dev->dev_icb != NULL);
  318. blkio = (NUTBLOCKIO *) dev->dev_dcb;
  319. node = (NUTSPINODE *) dev->dev_icb;
  320. NUTASSERT(blkio->blkio_info != NULL);
  321. pshft = ((AT25D_INFO *) blkio->blkio_info)->at25d_pshft;
  322. step = ((AT25D_INFO *) blkio->blkio_info)->at25d_psize;
  323. limit = ((AT25D_INFO *) blkio->blkio_info)->at25d_pages;
  324. sector = 256;
  325. while (len) {
  326. if (step > len) {
  327. step = len;
  328. }
  329. //TODO: write real code
  330. //1. Block erase 4k
  331. //2. write page
  332. //3. wait ready
  333. //4. repeat 2,3,4 up to 8 times
  334. //erase page
  335. if (At25dCommand(node, DFCMD_WRITE_ENABLE, 0, 1, NULL,NULL,0)){
  336. break;
  337. };
  338. if (At25dCommand(node, DFCMD_BLOCK_ERASE_4K,pgn << pshft, 4, NULL,NULL, 0)){
  339. break;
  340. }
  341. if (At25dWaitReady(node, AT25_WRITE_POLLS, 1)) {
  342. break;
  343. }
  344. while(len) {
  345. if(sector > len) {
  346. sector = len;
  347. };
  348. if (At25dCommand(node, DFCMD_WRITE_ENABLE, 0, 1, NULL,NULL,0)){
  349. break;
  350. };
  351. if (At25dCommand(node, DFCMD_WRITE, (pgn << pshft)+(uint8_t*)data-dp, 4, dp, NULL, step)){
  352. break;
  353. };
  354. if (At25dWaitReady(node, AT25_WRITE_POLLS, 1)) {
  355. break;
  356. }
  357. if (rc < 0) {
  358. rc = 0;
  359. }
  360. rc += sector;
  361. dp += sector;
  362. len -= sector;
  363. if (++pgn >= limit) {
  364. break;
  365. }
  366. }
  367. }
  368. return rc;
  369. };
  370. #ifdef __HARVARD_ARCH__
  371. int SpiAt25PageWrite_P (NUTDEVICE * dev, uint32_t pgn, PGM_P data, int len){
  372. return -1;
  373. }
  374. #endif
  375. int SpiAt25IOCtl (NUTDEVICE * dev, int req, void *conf){
  376. int rc = 0;
  377. switch (req) {
  378. case NUTBLKDEV_MEDIAAVAIL:
  379. /* Modification required for DataFlash cards. */
  380. {
  381. int *flg;
  382. NUTASSERT(conf != NULL);
  383. flg = (int *) conf;
  384. *flg = 1;
  385. }
  386. break;
  387. case NUTBLKDEV_MEDIACHANGE:
  388. /* Modification required for DataFlash cards. */
  389. {
  390. int *flg;
  391. NUTASSERT(conf != NULL);
  392. flg = (int *) conf;
  393. *flg = 0;
  394. }
  395. break;
  396. default:
  397. rc = -1;
  398. break;
  399. }
  400. return rc;
  401. };
  402. NUTSPINODE at25df = {
  403. NULL, /* SPI bus */
  404. NULL, /* additional parameters (dcb) */
  405. 1000000,/* SPI data rate TODO ? */
  406. 0, /* SPI mode */
  407. 8, /* data bits */
  408. 0 /* chip select index */
  409. };
  410. /*!
  411. * \brief AT45D DataFlash block I/O implementation structure.
  412. */
  413. static NUTBLOCKIO blkIoAt25df = {
  414. NULL, /*!< \brief Device specific parameters, blkio_info. */
  415. 0, /*!< \brief Total number of pages, blkio_blk_cnt. */
  416. 0, /*!< \brief Number of bytes per page, blkio_blk_siz. */
  417. MOUNT_OFFSET_AT45D0, /*!< \brief Number of sectors reserved at bottom, blkio_vol_bot. */
  418. MOUNT_TOP_RESERVE_AT45D0, /*!< \brief Number of sectors reserved at top, blkio_vol_top. */
  419. SpiAt25PageRead, /*!< \brief Read from node, blkio_read. */
  420. SpiAt25PageWrite, /*!< \brief Write to node, blkio_write. */
  421. #ifdef __HARVARD_ARCH__
  422. SpiAt25PageWrite_P, /*!< \brief Write program memory to node, blkio_write_P. */
  423. #endif
  424. SpiAt25IOCtl /*!< \brief Control functions, blkio_ioctl. */
  425. };
  426. NUTDEVICE devDataFlash0 = {
  427. 0, /* Pointer to next device, dev_next. */
  428. {'a', 't', '2', '5', 'd', 'f', '0', 0, 0}, /* Unique device name, dev_name. */
  429. IFTYP_BLKIO, /* Type of device, dev_type. */
  430. 0, /* Codec number, dev_base. */
  431. 0, /* First interrupt number, dev_irq (not used). */
  432. &at25df, /* Interface control block, dev_icb (not used). */
  433. &blkIoAt25df, /* Driver control block, dev_dcb. */
  434. At25dfInit, /* Driver initialization routine, dev_init. */
  435. NutBlockDeviceIOCtl, /* Driver specific control function, dev_ioctl. */
  436. NutBlockDeviceRead, /* Read from device, dev_read. */
  437. NutBlockDeviceWrite, /* Write to device, dev_write. */
  438. #ifdef __HARVARD_ARCH__
  439. NutBlockDeviceWrite_P, /* Write data from program space to device, dev_write_P. */
  440. #endif
  441. NutBlockDeviceOpen, /* Open a device or file, dev_open. */
  442. NutBlockDeviceClose, /* Close a device or file, dev_close. */
  443. NutBlockDeviceSize, /* Request file size, dev_size. */
  444. NULL, /* Select function, optional, not yet implemented */
  445. };