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 
00078 #include <cfg/os.h>
00079 #include <cfg/memory.h>
00080 
00081 #include <sys/timer.h>
00082 
00083 #include <string.h>
00084 #include <stdlib.h>
00085 
00086 #include <dev/at91_spi.h>
00087 #include <dev/at45db.h>
00088 
00089 #ifndef MAX_AT45_DEVICES
00090 #define MAX_AT45_DEVICES        1
00091 #endif
00092 
00093 #ifndef MAX_AT45_CMDLEN
00094 #define MAX_AT45_CMDLEN         8
00095 #endif
00096 
00097 #ifndef AT45_CONF_DFSPI
00098 #define AT45_CONF_DFSPI         SPI0_BASE
00099 #endif
00100 
00101 #ifndef AT45_CONF_DFPCS
00102 #define AT45_CONF_DFPCS         1
00103 #endif
00104 
00105 #ifndef AT45_ERASE_WAIT
00106 #define AT45_ERASE_WAIT         3000
00107 #endif
00108 
00109 #ifndef AT45_CHIP_ERASE_WAIT
00110 #define AT45_CHIP_ERASE_WAIT    50000
00111 #endif
00112 
00113 #ifndef AT45_WRITE_POLLS
00114 #define AT45_WRITE_POLLS        1000
00115 #endif
00116 
00127 #define DFCMD_CONT_READ_LF      0x03
00128 
00134 #define DFCMD_CONT_READ_HF      0x0B
00135 
00137 #define DFCMD_BLOCK_ERASE       0x50
00138 
00140 #define DFCMD_SECTOR_ERASE      0x7C
00141 
00143 #define DFCMD_PAGE_ERASE        0x81
00144 
00146 #define DFCMD_BUF1_PROG         0x82
00147 
00149 #define DFCMD_BUF1_FLASH        0x83
00150 
00152 #define DFCMD_BUF1_WRITE        0x84
00153 
00155 #define DFCMD_BUF2_PROG         0x85
00156 
00158 #define DFCMD_BUF2_FLASH        0x86
00159 
00161 #define DFCMD_BUF2_WRITE        0x87
00162 
00164 #define DFCMD_BUF1_FLASH_NE     0x88
00165 
00167 #define DFCMD_BUF2_FLASH_NE     0x89
00168 
00170 #define DFCMD_CHIP_ERASE        0xC7
00171 
00173 #define DFCMD_BUF1_READ_LF      0xD1
00174 
00179 #define DFCMD_READ_PAGE         0xD2
00180 
00182 #define DFCMD_BUF2_READ_LF      0xD3
00183 
00185 #define DFCMD_BUF1_READ         0xD4
00186 
00188 #define DFCMD_BUF2_READ         0xD6
00189 
00191 #define DFCMD_READ_STATUS       0xD7
00192 
00198 #define DFCMD_CONT_READ         0xE8
00199 
00201 #define AT45DB_AT91
00202 
00203 
00204 #if defined(AT45DB_SPI0_DEVICE)
00205 
00206 #include <dev/sppif0.h>
00207 #if defined(AT45DB_RESET_ACTIVE_HIGH)
00208 #define SpiReset(act)       Sppi0ChipReset(AT45DB_SPI0_DEVICE, act)
00209 #else
00210 #define SpiReset(act)       Sppi0ChipReset(AT45DB_SPI0_DEVICE, !act)
00211 #endif
00212 #define SpiSetMode()        Sppi0SetMode(AT45DB_SPI0_DEVICE, AT45DB_SPI_MODE)
00213 #define SpiSetSpeed()       Sppi0SetSpeed(AT45DB_SPI0_DEVICE, AT45DB_SPI_RATE)
00214 #if defined(AT45DB_SELECT_ACTIVE_HIGH)
00215 #define SpiSelect()         Sppi0SelectDevice(AT45DB_SPI0_DEVICE)
00216 #define SpiDeselect()       Sppi0DeselectDevice(AT45DB_SPI0_DEVICE)
00217 #else
00218 #define SpiSelect()         Sppi0NegSelectDevice(AT45DB_SPI0_DEVICE)
00219 #define SpiDeselect()       Sppi0NegDeselectDevice(AT45DB_SPI0_DEVICE)
00220 #endif
00221 #define SpiByte             Sppi0Byte
00222 
00223 #elif defined(AT45DB_SBBI0_DEVICE)
00224 
00225 #include <dev/sbbif0.h>
00226 #if defined(AT45DB_RESET_ACTIVE_HIGH)
00227 #define SpiReset(act)       Sbbi0ChipReset(AT45DB_SBBI0_DEVICE, act)
00228 #else
00229 #define SpiReset(act)       Sbbi0ChipReset(AT45DB_SBBI0_DEVICE, !act)
00230 #endif
00231 #define SpiSetMode()        Sbbi0SetMode(AT45DB_SBBI0_DEVICE, AT45DB_SPI_MODE)
00232 #define SpiSetSpeed()       Sbbi0SetSpeed(AT45DB_SBBI0_DEVICE, AT45DB_SPI_RATE)
00233 #if defined(AT45DB_SELECT_ACTIVE_HIGH)
00234 #define SpiSelect()         Sbbi0SelectDevice(AT45DB_SBBI0_DEVICE)
00235 #define SpiDeselect()       Sbbi0DeselectDevice(AT45DB_SBBI0_DEVICE)
00236 #else
00237 #define SpiSelect()         Sbbi0NegSelectDevice(AT45DB_SBBI0_DEVICE)
00238 #define SpiDeselect()       Sbbi0NegDeselectDevice(AT45DB_SBBI0_DEVICE)
00239 #endif
00240 #define SpiByte             Sbbi0Byte
00241 
00242 #endif
00243 
00247 typedef struct _AT45_DEVTAB {
00248     uint32_t devt_pages;
00249     unsigned int devt_pagsiz;
00250     unsigned int devt_offs;
00251     uint8_t devt_srmsk;
00252     uint8_t devt_srval;
00253 } AT45_DEVTAB;
00254 
00258 typedef struct _AT45DB_DCB {
00259     AT45_DEVTAB *dcb_devt;
00260     unsigned int dcb_spibas;
00261     unsigned int dcb_spipcs;
00262     uint8_t dcb_cmdbuf[MAX_AT45_CMDLEN];
00263 } AT45DB_DCB;
00264 
00268 AT45_DEVTAB at45_devt[] = {
00269     {512, 264, 9, 0x3C, 0x0C},  /* AT45DB011B - 128kB */
00270     {1025, 264, 9, 0x3C, 0x14}, /* AT45DB021B - 256kB */
00271     {2048, 264, 9, 0x3C, 0x1C}, /* AT45DB041B - 512kB */
00272     {4096, 264, 9, 0x3C, 0x24}, /* AT45DB081B - 1MB */
00273     {4096, 528, 10, 0x3C, 0x2C},        /* AT45DB0161B - 2MB */
00274     {8192, 528, 10, 0x3C, 0x34},        /* AT45DB0321B - 4MB */
00275     {8192, 1056, 11, 0x38, 0x38},       /* AT45DB0642 - 8MB */
00276     {0, 0, 0, 0, 0}             /* End of table */
00277 };
00278 
00282 static AT45DB_DCB dcbtab[MAX_AT45_DEVICES];
00283 
00284 /* Number of active chips. */
00285 static uint_least8_t dcbnum;
00286 
00287 /* Chip used for parameter storage. */
00288 static int dd_param = -1;
00289 
00301 int At45dbSendCmd(int dd, uint8_t op, uint32_t parm, int len, CONST void *tdata, void *rdata, int datalen)
00302 {
00303     uint8_t *cb = dcbtab[dd].dcb_cmdbuf;
00304 
00305     if (len > MAX_AT45_CMDLEN) {
00306         return -1;
00307     }
00308     memset(cb, 0, len);
00309     cb[0] = op;
00310     if (parm) {
00311         cb[1] = (uint8_t) (parm >> 16);
00312         cb[2] = (uint8_t) (parm >> 8);
00313         cb[3] = (uint8_t) parm;
00314     }
00315     return At91SpiTransfer2(dcbtab[dd].dcb_spibas, dcbtab[dd].dcb_spipcs, cb, cb, len, tdata, rdata, datalen);
00316 }
00317 
00318 uint8_t At45dbGetStatus(int dd)
00319 {
00320     uint8_t buf[2] = { DFCMD_READ_STATUS, 0xFF };
00321 
00322     if (At91SpiTransfer2(dcbtab[dd].dcb_spibas, dcbtab[dd].dcb_spipcs, buf, buf, 2, NULL, NULL, 0)) {
00323         return (uint8_t) - 1;
00324     }
00325     return buf[1];
00326 }
00327 
00333 int At45dbWaitReady(int dd, uint32_t tmo, int poll)
00334 {
00335     uint8_t sr;
00336 
00337     while (((sr = At45dbGetStatus(dd)) & 0x80) == 0) {
00338         if (!poll) {
00339             NutSleep(1);
00340         }
00341         if (tmo-- == 0) {
00342             return -1;
00343         }
00344     }
00345     return 0;
00346 }
00347 
00357 int At45dbInit(unsigned int spibas, unsigned int spipcs)
00358 {
00359     int dd = -1;
00360     uint8_t sr;
00361     uint_fast8_t i;
00362 
00363     for (i = 0; i < dcbnum; i++) {
00364         if (dcbtab[i].dcb_spibas == spibas && dcbtab[i].dcb_spipcs == spipcs) {
00365             return i;
00366         }
00367     }
00368 
00369     if (dcbnum >= MAX_AT45_DEVICES) {
00370         return -1;
00371     }
00372 
00373 #if defined(MCU_AT91SAM7X) || defined(MCU_AT91SAM7SE) || defined(MCU_AT91SAM9260) || defined(MCU_AT91SAM9XE)
00374     At91SpiInit(spibas);
00375     At91SpiReset(spibas);
00376     At91SpiInitChipSelects(spibas, _BV(spipcs));
00377     At91SpiSetRate(spibas, spipcs, 1000000);
00378     At91SpiSetModeFlags(spibas, spipcs, SPIMF_MASTER | SPIMF_SCKIAHI | SPIMF_CAPRISE);
00379 #elif defined(MCU_AT91R40008)
00380 #endif
00381 
00382     dcbtab[dcbnum].dcb_spibas = spibas;
00383     dcbtab[dcbnum].dcb_spipcs = spipcs;
00384     sr = At45dbGetStatus(dcbnum);
00385 
00386     for (i = 0; at45_devt[i].devt_pages; i++) {
00387         if ((sr & at45_devt[i].devt_srmsk) == at45_devt[i].devt_srval) {
00388             dcbtab[dcbnum].dcb_devt = &at45_devt[i];
00389             dd = dcbnum++;
00390             break;
00391         }
00392     }
00393     return dd;
00394 }
00395 
00399 int At45dbPageErase(int dd, uint32_t pgn)
00400 {
00401     pgn <<= dcbtab[dd].dcb_devt->devt_offs;
00402     return At45dbSendCmd(dd, DFCMD_PAGE_ERASE, pgn, 4, NULL, NULL, 0);
00403 }
00404 
00408 int At45dbChipErase(void)
00409 {
00410     return -1;
00411 }
00412 
00423 int At45dbPageRead(int dd, uint32_t pgn, void *data, unsigned int len)
00424 {
00425     pgn <<= dcbtab[dd].dcb_devt->devt_offs;
00426     return At45dbSendCmd(dd, DFCMD_CONT_READ, pgn, 8, data, data, len);
00427 }
00428 
00441 int At45dbPageWrite(int dd, uint32_t pgn, CONST void *data, unsigned int len)
00442 {
00443     int rc = -1;
00444     void *rp;
00445 
00446     if ((rp = malloc(len)) != NULL) {
00447         /* Copy data to dataflash RAM buffer. */
00448         if (At45dbSendCmd(dd, DFCMD_BUF1_WRITE, 0, 4, data, rp, len) == 0) {
00449             /* Flash RAM buffer. */
00450             pgn <<= dcbtab[dd].dcb_devt->devt_offs;
00451             if (At45dbSendCmd(dd, DFCMD_BUF1_FLASH, pgn, 4, NULL, NULL, 0) == 0) {
00452                 rc = At45dbWaitReady(dd, AT45_WRITE_POLLS, 1);
00453             }
00454         }
00455         free(rp);
00456     }
00457     return rc;
00458 }
00459 
00460 uint32_t At45dbPages(int dd)
00461 {
00462     return dcbtab[dd].dcb_devt->devt_pages;
00463 }
00464 
00465 unsigned int At45dbPageSize(int dd)
00466 {
00467     return dcbtab[dd].dcb_devt->devt_pagsiz;
00468 }
00469 
00470 uint32_t At45dbParamPage(void)
00471 {
00472 #ifdef AT45_CONF_PAGE
00473     return AT45_CONF_PAGE;
00474 #else
00475     return dcbtab[dd_param].dcb_devt->devt_pages - 1;
00476 #endif
00477 }
00478 
00490 int At45dbParamSize(void)
00491 {
00492     int rc;
00493 
00494     if (dd_param == -1 && (dd_param = At45dbInit(AT45_CONF_DFSPI, AT45_CONF_DFPCS)) == -1) {
00495         return -1;
00496     }
00497 #ifdef AT45_CONF_SIZE
00498     rc = AT45_CONF_SIZE;
00499 #else
00500     rc = dcbtab[dd_param].dcb_devt->devt_pagsiz;
00501 #endif
00502     return rc;
00503 }
00504 
00514 int At45dbParamRead(unsigned int pos, void *data, unsigned int len)
00515 {
00516     int rc = -1;
00517     uint8_t *buff;
00518     int csize = At45dbParamSize();
00519     uint32_t cpage = At45dbParamPage();
00520 
00521     /* Load the complete configuration area. */
00522     if (csize > len && (buff = malloc(csize)) != NULL) {
00523         rc = At45dbPageRead(dd_param, cpage, buff, csize);
00524         /* Copy requested contents to caller's buffer. */
00525         memcpy(data, buff + pos, len);
00526         free(buff);
00527     }
00528     return rc;
00529 }
00530 
00540 int At45dbParamWrite(unsigned int pos, CONST void *data, unsigned int len)
00541 {
00542     int rc = -1;
00543     uint8_t *buff;
00544     int csize = At45dbParamSize();
00545     uint32_t cpage = At45dbParamPage();
00546 
00547     /* Load the complete configuration area. */
00548     if (csize > len && (buff = malloc(csize)) != NULL) {
00549         rc = At45dbPageRead(dd_param, cpage, buff, csize);
00550         /* Compare old with new contents. */
00551         if (memcmp(buff + pos, data, len)) {
00552             /* New contents differs. Copy it into the sector buffer. */
00553             memcpy(buff + pos, data, len);
00554             /* Erase sector and write new data. */
00555             rc = At45dbPageWrite(dd_param, cpage, buff, csize);
00556         }
00557         free(buff);
00558     }
00559     return rc;
00560 }

© 2000-2010 by contributors - visit http://www.ethernut.de/