EFR32 Mighty Gecko 1 Software Documentation  efr32mg1-doc-5.1.2
nandflash.c
Go to the documentation of this file.
1 /**************************************************************************/
18 #include <stddef.h>
19 
20 #include "em_device.h"
21 #include "em_dma.h"
22 #include "em_ebi.h"
23 #include "dmactrl.h"
24 #include "nandflash.h"
25 
26 /**************************************************************************/
42 /* Define how NAND flash control signals is connected to the EFM32GG. */
43 #define NAND_POWER_PORT 1
44 #define NAND_POWER_PIN (1 << 15)
45 #define NAND_READY_PORT 3
46 #define NAND_READY_PIN (1 << 15)
47 #define NAND_CE_PORT 3
48 #define NAND_CE_PIN (1 << 14)
49 #define NAND_WP_PORT 3
50 #define NAND_WP_PIN (1 << 13)
51 #define NAND_ALE_BIT 24
52 #define NAND_CLE_BIT 25
53 
54 /* Values secifically for Numonyx NAND256W3A. */
55 #define NAND256W3A_SIGNATURE 0x7520
56 #define NAND256W3A_SIZE (32 * 1024 * 1024)
57 #define NAND256W3A_PAGESIZE 512
58 #define NAND256W3A_BLOCKSIZE (16 * 1024)
59 
60 /* Generic NAND flash definitions. */
61 #define NAND_PAGEADDR_MASK (NAND256W3A_PAGESIZE - 1)
62 #define NAND_BLOCKADDR_MASK (NAND256W3A_BLOCKSIZE - 1)
63 
64 #define NAND_RDA_CMD 0x00
65 #define NAND_RDB_CMD 0x01
66 #define NAND_RDC_CMD 0x50
67 #define NAND_RDSIGN_CMD 0x90
68 #define NAND_RDSTATUS_CMD 0x70
69 #define NAND_PAGEPROG1_CMD 0x80
70 #define NAND_PAGEPROG2_CMD 0x10
71 #define NAND_CPBPROG1_CMD 0x00
72 #define NAND_CPBPROG2_CMD 0x8A
73 #define NAND_CPBPROG3_CMD 0x10
74 #define NAND_BLOCKERASE1_CMD 0x60
75 #define NAND_BLOCKERASE2_CMD 0xD0
76 #define NAND_RST_CMD 0xFF
77 
78 #define NAND_STATUS_SR7 0x80
79 #define NAND_STATUS_SR6 0x40
80 #define NAND_STATUS_SR0 0x01
81 
82 /* NAND access macros. */
83 #define NAND_DATA8 *pNandData8
84 #define NAND_DATA16 *pNandData16
85 #define NAND_DATA32 *pNandData32
86 #define NAND_ADDR *pNandAddr
87 #define NAND_CMD *pNandCmd
88 
89 /* DMA configuration structures. */
90 static const DMA_Init_TypeDef dmaInit =
91 {
92  .hprot = 0,
93  .controlBlock = dmaControlBlock
94 };
95 
96 static const DMA_CfgChannel_TypeDef chnCfg =
97 {
98  .highPri = false, /* Default priority */
99  .enableInt = false, /* No interrupt on transfer completion */
100  .select = 0, /* Memory-memory transfers */
101  .cb = NULL /* No transfer completion callback */
102 };
103 
104 static const DMA_CfgDescr_TypeDef descCfgWr =
105 {
106  .dstInc = dmaDataIncNone,
107  .srcInc = dmaDataInc4,
108  .size = dmaDataSize4,
109  .arbRate = dmaArbitrate1,
110  .hprot = 0
111 };
112 
113 static const DMA_CfgDescr_TypeDef descCfgRd =
114 {
115  .dstInc = dmaDataInc4,
116  .srcInc = dmaDataIncNone,
117  .size = dmaDataSize4,
118  .arbRate = dmaArbitrate1,
119  .hprot = 0
120 };
121 
122 /* Private variables. */
123 static NANDFLASH_Info_TypeDef flashInfo;
124 static bool flashInitialized = false;
125 
126 static uint8_t volatile *pNandData8;
127 static uint16_t volatile *pNandData16;
128 static uint32_t volatile *pNandData32;
129 static uint8_t volatile *pNandAddr;
130 static uint8_t volatile *pNandCmd;
131 
132 /* Private function prototypes. */
133 __STATIC_INLINE void chipEnable(bool enable);
134 static int flashInterrogate(void);
135 __STATIC_INLINE void powerEnable(bool enable);
136 static uint16_t readSignature(void);
137 static uint8_t readStatus(void);
138 static void reset(void);
139 static void dmaRead(uint8_t *dst, int count);
140 static void dmaWrite(uint8_t *src, int count);
141 __STATIC_INLINE void waitReady(void);
142 __STATIC_INLINE void writeProtect(bool enable);
143 
146 /***************************************************************************/
156 bool NANDFLASH_AddressValid(uint32_t address)
157 {
158  if (flashInitialized)
159  {
160  if ((address >= flashInfo.baseAddress) &&
161  (address < (flashInfo.baseAddress + flashInfo.deviceSize)))
162  {
163  return true;
164  }
165  }
166 
167  return false;
168 }
169 
170 /***************************************************************************/
188 int NANDFLASH_CopyPage(uint32_t dstAddr, uint32_t srcAddr)
189 {
190  int status;
191 
192  if (!flashInitialized)
193  {
194  EFM_ASSERT(false);
196  }
197 
198  dstAddr &= ~NAND_PAGEADDR_MASK;
199  srcAddr &= ~NAND_PAGEADDR_MASK;
200 
201  if (!NANDFLASH_AddressValid(dstAddr) ||
202  !NANDFLASH_AddressValid(srcAddr) ||
203  /* Address bit 24 must be equal for source and destination page. */
204  ((dstAddr & (1 << 24)) != (srcAddr & (1 << 24))))
205  {
206  EFM_ASSERT(false);
208  }
209 
210  writeProtect(false);
211  chipEnable(true);
212 
213  NAND_CMD = NAND_CPBPROG1_CMD;
214  NAND_ADDR = (uint8_t) srcAddr;
215  /* Address bit 8 is not used, implicitely defined by NAND_RDA_CMD. */
216  NAND_ADDR = (uint8_t)(srcAddr >> 9);
217  NAND_ADDR = (uint8_t)(srcAddr >> 17);
218 
219  waitReady();
220 
221  NAND_CMD = NAND_CPBPROG2_CMD;
222  NAND_ADDR = (uint8_t) dstAddr;
223  /* Address bit 8 is not used, implicitely defined by NAND_RDA_CMD. */
224  NAND_ADDR = (uint8_t)(dstAddr >> 9);
225  NAND_ADDR = (uint8_t)(dstAddr >> 17);
226  NAND_CMD = NAND_CPBPROG3_CMD;
227 
228  waitReady();
229 
230  status = (readStatus() & NAND_STATUS_SR0) ?
232 
233  chipEnable(false);
234  writeProtect(true);
235 
236  return status;
237 }
238 
239 /***************************************************************************/
249 {
250  if (flashInitialized)
251  {
252  return &flashInfo;
253  }
254  return NULL;
255 }
256 
257 /***************************************************************************/
275 int NANDFLASH_EccCorrect(uint32_t generatedEcc, uint32_t readEcc, uint8_t *data)
276 {
278  #define ECC_MASK24 0x00FFFFFF /* 24 valid ECC parity bits. */
279  #define ECC_MASK 0x00555555 /* 12 ECC parity bits. */
280 
282  int count, bitNum, byteAddr;
283  uint32_t mask;
284  uint32_t syndrome;
285  uint32_t eccP; /* 12 even ECC parity bits. */
286  uint32_t eccPn; /* 12 odd ECC parity bits. */
287 
288  syndrome = (generatedEcc ^ readEcc) & ECC_MASK24;
289 
290  if (syndrome == 0)
291  return NANDFLASH_STATUS_OK; /* No errors in data. */
292 
293  eccPn = syndrome & ECC_MASK; /* Get twelve odd parity bits. */
294  eccP = (syndrome >> 1) & ECC_MASK; /* Get twelve even parity bits. */
295 
296  if ((eccPn ^ eccP) == ECC_MASK) /* 1-bit correctable error ? */
297  {
298  bitNum = (eccP & 0x01) |
299  ((eccP >> 1) & 0x02) |
300  ((eccP >> 2) & 0x04);
301 
302  byteAddr = ((eccP >> 6) & 0x001) |
303  ((eccP >> 7) & 0x002) |
304  ((eccP >> 8) & 0x004) |
305  ((eccP >> 9) & 0x008) |
306  ((eccP >> 10) & 0x010) |
307  ((eccP >> 11) & 0x020) |
308  ((eccP >> 12) & 0x040) |
309  ((eccP >> 13) & 0x080) |
310  ((eccP >> 14) & 0x100);
311 
312  data[ byteAddr ] ^= 1 << bitNum;
313 
314  return NANDFLASH_STATUS_OK;
315  }
316 
317  /* Count number of one's in the syndrome. */
318  count = 0;
319  mask = 0x00800000;
320  while (mask)
321  {
322  if (syndrome & mask)
323  count++;
324  mask >>= 1;
325  }
326 
327  if (count == 1) /* Error in the ECC itself. */
328  return NANDFLASH_ECC_ERROR;
329 
330  return NANDFLASH_ECC_UNCORRECTABLE; /* Unable to correct data. */
331 
333  #undef ECC_MASK
334  #undef ECC_MASK24
335 
336 }
337 
338 /***************************************************************************/
353 int NANDFLASH_EraseBlock(uint32_t address)
354 {
355  int status;
356 
357  if (!flashInitialized)
358  {
359  EFM_ASSERT(false);
361  }
362 
363  address &= ~NAND_BLOCKADDR_MASK;
364 
365  if (!NANDFLASH_AddressValid(address))
366  {
367  EFM_ASSERT(false);
369  }
370 
371  writeProtect(false);
372  chipEnable(true);
373 
374  NAND_CMD = NAND_BLOCKERASE1_CMD;
375  /* Coloumn address, bit 8 is not used, implicitely defined by NAND_RDA_CMD. */
376  NAND_ADDR = (uint8_t)(address >> 9);
377  NAND_ADDR = (uint8_t)(address >> 17);
378  NAND_CMD = NAND_BLOCKERASE2_CMD;
379 
380  waitReady();
381 
382  status = (readStatus() & NAND_STATUS_SR0) ?
384 
385  chipEnable(false);
386  writeProtect(true);
387 
388  return status;
389 }
390 
391 /***************************************************************************/
407 int NANDFLASH_Init(int dmaCh)
408 {
409  if ((dmaCh < -1) || (dmaCh >= DMA_CHAN_COUNT))
410  {
411  EFM_ASSERT(false);
413  }
414 
415  flashInfo.dmaCh = dmaCh;
416 
417  if (dmaCh >= 0)
418  {
419  DMA_Init((void*) &dmaInit); /* Initialize the DMA */
420  DMA_CfgChannel(dmaCh, (void*) &chnCfg); /* Configure the DMA channel */
421  }
422 
423  return flashInterrogate();
424 }
425 
426 /***************************************************************************/
442 int NANDFLASH_MarkBadBlock(uint32_t address)
443 {
444  if (!flashInitialized)
445  {
446  EFM_ASSERT(false);
448  }
449 
450  address &= ~NAND_BLOCKADDR_MASK;
451 
452  if (!NANDFLASH_AddressValid(address))
453  {
454  EFM_ASSERT(false);
456  }
457 
458  writeProtect(false);
459  chipEnable(true);
460 
461  NAND_CMD = NAND_RDC_CMD;
462  NAND_CMD = NAND_PAGEPROG1_CMD;
463  NAND_ADDR = (uint8_t) address;
464  /* Address bit 8 is not used, implicitely defined by NAND_RDC_CMD. */
465  NAND_ADDR = (uint8_t)(address >> 9);
466  NAND_ADDR = (uint8_t)(address >> 17);
467 
468  /* Write bad block marker 0x00 to the 6th byte in the spare area */
469  NAND_DATA32 = 0xFFFFFFFF;
470  NAND_DATA16 = 0x00FF;
471  NAND_CMD = NAND_PAGEPROG2_CMD;
472 
473  waitReady();
474  readStatus();
475 
476  chipEnable(false);
477  writeProtect(true);
478 
479  return NANDFLASH_STATUS_OK;
480 }
481 
482 /***************************************************************************/
500 int NANDFLASH_ReadPage(uint32_t address, uint8_t *buffer)
501 {
502  uint32_t i, readEcc, *p;
503 
504  if (!flashInitialized)
505  {
506  EFM_ASSERT(false);
508  }
509 
510  address &= ~NAND_PAGEADDR_MASK;
511 
512  if (!NANDFLASH_AddressValid(address))
513  {
514  EFM_ASSERT(false);
516  }
517 
518  chipEnable(true);
519 
520  NAND_CMD = NAND_RDA_CMD;
521  NAND_ADDR = (uint8_t) address;
522  /* Address bit 8 is not used, implicitely defined by NAND_RDA_CMD. */
523  NAND_ADDR = (uint8_t)(address >> 9);
524  NAND_ADDR = (uint8_t)(address >> 17);
525 
526  waitReady();
527 
528  EBI_StartNandEccGen();
529 
530  if (flashInfo.dmaCh == -1)
531  {
532  p = (uint32_t*) buffer;
533  for (i = 0; i < flashInfo.pageSize / 4; i++)
534  {
535  *p++ = NAND_DATA32;
536  }
537  }
538  else
539  {
540  dmaRead(buffer, flashInfo.pageSize);
541  }
542 
543  flashInfo.ecc = EBI_StopNandEccGen();
544 
545  if (flashInfo.dmaCh == -1)
546  {
547  p = (uint32_t*) flashInfo.spare;
548  for (i = 0; i < flashInfo.spareSize / 4; i++)
549  {
550  *p++ = NAND_DATA32;
551  }
552  }
553  else
554  {
555  dmaRead(flashInfo.spare, flashInfo.spareSize);
556  }
557 
558  chipEnable(false);
559 
560  readEcc = flashInfo.spare[ NAND_SPARE_ECC0_POS ];
561  readEcc += flashInfo.spare[ NAND_SPARE_ECC1_POS ] << 8;
562  readEcc += flashInfo.spare[ NAND_SPARE_ECC2_POS ] << 16;
563 
564  return NANDFLASH_EccCorrect(flashInfo.ecc, readEcc, buffer);
565 }
566 
567 /***************************************************************************/
581 int NANDFLASH_ReadSpare(uint32_t address, uint8_t *buffer)
582 {
583  uint32_t i, *p;
584 
585  if (!flashInitialized)
586  {
587  EFM_ASSERT(false);
589  }
590 
591  address &= ~NAND_PAGEADDR_MASK;
592 
593  if (!NANDFLASH_AddressValid(address))
594  {
595  EFM_ASSERT(false);
597  }
598 
599  chipEnable(true);
600 
601  NAND_CMD = NAND_RDC_CMD;
602  NAND_ADDR = (uint8_t) address;
603  /* Address bit 8 is not used, implicitely defined by NAND_RDC_CMD. */
604  NAND_ADDR = (uint8_t)(address >> 9);
605  NAND_ADDR = (uint8_t)(address >> 17);
606 
607  waitReady();
608 
609  if (flashInfo.dmaCh == -1)
610  {
611  p = (uint32_t*) buffer;
612  for (i = 0; i < flashInfo.spareSize / 4; i++)
613  {
614  *p++ = NAND_DATA32;
615  }
616  }
617  else
618  {
619  dmaRead(buffer, flashInfo.spareSize);
620  }
621 
622  chipEnable(false);
623 
624  return NANDFLASH_STATUS_OK;
625 }
626 
627 /***************************************************************************/
646 int NANDFLASH_WritePage(uint32_t address, uint8_t *buffer)
647 {
648  int status;
649  uint32_t i, *p;
650 
651  if (!flashInitialized)
652  {
653  EFM_ASSERT(false);
655  }
656 
657  address &= ~NAND_PAGEADDR_MASK;
658 
659  if (!NANDFLASH_AddressValid(address))
660  {
661  EFM_ASSERT(false);
663  }
664 
665  writeProtect(false);
666  chipEnable(true);
667 
668  NAND_CMD = NAND_RDA_CMD;
669  NAND_CMD = NAND_PAGEPROG1_CMD;
670  NAND_ADDR = (uint8_t) address;
671  /* Address bit 8 is not used, implicitely defined by NAND_RDA_CMD. */
672  NAND_ADDR = (uint8_t)(address >> 9);
673  NAND_ADDR = (uint8_t)(address >> 17);
674 
675  /* Wait for EBI idle in case of EBI writeBuffer is enabled */
676  while (EBI->STATUS & EBI_STATUS_AHBACT)
677  {
678  }
679  EBI_StartNandEccGen();
680 
681  if (flashInfo.dmaCh == -1)
682  {
683  p = (uint32_t*) buffer;
684  for (i = 0; i < flashInfo.pageSize / 4; i++)
685  {
686  NAND_DATA32 = *p++;
687  }
688  }
689  else
690  {
691  dmaWrite(buffer, flashInfo.pageSize);
692  }
693 
694  /* Wait for EBI idle in case of EBI writeBuffer is enabled */
695  while (EBI->STATUS & EBI_STATUS_AHBACT)
696  {
697  }
698  flashInfo.ecc = EBI_StopNandEccGen();
699 
700  /* Write ECC to spare area */
701  NAND_DATA32 = 0xFFFFFFFF;
702  NAND_DATA16 = 0xFFFF;
703  NAND_DATA8 = flashInfo.ecc;
704  NAND_DATA8 = flashInfo.ecc >> 8;
705  NAND_DATA8 = flashInfo.ecc >> 16;
706  NAND_CMD = NAND_PAGEPROG2_CMD;
707 
708  waitReady();
709 
710  status = (readStatus() & NAND_STATUS_SR0) ?
712 
713  chipEnable(false);
714  writeProtect(true);
715 
716  return status;
717 }
718 
721 /***************************************************************************/
724 __STATIC_INLINE void chipEnable(bool enable)
725 {
726  if (enable)
727  {
728  GPIO->P[NAND_CE_PORT].DOUTCLR = NAND_CE_PIN;
729  }
730  else
731  {
732  GPIO->P[NAND_CE_PORT].DOUTSET = NAND_CE_PIN;
733  }
734 }
735 
736 /***************************************************************************/
739 static int flashInterrogate(void)
740 {
741  flashInfo.baseAddress = EBI_BankAddress(EBI_BANK0);
742 
743  pNandData8 = (uint8_t volatile*) flashInfo.baseAddress;
744  pNandData16 = (uint16_t volatile*) pNandData8;
745  pNandData32 = (uint32_t volatile*) pNandData8;
746  pNandAddr = pNandData8 + (1 << NAND_ALE_BIT);
747  pNandCmd = pNandData8 + (1 << NAND_CLE_BIT);
748 
749  powerEnable(true);
750  waitReady();
751  chipEnable(true);
752  reset();
753 
754  if (readSignature() != NAND256W3A_SIGNATURE)
755  {
756  EFM_ASSERT(false);
758  }
759 
760  chipEnable(false);
761 
762  flashInfo.manufacturerCode = (uint8_t) NAND256W3A_SIGNATURE;
763  flashInfo.deviceCode = (uint8_t)(NAND256W3A_SIGNATURE >> 8);
764  flashInfo.deviceSize = NAND256W3A_SIZE;
765  flashInfo.pageSize = NAND256W3A_PAGESIZE;
766  flashInfo.spareSize = NAND256W3A_SPARESIZE;
767  flashInfo.blockSize = NAND256W3A_BLOCKSIZE;
768 
769  flashInitialized = true;
770 
771  return NANDFLASH_STATUS_OK;
772 }
773 
774 /***************************************************************************/
777 __STATIC_INLINE void powerEnable(bool enable)
778 {
779  if (enable)
780  {
781  GPIO->P[NAND_POWER_PORT].DOUTSET = NAND_POWER_PIN;
782  }
783  else
784  {
785  GPIO->P[NAND_POWER_PORT].DOUTCLR = NAND_POWER_PIN;
786  }
787 }
788 
789 /***************************************************************************/
792 static uint16_t readSignature(void)
793 {
794  NAND_CMD = NAND_RDSIGN_CMD;
795  return NAND_DATA16;
796 }
797 
798 /***************************************************************************/
801 static uint8_t readStatus(void)
802 {
803  NAND_CMD = NAND_RDSTATUS_CMD;
804  return NAND_DATA8;
805 }
806 
807 /***************************************************************************/
810 static void reset(void)
811 {
812  NAND_CMD = NAND_RST_CMD;
813  waitReady();
814 }
815 
816 /***************************************************************************/
819 static void dmaRead(uint8_t *dst, int count)
820 {
821  DMA_CfgDescr(flashInfo.dmaCh, true, (void*) &descCfgRd);
822  DMA_ActivateAuto(flashInfo.dmaCh, true, dst, (void*) pNandData32, (count / 4) - 1);
823  while ((dmaControlBlock[flashInfo.dmaCh].CTRL & _DMA_CTRL_CYCLE_CTRL_MASK)
824  != DMA_CTRL_CYCLE_CTRL_INVALID)
825  {
826  }
827 }
828 
829 /***************************************************************************/
832 static void dmaWrite(uint8_t *src, int count)
833 {
834  DMA_CfgDescr(flashInfo.dmaCh, true, (void*) &descCfgWr);
835  DMA_ActivateAuto(flashInfo.dmaCh, true, (void*) pNandData32, src, (count / 4) - 1);
836  while ((dmaControlBlock[flashInfo.dmaCh].CTRL & _DMA_CTRL_CYCLE_CTRL_MASK)
837  != DMA_CTRL_CYCLE_CTRL_INVALID)
838  {
839  }
840 }
841 
842 /***************************************************************************/
845 __STATIC_INLINE void waitReady(void)
846 {
847  /* Wait for EBI idle in case of EBI writeBuffer is enabled */
848  while (EBI->STATUS & EBI_STATUS_AHBACT)
849  {
850  }
851  /* Wait on Ready/Busy pin to become high */
852  while ((GPIO->P[NAND_READY_PORT].DIN & NAND_READY_PIN) == 0)
853  {
854  }
855 }
856 
857 /***************************************************************************/
860 __STATIC_INLINE void writeProtect(bool enable)
861 {
862  if (enable)
863  {
864  GPIO->P[NAND_WP_PORT].DOUTCLR = NAND_WP_PIN;
865  }
866  else
867  {
868  GPIO->P[NAND_WP_PORT].DOUTSET = NAND_WP_PIN;
869  }
870 }
871 
#define GPIO
#define NAND_SPARE_ECC2_POS
Definition: nandflash.h:40
uint8_t spare[NAND256W3A_SPARESIZE]
Definition: nandflash.h:66
int NANDFLASH_WritePage(uint32_t address, uint8_t *buffer)
Write a page in nand device. The ECC generated while writing the page data is written in the spare ar...
Definition: nandflash.c:646
CMSIS Cortex-M Peripheral Access Layer for Silicon Laboratories microcontroller devices.
int NANDFLASH_MarkBadBlock(uint32_t address)
Mark a block as bad.
Definition: nandflash.c:442
uint8_t manufacturerCode
Definition: nandflash.h:59
#define NAND_SPARE_ECC1_POS
Definition: nandflash.h:39
int NANDFLASH_CopyPage(uint32_t dstAddr, uint32_t srcAddr)
Copy a page within the device to a new location.
Definition: nandflash.c:188
EFM32GG_STK3700 nandflash driver.
External Bus Iterface (EBI) peripheral API.
int NANDFLASH_ReadSpare(uint32_t address, uint8_t *buffer)
Read the spare area content of a page.
Definition: nandflash.c:581
int NANDFLASH_Init(int dmaCh)
Initialize the NANDFLASH module.
Definition: nandflash.c:407
int NANDFLASH_EccCorrect(uint32_t generatedEcc, uint32_t readEcc, uint8_t *data)
Check generated ECC against ECC read from device and correct data if possible.
Definition: nandflash.c:275
NANDFLASH_Info_TypeDef * NANDFLASH_DeviceInfo(void)
Return a pointer to a NANDFLASH_Info_TypeDef structure, which contain vital nand flash device informa...
Definition: nandflash.c:248
#define NAND_SPARE_ECC0_POS
Definition: nandflash.h:38
NANDFLASH device information structure.
Definition: nandflash.h:56
#define NAND256W3A_SPARESIZE
Definition: nandflash.h:34
int NANDFLASH_ReadPage(uint32_t address, uint8_t *buffer)
Read a page from nand device. Ecc errors will be detected and corrected if possible. NANDFLASH_Info_TypeDef::ecc will be set to the ecc generated while reading the page data. NANDFLASH_Info_TypeDef::spare will be set to the content of the page spare area.
Definition: nandflash.c:500
int NANDFLASH_EraseBlock(uint32_t address)
Erase a block in the nand flash.
Definition: nandflash.c:353
Direct memory access (DMA) API.
DMA control data block.
bool NANDFLASH_AddressValid(uint32_t address)
Check if an address is valid for the nand flash device.
Definition: nandflash.c:156
#define DMA_CHAN_COUNT