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.13 2011/01/18 14:03:55 nvt-se Exp $
00030  */
00031 
00032 /**
00033  * \file
00034  *         Device driver for the ST M25P80 40MHz 1Mbyte external memory.
00035  * \author
00036  *         Björn Grönvall <bg@sics.se>
00037  *
00038  *         Data is written bit inverted (~-operator) to flash so that
00039  *         unwritten data will read as zeros (UNIX style).
00040  */
00041 
00042 #include <stdio.h>
00043 #include <string.h>
00044 
00045 #include <io.h>
00046 #include <signal.h>
00047 
00048 #include "contiki.h"
00049 
00050 #include "dev/spi.h"
00051 #include "dev/xmem.h"
00052 #include "dev/watchdog.h"
00053 
00054 #if 0
00055 #define PRINTF(...) printf(__VA_ARGS__)
00056 #else
00057 #define PRINTF(...) do {} while (0)
00058 #endif
00059 
00060 #define  SPI_FLASH_INS_WREN        0x06
00061 #define  SPI_FLASH_INS_WRDI        0x04
00062 #define  SPI_FLASH_INS_RDSR        0x05
00063 #define  SPI_FLASH_INS_WRSR        0x01
00064 #define  SPI_FLASH_INS_READ        0x03
00065 #define  SPI_FLASH_INS_FAST_READ   0x0b
00066 #define  SPI_FLASH_INS_PP          0x02
00067 #define  SPI_FLASH_INS_SE          0xd8
00068 #define  SPI_FLASH_INS_BE          0xc7
00069 #define  SPI_FLASH_INS_DP          0xb9
00070 #define  SPI_FLASH_INS_RES         0xab
00071 /*---------------------------------------------------------------------------*/
00072 static void
00073 write_enable(void)
00074 {
00075   int s;
00076 
00077   s = splhigh();
00078   SPI_FLASH_ENABLE();
00079   
00080   SPI_WRITE(SPI_FLASH_INS_WREN);
00081 
00082   SPI_FLASH_DISABLE();
00083   splx(s);
00084 }
00085 /*---------------------------------------------------------------------------*/
00086 static unsigned
00087 read_status_register(void)
00088 {
00089   unsigned char u;
00090 
00091   int s;
00092 
00093   s = splhigh();
00094   SPI_FLASH_ENABLE();
00095   
00096   SPI_WRITE(SPI_FLASH_INS_RDSR);
00097 
00098   SPI_FLUSH();
00099   SPI_READ(u);
00100 
00101   SPI_FLASH_DISABLE();
00102   splx(s);
00103 
00104   return u;
00105 }
00106 /*---------------------------------------------------------------------------*/
00107 /*
00108  * Wait for a write/erase operation to finish.
00109  */
00110 static unsigned
00111 wait_ready(void)
00112 {
00113   unsigned u;
00114   do {
00115     u = read_status_register();
00116     watchdog_periodic();
00117   } while(u & 0x01);            /* WIP=1, write in progress */
00118   return u;
00119 }
00120 /*---------------------------------------------------------------------------*/
00121 /*
00122  * Erase 64k bytes of data. It takes about 1s before WIP goes low!
00123  */
00124 static void
00125 erase_sector(unsigned long offset)
00126 {
00127   int s;
00128 
00129   wait_ready();
00130   write_enable();
00131 
00132   s = splhigh();
00133   SPI_FLASH_ENABLE();
00134   
00135   SPI_WRITE_FAST(SPI_FLASH_INS_SE);
00136   SPI_WRITE_FAST(offset >> 16); /* MSB */
00137   SPI_WRITE_FAST(offset >> 8);
00138   SPI_WRITE_FAST(offset >> 0);  /* LSB */
00139   SPI_WAITFORTx_ENDED();
00140 
00141   SPI_FLASH_DISABLE();
00142   splx(s);
00143 }
00144 /*---------------------------------------------------------------------------*/
00145 /*
00146  * Initialize external flash *and* SPI bus!
00147  */
00148 void
00149 xmem_init(void)
00150 {
00151   int s;
00152   spi_init();
00153 
00154   P4DIR |= BV(FLASH_CS) | BV(FLASH_HOLD) | BV(FLASH_PWR);
00155   P4OUT |= BV(FLASH_PWR);       /* P4.3 Output, turn on power! */
00156 
00157   /* Release from Deep Power-down */
00158   s = splhigh();
00159   SPI_FLASH_ENABLE();
00160   SPI_WRITE_FAST(SPI_FLASH_INS_RES);
00161   SPI_WAITFORTx_ENDED();
00162   SPI_FLASH_DISABLE();          /* Unselect flash. */
00163   splx(s);
00164 
00165   SPI_FLASH_UNHOLD();
00166 }
00167 /*---------------------------------------------------------------------------*/
00168 int
00169 xmem_pread(void *_p, int size, unsigned long offset)
00170 {
00171   unsigned char *p = _p;
00172   const unsigned char *end = p + size;
00173   int s;
00174 
00175   wait_ready();
00176 
00177   ENERGEST_ON(ENERGEST_TYPE_FLASH_READ);
00178 
00179   s = splhigh();
00180   SPI_FLASH_ENABLE();
00181 
00182   SPI_WRITE_FAST(SPI_FLASH_INS_READ);
00183   SPI_WRITE_FAST(offset >> 16); /* MSB */
00184   SPI_WRITE_FAST(offset >> 8);
00185   SPI_WRITE_FAST(offset >> 0);  /* LSB */
00186   SPI_WAITFORTx_ENDED();
00187   
00188   SPI_FLUSH();
00189   for(; p < end; p++) {
00190     unsigned char u;
00191     SPI_READ(u);
00192     *p = ~u;
00193   }
00194 
00195   SPI_FLASH_DISABLE();
00196   splx(s);
00197 
00198   ENERGEST_OFF(ENERGEST_TYPE_FLASH_READ);
00199 
00200   return size;
00201 }
00202 /*---------------------------------------------------------------------------*/
00203 static const unsigned char *
00204 program_page(unsigned long offset, const unsigned char *p, int nbytes)
00205 {
00206   const unsigned char *end = p + nbytes;
00207   int s;
00208 
00209   wait_ready();
00210   write_enable();
00211 
00212   s = splhigh();
00213   SPI_FLASH_ENABLE();
00214   
00215   SPI_WRITE_FAST(SPI_FLASH_INS_PP);
00216   SPI_WRITE_FAST(offset >> 16); /* MSB */
00217   SPI_WRITE_FAST(offset >> 8);
00218   SPI_WRITE_FAST(offset >> 0);  /* LSB */
00219 
00220   for(; p < end; p++) {
00221     SPI_WRITE_FAST(~*p);
00222   }
00223   SPI_WAITFORTx_ENDED();
00224 
00225   SPI_FLASH_DISABLE();
00226   splx(s);
00227 
00228   return p;
00229 }
00230 /*---------------------------------------------------------------------------*/
00231 int
00232 xmem_pwrite(const void *_buf, int size, unsigned long addr)
00233 {
00234   const unsigned char *p = _buf;
00235   const unsigned long end = addr + size;
00236   unsigned long i, next_page;
00237 
00238   ENERGEST_ON(ENERGEST_TYPE_FLASH_WRITE);
00239 
00240   for(i = addr; i < end;) {
00241     next_page = (i | 0xff) + 1;
00242     if(next_page > end) {
00243       next_page = end;
00244     }
00245     p = program_page(i, p, next_page - i);
00246     i = next_page;
00247   }
00248 
00249   ENERGEST_OFF(ENERGEST_TYPE_FLASH_WRITE);
00250 
00251   return size;
00252 }
00253 /*---------------------------------------------------------------------------*/
00254 int
00255 xmem_erase(long size, unsigned long addr)
00256 {
00257   unsigned long end = addr + size;
00258 
00259   if(size % XMEM_ERASE_UNIT_SIZE != 0) {
00260     PRINTF("xmem_erase: bad size\n");
00261     return -1;
00262   }
00263 
00264   if(addr % XMEM_ERASE_UNIT_SIZE != 0) {
00265     PRINTF("xmem_erase: bad offset\n");
00266     return -1;
00267   }
00268 
00269   for (; addr < end; addr += XMEM_ERASE_UNIT_SIZE) {
00270     erase_sector(addr);
00271   }
00272 
00273   return size;
00274 }
00275 /*---------------------------------------------------------------------------*/

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