Contiki 3.x
ext-flash.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/
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 copyright holder nor the names of its
14  * contributors may be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28  * OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 /*---------------------------------------------------------------------------*/
31 /**
32  * \addtogroup sensortag-cc26xx-ext-flash
33  * @{
34  *
35  * \file
36  * Driver for the LaunchPad Flash and the Sensortag WinBond W25X20CL/W25X40CL
37  */
38 /*---------------------------------------------------------------------------*/
39 #include "contiki.h"
40 #include "ext-flash.h"
41 #include "ti-lib.h"
42 #include "board-spi.h"
43 
44 #include <stdint.h>
45 #include <stdbool.h>
46 /*---------------------------------------------------------------------------*/
47 /* Instruction codes */
48 
49 #define BLS_CODE_PROGRAM 0x02 /**< Page Program */
50 #define BLS_CODE_READ 0x03 /**< Read Data */
51 #define BLS_CODE_READ_STATUS 0x05 /**< Read Status Register */
52 #define BLS_CODE_WRITE_ENABLE 0x06 /**< Write Enable */
53 #define BLS_CODE_SECTOR_ERASE 0x20 /**< Sector Erase */
54 #define BLS_CODE_MDID 0x90 /**< Manufacturer Device ID */
55 
56 #define BLS_CODE_PD 0xB9 /**< Power down */
57 #define BLS_CODE_RPD 0xAB /**< Release Power-Down */
58 /*---------------------------------------------------------------------------*/
59 /* Erase instructions */
60 
61 #define BLS_CODE_ERASE_4K 0x20 /**< Sector Erase */
62 #define BLS_CODE_ERASE_32K 0x52
63 #define BLS_CODE_ERASE_64K 0xD8
64 #define BLS_CODE_ERASE_ALL 0xC7 /**< Mass Erase */
65 /*---------------------------------------------------------------------------*/
66 /* Bitmasks of the status register */
67 
68 #define BLS_STATUS_SRWD_BM 0x80
69 #define BLS_STATUS_BP_BM 0x0C
70 #define BLS_STATUS_WEL_BM 0x02
71 #define BLS_STATUS_WIP_BM 0x01
72 
73 #define BLS_STATUS_BIT_BUSY 0x01 /**< Busy bit of the status register */
74 /*---------------------------------------------------------------------------*/
75 /* Part specific constants */
76 #define BLS_DEVICE_ID_W25X20CL 0x11
77 #define BLS_DEVICE_ID_W25X40CL 0x12
78 #define BLS_DEVICE_ID_MX25R8035F 0x14
79 #define BLS_DEVICE_ID_MX25R1635F 0x15
80 
81 #define BLS_WINBOND_MID 0xEF
82 #define BLS_MACRONIX_MID 0xC2
83 
84 #define BLS_PROGRAM_PAGE_SIZE 256
85 #define BLS_ERASE_SECTOR_SIZE 4096
86 /*---------------------------------------------------------------------------*/
87 #define VERIFY_PART_ERROR -1
88 #define VERIFY_PART_POWERED_DOWN 0
89 #define VERIFY_PART_OK 1
90 /*---------------------------------------------------------------------------*/
91 /**
92  * Clear external flash CSN line
93  */
94 static void
96 {
97  ti_lib_gpio_pin_write(BOARD_FLASH_CS, 0);
98 }
99 /*---------------------------------------------------------------------------*/
100 /**
101  * Set external flash CSN line
102  */
103 static void
104 deselect(void)
105 {
106  ti_lib_gpio_pin_write(BOARD_FLASH_CS, 1);
107 }
108 /*---------------------------------------------------------------------------*/
109 /**
110  * \brief Wait till previous erase/program operation completes.
111  * \return True when successful.
112  */
113 static bool
115 {
116  bool ret;
117  const uint8_t wbuf[1] = { BLS_CODE_READ_STATUS };
118 
119  select_on_bus();
120 
121  /* Throw away all garbages */
122  board_spi_flush();
123 
124  ret = board_spi_write(wbuf, sizeof(wbuf));
125 
126  if(ret == false) {
127  deselect();
128  return false;
129  }
130 
131  for(;;) {
132  uint8_t buf;
133  /* Note that this temporary implementation is not
134  * energy efficient.
135  * Thread could have yielded while waiting for flash
136  * erase/program to complete.
137  */
138  ret = board_spi_read(&buf, sizeof(buf));
139 
140  if(ret == false) {
141  /* Error */
142  deselect();
143  return false;
144  }
145  if(!(buf & BLS_STATUS_BIT_BUSY)) {
146  /* Now ready */
147  break;
148  }
149  }
150  deselect();
151  return true;
152 }
153 /*---------------------------------------------------------------------------*/
154 /**
155  * \brief Verify the flash part.
156  * \retval VERIFY_PART_OK The part was identified successfully
157  * \retval VERIFY_PART_ERROR There was an error communicating with the part
158  * \retval VERIFY_PART_POWERED_DOWN Communication was successful, but the part
159  * was powered down
160  */
161 static uint8_t
163 {
164  const uint8_t wbuf[] = { BLS_CODE_MDID, 0xFF, 0xFF, 0x00 };
165  uint8_t rbuf[2] = { 0, 0 };
166  bool ret;
167 
168  select_on_bus();
169 
170  ret = board_spi_write(wbuf, sizeof(wbuf));
171 
172  if(ret == false) {
173  deselect();
174  return VERIFY_PART_ERROR;
175  }
176 
177  ret = board_spi_read(rbuf, sizeof(rbuf));
178  deselect();
179 
180  if(ret == false) {
181  return VERIFY_PART_ERROR;
182  }
183 
184  if((rbuf[0] != BLS_WINBOND_MID && rbuf[0] != BLS_MACRONIX_MID) ||
185  (rbuf[1] != BLS_DEVICE_ID_W25X20CL && rbuf[1] != BLS_DEVICE_ID_W25X40CL
186  && rbuf[1] != BLS_DEVICE_ID_MX25R8035F
187  && rbuf[1] != BLS_DEVICE_ID_MX25R1635F)) {
188  return VERIFY_PART_POWERED_DOWN;
189  }
190  return VERIFY_PART_OK;
191 }
192 /*---------------------------------------------------------------------------*/
193 /**
194  * \brief Put the device in power save mode. No access to data; only
195  * the status register is accessible.
196  */
197 static void
199 {
200  uint8_t cmd;
201  uint8_t i;
202 
203  /* First, wait for the device to be ready */
204  if(wait_ready() == false) {
205  /* Entering here will leave the device in standby instead of powerdown */
206  return;
207  }
208 
209  cmd = BLS_CODE_PD;
210  select_on_bus();
211  board_spi_write(&cmd, sizeof(cmd));
212  deselect();
213 
214  i = 0;
215  while(i < 10) {
216  if(verify_part() == VERIFY_PART_POWERED_DOWN) {
217  /* Device is powered down */
218  return;
219  }
220  i++;
221  }
222 
223  /* Should not be required */
224  deselect();
225 }
226 /*---------------------------------------------------------------------------*/
227 /**
228  * \brief Take device out of power save mode and prepare it for normal operation
229  * \return True if the command was written successfully
230  */
231 static bool
233 {
234  uint8_t cmd;
235  bool success;
236 
237  cmd = BLS_CODE_RPD;
238  select_on_bus();
239  success = board_spi_write(&cmd, sizeof(cmd));
240 
241  if(success) {
242  success = wait_ready() == true ? true : false;
243  }
244 
245  deselect();
246 
247  return success;
248 }
249 /*---------------------------------------------------------------------------*/
250 /**
251  * \brief Enable write.
252  * \return True when successful.
253  */
254 static bool
256 {
257  bool ret;
258  const uint8_t wbuf[] = { BLS_CODE_WRITE_ENABLE };
259 
260  select_on_bus();
261  ret = board_spi_write(wbuf, sizeof(wbuf));
262  deselect();
263 
264  if(ret == false) {
265  return false;
266  }
267  return true;
268 }
269 /*---------------------------------------------------------------------------*/
270 bool
272 {
273  board_spi_open(4000000, BOARD_IOID_SPI_CLK_FLASH);
274 
275  /* GPIO pin configuration */
276  ti_lib_ioc_pin_type_gpio_output(BOARD_IOID_FLASH_CS);
277 
278  /* Default output to clear chip select */
279  deselect();
280 
281  /* Put the part is standby mode */
282  power_standby();
283 
284  return verify_part() == VERIFY_PART_OK ? true : false;
285 }
286 /*---------------------------------------------------------------------------*/
287 void
289 {
290  /* Put the part in low power mode */
291  power_down();
292 
293  board_spi_close();
294 }
295 /*---------------------------------------------------------------------------*/
296 bool
297 ext_flash_read(size_t offset, size_t length, uint8_t *buf)
298 {
299  uint8_t wbuf[4];
300 
301  /* Wait till previous erase/program operation completes */
302  bool ret = wait_ready();
303  if(ret == false) {
304  return false;
305  }
306 
307  /*
308  * SPI is driven with very low frequency (1MHz < 33MHz fR spec)
309  * in this implementation, hence it is not necessary to use fast read.
310  */
311  wbuf[0] = BLS_CODE_READ;
312  wbuf[1] = (offset >> 16) & 0xff;
313  wbuf[2] = (offset >> 8) & 0xff;
314  wbuf[3] = offset & 0xff;
315 
316  select_on_bus();
317 
318  if(board_spi_write(wbuf, sizeof(wbuf)) == false) {
319  /* failure */
320  deselect();
321  return false;
322  }
323 
324  ret = board_spi_read(buf, length);
325 
326  deselect();
327 
328  return ret;
329 }
330 /*---------------------------------------------------------------------------*/
331 bool
332 ext_flash_write(size_t offset, size_t length, const uint8_t *buf)
333 {
334  uint8_t wbuf[4];
335  bool ret;
336  size_t ilen; /* interim length per instruction */
337 
338  while(length > 0) {
339  /* Wait till previous erase/program operation completes */
340  ret = wait_ready();
341  if(ret == false) {
342  return false;
343  }
344 
345  ret = write_enable();
346  if(ret == false) {
347  return false;
348  }
349 
350  ilen = BLS_PROGRAM_PAGE_SIZE - (offset % BLS_PROGRAM_PAGE_SIZE);
351  if(length < ilen) {
352  ilen = length;
353  }
354 
355  wbuf[0] = BLS_CODE_PROGRAM;
356  wbuf[1] = (offset >> 16) & 0xff;
357  wbuf[2] = (offset >> 8) & 0xff;
358  wbuf[3] = offset & 0xff;
359 
360  offset += ilen;
361  length -= ilen;
362 
363  /* Upto 100ns CS hold time (which is not clear
364  * whether it's application only inbetween reads)
365  * is not imposed here since above instructions
366  * should be enough to delay
367  * as much. */
368  select_on_bus();
369 
370  if(board_spi_write(wbuf, sizeof(wbuf)) == false) {
371  /* failure */
372  deselect();
373  return false;
374  }
375 
376  if(board_spi_write(buf, ilen) == false) {
377  /* failure */
378  deselect();
379  return false;
380  }
381  buf += ilen;
382  deselect();
383  }
384 
385  return true;
386 }
387 /*---------------------------------------------------------------------------*/
388 bool
389 ext_flash_erase(size_t offset, size_t length)
390 {
391  /*
392  * Note that Block erase might be more efficient when the floor map
393  * is well planned for OTA, but to simplify this implementation,
394  * sector erase is used blindly.
395  */
396  uint8_t wbuf[4];
397  bool ret;
398  size_t i, numsectors;
399  size_t endoffset = offset + length - 1;
400 
401  offset = (offset / BLS_ERASE_SECTOR_SIZE) * BLS_ERASE_SECTOR_SIZE;
402  numsectors = (endoffset - offset + BLS_ERASE_SECTOR_SIZE - 1) / BLS_ERASE_SECTOR_SIZE;
403 
404  wbuf[0] = BLS_CODE_SECTOR_ERASE;
405 
406  for(i = 0; i < numsectors; i++) {
407  /* Wait till previous erase/program operation completes */
408  ret = wait_ready();
409  if(ret == false) {
410  return false;
411  }
412 
413  ret = write_enable();
414  if(ret == false) {
415  return false;
416  }
417 
418  wbuf[1] = (offset >> 16) & 0xff;
419  wbuf[2] = (offset >> 8) & 0xff;
420  wbuf[3] = offset & 0xff;
421 
422  select_on_bus();
423 
424  if(board_spi_write(wbuf, sizeof(wbuf)) == false) {
425  /* failure */
426  deselect();
427  return false;
428  }
429  deselect();
430 
431  offset += BLS_ERASE_SECTOR_SIZE;
432  }
433 
434  return true;
435 }
436 /*---------------------------------------------------------------------------*/
437 bool
439 {
440  bool ret;
441 
442  ret = ext_flash_open();
443  ext_flash_close();
444 
445  return ret;
446 }
447 /*---------------------------------------------------------------------------*/
448 void
450 {
451  ext_flash_open();
452  ext_flash_close();
453 }
454 /*---------------------------------------------------------------------------*/
455 /** @} */
bool ext_flash_test(void)
Test the flash (power on self-test)
Definition: ext-flash.c:438
#define BLS_CODE_READ_STATUS
Read Status Register.
Definition: ext-flash.c:51
#define BLS_CODE_MDID
Manufacturer Device ID.
Definition: ext-flash.c:54
bool ext_flash_read(size_t offset, size_t length, uint8_t *buf)
Read storage content.
Definition: ext-flash.c:297
Header file with macros which rename TI CC26xxware functions.
Header file for the Sensortag/LaunchPad SPI Driver.
#define BLS_CODE_PROGRAM
Page Program.
Definition: ext-flash.c:49
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
static void power_down(void)
Put the device in power save mode.
Definition: ext-flash.c:198
static void select_on_bus(void)
Clear external flash CSN line.
Definition: ext-flash.c:95
bool ext_flash_open()
Initialize storage driver.
Definition: ext-flash.c:271
void ext_flash_init()
Initialise the external flash.
Definition: ext-flash.c:449
static bool power_standby(void)
Take device out of power save mode and prepare it for normal operation.
Definition: ext-flash.c:232
void board_spi_close()
Close the SPI interface.
Definition: board-spi.c:145
static uint8_t verify_part(void)
Verify the flash part.
Definition: ext-flash.c:162
bool board_spi_write(const uint8_t *buf, size_t len)
Write to an SPI device.
Definition: board-spi.c:64
Header file for the Sensortag/LaunchPad External Flash Driver.
static void deselect(void)
Set external flash CSN line.
Definition: ext-flash.c:104
#define BLS_CODE_SECTOR_ERASE
Sector Erase.
Definition: ext-flash.c:53
#define BLS_CODE_PD
Power down.
Definition: ext-flash.c:56
bool board_spi_read(uint8_t *buf, size_t len)
Read from an SPI device.
Definition: board-spi.c:83
void board_spi_open(uint32_t bit_rate, uint32_t clk_pin)
Initialize the SPI interface.
Definition: board-spi.c:116
void board_spi_flush()
Clear data from the SPI interface.
Definition: board-spi.c:105
bool ext_flash_erase(size_t offset, size_t length)
Erase storage sectors corresponding to the range.
Definition: ext-flash.c:389
#define BLS_STATUS_BIT_BUSY
Busy bit of the status register.
Definition: ext-flash.c:73
bool ext_flash_write(size_t offset, size_t length, const uint8_t *buf)
Write to storage sectors.
Definition: ext-flash.c:332
#define BLS_CODE_READ
Read Data.
Definition: ext-flash.c:50
void ext_flash_close()
Close the storage driver.
Definition: ext-flash.c:288
#define BLS_CODE_RPD
Release Power-Down.
Definition: ext-flash.c:57
#define BLS_CODE_WRITE_ENABLE
Write Enable.
Definition: ext-flash.c:52