at45db.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006 by egnite Software GmbH. All rights reserved.
00003  * Copyright (C) 2008 by egnite GmbH. All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 3. Neither the name of the copyright holders nor the names of
00015  *    contributors may be used to endorse or promote products derived
00016  *    from this software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00019  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00020  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00021  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00022  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00023  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00024  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00025  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00026  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00027  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00028  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00029  * SUCH DAMAGE.
00030  *
00031  * For additional information see http://www.ethernut.de/
00032  *
00033  */
00034 
00068 #include <cfg/os.h>
00069 #include <cfg/memory.h>
00070 
00071 #include <sys/timer.h>
00072 
00073 #include <string.h>
00074 #include <stdlib.h>
00075 
00076 #include <dev/at91_spi.h>
00077 #include <dev/at45db.h>
00078 
00079 #ifndef MAX_AT45_DEVICES
00080 #define MAX_AT45_DEVICES        1
00081 #endif
00082 
00083 #ifndef MAX_AT45_CMDLEN
00084 #define MAX_AT45_CMDLEN         8
00085 #endif
00086 
00087 #ifndef AT45_CONF_DFSPI
00088 #define AT45_CONF_DFSPI         SPI0_BASE
00089 #endif
00090 
00091 #ifndef AT45_CONF_DFPCS
00092 #define AT45_CONF_DFPCS         1
00093 #endif
00094 
00095 #ifndef AT45_ERASE_WAIT
00096 #define AT45_ERASE_WAIT         3000
00097 #endif
00098 
00099 #ifndef AT45_CHIP_ERASE_WAIT
00100 #define AT45_CHIP_ERASE_WAIT    50000
00101 #endif
00102 
00103 #ifndef AT45_WRITE_POLLS
00104 #define AT45_WRITE_POLLS        1000
00105 #endif
00106 
00117 #define DFCMD_CONT_READ_LF      0x03
00118 
00124 #define DFCMD_CONT_READ_HF      0x0B
00125 
00127 #define DFCMD_BLOCK_ERASE       0x50
00128 
00130 #define DFCMD_SECTOR_ERASE      0x7C
00131 
00133 #define DFCMD_PAGE_ERASE        0x81
00134 
00136 #define DFCMD_BUF1_PROG         0x82
00137 
00139 #define DFCMD_BUF1_FLASH        0x83
00140 
00142 #define DFCMD_BUF1_WRITE        0x84
00143 
00145 #define DFCMD_BUF2_PROG         0x85
00146 
00148 #define DFCMD_BUF2_FLASH        0x86
00149 
00151 #define DFCMD_BUF2_WRITE        0x87
00152 
00154 #define DFCMD_BUF1_FLASH_NE     0x88
00155 
00157 #define DFCMD_BUF2_FLASH_NE     0x89
00158 
00160 #define DFCMD_CHIP_ERASE        0xC7
00161 
00163 #define DFCMD_BUF1_READ_LF      0xD1
00164 
00169 #define DFCMD_READ_PAGE         0xD2
00170 
00172 #define DFCMD_BUF2_READ_LF      0xD3
00173 
00175 #define DFCMD_BUF1_READ         0xD4
00176 
00178 #define DFCMD_BUF2_READ         0xD6
00179 
00181 #define DFCMD_READ_STATUS       0xD7
00182 
00188 #define DFCMD_CONT_READ         0xE8
00189 
00191 #define AT45DB_AT91
00192 
00193 
00194 #if defined(AT45DB_SPI0_DEVICE)
00195 
00196 #include <dev/sppif0.h>
00197 #if defined(AT45DB_RESET_ACTIVE_HIGH)
00198 #define SpiReset(act)       Sppi0ChipReset(AT45DB_SPI0_DEVICE, act)
00199 #else
00200 #define SpiReset(act)       Sppi0ChipReset(AT45DB_SPI0_DEVICE, !act)
00201 #endif
00202 #define SpiSetMode()        Sppi0SetMode(AT45DB_SPI0_DEVICE, AT45DB_SPI_MODE)
00203 #define SpiSetSpeed()       Sppi0SetSpeed(AT45DB_SPI0_DEVICE, AT45DB_SPI_RATE)
00204 #if defined(AT45DB_SELECT_ACTIVE_HIGH)
00205 #define SpiSelect()         Sppi0SelectDevice(AT45DB_SPI0_DEVICE)
00206 #define SpiDeselect()       Sppi0DeselectDevice(AT45DB_SPI0_DEVICE)
00207 #else
00208 #define SpiSelect()         Sppi0NegSelectDevice(AT45DB_SPI0_DEVICE)
00209 #define SpiDeselect()       Sppi0NegDeselectDevice(AT45DB_SPI0_DEVICE)
00210 #endif
00211 #define SpiByte             Sppi0Byte
00212 
00213 #elif defined(AT45DB_SBBI0_DEVICE)
00214 
00215 #include <dev/sbbif0.h>
00216 #if defined(VS10XX_RESET_ACTIVE_HIGH)
00217 #define SpiReset(act)       Sbbi0ChipReset(AT45DB_SBBI0_DEVICE, act)
00218 #else
00219 #define SpiReset(act)       Sbbi0ChipReset(AT45DB_SBBI0_DEVICE, !act)
00220 #endif
00221 #define SpiSetMode()        Sbbi0SetMode(AT45DB_SBBI0_DEVICE, AT45DB_SPI_MODE)
00222 #define SpiSetSpeed()       Sbbi0SetSpeed(AT45DB_SBBI0_DEVICE, AT45DB_SPI_RATE)
00223 #if defined(VS10XX_SELECT_ACTIVE_HIGH)
00224 #define SpiSelect()         Sbbi0SelectDevice(AT45DB_SBBI0_DEVICE)
00225 #define SpiDeselect()       Sbbi0DeselectDevice(AT45DB_SBBI0_DEVICE)
00226 #else
00227 #define SpiSelect()         Sbbi0NegSelectDevice(AT45DB_SBBI0_DEVICE)
00228 #define SpiDeselect()       Sbbi0NegDeselectDevice(AT45DB_SBBI0_DEVICE)
00229 #endif
00230 #define SpiByte             Sbbi0Byte
00231 
00232 #endif
00233 
00237 typedef struct _AT45_DEVTAB {
00238     uint32_t devt_pages;
00239     u_int devt_pagsiz;
00240     u_int devt_offs;
00241     uint8_t devt_srmsk;
00242     uint8_t devt_srval;
00243 } AT45_DEVTAB;
00244 
00248 typedef struct _AT45DB_DCB {
00249     AT45_DEVTAB *dcb_devt;
00250     u_int dcb_spibas;
00251     u_int dcb_spipcs;
00252     uint8_t dcb_cmdbuf[MAX_AT45_CMDLEN];
00253 } AT45DB_DCB;
00254 
00258 AT45_DEVTAB at45_devt[] = {
00259     {512, 264, 9, 0x3C, 0x0C},  /* AT45DB011B - 128kB */
00260     {1025, 264, 9, 0x3C, 0x14}, /* AT45DB021B - 256kB */
00261     {2048, 264, 9, 0x3C, 0x1C}, /* AT45DB041B - 512kB */
00262     {4096, 264, 9, 0x3C, 0x24}, /* AT45DB081B - 1MB */
00263     {4096, 528, 10, 0x3C, 0x2C},        /* AT45DB0161B - 2MB */
00264     {8192, 528, 10, 0x3C, 0x34},        /* AT45DB0321B - 4MB */
00265     {8192, 1056, 11, 0x38, 0x38},       /* AT45DB0642 - 8MB */
00266     {0, 0, 0, 0, 0}             /* End of table */
00267 };
00268 
00272 static AT45DB_DCB dcbtab[MAX_AT45_DEVICES];
00273 
00274 /* Number of active chips. */
00275 static uint_least8_t dcbnum;
00276 
00277 /* Chip used for parameter storage. */
00278 static int dd_param = -1;
00279 
00291 int At45dbSendCmd(int dd, uint8_t op, uint32_t parm, int len, CONST void *tdata, void *rdata, int datalen)
00292 {
00293     uint8_t *cb = dcbtab[dd].dcb_cmdbuf;
00294 
00295     if (len > MAX_AT45_CMDLEN) {
00296         return -1;
00297     }
00298     memset(cb, 0, len);
00299     cb[0] = op;
00300     if (parm) {
00301         cb[1] = (uint8_t) (parm >> 16);
00302         cb[2] = (uint8_t) (parm >> 8);
00303         cb[3] = (uint8_t) parm;
00304     }
00305     return At91SpiTransfer2(dcbtab[dd].dcb_spibas, dcbtab[dd].dcb_spipcs, cb, cb, len, tdata, rdata, datalen);
00306 }
00307 
00308 uint8_t At45dbGetStatus(int dd)
00309 {
00310     uint8_t buf[2] = { DFCMD_READ_STATUS, 0xFF };
00311 
00312     if (At91SpiTransfer2(dcbtab[dd].dcb_spibas, dcbtab[dd].dcb_spipcs, buf, buf, 2, NULL, NULL, 0)) {
00313         return (uint8_t) - 1;
00314     }
00315     return buf[1];
00316 }
00317 
00323 int At45dbWaitReady(int dd, uint32_t tmo, int poll)
00324 {
00325     uint8_t sr;
00326 
00327     while (((sr = At45dbGetStatus(dd)) & 0x80) == 0) {
00328         if (!poll) {
00329             NutSleep(1);
00330         }
00331         if (tmo-- == 0) {
00332             return -1;
00333         }
00334     }
00335     return 0;
00336 }
00337 
00347 int At45dbInit(u_int spibas, u_int spipcs)
00348 {
00349     int dd = -1;
00350     uint8_t sr;
00351     uint_fast8_t i;
00352 
00353     for (i = 0; i < dcbnum; i++) {
00354         if (dcbtab[i].dcb_spibas == spibas && dcbtab[i].dcb_spipcs == spipcs) {
00355             return i;
00356         }
00357     }
00358 
00359     if (dcbnum >= MAX_AT45_DEVICES) {
00360         return -1;
00361     }
00362 
00363 #if defined(MCU_AT91SAM7X256) || defined(MCU_AT91SAM9260) || defined(MCU_AT91SAM9XE512)
00364     At91SpiInit(spibas);
00365     At91SpiReset(spibas);
00366     At91SpiInitChipSelects(spibas, _BV(spipcs));
00367     At91SpiSetRate(spibas, spipcs, 1000000);
00368     At91SpiSetModeFlags(spibas, spipcs, SPIMF_MASTER | SPIMF_SCKIAHI | SPIMF_CAPRISE);
00369 #elif defined(MCU_AT91R40008)
00370 #endif
00371 
00372     dcbtab[dcbnum].dcb_spibas = spibas;
00373     dcbtab[dcbnum].dcb_spipcs = spipcs;
00374     sr = At45dbGetStatus(dcbnum);
00375 
00376     for (i = 0; at45_devt[i].devt_pages; i++) {
00377         if ((sr & at45_devt[i].devt_srmsk) == at45_devt[i].devt_srval) {
00378             dcbtab[dcbnum].dcb_devt = &at45_devt[i];
00379             dd = dcbnum++;
00380             break;
00381         }
00382     }
00383     return dd;
00384 }
00385 
00389 int At45dbPageErase(int dd, uint32_t pgn)
00390 {
00391     pgn <<= dcbtab[dd].dcb_devt->devt_offs;
00392     return At45dbSendCmd(dd, DFCMD_PAGE_ERASE, pgn, 4, NULL, NULL, 0);
00393 }
00394 
00398 int At45dbChipErase(void)
00399 {
00400     return -1;
00401 }
00402 
00413 int At45dbPageRead(int dd, uint32_t pgn, void *data, u_int len)
00414 {
00415     pgn <<= dcbtab[dd].dcb_devt->devt_offs;
00416     return At45dbSendCmd(dd, DFCMD_CONT_READ, pgn, 8, data, data, len);
00417 }
00418 
00431 int At45dbPageWrite(int dd, uint32_t pgn, CONST void *data, u_int len)
00432 {
00433     int rc = -1;
00434     void *rp;
00435 
00436     if ((rp = malloc(len)) != NULL) {
00437         /* Copy data to dataflash RAM buffer. */
00438         if (At45dbSendCmd(dd, DFCMD_BUF1_WRITE, 0, 4, data, rp, len) == 0) {
00439             /* Flash RAM buffer. */
00440             pgn <<= dcbtab[dd].dcb_devt->devt_offs;
00441             if (At45dbSendCmd(dd, DFCMD_BUF1_FLASH, pgn, 4, NULL, NULL, 0) == 0) {
00442                 rc = At45dbWaitReady(dd, AT45_WRITE_POLLS, 1);
00443             }
00444         }
00445         free(rp);
00446     }
00447     return rc;
00448 }
00449 
00450 uint32_t At45dbPages(int dd)
00451 {
00452     return dcbtab[dd].dcb_devt->devt_pages;
00453 }
00454 
00455 u_int At45dbPageSize(int dd)
00456 {
00457     return dcbtab[dd].dcb_devt->devt_pagsiz;
00458 }
00459 
00460 uint32_t At45dbParamPage(void)
00461 {
00462 #ifdef AT45_CONF_PAGE
00463     return AT45_CONF_PAGE;
00464 #else
00465     return dcbtab[dd_param].dcb_devt->devt_pages - 1;
00466 #endif
00467 }
00468 
00480 int At45dbParamSize(void)
00481 {
00482     int rc;
00483 
00484     if (dd_param == -1 && (dd_param = At45dbInit(AT45_CONF_DFSPI, AT45_CONF_DFPCS)) == -1) {
00485         return -1;
00486     }
00487 #ifdef AT45_CONF_SIZE
00488     rc = AT45_CONF_SIZE;
00489 #else
00490     rc = dcbtab[dd_param].dcb_devt->devt_pagsiz;
00491 #endif
00492     return rc;
00493 }
00494 
00504 int At45dbParamRead(u_int pos, void *data, u_int len)
00505 {
00506     int rc = -1;
00507     uint8_t *buff;
00508     int csize = At45dbParamSize();
00509     uint32_t cpage = At45dbParamPage();
00510 
00511     /* Load the complete configuration area. */
00512     if (csize > len && (buff = malloc(csize)) != NULL) {
00513         rc = At45dbPageRead(dd_param, cpage, buff, csize);
00514         /* Copy requested contents to caller's buffer. */
00515         memcpy(data, buff + pos, len);
00516         free(buff);
00517     }
00518     return rc;
00519 }
00520 
00530 int At45dbParamWrite(u_int pos, CONST void *data, u_int len)
00531 {
00532     int rc = -1;
00533     uint8_t *buff;
00534     int csize = At45dbParamSize();
00535     uint32_t cpage = At45dbParamPage();
00536 
00537     /* Load the complete configuration area. */
00538     if (csize > len && (buff = malloc(csize)) != NULL) {
00539         rc = At45dbPageRead(dd_param, cpage, buff, csize);
00540         /* Compare old with new contents. */
00541         if (memcmp(buff + pos, data, len)) {
00542             /* New contents differs. Copy it into the sector buffer. */
00543             memcpy(buff + pos, data, len);
00544             /* Erase sector and write new data. */
00545             rc = At45dbPageWrite(dd_param, cpage, buff, csize);
00546         }
00547         free(buff);
00548     }
00549     return rc;
00550 }

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/