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