Contiki-NG
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 ext-flash
33  * @{
34  *
35  * \file
36  * Implementation of a generic external SPI flash driver
37  */
38 /*---------------------------------------------------------------------------*/
39 #include "contiki.h"
40 #include "ext-flash.h"
41 #include "dev/spi.h"
42 #include "gpio-hal.h"
43 #include "sys/log.h"
44 
45 #include <stdint.h>
46 #include <stdbool.h>
47 /*---------------------------------------------------------------------------*/
48 #ifndef EXT_FLASH_SPI_CONTROLLER
49 
50 #define EXT_FLASH_SPI_CONTROLLER 0xFF /* No controller */
51 
52 #define EXT_FLASH_SPI_PIN_SCK GPIO_HAL_PIN_UNKNOWN
53 #define EXT_FLASH_SPI_PIN_MOSI GPIO_HAL_PIN_UNKNOWN
54 #define EXT_FLASH_SPI_PIN_MISO GPIO_HAL_PIN_UNKNOWN
55 #define EXT_FLASH_SPI_PIN_CS GPIO_HAL_PIN_UNKNOWN
56 
57 #define EXT_FLASH_DEVICE_ID 0xFF
58 #define EXT_FLASH_MID 0xFF
59 
60 #define EXT_FLASH_PROGRAM_PAGE_SIZE 256
61 #define EXT_FLASH_ERASE_SECTOR_SIZE 4096
62 
63 #endif /* EXT_FLASH_SPI_CONTROLLER */
64 /*---------------------------------------------------------------------------*/
65 /* Log configuration */
66 #define LOG_MODULE "ext-flash"
67 #define LOG_LEVEL LOG_LEVEL_NONE
68 /*---------------------------------------------------------------------------*/
69 /* Instruction codes */
70 
71 #define BLS_CODE_PROGRAM 0x02 /**< Page Program */
72 #define BLS_CODE_READ 0x03 /**< Read Data */
73 #define BLS_CODE_READ_STATUS 0x05 /**< Read Status Register */
74 #define BLS_CODE_WRITE_ENABLE 0x06 /**< Write Enable */
75 #define BLS_CODE_SECTOR_ERASE 0x20 /**< Sector Erase */
76 #define BLS_CODE_MDID 0x90 /**< Manufacturer Device ID */
77 
78 #define BLS_CODE_PD 0xB9 /**< Power down */
79 #define BLS_CODE_RPD 0xAB /**< Release Power-Down */
80 /*---------------------------------------------------------------------------*/
81 /* Erase instructions */
82 
83 #define BLS_CODE_ERASE_4K 0x20 /**< Sector Erase */
84 #define BLS_CODE_ERASE_32K 0x52
85 #define BLS_CODE_ERASE_64K 0xD8
86 #define BLS_CODE_ERASE_ALL 0xC7 /**< Mass Erase */
87 /*---------------------------------------------------------------------------*/
88 /* Bitmasks of the status register */
89 
90 #define BLS_STATUS_SRWD_BM 0x80
91 #define BLS_STATUS_BP_BM 0x0C
92 #define BLS_STATUS_WEL_BM 0x02
93 #define BLS_STATUS_WIP_BM 0x01
94 
95 #define BLS_STATUS_BIT_BUSY 0x01 /**< Busy bit of the status register */
96 /*---------------------------------------------------------------------------*/
97 #define VERIFY_PART_LOCKED -2
98 #define VERIFY_PART_ERROR -1
99 #define VERIFY_PART_POWERED_DOWN 0
100 #define VERIFY_PART_OK 1
101 /*---------------------------------------------------------------------------*/
102 static const spi_device_t flash_spi_configuration_default = {
103  .spi_controller = EXT_FLASH_SPI_CONTROLLER,
104  .pin_spi_sck = EXT_FLASH_SPI_PIN_SCK,
105  .pin_spi_miso = EXT_FLASH_SPI_PIN_MISO,
106  .pin_spi_mosi = EXT_FLASH_SPI_PIN_MOSI,
107  .pin_spi_cs = EXT_FLASH_SPI_PIN_CS,
108  .spi_bit_rate = 4000000,
109  .spi_pha = 0,
110  .spi_pol = 0
111 };
112 /*---------------------------------------------------------------------------*/
113 /**
114  * Get spi configuration, return default configuration if NULL
115  */
116 static const spi_device_t *
118 {
119  if(conf == NULL) {
120  return &flash_spi_configuration_default;
121  }
122  return conf;
123 }
124 /*---------------------------------------------------------------------------*/
125 /**
126  * Clear external flash CSN line
127  */
128 static bool
129 select_on_bus(const spi_device_t *flash_spi_configuration)
130 {
131  if(spi_select(flash_spi_configuration) == SPI_DEV_STATUS_OK) {
132  return true;
133  }
134  return false;
135 }
136 /*---------------------------------------------------------------------------*/
137 /**
138  * Set external flash CSN line
139  */
140 static void
141 deselect(const spi_device_t *flash_spi_configuration)
142 {
143  spi_deselect(flash_spi_configuration);
144 }
145 /*---------------------------------------------------------------------------*/
146 /**
147  * \brief Wait till previous erase/program operation completes.
148  * \return True when successful.
149  */
150 static bool
151 wait_ready(const spi_device_t *flash_spi_configuration)
152 {
153  bool ret;
154  const uint8_t wbuf[1] = { BLS_CODE_READ_STATUS };
155 
156  if(select_on_bus(flash_spi_configuration) == false) {
157  return false;
158  }
159 
160  ret = spi_write(flash_spi_configuration, wbuf, sizeof(wbuf));
161 
162  if(ret != SPI_DEV_STATUS_OK) {
163  deselect(flash_spi_configuration);
164  return false;
165  }
166 
167  for(;;) {
168  uint8_t buf;
169  /* Note that this temporary implementation is not
170  * energy efficient.
171  * Thread could have yielded while waiting for flash
172  * erase/program to complete.
173  */
174  ret = spi_read(flash_spi_configuration, &buf, sizeof(buf));
175 
176  if(ret != SPI_DEV_STATUS_OK) {
177  /* Error */
178  deselect(flash_spi_configuration);
179  return false;
180  }
181 
182  if(!(buf & BLS_STATUS_BIT_BUSY)) {
183  /* Now ready */
184  break;
185  }
186  }
187  deselect(flash_spi_configuration);
188  return true;
189 }
190 /*---------------------------------------------------------------------------*/
191 /**
192  * \brief Verify the flash part.
193  * \retval VERIFY_PART_OK The part was identified successfully
194  * \retval VERIFY_PART_ERROR There was an error communicating with the part
195  * \retval VERIFY_PART_POWERED_DOWN Communication was successful, but the part
196  * was powered down
197  */
198 static uint8_t
199 verify_part(const spi_device_t *flash_spi_configuration)
200 {
201  const uint8_t wbuf[] = { BLS_CODE_MDID, 0xFF, 0xFF, 0x00 };
202  uint8_t rbuf[2] = { 0, 0 };
203  bool ret;
204 
205  if(select_on_bus(flash_spi_configuration) == false) {
206  return VERIFY_PART_LOCKED;
207  }
208 
209  if(spi_write(flash_spi_configuration, wbuf, sizeof(wbuf)) != SPI_DEV_STATUS_OK) {
210  deselect(flash_spi_configuration);
211  return VERIFY_PART_ERROR;
212  }
213 
214  ret = spi_read(flash_spi_configuration, rbuf, sizeof(rbuf));
215  deselect(flash_spi_configuration);
216  if(ret != SPI_DEV_STATUS_OK) {
217  return VERIFY_PART_ERROR;
218  }
219 
220  LOG_DBG("Verify: %02x %02x\n", rbuf[0], rbuf[1]);
221 
222  if(rbuf[0] != EXT_FLASH_MID || rbuf[1] != EXT_FLASH_DEVICE_ID) {
223  return VERIFY_PART_POWERED_DOWN;
224  }
225  return VERIFY_PART_OK;
226 }
227 /*---------------------------------------------------------------------------*/
228 /**
229  * \brief Put the device in power save mode. No access to data; only
230  * the status register is accessible.
231  */
232 static bool
233 power_down(const spi_device_t *flash_spi_configuration)
234 {
235  uint8_t cmd;
236  uint8_t i;
237 
238  /* First, wait for the device to be ready */
239  if(wait_ready(flash_spi_configuration) == false) {
240  /* Entering here will leave the device in standby instead of powerdown */
241  return false;
242  }
243 
244  cmd = BLS_CODE_PD;
245  if(select_on_bus(flash_spi_configuration) == false) {
246  return false;
247  }
248 
249  if(spi_write_byte(flash_spi_configuration, cmd) != SPI_DEV_STATUS_OK) {
250  deselect(flash_spi_configuration);
251  return false;
252  }
253  deselect(flash_spi_configuration);
254 
255  i = 0;
256  while(i < 10) {
257  if(verify_part(flash_spi_configuration) == VERIFY_PART_POWERED_DOWN) {
258  /* Device is powered down */
259  return true;
260  }
261  i++;
262  }
263 
264  /* Should not be required */
265  deselect(flash_spi_configuration);
266  return false;
267 }
268 /*---------------------------------------------------------------------------*/
269 /**
270  * \brief Take device out of power save mode and prepare it for normal operation
271  * \return True if the command was written successfully
272  */
273 static bool
274 power_standby(const spi_device_t *flash_spi_configuration)
275 {
276  uint8_t cmd;
277  bool success;
278 
279  cmd = BLS_CODE_RPD;
280  if(select_on_bus(flash_spi_configuration) == false) {
281  return false;
282  }
283 
284  success = (spi_write(flash_spi_configuration, &cmd, sizeof(cmd)) == SPI_DEV_STATUS_OK);
285 
286  if(success) {
287  success = wait_ready(flash_spi_configuration) == true ? true : false;
288  }
289 
290  deselect(flash_spi_configuration);
291 
292  return success;
293 }
294 /*---------------------------------------------------------------------------*/
295 /**
296  * \brief Enable write.
297  * \return True when successful.
298  */
299 static bool
300 write_enable(const spi_device_t *flash_spi_configuration)
301 {
302  bool ret;
303  const uint8_t wbuf[] = { BLS_CODE_WRITE_ENABLE };
304 
305  if(select_on_bus(flash_spi_configuration) == false) {
306  return false;
307  }
308 
309  ret = (spi_write(flash_spi_configuration, wbuf, sizeof(wbuf)) == SPI_DEV_STATUS_OK);
310  deselect(flash_spi_configuration);
311 
312  if(ret == false) {
313  return false;
314  }
315  return true;
316 }
317 /*---------------------------------------------------------------------------*/
318 bool
320 {
321  const spi_device_t *flash_spi_configuration;
322 
323  flash_spi_configuration = get_spi_conf(conf);
324 
325  /* Check if platform has ext-flash */
326  if(flash_spi_configuration->pin_spi_sck == GPIO_HAL_PIN_UNKNOWN) {
327  return false;
328  }
329 
330  if(spi_acquire(flash_spi_configuration) != SPI_DEV_STATUS_OK) {
331  return false;
332  }
333  /* Default output to clear chip select */
334  deselect(flash_spi_configuration);
335 
336  /* Put the part is standby mode */
337  power_standby(flash_spi_configuration);
338 
339  if(verify_part(flash_spi_configuration) == VERIFY_PART_OK) {
340  return true;
341  }
342 
343  /* Failed to verify */
344  spi_release(flash_spi_configuration);
345  return false;
346 }
347 /*---------------------------------------------------------------------------*/
348 bool
350 {
351  bool ret;
352  const spi_device_t *flash_spi_configuration;
353 
354  flash_spi_configuration = get_spi_conf(conf);
355 
356  /* Put the part in low power mode */
357  ret = power_down(flash_spi_configuration);
358 
359  /* SPI is released no matter if power_down() succeeds or fails */
360  if(spi_release(flash_spi_configuration) != SPI_DEV_STATUS_OK) {
361  return false;
362  }
363 
364  return ret;
365 }
366 /*---------------------------------------------------------------------------*/
367 bool
368 ext_flash_read(const spi_device_t *conf, uint32_t offset, uint32_t length, uint8_t *buf)
369 {
370  uint8_t wbuf[4];
371  bool ret;
372 
373  const spi_device_t *flash_spi_configuration;
374 
375  flash_spi_configuration = get_spi_conf(conf);
376 
377  /* Wait till previous erase/program operation completes */
378  if(wait_ready(flash_spi_configuration) == false) {
379  return false;
380  }
381 
382  /*
383  * SPI is driven with very low frequency (1MHz < 33MHz fR spec)
384  * in this implementation, hence it is not necessary to use fast read.
385  */
386  wbuf[0] = BLS_CODE_READ;
387  wbuf[1] = (offset >> 16) & 0xff;
388  wbuf[2] = (offset >> 8) & 0xff;
389  wbuf[3] = offset & 0xff;
390 
391  if(select_on_bus(flash_spi_configuration) == false) {
392  return false;
393  }
394 
395  if(spi_write(flash_spi_configuration, wbuf, sizeof(wbuf)) != SPI_DEV_STATUS_OK) {
396  /* failure */
397  deselect(flash_spi_configuration);
398  return false;
399  }
400 
401  ret = (spi_read(flash_spi_configuration, buf, length) == SPI_DEV_STATUS_OK);
402 
403  deselect(flash_spi_configuration);
404 
405  return ret;
406 }
407 /*---------------------------------------------------------------------------*/
408 bool
409 ext_flash_write(const spi_device_t *conf, uint32_t offset, uint32_t length, const uint8_t *buf)
410 {
411  uint8_t wbuf[4];
412  uint32_t ilen; /* interim length per instruction */
413 
414  const spi_device_t *flash_spi_configuration;
415 
416  flash_spi_configuration = get_spi_conf(conf);
417 
418  while(length > 0) {
419  /* Wait till previous erase/program operation completes */
420  if(wait_ready(flash_spi_configuration) == false) {
421  return false;
422  }
423 
424  if(write_enable(flash_spi_configuration) == false) {
425  return false;
426  }
427 
428  ilen = EXT_FLASH_PROGRAM_PAGE_SIZE - (offset % EXT_FLASH_PROGRAM_PAGE_SIZE);
429  if(length < ilen) {
430  ilen = length;
431  }
432 
433  wbuf[0] = BLS_CODE_PROGRAM;
434  wbuf[1] = (offset >> 16) & 0xff;
435  wbuf[2] = (offset >> 8) & 0xff;
436  wbuf[3] = offset & 0xff;
437 
438  offset += ilen;
439  length -= ilen;
440 
441  /* Upto 100ns CS hold time (which is not clear
442  * whether it's application only inbetween reads)
443  * is not imposed here since above instructions
444  * should be enough to delay
445  * as much. */
446  if(select_on_bus(flash_spi_configuration) == false) {
447  return false;
448  }
449 
450  if(spi_write(flash_spi_configuration, wbuf, sizeof(wbuf)) != SPI_DEV_STATUS_OK) {
451  /* failure */
452  deselect(flash_spi_configuration);
453  return false;
454  }
455 
456  if(spi_write(flash_spi_configuration, buf, ilen) != SPI_DEV_STATUS_OK) {
457  /* failure */
458  deselect(flash_spi_configuration);
459  return false;
460  }
461  buf += ilen;
462  deselect(flash_spi_configuration);
463  }
464 
465  return true;
466 }
467 /*---------------------------------------------------------------------------*/
468 bool
469 ext_flash_erase(const spi_device_t *conf, uint32_t offset, uint32_t length)
470 {
471  /*
472  * Note that Block erase might be more efficient when the floor map
473  * is well planned for OTA, but to simplify this implementation,
474  * sector erase is used blindly.
475  */
476  uint8_t wbuf[4];
477  uint32_t i, numsectors;
478  uint32_t endoffset = offset + length - 1;
479 
480  const spi_device_t *flash_spi_configuration;
481 
482  flash_spi_configuration = get_spi_conf(conf);
483 
484  offset = (offset / EXT_FLASH_ERASE_SECTOR_SIZE) * EXT_FLASH_ERASE_SECTOR_SIZE;
485  numsectors = (endoffset - offset + EXT_FLASH_ERASE_SECTOR_SIZE - 1) / EXT_FLASH_ERASE_SECTOR_SIZE;
486 
487  wbuf[0] = BLS_CODE_SECTOR_ERASE;
488 
489  for(i = 0; i < numsectors; i++) {
490  /* Wait till previous erase/program operation completes */
491  if(wait_ready(flash_spi_configuration) == false) {
492  return false;
493  }
494 
495  if(write_enable(flash_spi_configuration) == false) {
496  return false;
497  }
498 
499  wbuf[1] = (offset >> 16) & 0xff;
500  wbuf[2] = (offset >> 8) & 0xff;
501  wbuf[3] = offset & 0xff;
502 
503  if(select_on_bus(flash_spi_configuration) == false) {
504  return false;
505  }
506 
507  if(spi_write(flash_spi_configuration, wbuf, sizeof(wbuf)) != SPI_DEV_STATUS_OK) {
508  /* failure */
509  deselect(flash_spi_configuration);
510  return false;
511  }
512  deselect(flash_spi_configuration);
513 
514  offset += EXT_FLASH_ERASE_SECTOR_SIZE;
515  }
516 
517  return true;
518 }
519 /*---------------------------------------------------------------------------*/
520 bool
522 {
523  if(ext_flash_open(conf) == false) {
524  return false;
525  }
526 
527  if(ext_flash_close(conf) == false) {
528  return false;
529  }
530 
531  LOG_INFO("Flash init successful\n");
532 
533  return true;
534 }
535 /*---------------------------------------------------------------------------*/
536 /** @} */
#define BLS_CODE_WRITE_ENABLE
Write Enable.
Definition: ext-flash.c:74
#define BLS_CODE_PROGRAM
Page Program.
Definition: ext-flash.c:71
spi_status_t spi_select(const spi_device_t *dev)
Selects the SPI peripheral.
Definition: spi.c:68
static void deselect(const spi_device_t *flash_spi_configuration)
Set external flash CSN line.
Definition: ext-flash.c:141
bool ext_flash_read(const spi_device_t *conf, uint32_t offset, uint32_t length, uint8_t *buf)
Read storage content.
Definition: ext-flash.c:368
static bool write_enable(const spi_device_t *flash_spi_configuration)
Enable write.
Definition: ext-flash.c:300
spi_status_t spi_read(const spi_device_t *dev, uint8_t *buf, int size)
Reads a buffer from an SPI device.
Definition: spi.c:140
spi_status_t spi_write_byte(const spi_device_t *dev, uint8_t data)
Writes a single byte to an SPI device.
Definition: spi.c:98
#define BLS_CODE_READ_STATUS
Read Status Register.
Definition: ext-flash.c:73
#define GPIO_HAL_PIN_UNKNOWN
Unknown GPIO.
Definition: gpio-hal.h:140
#define BLS_CODE_PD
Power down.
Definition: ext-flash.c:78
bool ext_flash_open(const spi_device_t *conf)
Initialize storage driver.
Definition: ext-flash.c:319
bool ext_flash_erase(const spi_device_t *conf, uint32_t offset, uint32_t length)
Erase storage sectors corresponding to the range.
Definition: ext-flash.c:469
Header file for the SPI HAL.
static bool power_down(const spi_device_t *flash_spi_configuration)
Put the device in power save mode.
Definition: ext-flash.c:233
static bool select_on_bus(const spi_device_t *flash_spi_configuration)
Clear external flash CSN line.
Definition: ext-flash.c:129
spi_status_t spi_write(const spi_device_t *dev, const uint8_t *data, int size)
Writes a buffer to an SPI device.
Definition: spi.c:112
spi_status_t spi_acquire(const spi_device_t *dev)
Locks and then opens an SPI controller.
Definition: spi.c:46
spi_status_t spi_deselect(const spi_device_t *dev)
Deselects the SPI peripheral.
Definition: spi.c:80
bool ext_flash_close(const spi_device_t *conf)
Close the storage driver.
Definition: ext-flash.c:349
static bool wait_ready(const spi_device_t *flash_spi_configuration)
Wait till previous erase/program operation completes.
Definition: ext-flash.c:151
#define BLS_CODE_MDID
Manufacturer Device ID.
Definition: ext-flash.c:76
Header file for the external SPI flash API.
static bool power_standby(const spi_device_t *flash_spi_configuration)
Take device out of power save mode and prepare it for normal operation.
Definition: ext-flash.c:274
bool ext_flash_init(const spi_device_t *conf)
Initialise the external flash.
Definition: ext-flash.c:521
SPI Device Configuration.
Definition: spi.h:98
spi_status_t spi_release(const spi_device_t *dev)
Closes and then unlocks an SPI controller.
Definition: spi.c:57
#define BLS_CODE_RPD
Release Power-Down.
Definition: ext-flash.c:79
#define BLS_CODE_READ
Read Data.
Definition: ext-flash.c:72
Header file for the GPIO HAL.
Header file for the logging system
#define BLS_CODE_SECTOR_ERASE
Sector Erase.
Definition: ext-flash.c:75
#define BLS_STATUS_BIT_BUSY
Busy bit of the status register.
Definition: ext-flash.c:95
static uint8_t verify_part(const spi_device_t *flash_spi_configuration)
Verify the flash part.
Definition: ext-flash.c:199
bool ext_flash_write(const spi_device_t *conf, uint32_t offset, uint32_t length, const uint8_t *buf)
Write to storage sectors.
Definition: ext-flash.c:409
static const spi_device_t * get_spi_conf(const spi_device_t *conf)
Get spi configuration, return default configuration if NULL.
Definition: ext-flash.c:117