Contiki 2.5
xmem.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2006, Swedish Institute of Computer Science
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * @(#)$Id: xmem.c,v 1.13 2011/01/18 14:03:55 nvt-se Exp $
30  */
31 
32 /**
33  * \file
34  * Device driver for the ST M25P80 40MHz 1Mbyte external memory.
35  * \author
36  * Björn Grönvall <bg@sics.se>
37  *
38  * Data is written bit inverted (~-operator) to flash so that
39  * unwritten data will read as zeros (UNIX style).
40  */
41 
42 
43 #include "contiki.h"
44 #include <stdio.h>
45 #include <string.h>
46 
47 #include "dev/spi.h"
48 #include "dev/xmem.h"
49 #include "dev/watchdog.h"
50 
51 #if 0
52 #define PRINTF(...) printf(__VA_ARGS__)
53 #else
54 #define PRINTF(...) do {} while (0)
55 #endif
56 
57 #define SPI_FLASH_INS_WREN 0x06
58 #define SPI_FLASH_INS_WRDI 0x04
59 #define SPI_FLASH_INS_RDSR 0x05
60 #define SPI_FLASH_INS_WRSR 0x01
61 #define SPI_FLASH_INS_READ 0x03
62 #define SPI_FLASH_INS_FAST_READ 0x0b
63 #define SPI_FLASH_INS_PP 0x02
64 #define SPI_FLASH_INS_SE 0xd8
65 #define SPI_FLASH_INS_BE 0xc7
66 #define SPI_FLASH_INS_DP 0xb9
67 #define SPI_FLASH_INS_RES 0xab
68 /*---------------------------------------------------------------------------*/
69 static void
70 write_enable(void)
71 {
72  int s;
73 
74  s = splhigh();
75  SPI_FLASH_ENABLE();
76 
77  SPI_WRITE(SPI_FLASH_INS_WREN);
78 
79  SPI_FLASH_DISABLE();
80  splx(s);
81 }
82 /*---------------------------------------------------------------------------*/
83 static unsigned
84 read_status_register(void)
85 {
86  unsigned char u;
87 
88  int s;
89 
90  s = splhigh();
91  SPI_FLASH_ENABLE();
92 
93  SPI_WRITE(SPI_FLASH_INS_RDSR);
94 
95  SPI_FLUSH();
96  SPI_READ(u);
97 
98  SPI_FLASH_DISABLE();
99  splx(s);
100 
101  return u;
102 }
103 /*---------------------------------------------------------------------------*/
104 /*
105  * Wait for a write/erase operation to finish.
106  */
107 static unsigned
108 wait_ready(void)
109 {
110  unsigned u;
111  do {
112  u = read_status_register();
113  watchdog_periodic();
114  } while(u & 0x01); /* WIP=1, write in progress */
115  return u;
116 }
117 /*---------------------------------------------------------------------------*/
118 /*
119  * Erase 64k bytes of data. It takes about 1s before WIP goes low!
120  */
121 static void
122 erase_sector(unsigned long offset)
123 {
124  int s;
125 
126  wait_ready();
127  write_enable();
128 
129  s = splhigh();
130  SPI_FLASH_ENABLE();
131 
132  SPI_WRITE_FAST(SPI_FLASH_INS_SE);
133  SPI_WRITE_FAST(offset >> 16); /* MSB */
134  SPI_WRITE_FAST(offset >> 8);
135  SPI_WRITE_FAST(offset >> 0); /* LSB */
136  SPI_WAITFORTx_ENDED();
137 
138  SPI_FLASH_DISABLE();
139  splx(s);
140 }
141 /*---------------------------------------------------------------------------*/
142 /*
143  * Initialize external flash *and* SPI bus!
144  */
145 void
146 xmem_init(void)
147 {
148  int s;
149  spi_init();
150 
151  P4DIR |= BV(FLASH_CS) | BV(FLASH_HOLD) | BV(FLASH_PWR);
152  P4OUT |= BV(FLASH_PWR); /* P4.3 Output, turn on power! */
153 
154  /* Release from Deep Power-down */
155  s = splhigh();
156  SPI_FLASH_ENABLE();
157  SPI_WRITE_FAST(SPI_FLASH_INS_RES);
158  SPI_WAITFORTx_ENDED();
159  SPI_FLASH_DISABLE(); /* Unselect flash. */
160  splx(s);
161 
162  SPI_FLASH_UNHOLD();
163 }
164 /*---------------------------------------------------------------------------*/
165 int
166 xmem_pread(void *_p, int size, unsigned long offset)
167 {
168  unsigned char *p = _p;
169  const unsigned char *end = p + size;
170  int s;
171 
172  wait_ready();
173 
174  ENERGEST_ON(ENERGEST_TYPE_FLASH_READ);
175 
176  s = splhigh();
177  SPI_FLASH_ENABLE();
178 
179  SPI_WRITE_FAST(SPI_FLASH_INS_READ);
180  SPI_WRITE_FAST(offset >> 16); /* MSB */
181  SPI_WRITE_FAST(offset >> 8);
182  SPI_WRITE_FAST(offset >> 0); /* LSB */
183  SPI_WAITFORTx_ENDED();
184 
185  SPI_FLUSH();
186  for(; p < end; p++) {
187  unsigned char u;
188  SPI_READ(u);
189  *p = ~u;
190  }
191 
192  SPI_FLASH_DISABLE();
193  splx(s);
194 
195  ENERGEST_OFF(ENERGEST_TYPE_FLASH_READ);
196 
197  return size;
198 }
199 /*---------------------------------------------------------------------------*/
200 static const unsigned char *
201 program_page(unsigned long offset, const unsigned char *p, int nbytes)
202 {
203  const unsigned char *end = p + nbytes;
204  int s;
205 
206  wait_ready();
207  write_enable();
208 
209  s = splhigh();
210  SPI_FLASH_ENABLE();
211 
212  SPI_WRITE_FAST(SPI_FLASH_INS_PP);
213  SPI_WRITE_FAST(offset >> 16); /* MSB */
214  SPI_WRITE_FAST(offset >> 8);
215  SPI_WRITE_FAST(offset >> 0); /* LSB */
216 
217  for(; p < end; p++) {
218  SPI_WRITE_FAST(~*p);
219  }
220  SPI_WAITFORTx_ENDED();
221 
222  SPI_FLASH_DISABLE();
223  splx(s);
224 
225  return p;
226 }
227 /*---------------------------------------------------------------------------*/
228 int
229 xmem_pwrite(const void *_buf, int size, unsigned long addr)
230 {
231  const unsigned char *p = _buf;
232  const unsigned long end = addr + size;
233  unsigned long i, next_page;
234 
235  ENERGEST_ON(ENERGEST_TYPE_FLASH_WRITE);
236 
237  for(i = addr; i < end;) {
238  next_page = (i | 0xff) + 1;
239  if(next_page > end) {
240  next_page = end;
241  }
242  p = program_page(i, p, next_page - i);
243  i = next_page;
244  }
245 
246  ENERGEST_OFF(ENERGEST_TYPE_FLASH_WRITE);
247 
248  return size;
249 }
250 /*---------------------------------------------------------------------------*/
251 int
252 xmem_erase(long size, unsigned long addr)
253 {
254  unsigned long end = addr + size;
255 
256  if(size % XMEM_ERASE_UNIT_SIZE != 0) {
257  PRINTF("xmem_erase: bad size\n");
258  return -1;
259  }
260 
261  if(addr % XMEM_ERASE_UNIT_SIZE != 0) {
262  PRINTF("xmem_erase: bad offset\n");
263  return -1;
264  }
265 
266  for (; addr < end; addr += XMEM_ERASE_UNIT_SIZE) {
267  erase_sector(addr);
268  }
269 
270  return size;
271 }
272 /*---------------------------------------------------------------------------*/