at45db.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006 by egnite Software GmbH. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00021  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  *
00032  */
00033 
00055 #include <cfg/os.h>
00056 #include <cfg/memory.h>
00057 
00058 #include <sys/timer.h>
00059 
00060 #include <string.h>
00061 #include <stdlib.h>
00062 
00063 #include <dev/at91_spi.h>
00064 #include <dev/at45db.h>
00065 
00066 #ifndef MAX_AT45_DEVICES
00067 #define MAX_AT45_DEVICES        1
00068 #endif
00069 
00070 #ifndef MAX_AT45_CMDLEN
00071 #define MAX_AT45_CMDLEN         8
00072 #endif
00073 
00074 #ifndef AT45_CONF_DFSPI
00075 #define AT45_CONF_DFSPI         SPI0_BASE
00076 #endif
00077 
00078 #ifndef AT45_CONF_DFPCS
00079 #define AT45_CONF_DFPCS         1
00080 #endif
00081 
00082 #ifndef AT45_ERASE_WAIT
00083 #define AT45_ERASE_WAIT         3000
00084 #endif
00085 
00086 #ifndef AT45_CHIP_ERASE_WAIT
00087 #define AT45_CHIP_ERASE_WAIT    50000
00088 #endif
00089 
00090 #ifndef AT45_WRITE_POLLS
00091 #define AT45_WRITE_POLLS        1000
00092 #endif
00093 
00104 #define DFCMD_CONT_READ_LF      0x03
00105 
00111 #define DFCMD_CONT_READ_HF      0x0B
00112 
00114 #define DFCMD_BLOCK_ERASE       0x50
00115 
00117 #define DFCMD_SECTOR_ERASE      0x7C
00118 
00120 #define DFCMD_PAGE_ERASE        0x81
00121 
00123 #define DFCMD_BUF1_PROG         0x82
00124 
00126 #define DFCMD_BUF1_FLASH        0x83
00127 
00129 #define DFCMD_BUF1_WRITE        0x84
00130 
00132 #define DFCMD_BUF2_PROG         0x85
00133 
00135 #define DFCMD_BUF2_FLASH        0x86
00136 
00138 #define DFCMD_BUF2_WRITE        0x87
00139 
00141 #define DFCMD_BUF1_FLASH_NE     0x88
00142 
00144 #define DFCMD_BUF2_FLASH_NE     0x89
00145 
00147 #define DFCMD_CHIP_ERASE        0xC7
00148 
00150 #define DFCMD_BUF1_READ_LF      0xD1
00151 
00156 #define DFCMD_READ_PAGE         0xD2
00157 
00159 #define DFCMD_BUF2_READ_LF      0xD3
00160 
00162 #define DFCMD_BUF1_READ         0xD4
00163 
00165 #define DFCMD_BUF2_READ         0xD6
00166 
00168 #define DFCMD_READ_STATUS       0xD7
00169 
00175 #define DFCMD_CONT_READ         0xE8
00176 
00178 #define AT45DB_AT91
00179 
00180 
00181 #if defined(AT45DB_SPI0_DEVICE)
00182 
00183 #include <dev/sppif0.h>
00184 #if defined(AT45DB_RESET_ACTIVE_HIGH)
00185 #define SpiReset(act)       Sppi0ChipReset(AT45DB_SPI0_DEVICE, act)
00186 #else
00187 #define SpiReset(act)       Sppi0ChipReset(AT45DB_SPI0_DEVICE, !act)
00188 #endif
00189 #define SpiSetMode()        Sppi0SetMode(AT45DB_SPI0_DEVICE, AT45DB_SPI_MODE)
00190 #define SpiSetSpeed()       Sppi0SetSpeed(AT45DB_SPI0_DEVICE, AT45DB_SPI_RATE)
00191 #if defined(AT45DB_SELECT_ACTIVE_HIGH)
00192 #define SpiSelect()         Sppi0SelectDevice(AT45DB_SPI0_DEVICE)
00193 #define SpiDeselect()       Sppi0DeselectDevice(AT45DB_SPI0_DEVICE)
00194 #else
00195 #define SpiSelect()         Sppi0NegSelectDevice(AT45DB_SPI0_DEVICE)
00196 #define SpiDeselect()       Sppi0NegDeselectDevice(AT45DB_SPI0_DEVICE)
00197 #endif
00198 #define SpiByte             Sppi0Byte
00199 
00200 #elif defined(AT45DB_SBBI0_DEVICE)
00201 
00202 #include <dev/sbbif0.h>
00203 #if defined(VS10XX_RESET_ACTIVE_HIGH)
00204 #define SpiReset(act)       Sbbi0ChipReset(AT45DB_SBBI0_DEVICE, act)
00205 #else
00206 #define SpiReset(act)       Sbbi0ChipReset(AT45DB_SBBI0_DEVICE, !act)
00207 #endif
00208 #define SpiSetMode()        Sbbi0SetMode(AT45DB_SBBI0_DEVICE, AT45DB_SPI_MODE)
00209 #define SpiSetSpeed()       Sbbi0SetSpeed(AT45DB_SBBI0_DEVICE, AT45DB_SPI_RATE)
00210 #if defined(VS10XX_SELECT_ACTIVE_HIGH)
00211 #define SpiSelect()         Sbbi0SelectDevice(AT45DB_SBBI0_DEVICE)
00212 #define SpiDeselect()       Sbbi0DeselectDevice(AT45DB_SBBI0_DEVICE)
00213 #else
00214 #define SpiSelect()         Sbbi0NegSelectDevice(AT45DB_SBBI0_DEVICE)
00215 #define SpiDeselect()       Sbbi0NegDeselectDevice(AT45DB_SBBI0_DEVICE)
00216 #endif
00217 #define SpiByte             Sbbi0Byte
00218 
00219 #endif
00220 
00224 typedef struct _AT45_DEVTAB {
00225     u_long devt_pages;
00226     u_int devt_pagsiz;
00227     u_int devt_offs;
00228     u_char devt_srmsk;
00229     u_char devt_srval;
00230 } AT45_DEVTAB;
00231 
00235 typedef struct _AT45DB_DCB {
00236     AT45_DEVTAB *dcb_devt;
00237     u_int dcb_spibas;
00238     u_int dcb_spipcs;
00239     u_char dcb_cmdbuf[MAX_AT45_CMDLEN];
00240 } AT45DB_DCB;
00241 
00245 AT45_DEVTAB at45_devt[] = {
00246     {512, 264, 9, 0x3C, 0x0C},  /* AT45DB011B - 128kB */
00247     {1025, 264, 9, 0x3C, 0x14}, /* AT45DB021B - 256kB */
00248     {2048, 264, 9, 0x3C, 0x1C}, /* AT45DB041B - 512kB */
00249     {4096, 264, 9, 0x3C, 0x24}, /* AT45DB081B - 1MB */
00250     {4096, 528, 10, 0x3C, 0x2C},        /* AT45DB0161B - 2MB */
00251     {8192, 528, 10, 0x3C, 0x34},        /* AT45DB0321B - 4MB */
00252     {8192, 1056, 11, 0x38, 0x38},       /* AT45DB0642 - 8MB */
00253     {0, 0, 0, 0, 0}             /* End of table */
00254 };
00255 
00259 static AT45DB_DCB dcbtab[MAX_AT45_DEVICES];
00260 
00261 /* Number of active chips. */
00262 static int dcbnum;
00263 
00264 /* Chip used for parameter storage. */
00265 static int dd_param = -1;
00266 
00278 int At45dbSendCmd(int dd, u_char op, u_long parm, int len, CONST void *tdata, void *rdata, int datalen)
00279 {
00280     u_char *cb = dcbtab[dd].dcb_cmdbuf;
00281 
00282     if (len > MAX_AT45_CMDLEN) {
00283         return -1;
00284     }
00285     memset(cb, 0, len);
00286     cb[0] = op;
00287     if (parm) {
00288         cb[1] = (u_char) (parm >> 16);
00289         cb[2] = (u_char) (parm >> 8);
00290         cb[3] = (u_char) parm;
00291     }
00292     return At91SpiTransfer2(dcbtab[dd].dcb_spibas, dcbtab[dd].dcb_spipcs, cb, cb, len, tdata, rdata, datalen);
00293 }
00294 
00295 u_char At45dbGetStatus(int dd)
00296 {
00297     u_char buf[2] = { DFCMD_READ_STATUS, 0xFF };
00298 
00299     if (At91SpiTransfer2(dcbtab[dd].dcb_spibas, dcbtab[dd].dcb_spipcs, buf, buf, 2, NULL, NULL, 0)) {
00300         return (u_char) - 1;
00301     }
00302     return buf[1];
00303 }
00304 
00310 int At45dbWaitReady(int dd, u_long tmo, int poll)
00311 {
00312     u_char sr;
00313 
00314     while (((sr = At45dbGetStatus(dd)) & 0x80) == 0) {
00315         if (!poll) {
00316             NutSleep(1);
00317         }
00318         if (tmo-- == 0) {
00319             return -1;
00320         }
00321     }
00322     return 0;
00323 }
00324 
00334 int At45dbInit(u_int spibas, u_int spipcs)
00335 {
00336     int dd = -1;
00337     u_char sr;
00338     int i;
00339 
00340     for (i = 0; i < dcbnum; i++) {
00341         if (dcbtab[i].dcb_spibas == spibas && dcbtab[i].dcb_spipcs == spipcs) {
00342             return i;
00343         }
00344     }
00345 
00346     if (dcbnum >= MAX_AT45_DEVICES) {
00347         return -1;
00348     }
00349 
00350 #if defined(MCU_AT91SAM7X256) || defined(MCU_AT91SAM9260)
00351     At91SpiInit(spibas);
00352     At91SpiReset(spibas);
00353     At91SpiInitChipSelects(spibas, _BV(spipcs));
00354     At91SpiSetRate(spibas, spipcs, 1000000);
00355     At91SpiSetModeFlags(spibas, spipcs, SPIMF_MASTER | SPIMF_SCKIAHI | SPIMF_CAPRISE);
00356 #elif defined(MCU_AT91R40008)
00357 #endif
00358 
00359     dcbtab[dcbnum].dcb_spibas = spibas;
00360     dcbtab[dcbnum].dcb_spipcs = spipcs;
00361     sr = At45dbGetStatus(dcbnum);
00362 
00363     for (i = 0; at45_devt[i].devt_pages; i++) {
00364         if ((sr & at45_devt[i].devt_srmsk) == at45_devt[i].devt_srval) {
00365             dcbtab[dcbnum].dcb_devt = &at45_devt[i];
00366             dd = dcbnum++;
00367             break;
00368         }
00369     }
00370     return dd;
00371 }
00372 
00376 int At45dbPageErase(int dd, u_int pgn)
00377 {
00378     return At45dbSendCmd(dd, DFCMD_PAGE_ERASE, pgn, 4, NULL, NULL, 0);
00379 }
00380 
00384 int At45dbChipErase(void)
00385 {
00386     return -1;
00387 }
00388 
00399 int At45dbPageRead(int dd, u_long pgn, void *data, u_int len)
00400 {
00401     pgn <<= dcbtab[dd].dcb_devt->devt_offs;
00402     return At45dbSendCmd(dd, DFCMD_CONT_READ, pgn, 8, data, data, len);
00403 }
00404 
00417 int At45dbPageWrite(int dd, u_int pgn, CONST void *data, u_int len)
00418 {
00419     int rc = -1;
00420     void *rp;
00421 
00422     if ((rp = malloc(len)) != NULL) {
00423         /* Copy data to dataflash RAM buffer. */
00424         if (At45dbSendCmd(dd, DFCMD_BUF1_WRITE, 0, 4, data, rp, len) == 0) {
00425             /* Flash RAM buffer. */
00426             pgn <<= dcbtab[dd].dcb_devt->devt_offs;
00427             if (At45dbSendCmd(dd, DFCMD_BUF1_FLASH, pgn, 4, NULL, NULL, 0) == 0) {
00428                 rc = At45dbWaitReady(dd, AT45_WRITE_POLLS, 1);
00429             }
00430         }
00431         free(rp);
00432     }
00433     return rc;
00434 }
00435 
00436 u_long At45dbParamPage(void)
00437 {
00438 #ifdef AT45_CONF_PAGE
00439     return AT45_CONF_PAGE;
00440 #else
00441     return dcbtab[dd_param].dcb_devt->devt_pages - 1;
00442 #endif
00443 }
00444 
00456 int At45dbParamSize(void)
00457 {
00458     int rc;
00459 
00460     if (dd_param == -1 && (dd_param = At45dbInit(AT45_CONF_DFSPI, AT45_CONF_DFPCS)) == -1) {
00461         return -1;
00462     }
00463 #ifdef AT45_CONF_SIZE
00464     rc = AT45_CONF_SIZE;
00465 #else
00466     rc = dcbtab[dd_param].dcb_devt->devt_pagsiz;
00467 #endif
00468     return rc;
00469 }
00470 
00480 int At45dbParamRead(u_int pos, void *data, u_int len)
00481 {
00482     int rc = -1;
00483     u_char *buff;
00484     int csize = At45dbParamSize();
00485     u_long cpage = At45dbParamPage();
00486 
00487     /* Load the complete configuration area. */
00488     if (csize > len && (buff = malloc(csize)) != NULL) {
00489         rc = At45dbPageRead(dd_param, cpage, buff, csize);
00490         /* Copy requested contents to caller's buffer. */
00491         memcpy(data, buff + pos, len);
00492         free(buff);
00493     }
00494     return rc;
00495 }
00496 
00506 int At45dbParamWrite(u_int pos, CONST void *data, u_int len)
00507 {
00508     int rc = -1;
00509     u_char *buff;
00510     int csize = At45dbParamSize();
00511     u_long cpage = At45dbParamPage();
00512 
00513     /* Load the complete configuration area. */
00514     if (csize > len && (buff = malloc(csize)) != NULL) {
00515         rc = At45dbPageRead(dd_param, cpage, buff, csize);
00516         /* Compare old with new contents. */
00517         if (memcmp(buff + pos, data, len)) {
00518             /* New contents differs. Copy it into the sector buffer. */
00519             memcpy(buff + pos, data, len);
00520             /* Erase sector and write new data. */
00521             rc = At45dbPageWrite(dd_param, cpage, buff, csize);
00522         }
00523         free(buff);
00524     }
00525     return rc;
00526 }

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