xmem.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2006, Swedish Institute of Computer Science
00003  * 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  * 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 Institute nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  *
00029  * @(#)$Id: xmem.c,v 1.2 2011/01/18 15:48:38 nifi Exp $
00030  */
00031 
00032 /**
00033  * \file
00034  *         Device driver for the ST M25P16 40MHz 1Mbyte external memory.
00035  * \author
00036  *         Björn Grönvall <bg@sics.se>
00037  *         Enric M. Calvo <ecalvo@zolertia.com>
00038  *
00039  *         Data is written bit inverted (~-operator) to flash so that
00040  *         unwritten data will read as zeros (UNIX style).
00041  */
00042 
00043 #include <stdio.h>
00044 #include <string.h>
00045 
00046 #include <io.h>
00047 #include <signal.h>
00048 
00049 #include "contiki.h"
00050 
00051 #include "dev/spi.h"
00052 #include "dev/xmem.h"
00053 #include "dev/watchdog.h"
00054 
00055 #if 1
00056 #define PRINTF(...) printf(__VA_ARGS__)
00057 #else
00058 #define PRINTF(...) do {} while (0)
00059 #endif
00060 
00061 #define  SPI_FLASH_INS_WREN        0x06
00062 #define  SPI_FLASH_INS_WRDI        0x04
00063 #define  SPI_FLASH_INS_RDSR        0x05
00064 #define  SPI_FLASH_INS_WRSR        0x01
00065 #define  SPI_FLASH_INS_READ        0x03
00066 #define  SPI_FLASH_INS_FAST_READ   0x0b
00067 #define  SPI_FLASH_INS_PP          0x02
00068 #define  SPI_FLASH_INS_SE          0xd8
00069 #define  SPI_FLASH_INS_BE          0xc7
00070 #define  SPI_FLASH_INS_DP          0xb9
00071 #define  SPI_FLASH_INS_RES         0xab
00072 /*---------------------------------------------------------------------------*/
00073 static void
00074 write_enable(void)
00075 {
00076   int s;
00077 
00078   s = splhigh();
00079   SPI_FLASH_ENABLE();
00080   
00081   SPI_WRITE(SPI_FLASH_INS_WREN);
00082 
00083   SPI_FLASH_DISABLE();
00084   splx(s);
00085 }
00086 /*---------------------------------------------------------------------------*/
00087 static unsigned
00088 read_status_register(void)
00089 {
00090   unsigned char u;
00091 
00092   int s;
00093 
00094   s = splhigh();
00095   SPI_FLASH_ENABLE();
00096   
00097 
00098   SPI_WRITE(SPI_FLASH_INS_RDSR);
00099 
00100   SPI_FLUSH();
00101   SPI_READ(u);
00102 
00103   SPI_FLASH_DISABLE();
00104   splx(s);
00105 
00106   return u;
00107 }
00108 /*---------------------------------------------------------------------------*/
00109 /*
00110  * Wait for a write/erase operation to finish.
00111  */
00112 static unsigned
00113 wait_ready(void)
00114 {
00115   unsigned u;
00116   do {
00117     u = read_status_register();
00118     watchdog_periodic();
00119   } while(u & 0x01);            /* WIP=1, write in progress */
00120   return u;
00121 }
00122 /*---------------------------------------------------------------------------*/
00123 /*
00124  * Erase 64k bytes of data. It takes about 1s before WIP goes low!
00125  */
00126 static void
00127 erase_sector(unsigned long offset)
00128 {
00129   int s;
00130   wait_ready();
00131 
00132   write_enable();
00133 
00134   s = splhigh();
00135   SPI_FLASH_ENABLE();
00136   
00137   SPI_WRITE_FAST(SPI_FLASH_INS_SE);
00138   SPI_WRITE_FAST(offset >> 16); /* MSB */
00139   SPI_WRITE_FAST(offset >> 8);
00140   SPI_WRITE_FAST(offset >> 0);  /* LSB */
00141   SPI_WAITFORTx_ENDED();
00142 
00143   SPI_FLASH_DISABLE();
00144   splx(s);
00145 }
00146 /*---------------------------------------------------------------------------*/
00147 /*
00148  * Initialize external flash *and* SPI bus!
00149  */
00150 void
00151 xmem_init(void)
00152 {
00153   spi_init();
00154 
00155   P4DIR |= BV(FLASH_CS);   // Unnecessary for Zolertia Z1  | BV(FLASH_PWR);
00156   P5DIR |= BV(FLASH_HOLD); // In P5 for Z1
00157 
00158   SPI_FLASH_DISABLE();          /* Unselect flash. */
00159   SPI_FLASH_UNHOLD();
00160 }
00161 /*---------------------------------------------------------------------------*/
00162 int
00163 xmem_pread(void *_p, int size, unsigned long offset)
00164 {
00165   unsigned char *p = _p;
00166   const unsigned char *end = p + size;
00167   int s;
00168   wait_ready();
00169 
00170   ENERGEST_ON(ENERGEST_TYPE_FLASH_READ);
00171 
00172   s = splhigh();
00173   SPI_FLASH_ENABLE();
00174 
00175   SPI_WRITE_FAST(SPI_FLASH_INS_READ);
00176   SPI_WRITE_FAST(offset >> 16); /* MSB */
00177   SPI_WRITE_FAST(offset >> 8);
00178   SPI_WRITE_FAST(offset >> 0);  /* LSB */
00179   SPI_WAITFORTx_ENDED();
00180   
00181   SPI_FLUSH();
00182   for(; p < end; p++) {
00183     unsigned char u;
00184     SPI_READ(u);
00185     *p = ~u;
00186   }
00187 
00188   SPI_FLASH_DISABLE();
00189   splx(s);
00190 
00191   ENERGEST_OFF(ENERGEST_TYPE_FLASH_READ);
00192 
00193   return size;
00194 }
00195 /*---------------------------------------------------------------------------*/
00196 static const char *
00197 program_page(unsigned long offset, const unsigned char *p, int nbytes)
00198 {
00199   const unsigned char *end = p + nbytes;
00200   int s;
00201 
00202   wait_ready();
00203 
00204   write_enable();
00205 
00206   s = splhigh();
00207   SPI_FLASH_ENABLE();
00208   
00209   SPI_WRITE_FAST(SPI_FLASH_INS_PP);
00210   SPI_WRITE_FAST(offset >> 16); /* MSB */
00211   SPI_WRITE_FAST(offset >> 8);
00212   SPI_WRITE_FAST(offset >> 0);  /* LSB */
00213 
00214   for(; p < end; p++) {
00215     SPI_WRITE_FAST(~*p);
00216   }
00217   SPI_WAITFORTx_ENDED();
00218 
00219   SPI_FLASH_DISABLE();
00220   splx(s);
00221 
00222   return p;
00223 }
00224 /*---------------------------------------------------------------------------*/
00225 int
00226 xmem_pwrite(const void *_buf, int size, unsigned long addr)
00227 {
00228   const unsigned char *p = _buf;
00229   const unsigned long end = addr + size;
00230   unsigned long i, next_page;
00231 
00232   ENERGEST_ON(ENERGEST_TYPE_FLASH_WRITE);
00233   
00234   for(i = addr; i < end;) {
00235     next_page = (i | 0xff) + 1;
00236     if(next_page > end) {
00237       next_page = end;
00238     }
00239     p = program_page(i, p, next_page - i);
00240     i = next_page;
00241   }
00242 
00243   ENERGEST_OFF(ENERGEST_TYPE_FLASH_WRITE);
00244 
00245   return size;
00246 }
00247 /*---------------------------------------------------------------------------*/
00248 int
00249 xmem_erase(long size, unsigned long addr)
00250 {
00251   unsigned long end = addr + size;
00252 
00253   if(size % XMEM_ERASE_UNIT_SIZE != 0) {
00254     PRINTF("xmem_erase: bad size\n");
00255     return -1;
00256   }
00257 
00258   if(addr % XMEM_ERASE_UNIT_SIZE != 0) {
00259     PRINTF("xmem_erase: bad offset\n");
00260     return -1;
00261   }
00262 
00263   for (; addr < end; addr += XMEM_ERASE_UNIT_SIZE) {
00264     erase_sector(addr);
00265   }
00266 
00267   return size;
00268 }
00269 /*---------------------------------------------------------------------------*/

Generated on Mon Apr 11 14:23:43 2011 for Contiki 2.5 by  doxygen 1.6.1