Contiki 2.6
|
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 /*---------------------------------------------------------------------------*/