ChibiOS  0.0.0
m25q.c
Go to the documentation of this file.
1 /*
2  ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
3 
4  This file is part of ChibiOS.
5 
6  ChibiOS is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 3 of the License, or
9  (at your option) any later version.
10 
11  ChibiOS is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 /**
21  * @file m25q.c
22  * @brief Micron serial flash driver code.
23  *
24  * @addtogroup M25Q
25  * @ingroup EX_MICRON
26  * @{
27  */
28 
29 #include <string.h>
30 
31 #include "hal.h"
32 #include "m25q.h"
33 
34 /*===========================================================================*/
35 /* Driver local definitions. */
36 /*===========================================================================*/
37 
38 #define PAGE_SIZE 256U
39 #define PAGE_MASK (PAGE_SIZE - 1U)
40 
41 #if M25Q_USE_SUB_SECTORS == TRUE
42 #define SECTOR_SIZE 0x00001000U
43 #define CMD_SECTOR_ERASE M25Q_CMD_SUBSECTOR_ERASE
44 #else
45 #define SECTOR_SIZE 0x00010000U
46 #define CMD_SECTOR_ERASE M25Q_CMD_SECTOR_ERASE
47 #endif
48 
49 /*===========================================================================*/
50 /* Driver exported variables. */
51 /*===========================================================================*/
52 
53 /*===========================================================================*/
54 /* Driver local variables and types. */
55 /*===========================================================================*/
56 
57 static const flash_descriptor_t *m25q_get_descriptor(void *instance);
58 static flash_error_t m25q_read(void *instance, flash_offset_t offset,
59  size_t n, uint8_t *rp);
60 static flash_error_t m25q_program(void *instance, flash_offset_t offset,
61  size_t n, const uint8_t *pp);
62 static flash_error_t m25q_start_erase_all(void *instance);
63 static flash_error_t m25q_start_erase_sector(void *instance,
64  flash_sector_t sector);
65 static flash_error_t m25q_query_erase(void *instance, uint32_t *msec);
66 static flash_error_t m25q_verify_erase(void *instance, flash_sector_t sector);
67 static flash_error_t m25q_read_sfdp(void *instance, flash_offset_t offset,
68  size_t n, uint8_t *rp);
69 
70 /**
71  * @brief Virtual methods table.
72  */
73 static const struct M25QDriverVMT m25q_vmt = {
74  (size_t)0,
75  m25q_get_descriptor, m25q_read, m25q_program,
76  m25q_start_erase_all, m25q_start_erase_sector,
77  m25q_query_erase, m25q_verify_erase,
78  m25q_read_sfdp
79 };
80 
81 /**
82  * @brief N25Q128 descriptor.
83  */
85  .attributes = FLASH_ATTR_ERASED_IS_ONE | FLASH_ATTR_REWRITABLE |
86  FLASH_ATTR_SUSPEND_ERASE_CAPABLE,
87  .page_size = 256U,
88  .sectors_count = 0U, /* It is overwritten.*/
89  .sectors = NULL,
90  .sectors_size = SECTOR_SIZE,
91  .address = 0U
92 };
93 
94 #if JESD216_BUS_MODE != JESD216_BUS_MODE_SPI
95 /* Initial M25Q_CMD_READ_ID command.*/
96 static const qspi_command_t m25q_cmd_read_id = {
97  .cfg = QSPI_CFG_CMD(M25Q_CMD_READ_ID) |
98 #if M25Q_SWITCH_WIDTH == TRUE
99  QSPI_CFG_CMD_MODE_ONE_LINE |
100  QSPI_CFG_DATA_MODE_ONE_LINE,
101 #else
102 #if JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI1L
103  QSPI_CFG_CMD_MODE_ONE_LINE |
104  QSPI_CFG_DATA_MODE_ONE_LINE,
105 #elif JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI2L
106  QSPI_CFG_CMD_MODE_TWO_LINES |
107  QSPI_CFG_DATA_MODE_TWO_LINES,
108 #else
109  QSPI_CFG_CMD_MODE_FOUR_LINES |
110  QSPI_CFG_DATA_MODE_FOUR_LINES,
111 #endif
112 #endif
113  .addr = 0,
114  .alt = 0
115 };
116 
117 /* Initial M25Q_CMD_WRITE_ENHANCED_V_CONF_REGISTER command.*/
118 static const qspi_command_t m25q_cmd_write_evconf = {
119  .cfg = QSPI_CFG_CMD(M25Q_CMD_WRITE_ENHANCED_V_CONF_REGISTER) |
120 #if M25Q_SWITCH_WIDTH == TRUE
121  QSPI_CFG_CMD_MODE_ONE_LINE |
122  QSPI_CFG_DATA_MODE_ONE_LINE,
123 #else
124 #if JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI1L
125  QSPI_CFG_CMD_MODE_ONE_LINE |
126  QSPI_CFG_DATA_MODE_ONE_LINE,
127 #elif JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI2L
128  QSPI_CFG_CMD_MODE_TWO_LINES |
129  QSPI_CFG_DATA_MODE_TWO_LINES,
130 #else
131  QSPI_CFG_CMD_MODE_FOUR_LINES |
132  QSPI_CFG_DATA_MODE_FOUR_LINES,
133 #endif
134 #endif
135  .addr = 0,
136  .alt = 0
137 };
138 
139 /* Initial M25Q_CMD_WRITE_ENABLE command.*/
140 static const qspi_command_t m25q_cmd_write_enable = {
141  .cfg = QSPI_CFG_CMD(M25Q_CMD_WRITE_ENABLE) |
142 #if M25Q_SWITCH_WIDTH == TRUE
143  QSPI_CFG_CMD_MODE_ONE_LINE,
144 #else
145 #if JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI1L
146  QSPI_CFG_CMD_MODE_ONE_LINE,
147 #elif JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI2L
148  QSPI_CFG_CMD_MODE_TWO_LINES,
149 #else
150  QSPI_CFG_CMD_MODE_FOUR_LINES,
151 #endif
152 #endif
153  .addr = 0,
154  .alt = 0
155 };
156 
157 /* Bus width initialization.*/
158 #if JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI1L
159 static const uint8_t m25q_evconf_value[1] = {0xCF};
160 #elif JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI2L
161 static const uint8_t m25q_evconf_value[1] = {0x8F};
162 #else
163 static const uint8_t m25q_evconf_value[1] = {0x4F};
164 #endif
165 #endif /* JESD216_BUS_MODE != JESD216_BUS_MODE_SPI */
166 
167 static const uint8_t m25q_manufacturer_ids[] = M25Q_SUPPORTED_MANUFACTURE_IDS;
168 static const uint8_t m25q_memory_type_ids[] = M25Q_SUPPORTED_MEMORY_TYPE_IDS;
169 
170 /*===========================================================================*/
171 /* Driver local functions. */
172 /*===========================================================================*/
173 
174 static bool m25q_find_id(const uint8_t *set, size_t size, uint8_t element) {
175  size_t i;
176 
177  for (i = 0; i < size; i++) {
178  if (set[i] == element) {
179  return true;
180  }
181  }
182  return false;
183 }
184 
185 #if (JESD216_BUS_MODE != JESD216_BUS_MODE_SPI) || defined(__DOXYGEN__)
186 void m25q_reset_xip(M25QDriver *devp) {
187  static const uint8_t flash_conf[1] = {
188  (M25Q_READ_DUMMY_CYCLES << 4U) | 0x0FU
189  };
190  qspi_command_t cmd;
191  uint8_t buf[1];
192 
193  /* Resetting XIP mode by reading one byte without XIP confirmation bit.*/
194  cmd.alt = 0xFF;
195  cmd.addr = 0;
196  cmd.cfg = QSPI_CFG_CMD_MODE_NONE |
197  QSPI_CFG_ADDR_SIZE_24 |
198 #if JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI1L
199  QSPI_CFG_ADDR_MODE_ONE_LINE |
200  QSPI_CFG_DATA_MODE_ONE_LINE |
201 #elif JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI2L
202  QSPI_CFG_ADDR_MODE_TWO_LINES |
203  QSPI_CFG_DATA_MODE_TWO_LINES |
204 #else
205  QSPI_CFG_ADDR_MODE_FOUR_LINES |
206  QSPI_CFG_DATA_MODE_FOUR_LINES |
207 #endif
208  QSPI_CFG_ALT_MODE_FOUR_LINES | /* Always 4 lines, note.*/
209  QSPI_CFG_ALT_SIZE_8 |
210  QSPI_CFG_DUMMY_CYCLES(M25Q_READ_DUMMY_CYCLES - 2);
211  qspiReceive(devp->config->busp, &cmd, 1, buf);
212 
213  /* Enabling write operation.*/
214  jesd216_cmd(devp->config->busp, M25Q_CMD_WRITE_ENABLE);
215 
216  /* Rewriting volatile configuration register.*/
217  jesd216_cmd_send(devp->config->busp, M25Q_CMD_WRITE_V_CONF_REGISTER,
218  1, flash_conf);
219 }
220 
221 void m25q_reset_memory(M25QDriver *devp) {
222 
223  /* 1x M25Q_CMD_RESET_ENABLE command.*/
224  static const qspi_command_t cmd_reset_enable_1 = {
225  .cfg = QSPI_CFG_CMD(M25Q_CMD_RESET_ENABLE) |
226  QSPI_CFG_CMD_MODE_ONE_LINE,
227  .addr = 0,
228  .alt = 0
229  };
230 
231  /* 1x M25Q_CMD_RESET_MEMORY command.*/
232  static const qspi_command_t cmd_reset_memory_1 = {
233  .cfg = QSPI_CFG_CMD(M25Q_CMD_RESET_MEMORY) |
234  QSPI_CFG_CMD_MODE_ONE_LINE,
235  .addr = 0,
236  .alt = 0
237  };
238 
239  /* If the device is in one bit mode then the following commands are
240  rejected because shorter than 8 bits. If the device is in multiple
241  bits mode then the commands are accepted and the device is reset to
242  one bit mode.*/
243 #if JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI4L
244  /* 4x M25Q_CMD_RESET_ENABLE command.*/
245  static const qspi_command_t cmd_reset_enable_4 = {
246  .cfg = QSPI_CFG_CMD(M25Q_CMD_RESET_ENABLE) |
247  QSPI_CFG_CMD_MODE_FOUR_LINES,
248  .addr = 0,
249  .alt = 0
250  };
251 
252  /* 4x M25Q_CMD_RESET_MEMORY command.*/
253  static const qspi_command_t cmd_reset_memory_4 = {
254  .cfg = QSPI_CFG_CMD(M25Q_CMD_RESET_MEMORY) |
255  QSPI_CFG_CMD_MODE_FOUR_LINES,
256  .addr = 0,
257  .alt = 0
258  };
259 
260  qspiCommand(devp->config->busp, &cmd_reset_enable_4);
261  qspiCommand(devp->config->busp, &cmd_reset_memory_4);
262 #else
263  /* 2x M25Q_CMD_RESET_ENABLE command.*/
264  static const qspi_command_t cmd_reset_enable_2 = {
265  .cfg = QSPI_CFG_CMD(M25Q_CMD_RESET_ENABLE) |
266  QSPI_CFG_CMD_MODE_TWO_LINES,
267  .addr = 0,
268  .alt = 0
269  };
270 
271  /* 2x M25Q_CMD_RESET_MEMORY command.*/
272  static const qspi_command_t cmd_reset_memory_2 = {
273  .cfg = QSPI_CFG_CMD(M25Q_CMD_RESET_MEMORY) |
274  QSPI_CFG_CMD_MODE_TWO_LINES,
275  .addr = 0,
276  .alt = 0
277  };
278 
279  qspiCommand(devp->config->busp, &cmd_reset_enable_2);
280  qspiCommand(devp->config->busp, &cmd_reset_memory_2);
281 #endif
282 
283  /* Now the device should be in one bit mode for sure and we perform a
284  device reset.*/
285  qspiCommand(devp->config->busp, &cmd_reset_enable_1);
286  qspiCommand(devp->config->busp, &cmd_reset_memory_1);
287 }
288 #endif /* JESD216_BUS_MODE != JESD216_BUS_MODE_SPI */
289 
290 static flash_error_t m25q_poll_status(M25QDriver *devp) {
291  uint8_t sts;
292 
293  do {
294 #if M25Q_NICE_WAITING == TRUE
296 #endif
297  /* Read status command.*/
298  jesd216_cmd_receive(devp->config->busp, M25Q_CMD_READ_FLAG_STATUS_REGISTER,
299  1, &sts);
300  } while ((sts & M25Q_FLAGS_PROGRAM_ERASE) == 0U);
301 
302  /* Checking for errors.*/
303  if ((sts & M25Q_FLAGS_ALL_ERRORS) != 0U) {
304  /* Clearing status register.*/
305  jesd216_cmd(devp->config->busp, M25Q_CMD_CLEAR_FLAG_STATUS_REGISTER);
306 
307  /* Program operation failed.*/
308  return FLASH_ERROR_PROGRAM;
309  }
310 
311  return FLASH_NO_ERROR;
312 }
313 
314 static const flash_descriptor_t *m25q_get_descriptor(void *instance) {
315  M25QDriver *devp = (M25QDriver *)instance;
316 
317  osalDbgCheck(instance != NULL);
318  osalDbgAssert((devp->state != FLASH_UNINIT) && (devp->state != FLASH_STOP),
319  "invalid state");
320 
321  return &m25q_descriptor;
322 }
323 
324 static flash_error_t m25q_read(void *instance, flash_offset_t offset,
325  size_t n, uint8_t *rp) {
326  M25QDriver *devp = (M25QDriver *)instance;
327 
328  osalDbgCheck((instance != NULL) && (rp != NULL) && (n > 0U));
329  osalDbgCheck((size_t)offset + n <= (size_t)m25q_descriptor.sectors_count *
330  (size_t)m25q_descriptor.sectors_size);
331  osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
332  "invalid state");
333 
334  if (devp->state == FLASH_ERASE) {
335  return FLASH_BUSY_ERASING;
336  }
337 
338  /* Bus acquired.*/
339  jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
340 
341  /* FLASH_READY state while the operation is performed.*/
342  devp->state = FLASH_READ;
343 
344 #if JESD216_BUS_MODE != JESD216_BUS_MODE_SPI
345  /* Fast read command in QSPI mode.*/
346  jesd216_cmd_addr_dummy_receive(devp->config->busp, M25Q_CMD_FAST_READ,
347  offset, M25Q_READ_DUMMY_CYCLES, n, rp);
348 #else
349  /* Normal read command in SPI mode.*/
350  jesd216_cmd_addr_receive(devp->config->busp, M25Q_CMD_READ,
351  offset, n, rp);
352 #endif
353 
354  /* Ready state again.*/
355  devp->state = FLASH_READY;
356 
357  /* Bus released.*/
358  jesd216_bus_release(devp->config->busp);
359 
360  return FLASH_NO_ERROR;
361 }
362 
363 static flash_error_t m25q_program(void *instance, flash_offset_t offset,
364  size_t n, const uint8_t *pp) {
365  M25QDriver *devp = (M25QDriver *)instance;
366 
367  osalDbgCheck((instance != NULL) && (pp != NULL) && (n > 0U));
368  osalDbgCheck((size_t)offset + n <= (size_t)m25q_descriptor.sectors_count *
369  (size_t)m25q_descriptor.sectors_size);
370  osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
371  "invalid state");
372 
373  if (devp->state == FLASH_ERASE) {
374  return FLASH_BUSY_ERASING;
375  }
376 
377  /* Bus acquired.*/
378  jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
379 
380  /* FLASH_PGM state while the operation is performed.*/
381  devp->state = FLASH_PGM;
382 
383  /* Data is programmed page by page.*/
384  while (n > 0U) {
385  flash_error_t err;
386 
387  /* Data size that can be written in a single program page operation.*/
388  size_t chunk = (size_t)(((offset | PAGE_MASK) + 1U) - offset);
389  if (chunk > n) {
390  chunk = n;
391  }
392 
393  /* Enabling write operation.*/
394  jesd216_cmd(devp->config->busp, M25Q_CMD_WRITE_ENABLE);
395 
396  /* Page program command.*/
397  jesd216_cmd_addr_send(devp->config->busp, M25Q_CMD_PAGE_PROGRAM, offset,
398  chunk, pp);
399 
400  /* Wait for status and check errors.*/
401  err = m25q_poll_status(devp);
402  if (err != FLASH_NO_ERROR) {
403 
404  /* Bus released.*/
405  jesd216_bus_release(devp->config->busp);
406 
407  return err;
408  }
409 
410  /* Next page.*/
411  offset += chunk;
412  pp += chunk;
413  n -= chunk;
414  }
415 
416  /* Ready state again.*/
417  devp->state = FLASH_READY;
418 
419  /* Bus released.*/
420  jesd216_bus_release(devp->config->busp);
421 
422  return FLASH_NO_ERROR;
423 }
424 
425 static flash_error_t m25q_start_erase_all(void *instance) {
426  M25QDriver *devp = (M25QDriver *)instance;
427 
428  osalDbgCheck(instance != NULL);
429  osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
430  "invalid state");
431 
432  if (devp->state == FLASH_ERASE) {
433  return FLASH_BUSY_ERASING;
434  }
435 
436  /* Bus acquired.*/
437  jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
438 
439  /* FLASH_ERASE state while the operation is performed.*/
440  devp->state = FLASH_ERASE;
441 
442  /* Enabling write operation.*/
443  jesd216_cmd(devp->config->busp, M25Q_CMD_WRITE_ENABLE);
444 
445  /* Bulk erase command.*/
446  jesd216_cmd(devp->config->busp, M25Q_CMD_BULK_ERASE);
447 
448  /* Bus released.*/
449  jesd216_bus_release(devp->config->busp);
450 
451  return FLASH_NO_ERROR;
452 }
453 
454 static flash_error_t m25q_start_erase_sector(void *instance,
455  flash_sector_t sector) {
456  M25QDriver *devp = (M25QDriver *)instance;
457  flash_offset_t offset = (flash_offset_t)(sector * SECTOR_SIZE);
458 
459  osalDbgCheck(instance != NULL);
460  osalDbgCheck(sector < m25q_descriptor.sectors_count);
461  osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
462  "invalid state");
463 
464  if (devp->state == FLASH_ERASE) {
465  return FLASH_BUSY_ERASING;
466  }
467 
468  /* Bus acquired.*/
469  jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
470 
471  /* FLASH_ERASE state while the operation is performed.*/
472  devp->state = FLASH_ERASE;
473 
474  /* Enabling write operation.*/
475  jesd216_cmd(devp->config->busp, M25Q_CMD_WRITE_ENABLE);
476 
477  /* Sector erase command.*/
478  jesd216_cmd_addr(devp->config->busp, M25Q_CMD_SECTOR_ERASE, offset);
479 
480  /* Bus released.*/
481  jesd216_bus_release(devp->config->busp);
482 
483  return FLASH_NO_ERROR;
484 }
485 
486 static flash_error_t m25q_verify_erase(void *instance,
487  flash_sector_t sector) {
488  M25QDriver *devp = (M25QDriver *)instance;
489  uint8_t cmpbuf[M25Q_COMPARE_BUFFER_SIZE];
490  flash_offset_t offset;
491  size_t n;
492 
493  osalDbgCheck(instance != NULL);
494  osalDbgCheck(sector < m25q_descriptor.sectors_count);
495  osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
496  "invalid state");
497 
498  if (devp->state == FLASH_ERASE) {
499  return FLASH_BUSY_ERASING;
500  }
501 
502  /* Bus acquired.*/
503  jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
504 
505  /* FLASH_READY state while the operation is performed.*/
506  devp->state = FLASH_READ;
507 
508  /* Read command.*/
509  offset = (flash_offset_t)(sector * SECTOR_SIZE);
510  n = SECTOR_SIZE;
511  while (n > 0U) {
512  uint8_t *p;
513 
514 #if JESD216_BUS_MODE != JESD216_BUS_MODE_SPI
515  jesd216_cmd_addr_dummy_receive(devp->config->busp, M25Q_CMD_FAST_READ,
516  offset, M25Q_READ_DUMMY_CYCLES,
517  sizeof cmpbuf, cmpbuf);
518 #else
519  /* Normal read command in SPI mode.*/
520  jesd216_cmd_addr_receive(devp->config->busp, M25Q_CMD_READ,
521  offset, sizeof cmpbuf, cmpbuf);
522 #endif
523 
524  /* Checking for erased state of current buffer.*/
525  for (p = cmpbuf; p < &cmpbuf[M25Q_COMPARE_BUFFER_SIZE]; p++) {
526  if (*p != 0xFFU) {
527  /* Ready state again.*/
528  devp->state = FLASH_READY;
529 
530  /* Bus released.*/
531  jesd216_bus_release(devp->config->busp);
532 
533  return FLASH_ERROR_VERIFY;
534  }
535  }
536 
537  offset += sizeof cmpbuf;
538  n -= sizeof cmpbuf;
539  }
540 
541  /* Ready state again.*/
542  devp->state = FLASH_READY;
543 
544  /* Bus released.*/
545  jesd216_bus_release(devp->config->busp);
546 
547  return FLASH_NO_ERROR;
548 }
549 
550 static flash_error_t m25q_query_erase(void *instance, uint32_t *msec) {
551  M25QDriver *devp = (M25QDriver *)instance;
552  uint8_t sts;
553 
554  osalDbgCheck(instance != NULL);
555  osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
556  "invalid state");
557 
558  /* If there is an erase in progress then the device must be checked.*/
559  if (devp->state == FLASH_ERASE) {
560 
561  /* Bus acquired.*/
562  jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
563 
564  /* Read status command.*/
565  jesd216_cmd_receive(devp->config->busp, M25Q_CMD_READ_FLAG_STATUS_REGISTER,
566  1, &sts);
567 
568  /* If the P/E bit is zero (busy) or the flash in a suspended state then
569  report that the operation is still in progress.*/
570  if (((sts & M25Q_FLAGS_PROGRAM_ERASE) == 0U) ||
571  ((sts & M25Q_FLAGS_ERASE_SUSPEND) != 0U)) {
572 
573  /* Bus released.*/
574  jesd216_bus_release(devp->config->busp);
575 
576  /* Recommended time before polling again, this is a simplified
577  implementation.*/
578  if (msec != NULL) {
579  *msec = 1U;
580  }
581 
582  return FLASH_BUSY_ERASING;
583  }
584 
585  /* The device is ready to accept commands.*/
586  devp->state = FLASH_READY;
587 
588  /* Checking for errors.*/
589  if ((sts & M25Q_FLAGS_ALL_ERRORS) != 0U) {
590 
591  /* Clearing status register.*/
592  jesd216_cmd(devp->config->busp, M25Q_CMD_CLEAR_FLAG_STATUS_REGISTER);
593 
594  /* Erase operation failed.*/
595  return FLASH_ERROR_ERASE;
596  }
597 
598  /* Bus released.*/
599  jesd216_bus_release(devp->config->busp);
600  }
601 
602  return FLASH_NO_ERROR;
603 }
604 
605 static flash_error_t m25q_read_sfdp(void *instance, flash_offset_t offset,
606  size_t n, uint8_t *rp) {
607 
608  (void)instance;
609  (void)rp;
610  (void)offset;
611  (void)n;
612 
613  return FLASH_NO_ERROR;
614 }
615 
616 /*===========================================================================*/
617 /* Driver exported functions. */
618 /*===========================================================================*/
619 
620 /**
621  * @brief Initializes an instance.
622  *
623  * @param[out] devp pointer to the @p M25QDriver object
624  *
625  * @init
626  */
628 
629  osalDbgCheck(devp != NULL);
630 
631  devp->vmt = &m25q_vmt;
632  devp->state = FLASH_STOP;
633  devp->config = NULL;
634 }
635 
636 /**
637  * @brief Configures and activates N25Q128 driver.
638  *
639  * @param[in] devp pointer to the @p M25QDriver object
640  * @param[in] config pointer to the configuration
641  *
642  * @api
643  */
644 void m25qStart(M25QDriver *devp, const M25QConfig *config) {
645 
646  osalDbgCheck((devp != NULL) && (config != NULL));
647  osalDbgAssert(devp->state != FLASH_UNINIT, "invalid state");
648 
649  devp->config = config;
650 
651  if (devp->state == FLASH_STOP) {
652 
653  /* Bus acquisition.*/
654  jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
655 
656 #if JESD216_BUS_MODE == JESD216_BUS_MODE_SPI
657  /* Reading device ID.*/
658  jesd216_cmd_receive(devp->config->busp, M25Q_CMD_READ_ID,
659  sizeof devp->device_id, devp->device_id);
660 
661 #else /* JESD216_BUS_MODE != JESD216_BUS_MODE_SPI */
662  /* Attempting a reset of the XIP mode, it could be in an unexpected state
663  because a CPU reset does not reset the memory too.*/
664  m25q_reset_xip(devp);
665 
666  /* Attempting a eeset of the device, it could be in an unexpected state
667  because a CPU reset does not reset the memory too.*/
668  m25q_reset_memory(devp);
669 
670  /* Reading device ID and unique ID.*/
671  qspiReceive(devp->config->busp, &m25q_cmd_read_id,
672  sizeof devp->device_id, devp->device_id);
673 #endif /* JESD216_BUS_MODE != JESD216_BUS_MODE_SPI */
674 
675  /* Checking if the device is white listed.*/
676  osalDbgAssert(m25q_find_id(m25q_manufacturer_ids,
677  sizeof m25q_manufacturer_ids,
678  devp->device_id[0]),
679  "invalid manufacturer id");
680  osalDbgAssert(m25q_find_id(m25q_memory_type_ids,
681  sizeof m25q_memory_type_ids,
682  devp->device_id[1]),
683  "invalid memory type id");
684 
685 #if (JESD216_BUS_MODE != JESD216_BUS_MODE_SPI) && (M25Q_SWITCH_WIDTH == TRUE)
686  /* Setting up final bus width.*/
687  qspiCommand(devp->config->busp, &m25q_cmd_write_enable);
688  qspiSend(devp->config->busp, &m25q_cmd_write_evconf, 1, m25q_evconf_value);
689 
690  {
691  uint8_t id[3];
692 
693  /* Reading ID again for confirmation.*/
694  jesd216_cmd_receive(devp->config->busp, M25Q_CMD_MULTIPLE_IO_READ_ID,
695  3, id);
696 
697  /* Checking if the device is white listed.*/
698  osalDbgAssert(memcmp(id, devp->device_id, 3) == 0,
699  "id confirmation failed");
700  }
701 #endif
702 
703  /* Setting up the device size.*/
704  m25q_descriptor.sectors_count = (1U << (size_t)devp->device_id[2]) /
705  SECTOR_SIZE;
706 
707 #if (JESD216_BUS_MODE != JESD216_BUS_MODE_SPI)
708  {
709  static const uint8_t flash_conf[1] = {
710  (M25Q_READ_DUMMY_CYCLES << 4U) | 0x0FU
711  };
712 
713  /* Setting up the dummy cycles to be used for fast read operations.*/
714  jesd216_cmd(devp->config->busp, M25Q_CMD_WRITE_ENABLE);
715  jesd216_cmd_send(devp->config->busp, M25Q_CMD_WRITE_V_CONF_REGISTER,
716  1, flash_conf);
717  }
718 #endif
719 
720  /* Driver in ready state.*/
721  devp->state = FLASH_READY;
722 
723  /* Bus release.*/
724  jesd216_bus_release(devp->config->busp);
725  }
726 }
727 
728 /**
729  * @brief Deactivates the N25Q128 driver.
730  *
731  * @param[in] devp pointer to the @p M25QDriver object
732  *
733  * @api
734  */
735 void m25qStop(M25QDriver *devp) {
736 
737  osalDbgCheck(devp != NULL);
738  osalDbgAssert(devp->state != FLASH_UNINIT, "invalid state");
739 
740  if (devp->state != FLASH_STOP) {
741 
742  /* Bus acquisition.*/
743  jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
744 
745  /* Stopping bus device.*/
746  jesd216_stop(devp->config->busp);
747 
748  /* Deleting current configuration.*/
749  devp->config = NULL;
750 
751  /* Driver stopped.*/
752  devp->state = FLASH_STOP;
753 
754  /* Bus release.*/
755  jesd216_bus_release(devp->config->busp);
756  }
757 }
758 
759 #if (JESD216_BUS_MODE != JESD216_BUS_MODE_SPI) || defined(__DOXYGEN__)
760 #if (QSPI_SUPPORTS_MEMMAP == TRUE) || defined(__DOXYGEN__)
761 /**
762  * @brief Enters the memory Mapping mode.
763  * @details The memory mapping mode is only available when the QSPI mode
764  * is selected and the underlying QSPI controller supports the
765  * feature.
766  *
767  * @param[in] devp pointer to the @p M25QDriver object
768  * @param[out] addrp pointer to the memory start address of the mapped
769  * flash or @p NULL
770  *
771  * @api
772  */
773 void m25qMemoryMap(M25QDriver *devp, uint8_t **addrp) {
774  static const uint8_t flash_status_xip[1] = {
775  (M25Q_READ_DUMMY_CYCLES << 4U) | 0x07U
776  };
777  qspi_command_t cmd;
778 
779  /* Bus acquisition.*/
780  jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
781 
782  /* Activating XIP mode in the device.*/
783  jesd216_cmd(devp->config->busp, M25Q_CMD_WRITE_ENABLE);
784  jesd216_cmd_send(devp->config->busp, M25Q_CMD_WRITE_V_CONF_REGISTER,
785  1, flash_status_xip);
786 
787  /* Putting the QSPI driver in memory mapped mode.*/
788  cmd.cfg = QSPI_CFG_CMD(M25Q_CMD_FAST_READ) |
789  QSPI_CFG_ADDR_SIZE_24 |
790 #if JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI1L
791  QSPI_CFG_CMD_MODE_ONE_LINE |
792  QSPI_CFG_ADDR_MODE_ONE_LINE |
793  QSPI_CFG_DATA_MODE_ONE_LINE |
794 #elif JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI2L
795  QSPI_CFG_CMD_MODE_TWO_LINES |
796  QSPI_CFG_ADDR_MODE_TWO_LINES |
797  QSPI_CFG_DATA_MODE_TWO_LINES |
798 #else
799  QSPI_CFG_CMD_MODE_FOUR_LINES |
800  QSPI_CFG_ADDR_MODE_FOUR_LINES |
801  QSPI_CFG_DATA_MODE_FOUR_LINES |
802 #endif
803  QSPI_CFG_ALT_MODE_FOUR_LINES | /* Always 4 lines, note.*/
804  QSPI_CFG_ALT_SIZE_8 |
805  QSPI_CFG_SIOO |
806  QSPI_CFG_DUMMY_CYCLES(M25Q_READ_DUMMY_CYCLES - 2);
807 
808  qspiMapFlash(devp->config->busp, &cmd, addrp);
809 
810  /* Bus release.*/
811  jesd216_bus_release(devp->config->busp);
812 }
813 
814 /**
815  * @brief Leaves the memory Mapping mode.
816  *
817  * @param[in] devp pointer to the @p M25QDriver object
818  *
819  * @api
820  */
822 
823  /* Bus acquisition.*/
824  jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
825 
826  qspiUnmapFlash(devp->config->busp);
827 
828  m25q_reset_xip(devp);
829 
830  /* Bus release.*/
831  jesd216_bus_release(devp->config->busp);
832 }
833 #endif /* QSPI_SUPPORTS_MEMMAP == TRUE */
834 #endif /* JESD216_BUS_MODE != JESD216_BUS_MODE_SPI */
835 
836 /** @} */
uint8_t device_id[20]
Device ID and unique ID.
Definition: m25q.h:244
uint32_t flash_sector_t
Type of a flash sector number.
Definition: hal_flash.h:88
void m25qMemoryMap(M25QDriver *devp, uint8_t **addrp)
Enters the memory Mapping mode.
Definition: m25q.c:773
#define M25Q_SUPPORTED_MEMORY_TYPE_IDS
Supported memory type identifiers.
Definition: m25q.h:173
uint32_t attributes
Device_attributes.
Definition: hal_flash.h:111
void m25qObjectInit(M25QDriver *devp)
Initializes an instance.
Definition: m25q.c:627
void qspiUnmapFlash(QSPIDriver *qspip)
Unmaps from memory space a QSPI flash device.
Definition: hal_qspi.c:339
const struct M25QDriverVMT * vmt
M25QDriver Virtual Methods Table.
Definition: m25q.h:235
#define M25Q_READ_DUMMY_CYCLES
Number of dummy cycles for fast read (1..15).
Definition: m25q.h:130
HAL subsystem header.
uint32_t sectors_size
Size of sectors for devices with uniform sector size.
Definition: hal_flash.h:131
void m25qStart(M25QDriver *devp, const M25QConfig *config)
Configures and activates N25Q128 driver.
Definition: m25q.c:644
static flash_descriptor_t m25q_descriptor
N25Q128 descriptor.
Definition: m25q.c:84
#define osalThreadSleepMilliseconds(msecs)
Delays the invoking thread for the specified number of milliseconds.
Definition: osal.h:451
Type of M25Q flash class.
Definition: m25q.h:231
void m25qStop(M25QDriver *devp)
Deactivates the N25Q128 driver.
Definition: m25q.c:735
Type of a flash device descriptor.
Definition: hal_flash.h:107
M25Q virtual methods table.
Definition: m25q.h:222
Micron serial flash driver header.
static const struct M25QDriverVMT m25q_vmt
Virtual methods table.
Definition: m25q.c:73
void qspiReceive(QSPIDriver *qspip, const qspi_command_t *cmdp, size_t n, uint8_t *rxbuf)
Sends a command then receives data over the QSPI bus.
Definition: hal_qspi.c:281
flash_error_t
Type of a flash error code.
Definition: hal_flash.h:70
#define osalDbgCheck(c)
Function parameters check.
Definition: osal.h:278
#define M25Q_SUPPORTED_MANUFACTURE_IDS
Supported JEDEC manufacturer identifiers.
Definition: m25q.h:166
#define M25Q_COMPARE_BUFFER_SIZE
Size of the compare buffer.
Definition: m25q.h:184
_jesd216_flash_data const M25QConfig * config
Current configuration data.
Definition: m25q.h:240
void qspiSend(QSPIDriver *qspip, const qspi_command_t *cmdp, size_t n, const uint8_t *txbuf)
Sends a command with data over the QSPI bus.
Definition: hal_qspi.c:249
uint32_t flash_offset_t
Type of a flash offset.
Definition: hal_flash.h:83
void m25qMemoryUnmap(M25QDriver *devp)
Leaves the memory Mapping mode.
Definition: m25q.c:821
void qspiMapFlash(QSPIDriver *qspip, const qspi_command_t *cmdp, uint8_t **addrp)
Maps in memory space a QSPI flash device.
Definition: hal_qspi.c:313
void qspiCommand(QSPIDriver *qspip, const qspi_command_t *cmdp)
Sends a command without data phase.
Definition: hal_qspi.c:219
#define osalDbgAssert(c, remark)
Condition assertion.
Definition: osal.h:258
Type of a M25Q configuration structure.
Definition: m25q.h:207
flash_sector_t sectors_count
Number of sectors in the device.
Definition: hal_flash.h:119
Type of a QSPI command descriptor.
Definition: hal_qspi.h:125