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