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 
00058 #include <cfg/os.h>
00059 #include <cfg/memory.h>
00060 
00061 #include <sys/timer.h>
00062 
00063 #include <string.h>
00064 #include <stdlib.h>
00065 
00066 #include <dev/at91_spi.h>
00067 #include <dev/at45db.h>
00068 
00069 #ifndef MAX_AT45_DEVICES
00070 #define MAX_AT45_DEVICES        1
00071 #endif
00072 
00073 #ifndef MAX_AT45_CMDLEN
00074 #define MAX_AT45_CMDLEN         8
00075 #endif
00076 
00077 #ifndef AT45_CONF_DFSPI
00078 #define AT45_CONF_DFSPI         SPI0_BASE
00079 #endif
00080 
00081 #ifndef AT45_CONF_DFPCS
00082 #define AT45_CONF_DFPCS         1
00083 #endif
00084 
00085 #ifndef AT45_ERASE_WAIT
00086 #define AT45_ERASE_WAIT         3000
00087 #endif
00088 
00089 #ifndef AT45_CHIP_ERASE_WAIT
00090 #define AT45_CHIP_ERASE_WAIT    50000
00091 #endif
00092 
00093 #ifndef AT45_WRITE_POLLS
00094 #define AT45_WRITE_POLLS        1000
00095 #endif
00096 
00107 #define DFCMD_CONT_READ_LF      0x03
00108 
00114 #define DFCMD_CONT_READ_HF      0x0B
00115 
00117 #define DFCMD_BLOCK_ERASE       0x50
00118 
00120 #define DFCMD_SECTOR_ERASE      0x7C
00121 
00123 #define DFCMD_PAGE_ERASE        0x81
00124 
00126 #define DFCMD_BUF1_PROG         0x82
00127 
00129 #define DFCMD_BUF1_FLASH        0x83
00130 
00132 #define DFCMD_BUF1_WRITE        0x84
00133 
00135 #define DFCMD_BUF2_PROG         0x85
00136 
00138 #define DFCMD_BUF2_FLASH        0x86
00139 
00141 #define DFCMD_BUF2_WRITE        0x87
00142 
00144 #define DFCMD_BUF1_FLASH_NE     0x88
00145 
00147 #define DFCMD_BUF2_FLASH_NE     0x89
00148 
00150 #define DFCMD_CHIP_ERASE        0xC7
00151 
00153 #define DFCMD_BUF1_READ_LF      0xD1
00154 
00159 #define DFCMD_READ_PAGE         0xD2
00160 
00162 #define DFCMD_BUF2_READ_LF      0xD3
00163 
00165 #define DFCMD_BUF1_READ         0xD4
00166 
00168 #define DFCMD_BUF2_READ         0xD6
00169 
00171 #define DFCMD_READ_STATUS       0xD7
00172 
00178 #define DFCMD_CONT_READ         0xE8
00179 
00181 #define AT45DB_AT91
00182 
00183 
00184 #if defined(AT45DB_SPI0_DEVICE)
00185 
00186 #include <dev/sppif0.h>
00187 #if defined(AT45DB_RESET_ACTIVE_HIGH)
00188 #define SpiReset(act)       Sppi0ChipReset(AT45DB_SPI0_DEVICE, act)
00189 #else
00190 #define SpiReset(act)       Sppi0ChipReset(AT45DB_SPI0_DEVICE, !act)
00191 #endif
00192 #define SpiSetMode()        Sppi0SetMode(AT45DB_SPI0_DEVICE, AT45DB_SPI_MODE)
00193 #define SpiSetSpeed()       Sppi0SetSpeed(AT45DB_SPI0_DEVICE, AT45DB_SPI_RATE)
00194 #if defined(AT45DB_SELECT_ACTIVE_HIGH)
00195 #define SpiSelect()         Sppi0SelectDevice(AT45DB_SPI0_DEVICE)
00196 #define SpiDeselect()       Sppi0DeselectDevice(AT45DB_SPI0_DEVICE)
00197 #else
00198 #define SpiSelect()         Sppi0NegSelectDevice(AT45DB_SPI0_DEVICE)
00199 #define SpiDeselect()       Sppi0NegDeselectDevice(AT45DB_SPI0_DEVICE)
00200 #endif
00201 #define SpiByte             Sppi0Byte
00202 
00203 #elif defined(AT45DB_SBBI0_DEVICE)
00204 
00205 #include <dev/sbbif0.h>
00206 #if defined(VS10XX_RESET_ACTIVE_HIGH)
00207 #define SpiReset(act)       Sbbi0ChipReset(AT45DB_SBBI0_DEVICE, act)
00208 #else
00209 #define SpiReset(act)       Sbbi0ChipReset(AT45DB_SBBI0_DEVICE, !act)
00210 #endif
00211 #define SpiSetMode()        Sbbi0SetMode(AT45DB_SBBI0_DEVICE, AT45DB_SPI_MODE)
00212 #define SpiSetSpeed()       Sbbi0SetSpeed(AT45DB_SBBI0_DEVICE, AT45DB_SPI_RATE)
00213 #if defined(VS10XX_SELECT_ACTIVE_HIGH)
00214 #define SpiSelect()         Sbbi0SelectDevice(AT45DB_SBBI0_DEVICE)
00215 #define SpiDeselect()       Sbbi0DeselectDevice(AT45DB_SBBI0_DEVICE)
00216 #else
00217 #define SpiSelect()         Sbbi0NegSelectDevice(AT45DB_SBBI0_DEVICE)
00218 #define SpiDeselect()       Sbbi0NegDeselectDevice(AT45DB_SBBI0_DEVICE)
00219 #endif
00220 #define SpiByte             Sbbi0Byte
00221 
00222 #endif
00223 
00227 typedef struct _AT45_DEVTAB {
00228     u_long devt_pages;
00229     u_int devt_pagsiz;
00230     u_int devt_offs;
00231     u_char devt_srmsk;
00232     u_char devt_srval;
00233 } AT45_DEVTAB;
00234 
00238 typedef struct _AT45DB_DCB {
00239     AT45_DEVTAB *dcb_devt;
00240     u_int dcb_spibas;
00241     u_int dcb_spipcs;
00242     u_char dcb_cmdbuf[MAX_AT45_CMDLEN];
00243 } AT45DB_DCB;
00244 
00248 AT45_DEVTAB at45_devt[] = {
00249     {512, 264, 9, 0x3C, 0x0C},  /* AT45DB011B - 128kB */
00250     {1025, 264, 9, 0x3C, 0x14}, /* AT45DB021B - 256kB */
00251     {2048, 264, 9, 0x3C, 0x1C}, /* AT45DB041B - 512kB */
00252     {4096, 264, 9, 0x3C, 0x24}, /* AT45DB081B - 1MB */
00253     {4096, 528, 10, 0x3C, 0x2C},        /* AT45DB0161B - 2MB */
00254     {8192, 528, 10, 0x3C, 0x34},        /* AT45DB0321B - 4MB */
00255     {8192, 1056, 11, 0x38, 0x38},       /* AT45DB0642 - 8MB */
00256     {0, 0, 0, 0, 0}             /* End of table */
00257 };
00258 
00262 static AT45DB_DCB dcbtab[MAX_AT45_DEVICES];
00263 
00264 /* Number of active chips. */
00265 static int dcbnum;
00266 
00267 /* Chip used for parameter storage. */
00268 static int dd_param = -1;
00269 
00281 int At45dbSendCmd(int dd, u_char op, u_long parm, int len, CONST void *tdata, void *rdata, int datalen)
00282 {
00283     u_char *cb = dcbtab[dd].dcb_cmdbuf;
00284 
00285     if (len > MAX_AT45_CMDLEN) {
00286         return -1;
00287     }
00288     memset(cb, 0, len);
00289     cb[0] = op;
00290     if (parm) {
00291         cb[1] = (u_char) (parm >> 16);
00292         cb[2] = (u_char) (parm >> 8);
00293         cb[3] = (u_char) parm;
00294     }
00295     return At91SpiTransfer2(dcbtab[dd].dcb_spibas, dcbtab[dd].dcb_spipcs, cb, cb, len, tdata, rdata, datalen);
00296 }
00297 
00298 u_char At45dbGetStatus(int dd)
00299 {
00300     u_char buf[2] = { DFCMD_READ_STATUS, 0xFF };
00301 
00302     if (At91SpiTransfer2(dcbtab[dd].dcb_spibas, dcbtab[dd].dcb_spipcs, buf, buf, 2, NULL, NULL, 0)) {
00303         return (u_char) - 1;
00304     }
00305     return buf[1];
00306 }
00307 
00313 int At45dbWaitReady(int dd, u_long tmo, int poll)
00314 {
00315     u_char sr;
00316 
00317     while (((sr = At45dbGetStatus(dd)) & 0x80) == 0) {
00318         if (!poll) {
00319             NutSleep(1);
00320         }
00321         if (tmo-- == 0) {
00322             return -1;
00323         }
00324     }
00325     return 0;
00326 }
00327 
00337 int At45dbInit(u_int spibas, u_int spipcs)
00338 {
00339     int dd = -1;
00340     u_char sr;
00341     int i;
00342 
00343     for (i = 0; i < dcbnum; i++) {
00344         if (dcbtab[i].dcb_spibas == spibas && dcbtab[i].dcb_spipcs == spipcs) {
00345             return i;
00346         }
00347     }
00348 
00349     if (dcbnum >= MAX_AT45_DEVICES) {
00350         return -1;
00351     }
00352 
00353 #if defined(MCU_AT91SAM7X256) || defined(MCU_AT91SAM9260)
00354     At91SpiInit(spibas);
00355     At91SpiReset(spibas);
00356     At91SpiInitChipSelects(spibas, _BV(spipcs));
00357     At91SpiSetRate(spibas, spipcs, 1000000);
00358     At91SpiSetModeFlags(spibas, spipcs, SPIMF_MASTER | SPIMF_SCKIAHI | SPIMF_CAPRISE);
00359 #elif defined(MCU_AT91R40008)
00360 #endif
00361 
00362     dcbtab[dcbnum].dcb_spibas = spibas;
00363     dcbtab[dcbnum].dcb_spipcs = spipcs;
00364     sr = At45dbGetStatus(dcbnum);
00365 
00366     for (i = 0; at45_devt[i].devt_pages; i++) {
00367         if ((sr & at45_devt[i].devt_srmsk) == at45_devt[i].devt_srval) {
00368             dcbtab[dcbnum].dcb_devt = &at45_devt[i];
00369             dd = dcbnum++;
00370             break;
00371         }
00372     }
00373     return dd;
00374 }
00375 
00379 int At45dbPageErase(int dd, u_int pgn)
00380 {
00381     pgn <<= dcbtab[dd].dcb_devt->devt_offs;
00382     return At45dbSendCmd(dd, DFCMD_PAGE_ERASE, pgn, 4, NULL, NULL, 0);
00383 }
00384 
00388 int At45dbChipErase(void)
00389 {
00390     return -1;
00391 }
00392 
00403 int At45dbPageRead(int dd, u_long pgn, void *data, u_int len)
00404 {
00405     pgn <<= dcbtab[dd].dcb_devt->devt_offs;
00406     return At45dbSendCmd(dd, DFCMD_CONT_READ, pgn, 8, data, data, len);
00407 }
00408 
00421 int At45dbPageWrite(int dd, u_int pgn, CONST void *data, u_int len)
00422 {
00423     int rc = -1;
00424     void *rp;
00425 
00426     if ((rp = malloc(len)) != NULL) {
00427         /* Copy data to dataflash RAM buffer. */
00428         if (At45dbSendCmd(dd, DFCMD_BUF1_WRITE, 0, 4, data, rp, len) == 0) {
00429             /* Flash RAM buffer. */
00430             pgn <<= dcbtab[dd].dcb_devt->devt_offs;
00431             if (At45dbSendCmd(dd, DFCMD_BUF1_FLASH, pgn, 4, NULL, NULL, 0) == 0) {
00432                 rc = At45dbWaitReady(dd, AT45_WRITE_POLLS, 1);
00433             }
00434         }
00435         free(rp);
00436     }
00437     return rc;
00438 }
00439 
00440 u_long At45dbParamPage(void)
00441 {
00442 #ifdef AT45_CONF_PAGE
00443     return AT45_CONF_PAGE;
00444 #else
00445     return dcbtab[dd_param].dcb_devt->devt_pages - 1;
00446 #endif
00447 }
00448 
00460 int At45dbParamSize(void)
00461 {
00462     int rc;
00463 
00464     if (dd_param == -1 && (dd_param = At45dbInit(AT45_CONF_DFSPI, AT45_CONF_DFPCS)) == -1) {
00465         return -1;
00466     }
00467 #ifdef AT45_CONF_SIZE
00468     rc = AT45_CONF_SIZE;
00469 #else
00470     rc = dcbtab[dd_param].dcb_devt->devt_pagsiz;
00471 #endif
00472     return rc;
00473 }
00474 
00484 int At45dbParamRead(u_int pos, void *data, u_int len)
00485 {
00486     int rc = -1;
00487     u_char *buff;
00488     int csize = At45dbParamSize();
00489     u_long cpage = At45dbParamPage();
00490 
00491     /* Load the complete configuration area. */
00492     if (csize > len && (buff = malloc(csize)) != NULL) {
00493         rc = At45dbPageRead(dd_param, cpage, buff, csize);
00494         /* Copy requested contents to caller's buffer. */
00495         memcpy(data, buff + pos, len);
00496         free(buff);
00497     }
00498     return rc;
00499 }
00500 
00510 int At45dbParamWrite(u_int pos, CONST void *data, u_int len)
00511 {
00512     int rc = -1;
00513     u_char *buff;
00514     int csize = At45dbParamSize();
00515     u_long cpage = At45dbParamPage();
00516 
00517     /* Load the complete configuration area. */
00518     if (csize > len && (buff = malloc(csize)) != NULL) {
00519         rc = At45dbPageRead(dd_param, cpage, buff, csize);
00520         /* Compare old with new contents. */
00521         if (memcmp(buff + pos, data, len)) {
00522             /* New contents differs. Copy it into the sector buffer. */
00523             memcpy(buff + pos, data, len);
00524             /* Erase sector and write new data. */
00525             rc = At45dbPageWrite(dd_param, cpage, buff, csize);
00526         }
00527         free(buff);
00528     }
00529     return rc;
00530 }

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