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 
00062 #include <cfg/os.h>
00063 #include <cfg/memory.h>
00064 
00065 #include <sys/timer.h>
00066 
00067 #include <string.h>
00068 #include <stdlib.h>
00069 
00070 #include <dev/at91_spi.h>
00071 #include <dev/at45db.h>
00072 
00073 #ifndef MAX_AT45_DEVICES
00074 #define MAX_AT45_DEVICES        1
00075 #endif
00076 
00077 #ifndef MAX_AT45_CMDLEN
00078 #define MAX_AT45_CMDLEN         8
00079 #endif
00080 
00081 #ifndef AT45_CONF_DFSPI
00082 #define AT45_CONF_DFSPI         SPI0_BASE
00083 #endif
00084 
00085 #ifndef AT45_CONF_DFPCS
00086 #define AT45_CONF_DFPCS         1
00087 #endif
00088 
00089 #ifndef AT45_ERASE_WAIT
00090 #define AT45_ERASE_WAIT         3000
00091 #endif
00092 
00093 #ifndef AT45_CHIP_ERASE_WAIT
00094 #define AT45_CHIP_ERASE_WAIT    50000
00095 #endif
00096 
00097 #ifndef AT45_WRITE_POLLS
00098 #define AT45_WRITE_POLLS        1000
00099 #endif
00100 
00111 #define DFCMD_CONT_READ_LF      0x03
00112 
00118 #define DFCMD_CONT_READ_HF      0x0B
00119 
00121 #define DFCMD_BLOCK_ERASE       0x50
00122 
00124 #define DFCMD_SECTOR_ERASE      0x7C
00125 
00127 #define DFCMD_PAGE_ERASE        0x81
00128 
00130 #define DFCMD_BUF1_PROG         0x82
00131 
00133 #define DFCMD_BUF1_FLASH        0x83
00134 
00136 #define DFCMD_BUF1_WRITE        0x84
00137 
00139 #define DFCMD_BUF2_PROG         0x85
00140 
00142 #define DFCMD_BUF2_FLASH        0x86
00143 
00145 #define DFCMD_BUF2_WRITE        0x87
00146 
00148 #define DFCMD_BUF1_FLASH_NE     0x88
00149 
00151 #define DFCMD_BUF2_FLASH_NE     0x89
00152 
00154 #define DFCMD_CHIP_ERASE        0xC7
00155 
00157 #define DFCMD_BUF1_READ_LF      0xD1
00158 
00163 #define DFCMD_READ_PAGE         0xD2
00164 
00166 #define DFCMD_BUF2_READ_LF      0xD3
00167 
00169 #define DFCMD_BUF1_READ         0xD4
00170 
00172 #define DFCMD_BUF2_READ         0xD6
00173 
00175 #define DFCMD_READ_STATUS       0xD7
00176 
00182 #define DFCMD_CONT_READ         0xE8
00183 
00185 #define AT45DB_AT91
00186 
00187 
00188 #if defined(AT45DB_SPI0_DEVICE)
00189 
00190 #include <dev/sppif0.h>
00191 #if defined(AT45DB_RESET_ACTIVE_HIGH)
00192 #define SpiReset(act)       Sppi0ChipReset(AT45DB_SPI0_DEVICE, act)
00193 #else
00194 #define SpiReset(act)       Sppi0ChipReset(AT45DB_SPI0_DEVICE, !act)
00195 #endif
00196 #define SpiSetMode()        Sppi0SetMode(AT45DB_SPI0_DEVICE, AT45DB_SPI_MODE)
00197 #define SpiSetSpeed()       Sppi0SetSpeed(AT45DB_SPI0_DEVICE, AT45DB_SPI_RATE)
00198 #if defined(AT45DB_SELECT_ACTIVE_HIGH)
00199 #define SpiSelect()         Sppi0SelectDevice(AT45DB_SPI0_DEVICE)
00200 #define SpiDeselect()       Sppi0DeselectDevice(AT45DB_SPI0_DEVICE)
00201 #else
00202 #define SpiSelect()         Sppi0NegSelectDevice(AT45DB_SPI0_DEVICE)
00203 #define SpiDeselect()       Sppi0NegDeselectDevice(AT45DB_SPI0_DEVICE)
00204 #endif
00205 #define SpiByte             Sppi0Byte
00206 
00207 #elif defined(AT45DB_SBBI0_DEVICE)
00208 
00209 #include <dev/sbbif0.h>
00210 #if defined(VS10XX_RESET_ACTIVE_HIGH)
00211 #define SpiReset(act)       Sbbi0ChipReset(AT45DB_SBBI0_DEVICE, act)
00212 #else
00213 #define SpiReset(act)       Sbbi0ChipReset(AT45DB_SBBI0_DEVICE, !act)
00214 #endif
00215 #define SpiSetMode()        Sbbi0SetMode(AT45DB_SBBI0_DEVICE, AT45DB_SPI_MODE)
00216 #define SpiSetSpeed()       Sbbi0SetSpeed(AT45DB_SBBI0_DEVICE, AT45DB_SPI_RATE)
00217 #if defined(VS10XX_SELECT_ACTIVE_HIGH)
00218 #define SpiSelect()         Sbbi0SelectDevice(AT45DB_SBBI0_DEVICE)
00219 #define SpiDeselect()       Sbbi0DeselectDevice(AT45DB_SBBI0_DEVICE)
00220 #else
00221 #define SpiSelect()         Sbbi0NegSelectDevice(AT45DB_SBBI0_DEVICE)
00222 #define SpiDeselect()       Sbbi0NegDeselectDevice(AT45DB_SBBI0_DEVICE)
00223 #endif
00224 #define SpiByte             Sbbi0Byte
00225 
00226 #endif
00227 
00231 typedef struct _AT45_DEVTAB {
00232     u_long devt_pages;
00233     u_int devt_pagsiz;
00234     u_int devt_offs;
00235     u_char devt_srmsk;
00236     u_char devt_srval;
00237 } AT45_DEVTAB;
00238 
00242 typedef struct _AT45DB_DCB {
00243     AT45_DEVTAB *dcb_devt;
00244     u_int dcb_spibas;
00245     u_int dcb_spipcs;
00246     u_char dcb_cmdbuf[MAX_AT45_CMDLEN];
00247 } AT45DB_DCB;
00248 
00252 AT45_DEVTAB at45_devt[] = {
00253     {512, 264, 9, 0x3C, 0x0C},  /* AT45DB011B - 128kB */
00254     {1025, 264, 9, 0x3C, 0x14}, /* AT45DB021B - 256kB */
00255     {2048, 264, 9, 0x3C, 0x1C}, /* AT45DB041B - 512kB */
00256     {4096, 264, 9, 0x3C, 0x24}, /* AT45DB081B - 1MB */
00257     {4096, 528, 10, 0x3C, 0x2C},        /* AT45DB0161B - 2MB */
00258     {8192, 528, 10, 0x3C, 0x34},        /* AT45DB0321B - 4MB */
00259     {8192, 1056, 11, 0x38, 0x38},       /* AT45DB0642 - 8MB */
00260     {0, 0, 0, 0, 0}             /* End of table */
00261 };
00262 
00266 static AT45DB_DCB dcbtab[MAX_AT45_DEVICES];
00267 
00268 /* Number of active chips. */
00269 static int dcbnum;
00270 
00271 /* Chip used for parameter storage. */
00272 static int dd_param = -1;
00273 
00285 int At45dbSendCmd(int dd, u_char op, u_long parm, int len, CONST void *tdata, void *rdata, int datalen)
00286 {
00287     u_char *cb = dcbtab[dd].dcb_cmdbuf;
00288 
00289     if (len > MAX_AT45_CMDLEN) {
00290         return -1;
00291     }
00292     memset(cb, 0, len);
00293     cb[0] = op;
00294     if (parm) {
00295         cb[1] = (u_char) (parm >> 16);
00296         cb[2] = (u_char) (parm >> 8);
00297         cb[3] = (u_char) parm;
00298     }
00299     return At91SpiTransfer2(dcbtab[dd].dcb_spibas, dcbtab[dd].dcb_spipcs, cb, cb, len, tdata, rdata, datalen);
00300 }
00301 
00302 u_char At45dbGetStatus(int dd)
00303 {
00304     u_char buf[2] = { DFCMD_READ_STATUS, 0xFF };
00305 
00306     if (At91SpiTransfer2(dcbtab[dd].dcb_spibas, dcbtab[dd].dcb_spipcs, buf, buf, 2, NULL, NULL, 0)) {
00307         return (u_char) - 1;
00308     }
00309     return buf[1];
00310 }
00311 
00317 int At45dbWaitReady(int dd, u_long tmo, int poll)
00318 {
00319     u_char sr;
00320 
00321     while (((sr = At45dbGetStatus(dd)) & 0x80) == 0) {
00322         if (!poll) {
00323             NutSleep(1);
00324         }
00325         if (tmo-- == 0) {
00326             return -1;
00327         }
00328     }
00329     return 0;
00330 }
00331 
00341 int At45dbInit(u_int spibas, u_int spipcs)
00342 {
00343     int dd = -1;
00344     u_char sr;
00345     int i;
00346 
00347     for (i = 0; i < dcbnum; i++) {
00348         if (dcbtab[i].dcb_spibas == spibas && dcbtab[i].dcb_spipcs == spipcs) {
00349             return i;
00350         }
00351     }
00352 
00353     if (dcbnum >= MAX_AT45_DEVICES) {
00354         return -1;
00355     }
00356 
00357 #if defined(MCU_AT91SAM7X256) || defined(MCU_AT91SAM9260)
00358     At91SpiInit(spibas);
00359     At91SpiReset(spibas);
00360     At91SpiInitChipSelects(spibas, _BV(spipcs));
00361     At91SpiSetRate(spibas, spipcs, 1000000);
00362     At91SpiSetModeFlags(spibas, spipcs, SPIMF_MASTER | SPIMF_SCKIAHI | SPIMF_CAPRISE);
00363 #elif defined(MCU_AT91R40008)
00364 #endif
00365 
00366     dcbtab[dcbnum].dcb_spibas = spibas;
00367     dcbtab[dcbnum].dcb_spipcs = spipcs;
00368     sr = At45dbGetStatus(dcbnum);
00369 
00370     for (i = 0; at45_devt[i].devt_pages; i++) {
00371         if ((sr & at45_devt[i].devt_srmsk) == at45_devt[i].devt_srval) {
00372             dcbtab[dcbnum].dcb_devt = &at45_devt[i];
00373             dd = dcbnum++;
00374             break;
00375         }
00376     }
00377     return dd;
00378 }
00379 
00383 int At45dbPageErase(int dd, u_long pgn)
00384 {
00385     pgn <<= dcbtab[dd].dcb_devt->devt_offs;
00386     return At45dbSendCmd(dd, DFCMD_PAGE_ERASE, pgn, 4, NULL, NULL, 0);
00387 }
00388 
00392 int At45dbChipErase(void)
00393 {
00394     return -1;
00395 }
00396 
00407 int At45dbPageRead(int dd, u_long pgn, void *data, u_int len)
00408 {
00409     pgn <<= dcbtab[dd].dcb_devt->devt_offs;
00410     return At45dbSendCmd(dd, DFCMD_CONT_READ, pgn, 8, data, data, len);
00411 }
00412 
00425 int At45dbPageWrite(int dd, u_long pgn, CONST void *data, u_int len)
00426 {
00427     int rc = -1;
00428     void *rp;
00429 
00430     if ((rp = malloc(len)) != NULL) {
00431         /* Copy data to dataflash RAM buffer. */
00432         if (At45dbSendCmd(dd, DFCMD_BUF1_WRITE, 0, 4, data, rp, len) == 0) {
00433             /* Flash RAM buffer. */
00434             pgn <<= dcbtab[dd].dcb_devt->devt_offs;
00435             if (At45dbSendCmd(dd, DFCMD_BUF1_FLASH, pgn, 4, NULL, NULL, 0) == 0) {
00436                 rc = At45dbWaitReady(dd, AT45_WRITE_POLLS, 1);
00437             }
00438         }
00439         free(rp);
00440     }
00441     return rc;
00442 }
00443 
00444 u_long At45dbPages(int dd)
00445 {
00446     return dcbtab[dd].dcb_devt->devt_pages;
00447 }
00448 
00449 u_int At45dbPageSize(int dd)
00450 {
00451     return dcbtab[dd].dcb_devt->devt_pagsiz;
00452 }
00453 
00454 u_long At45dbParamPage(void)
00455 {
00456 #ifdef AT45_CONF_PAGE
00457     return AT45_CONF_PAGE;
00458 #else
00459     return dcbtab[dd_param].dcb_devt->devt_pages - 1;
00460 #endif
00461 }
00462 
00474 int At45dbParamSize(void)
00475 {
00476     int rc;
00477 
00478     if (dd_param == -1 && (dd_param = At45dbInit(AT45_CONF_DFSPI, AT45_CONF_DFPCS)) == -1) {
00479         return -1;
00480     }
00481 #ifdef AT45_CONF_SIZE
00482     rc = AT45_CONF_SIZE;
00483 #else
00484     rc = dcbtab[dd_param].dcb_devt->devt_pagsiz;
00485 #endif
00486     return rc;
00487 }
00488 
00498 int At45dbParamRead(u_int pos, void *data, u_int len)
00499 {
00500     int rc = -1;
00501     u_char *buff;
00502     int csize = At45dbParamSize();
00503     u_long cpage = At45dbParamPage();
00504 
00505     /* Load the complete configuration area. */
00506     if (csize > len && (buff = malloc(csize)) != NULL) {
00507         rc = At45dbPageRead(dd_param, cpage, buff, csize);
00508         /* Copy requested contents to caller's buffer. */
00509         memcpy(data, buff + pos, len);
00510         free(buff);
00511     }
00512     return rc;
00513 }
00514 
00524 int At45dbParamWrite(u_int pos, CONST void *data, u_int len)
00525 {
00526     int rc = -1;
00527     u_char *buff;
00528     int csize = At45dbParamSize();
00529     u_long cpage = At45dbParamPage();
00530 
00531     /* Load the complete configuration area. */
00532     if (csize > len && (buff = malloc(csize)) != NULL) {
00533         rc = At45dbPageRead(dd_param, cpage, buff, csize);
00534         /* Compare old with new contents. */
00535         if (memcmp(buff + pos, data, len)) {
00536             /* New contents differs. Copy it into the sector buffer. */
00537             memcpy(buff + pos, data, len);
00538             /* Erase sector and write new data. */
00539             rc = At45dbPageWrite(dd_param, cpage, buff, csize);
00540         }
00541         free(buff);
00542     }
00543     return rc;
00544 }

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