Contiki 3.x
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  */
30 
31 /**
32  * \file
33  * Device driver for the ST M25P16 40MHz 1Mbyte external memory.
34  * \author
35  * Björn Grönvall <bg@sics.se>
36  * Enric M. Calvo <ecalvo@zolertia.com>
37  *
38  * Data is written bit inverted (~-operator) to flash so that
39  * unwritten data will read as zeros (UNIX style).
40  */
41 
42 #include <stdio.h>
43 #include <string.h>
44 
45 #include "contiki.h"
46 #include "dev/spi.h"
47 #include "dev/xmem.h"
48 #include "dev/watchdog.h"
49 
50 #if 1
51 #define PRINTF(...) printf(__VA_ARGS__)
52 #else
53 #define PRINTF(...) do {} while (0)
54 #endif
55 
56 #define SPI_FLASH_INS_WREN 0x06
57 #define SPI_FLASH_INS_WRDI 0x04
58 #define SPI_FLASH_INS_RDSR 0x05
59 #define SPI_FLASH_INS_WRSR 0x01
60 #define SPI_FLASH_INS_READ 0x03
61 #define SPI_FLASH_INS_FAST_READ 0x0b
62 #define SPI_FLASH_INS_PP 0x02
63 #define SPI_FLASH_INS_SE 0xd8
64 #define SPI_FLASH_INS_BE 0xc7
65 #define SPI_FLASH_INS_DP 0xb9
66 #define SPI_FLASH_INS_RES 0xab
67 /*---------------------------------------------------------------------------*/
68 static void
69 write_enable(void)
70 {
71  int s;
72 
73  s = splhigh();
74  SPI_FLASH_ENABLE();
75 
76  SPI_WRITE(SPI_FLASH_INS_WREN);
77 
78  SPI_FLASH_DISABLE();
79  splx(s);
80 }
81 /*---------------------------------------------------------------------------*/
82 static unsigned
83 read_status_register(void)
84 {
85  unsigned char u;
86 
87  int s;
88 
89  s = splhigh();
90  SPI_FLASH_ENABLE();
91 
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();
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  wait_ready();
126 
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 
140  SPI_FLUSH(); //(void)SPI_RXBUF; /* Dummy read of SPI RX Buffer to ensure that there is no stray data. */
141 
142  splx(s);
143 }
144 /*---------------------------------------------------------------------------*/
145 /*
146  * Initialize external flash *and* SPI bus!
147  */
148 void
149 xmem_init(void)
150 {
151  //spi_init();
152 
153  P4DIR |= BV(FLASH_CS); // Unnecessary for Zolertia Z1 | BV(FLASH_PWR);
154  P5DIR |= BV(FLASH_HOLD); // In P5 for Z1
155 
156  SPI_FLASH_DISABLE(); /* Unselect flash. */
157  SPI_FLASH_UNHOLD();
158 }
159 /*---------------------------------------------------------------------------*/
160 int
161 xmem_pread(void *_p, int size, unsigned long offset)
162 {
163  unsigned char *p = _p;
164  const unsigned char *end = p + size;
165  int s;
166  wait_ready();
167 
168  ENERGEST_ON(ENERGEST_TYPE_FLASH_READ);
169 
170  s = splhigh();
171  SPI_FLASH_ENABLE();
172 
173  SPI_WRITE_FAST(SPI_FLASH_INS_READ);
174  SPI_WRITE_FAST(offset >> 16); /* MSB */
175  SPI_WRITE_FAST(offset >> 8);
176  SPI_WRITE_FAST(offset >> 0); /* LSB */
177  SPI_WAITFORTx_ENDED();
178 
179  SPI_FLUSH();
180  for(; p < end; p++) {
181  unsigned char u;
182  SPI_READ(u);
183  *p = ~u;
184  }
185 
186  SPI_FLASH_DISABLE();
187  splx(s);
188 
189  ENERGEST_OFF(ENERGEST_TYPE_FLASH_READ);
190 
191  return size;
192 }
193 /*---------------------------------------------------------------------------*/
194 static const unsigned char *
195 program_page(unsigned long offset, const unsigned char *p, int nbytes)
196 {
197  const unsigned char *end = p + nbytes;
198  int s;
199 
200  wait_ready();
201 
202  write_enable();
203 
204  s = splhigh();
205  SPI_FLASH_ENABLE();
206 
207  SPI_WRITE_FAST(SPI_FLASH_INS_PP);
208  SPI_WRITE_FAST(offset >> 16); /* MSB */
209  SPI_WRITE_FAST(offset >> 8);
210  SPI_WRITE_FAST(offset >> 0); /* LSB */
211 
212  for(; p < end; p++) {
213  SPI_WRITE_FAST(~*p);
214  }
215  SPI_WAITFORTx_ENDED();
216 
217  SPI_FLASH_DISABLE();
218  SPI_FLUSH(); //(void)SPI_RXBUF; /* Dummy read of SPI RX Buffer to ensure that there is no stray data. */
219  splx(s);
220 
221  return p;
222 }
223 /*---------------------------------------------------------------------------*/
224 int
225 xmem_pwrite(const void *_buf, int size, unsigned long addr)
226 {
227  const unsigned char *p = _buf;
228  const unsigned long end = addr + size;
229  unsigned long i, next_page;
230 
231  ENERGEST_ON(ENERGEST_TYPE_FLASH_WRITE);
232 
233  for(i = addr; i < end;) {
234  next_page = (i | 0xff) + 1;
235  if(next_page > end) {
236  next_page = end;
237  }
238  p = program_page(i, p, next_page - i);
239  i = next_page;
240  }
241 
242  ENERGEST_OFF(ENERGEST_TYPE_FLASH_WRITE);
243 
244  return size;
245 }
246 /*---------------------------------------------------------------------------*/
247 int
248 xmem_erase(long size, unsigned long addr)
249 {
250  unsigned long end = addr + size;
251 
252  if(size % XMEM_ERASE_UNIT_SIZE != 0) {
253  PRINTF("xmem_erase: bad size\n");
254  return -1;
255  }
256 
257  if(addr % XMEM_ERASE_UNIT_SIZE != 0) {
258  PRINTF("xmem_erase: bad offset\n");
259  return -1;
260  }
261 
262  for (; addr < end; addr += XMEM_ERASE_UNIT_SIZE) {
263  erase_sector(addr);
264  }
265 
266  return size;
267 }
268 /*---------------------------------------------------------------------------*/
static uip_ds6_addr_t * addr
Pointer to a router list entry.
Definition: uip-nd6.c:124
static bool wait_ready(void)
Wait till previous erase/program operation completes.
Definition: ext-flash.c:114
static bool write_enable(void)
Enable write.
Definition: ext-flash.c:255
void watchdog_periodic(void)
Writes the WDT clear sequence.
Definition: watchdog.c:64