Contiki 2.6

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