细说STM32H743XIH6单片机通过FMC访问片外NAND Flash的方法及实例

目录

一、工程配置

[1、SYSTEM CORE](#1、SYSTEM CORE)

(1)RCC

(2)CORTEX_M7

(3)NVIC

[2、TRACE AND DEBUG](#2、TRACE AND DEBUG)

3、Connectivity

(1)USART1

(2)FMC

[4、Code Generator](#4、Code Generator)

二、软件设计

1、nand_flash.h/.c

(1)先计算FLASH的物理页地址

(2)再计算FLASH的物理块地址

(3)再计算FLASH的物理plane地址

(4)再计算FLASH的逻辑块地址

(5)再计算FLASH的逻辑页地址

(6)最后计算FLASH的逻辑plane地址

2、main.c

[(1)查询NAND FLASH的参数](#(1)查询NAND FLASH的参数)

(2)建立逻辑盘符与物理地址之间的映射关系

[(3)调用HAL函数对NAND FLASH进行访问](#(3)调用HAL函数对NAND FLASH进行访问)

三、调试与运行

1、运行结果

2、完整的代码


本文通过实例旨在进一步介绍STM32H743单片机通过FMC扩展NAND FLASH的方法。本文作者通过编写NAND FLASH的驱动,实现了NAND_AddressTypeDef实例的逻辑盘符与物理地址的映射方法。进一步地,通过此驱动,本文可以放心确认逻辑盘符的编号只在同一个block里连续排列,跨block时,逻辑page编号从0开始重新排列。

通过这样的驱动定义,NAND_AddressTypeDef实例的含义一目了然,便于读者和编程人员阅读和理解。比如:NAND_AddressTypeDef addr ={0,0,0}代表page0,plane0,block0;{63,0,1023}代表page63,plane0,block1023;{63,0,1000}代表page63,plane0,block1000;虽然page的编号都是63,但是前者是block1023的page63,后者是block1000的page63。依此类推。

为了更好地理解本文所述内容,可以参考本文作者写的其他本章,参考文章:

细说STM32F407单片机通过FSMC访问片外NAND Flash的方法及实例_mcu移植nand flash-CSDN博客 https://wenchm.blog.csdn.net/article/details/155067571?spm=1011.2415.3001.5331

本文使用安富莱的开发板,STM32-V7;核心板MCU,STM32H743XIH6;核心板载的NAND FLASH:HY27UF081G2A=(2K+64)bytes*1024blocks*1plane;原理图:

本文开发环境使用STM32CubeIDE Version: 1.19.0;

一、工程配置

1、SYSTEM CORE

(1)RCC

HSE外部晶振,25MHz。

(2)CORTEX_M7

禁用I_Cache和D_Cache。

(3)NVIC

修改timebase中断为0,其余默认;

2、TRACE AND DEBUG

选择serial wire。

3、Connectivity

(1)USART1

参数选择默认;

(2)FMC

其中,

cpp 复制代码
TCLRSetupTime=tCLR/tHCLK=15/5=3;
TARSetupTime =tAR/tHCLK=15/5=3;

其中的common space timing in HCLK cycles和attribute space timing in HCLK cycles等8个参数,按照参考文章提供的方法试算,试算的结果不一定符合要求,但接近目标的要求,多测试几次,就会摸索到最合适的参数了。

其中,characteristic infomation按照NAND FLASH数据手册填写。

4、Code Generator

二、软件设计

编译、IDE自动生成驱动。

1、nand_flash.h/.c

这个驱动是本文最大的创新点和贡献。其方法思路是:

(1)先计算FLASH的物理页地址

cpp 复制代码
/* USER CODE BEGIN PRIVATE_DEFINES */
/* @brief 	K9F1G08U0B,128M x 8 Bit NAND Flash Memory,
 * 			total 128M bytes used to USBD MSC
 * 			1 Page	= (2048+64)Bytes
 * 			1 Block	= (2048+64)Bytes x 64 Pages
 *					= (128K + 4K)Bytes
 *			1 Device= (128K + 4K)Bytes x 1024 Blocks
 *					= (128M + 4M)Bytes
 */

/* FSMC Nand Flash Base address. */
#define NAND_FLASH_BASE NAND_DEVICE

/* NAND FLASH PHYSIC LUN BASE ADDRESS*/
#define FLASH_PAGE_BASE		((uint32_t)NAND_FLASH_BASE)
#define FLASH_BLOCKE_BASE	((uint32_t)NAND_FLASH_BASE)
#define FLASH_PLANE_BASE	((uint32_t)NAND_FLASH_BASE)


/** 
 * @brief Calculte physics address. 
 */
/* Base physics address of the Nand Flash pages. */
#define ADDR_FLASH_PAGE_0	((uint32_t)(FLASH_PAGE_BASE + 0x0)) /* Base @ of Page0, 2 Kbyte */
#define ADDR_FLASH_PAGE_1	((uint32_t)(FLASH_PAGE_BASE + 0x800)) /* Base @ of Page1, 2 Kbyte */
#define ADDR_FLASH_PAGE_2	((uint32_t)(FLASH_PAGE_BASE + 0x1000)) /* Base @ of Page2, 2 Kbyte */
#define ADDR_FLASH_PAGE_3	((uint32_t)(FLASH_PAGE_BASE + 0x1800)) /* Base @ of Page3, 2 Kbyte */
#define ADDR_FLASH_PAGE_4	((uint32_t)(FLASH_PAGE_BASE + 0x2000)) /* Base @ of Page4, 2 Kbyte */
#define ADDR_FLASH_PAGE_5	((uint32_t)(FLASH_PAGE_BASE + 0x2800)) /* Base @ of Page5, 2 Kbyte */

...  ....
//省去中间众多宏定义
... ....

#define ADDR_FLASH_PAGE_65528	((uint32_t)(FLASH_PAGE_BASE + 0x7ffc000)) /* Base @ of Page65528, 2 Kbyte */
#define ADDR_FLASH_PAGE_65529	((uint32_t)(FLASH_PAGE_BASE + 0x7ffc800)) /* Base @ of Page65529, 2 Kbyte */
#define ADDR_FLASH_PAGE_65530	((uint32_t)(FLASH_PAGE_BASE + 0x7ffd000)) /* Base @ of Page65530, 2 Kbyte */
#define ADDR_FLASH_PAGE_65531	((uint32_t)(FLASH_PAGE_BASE + 0x7ffd800)) /* Base @ of Page65531, 2 Kbyte */
#define ADDR_FLASH_PAGE_65532	((uint32_t)(FLASH_PAGE_BASE + 0x7ffe000)) /* Base @ of Page65532, 2 Kbyte */
#define ADDR_FLASH_PAGE_65533	((uint32_t)(FLASH_PAGE_BASE + 0x7ffe800)) /* Base @ of Page65533, 2 Kbyte */
#define ADDR_FLASH_PAGE_65534	((uint32_t)(FLASH_PAGE_BASE + 0x7fff000)) /* Base @ of Page65534, 2 Kbyte */
#define ADDR_FLASH_PAGE_65535	((uint32_t)(FLASH_PAGE_BASE + 0x7fff800)) /* Base @ of Page65535, 2 Kbyte */

(2)再计算FLASH的物理块地址

cpp 复制代码
/* Base physics address of the Nand Flash blocks. */
#define ADDR_FLASH_BLOCK_0	((uint32_t)(FLASH_BLOCKE_BASE + 0x0)) /* Base @ of Block0, 128Kbyte */
#define ADDR_FLASH_BLOCK_1	((uint32_t)(FLASH_BLOCKE_BASE + 0x20000)) /* Base @ of Block1, 128Kbyte */
#define ADDR_FLASH_BLOCK_2	((uint32_t)(FLASH_BLOCKE_BASE + 0x40000)) /* Base @ of Block2, 128Kbyte */
#define ADDR_FLASH_BLOCK_3	((uint32_t)(FLASH_BLOCKE_BASE + 0x60000)) /* Base @ of Block3, 128Kbyte */
#define ADDR_FLASH_BLOCK_4	((uint32_t)(FLASH_BLOCKE_BASE + 0x80000)) /* Base @ of Block4, 128Kbyte */
#define ADDR_FLASH_BLOCK_5	((uint32_t)(FLASH_BLOCKE_BASE + 0xa0000)) /* Base @ of Block5, 128Kbyte */
#define ADDR_FLASH_BLOCK_6	((uint32_t)(FLASH_BLOCKE_BASE + 0xc0000)) /* Base @ of Block6, 128Kbyte */
#define ADDR_FLASH_BLOCK_7	((uint32_t)(FLASH_BLOCKE_BASE + 0xe0000)) /* Base @ of Block7, 128Kbyte */
#define ADDR_FLASH_BLOCK_8	((uint32_t)(FLASH_BLOCKE_BASE + 0x100000)) /* Base @ of Block8, 128Kbyte */
#define ADDR_FLASH_BLOCK_9	((uint32_t)(FLASH_BLOCKE_BASE + 0x120000)) /* Base @ of Block9, 128Kbyte */

//省略众多宏定义

#define ADDR_FLASH_BLOCK_1019	((uint32_t)(FLASH_BLOCKE_BASE + 0x7f60000)) /* Base @ of Block1019, 128Kbyte */
#define ADDR_FLASH_BLOCK_1020	((uint32_t)(FLASH_BLOCKE_BASE + 0x7f80000)) /* Base @ of Block1020, 128Kbyte */
#define ADDR_FLASH_BLOCK_1021	((uint32_t)(FLASH_BLOCKE_BASE + 0x7fa0000)) /* Base @ of Block1021, 128Kbyte */
#define ADDR_FLASH_BLOCK_1022	((uint32_t)(FLASH_BLOCKE_BASE + 0x7fc0000)) /* Base @ of Block1022, 128Kbyte */
#define ADDR_FLASH_BLOCK_1023	((uint32_t)(FLASH_BLOCKE_BASE + 0x7fe0000)) /* Base @ of Block1023, 128Kbyte */

(3)再计算FLASH的物理plane地址

cpp 复制代码
/* Base physics address of the Nand Flash plane. */
#define ADDR_FLASH_PLANE_0	((uint32_t)FLASH_PLANE_BASE) /* Base @ of Plane 0, 128 Mbyte */

(4)再计算FLASH的逻辑块地址

cpp 复制代码
/* logic address of the Nand Flash logic blocks. */
#define FLASH_BLOCK_0	((uint16_t)0U) /*!< Logic Block 0 */
#define FLASH_BLOCK_1	((uint16_t)1U) /*!< Logic Block 1 */
#define FLASH_BLOCK_2	((uint16_t)2U) /*!< Logic Block 2 */
#define FLASH_BLOCK_3	((uint16_t)3U) /*!< Logic Block 3 */

//省略中间的定义

#define FLASH_BLOCK_1020	((uint16_t)1020U) /*!< Logic Block 1020 */
#define FLASH_BLOCK_1021	((uint16_t)1021U) /*!< Logic Block 1021 */
#define FLASH_BLOCK_1022	((uint16_t)1022U) /*!< Logic Block 1022 */
#define FLASH_BLOCK_1023	((uint16_t)1023U) /*!< Logic Block 1023 */

(5)再计算FLASH的逻辑页地址

cpp 复制代码
/* logic address of the Nand Flash logic pages. */
#ifdef FLASH_BLOCK_0
#define FLASH_PAGE_0	((uint16_t)0U) /*!< Logic Page 0 of Logic Block 0*/
#define FLASH_PAGE_1	((uint16_t)1U) /*!< Logic Page 1 of Logic Block 0*/
#define FLASH_PAGE_2	((uint16_t)2U) /*!< Logic Page 2 of Logic Block 0*/
#define FLASH_PAGE_3	((uint16_t)3U) /*!< Logic Page 3 of Logic Block 0*/
#define FLASH_PAGE_4	((uint16_t)4U) /*!< Logic Page 4 of Logic Block 0*/
#define FLASH_PAGE_5	((uint16_t)5U) /*!< Logic Page 5 of Logic Block 0*/
#define FLASH_PAGE_6	((uint16_t)6U) /*!< Logic Page 6 of Logic Block 0*/
#define FLASH_PAGE_7	((uint16_t)7U) /*!< Logic Page 7 of Logic Block 0*/
#define FLASH_PAGE_8	((uint16_t)8U) /*!< Logic Page 8 of Logic Block 0*/
#define FLASH_PAGE_9	((uint16_t)9U) /*!< Logic Page 9 of Logic Block 0*/

//省略中间的定义

#define FLASH_PAGE_62	((uint16_t)62U) /*!< Logic Page 62 of Logic Block 0*/
#define FLASH_PAGE_63	((uint16_t)63U) /*!< Logic Page 63 of Logic Block 0*/
#endif

#ifdef FLASH_BLOCK_1
#define FLASH_PAGE_0	((uint16_t)0U) /*!< Logic Page 0 of Logic Block 1*/
#define FLASH_PAGE_1	((uint16_t)1U) /*!< Logic Page 1 of Logic Block 1*/
#define FLASH_PAGE_2	((uint16_t)2U) /*!< Logic Page 2 of Logic Block 1*/

//省略中间的定义

#define FLASH_PAGE_60	((uint16_t)60U) /*!< Logic Page 60 of Logic Block 1023*/
#define FLASH_PAGE_61	((uint16_t)61U) /*!< Logic Page 61 of Logic Block 1023*/
#define FLASH_PAGE_62	((uint16_t)62U) /*!< Logic Page 62 of Logic Block 1023*/
#define FLASH_PAGE_63	((uint16_t)63U) /*!< Logic Page 63 of Logic Block 1023*/
#endif

(6)最后计算FLASH的逻辑plane地址

cpp 复制代码
/* logic address of the Nand Flash logic plane. */
#define FLASH_PLANE_0    ((uint16_t)0U) /*!< Plane Number 0 */

在这个驱动函数里,我们已经定义了物理地址和逻辑地址。在下面的函数里只要建立起来物理地址和逻辑地址之间的一一对应的映射关系,那么就实现了addr从逻辑盘符到物理地址(0x7000 0000基)的映射关系。也就知道了,我们写FLASH,写到了哪里去,读FLASH,从哪里读出来

2、main.c

main.c核心代码是由IDE自动生成的。

部分的私有代码,可以卸载main.c的沙箱里。

(1)查询NAND FLASH的参数

调用HAL函数查询NAND FLASH状态;

调用fsmc.c查询NAND FLASH参数,这里查询参数调用的是fsmc.c而不是HAL驱动函数,这些参数是配置工程的时候,手动输入进去的。

cpp 复制代码
  /* USER CODE BEGIN 2 */
  printf("Test FMC NAND FLASH R/W.\n\r");

  HAL_NAND_StateTypeDef sta;	//0=reset,1=ready,2=busy,3=error
  sta = HAL_NAND_GetState(&hnand1);
  if(sta ==0)
	  printf("Nand Flash status is reset.\n\r");
  else if(sta ==1)
  	  printf("Nand Flash status is ready.\n\r");
  else if(sta ==2)
  	  printf("Nand Flash status is busy.\n\r");
  else if(sta ==3)
  	  printf("Nand Flash status is error.\n\r");

  printf("Nand Flash pagesize = %ld\n",hnand1.Config.PageSize);
  printf("Nand Flash SpareAreaSize = %ld\n",hnand1.Config.SpareAreaSize);
  printf("Nand Flash PlaneSize = %ld\n",hnand1.Config.PlaneSize);
  printf("Nand Flash BlockSize = %ld\n",hnand1.Config.BlockSize);
  printf("Nand Flash BlockNbr = %ld\n",hnand1.Config.BlockNbr);
  printf("Nand Flash PlaneNbr = %ld\n\r",hnand1.Config.PlaneNbr);

  FSMC_NAND_Test();
  /* USER CODE END 2 */

(2)建立逻辑盘符与物理地址之间的映射关系

这一部分,想法和手段都是本文的核心,其创造性在于通过使用寄存器编程的方法,把建立的私有nand_flash.h驱动里创建的逻辑盘符(如{page1,plane0,block1023})映射到物理地址(如0x70000001)。

cpp 复制代码
  //logic drive mapped to physic drive
  NAND_AddressTypeDef addr ={	//初始化
		  addr.Page =0,
  	  	  addr.Plane =0,
  	  	  addr.Block =0
  	  	  };
  addr.Page = FLASH_PAGE_63;
  addr.Plane= FLASH_PLANE_0;
  addr.Block= FLASH_BLOCK_1023;

  *(uint32_t*)((uint32_t)(addr.Page)) =ADDR_FLASH_PAGE_65535;
  *(uint32_t*)((uint32_t)(addr.Plane)) =ADDR_FLASH_PLANE_0;
  *(uint32_t*)((uint32_t)(addr.Block)) =ADDR_FLASH_BLOCK_1023;

//  *(uint32_t*)((uint32_t)(FLASH_BLOCK_1023)) =ADDR_FLASH_BLOCK_1023; 	//也可以这样映射

注意:plane0,block1023的page63是NAND FLASH的最大一个page页,其物理地址是ADDR_FLASH_PAGE_65535。其它依次类推;

未完成的事业:这部分内容还没有完成,就是建立不同的block里的page自动映射物理地址的驱动。感兴趣的网友可以尝试写一写这个驱动。

(3)调用HAL函数对NAND FLASH进行访问

STM32CubeIDE自动生成的有关NAND FLASH的驱动有两个,其中,stm32h7xx_hal_nand.c/.h里定义的函数可以用来访问片外的FLASH;而stm32h7xx_hal_flash_ex.c/.h里定义的函数只适用于MCU片内的FLASH。

在main..h里声明了本文用于访问NAND FLASH的函数:

cpp 复制代码
/* USER CODE BEGIN EFP */
void FSMC_NAND_Test(void);
/* USER CODE END EFP */

在main.c的沙箱4里定义了这个私有函数的实现:

cpp 复制代码
/* USER CODE BEGIN 4 */
void FSMC_NAND_Test(void)
{
  //logic drive mapped to physic drive
  NAND_AddressTypeDef addr ={	//初始化
		  addr.Page =0,
  	  	  addr.Plane =0,
  	  	  addr.Block =0
  	  	  };
  addr.Page = FLASH_PAGE_63;
  addr.Plane= FLASH_PLANE_0;
  addr.Block= FLASH_BLOCK_1023;

  *(uint32_t*)((uint32_t)(addr.Page)) =ADDR_FLASH_PAGE_63;
  *(uint32_t*)((uint32_t)(addr.Plane)) =ADDR_FLASH_PLANE_0;
  *(uint32_t*)((uint32_t)(addr.Block)) =ADDR_FLASH_BLOCK_1023;

//  *(uint32_t*)((uint32_t)(FLASH_BLOCK_1023)) =ADDR_FLASH_BLOCK_1023; 	//也可以这样映射

  // test Reset
  printf("test NAND_Reset.\r\n");
  HAL_StatusTypeDef ret1 =HAL_NAND_Reset(&hnand1);	// all bit set 0xFF
  if(ret1 ==0)
	  printf("Nand Flash reset is HAL_OK.\n\r");
  else if(ret1 ==1)
  	  printf("Nand Flash reset is HAL_ERROR.\n\r");
  else if(ret1 ==2)
  	  printf("Nand Flash reset is HAL_BUSY.\n\r");
  else if(ret1 ==3)
  	  printf("Nand Flash reset is HAL_TIMEOUT.\n\r");
  HAL_Delay(500);

  //test erase a block
  printf("test erase a block.\r\n");
  HAL_StatusTypeDef ret = HAL_NAND_Erase_Block(&hnand1, &addr);
  if(ret ==0)
	  printf("erase block is HAL_OK.\n\r");
  else if(ret ==1)
	  printf("erase block is HAL_ERROR.\n\r");
  else if(ret ==2)
	  printf("erase block is HAL_BUSY.\n\r");
  else if(ret ==3)
	  printf("erase block is HAL_TIMEOUT.\n\r");

  // test READ_ID
  NAND_IDTypeDef info;
  HAL_StatusTypeDef ret2 =HAL_NAND_Read_ID(&hnand1, &info);
  if(ret2 ==0)
	  printf("Nand Flash Read_ID is HAL_OK.\n");
  else if(ret2 ==1)
  	  printf("Nand Flash Read_ID is HAL_ERROR.\n");
  else if(ret2 ==2)
  	  printf("Nand Flash Read_ID is HAL_BUSY.\n");
  else if(ret2 ==3)
  	  printf("Nand Flash Read_ID is HAL_TIMEOUT.\n");

  printf("Nand Flash ID = %02X-%02X-%02X-%02X\n\r",info.Maker_Id, info.Device_Id,info.Third_Id,info.Fourth_Id);
  printf("\r\n");


  //test write
  uint8_t buffer_write[2048];
  for(int i = 0; i < 2048; i++)
  {
	  buffer_write[i] = (uint8_t)i;
  }

  //Write into page 63 of the {63,0,1023} defined above.
  HAL_StatusTypeDef ret3 = HAL_NAND_Write_Page_8b(&hnand1, &addr, buffer_write, 1);
  if(ret3 == 0)
	  printf("write natural numbers into a page is HAL_OK。\r\n");
  else if(ret3 == 1)
	  printf("write natural numbers into a page is HAL_ERROR。\r\n");
  else if(ret3 == 2)
	  printf("write natural numbers into a page is HAL_BUSY。\r\n");
  else if(ret3 == 3)
	  printf("write natural numbers into a page is HAL_TIMEOUT。\r\n");

  printf("\r\n");

  //test memory Read_Status
/**
  * @brief NAND memory status
  * NAND_VALID_ADDRESS         0x00000100UL
  * NAND_INVALID_ADDRESS       0x00000200UL
  * NAND_TIMEOUT_ERROR         0x00000400UL
  * NAND_BUSY                  0x00000000UL
  * NAND_ERROR                 0x00000001UL
  * NAND_READY                 0x00000040UL
  */
/**
  * @brief  NAND memory read status
  * @param  hnand pointer to a NAND_HandleTypeDef structure that contains
  *                the configuration information for NAND module.
  * @retval NAND status
  */
  uint32_t sta = HAL_NAND_Read_Status(&hnand1);
  printf("Read_Status() find out whether read, program or erase operation is completed,\r\n"
		  "and whether the program or erase operation is completed successfully.\r\n");
  printf("NAND memory read status is 0x%lx.\r\n",sta);
  if(sta ==0x00000100UL)
	  printf("NAND memory read status is NAND_VALID_ADDRESS.\r\n");
  else if(sta ==0x00000200UL)
	  printf("NAND memory read status is NAND_INVALID_ADDRESS.\r\n");
  else if(sta ==0x00000400UL)
	  printf("NAND memory read status is NAND_TIMEOUT_ERROR.\r\n");
  else if(sta ==0x00000000UL)
	  printf("NAND memory read status is NAND_BUSY.\r\n");
  else if(sta ==0x00000001UL)
	  printf("NAND memory read status is NAND_ERROR.\r\n");
  else if(sta ==0x00000040UL)
	  printf("NAND memory read status is NAND_READY.\r\n");
  printf("\r\n");

  //test read
  uint8_t buffer1[2048];
  memset(buffer1, 0, 2048);
  HAL_StatusTypeDef ret4 = HAL_NAND_Read_Page_8b(&hnand1, &addr, buffer1, 1);
  if(ret4 == 0)
  {
	  printf("Read a written page, each byte shows natural numbers.\r\n");
	  for(int i = 0; i < 64; i++)
	  {
		  printf("%02X,",buffer1[i]);
	  }
	  printf("\r\n");
  }
  printf("\r\n");

  uint8_t buffer[2048];
  addr.Page = 1;
  addr.Plane= 0;
  addr.Block= 1;
  *(uint32_t*)((uint32_t)(addr.Page)) =ADDR_FLASH_PAGE_1;
  *(uint32_t*)((uint32_t)(addr.Plane)) =ADDR_FLASH_PLANE_0;
  *(uint32_t*)((uint32_t)(addr.Block)) =ADDR_FLASH_BLOCK_1;
  memset(buffer, 0, 2048);
  HAL_StatusTypeDef ret5 = HAL_NAND_Read_Page_8b(&hnand1, &addr, buffer, 1);
  if(ret5 == 0)
  {
	  printf("Read a page that has not been written, each byte shows 0xFF.\r\n");
	  for(int i = 0; i < 64; i++)
	  {
		  printf("%02X,",buffer[i]);
	  }
	  printf("\r\n");
  }

}


int __io_putchar(int ch)
{
	HAL_UART_Transmit(&huart1,(uint8_t*)&ch,1,0xFFFF);
	return ch;
}
/* USER CODE END 4 */

三、调试与运行

1、运行结果

代码书写完毕后,下载,通过串口助手,观察到结果很理想,达到了设计者的目的。

cpp 复制代码
Test FMC NAND FLASH R/W.

Nand Flash status is ready.

Nand Flash pagesize = 2048
Nand Flash SpareAreaSize = 64
Nand Flash PlaneSize = 1024
Nand Flash BlockSize = 64
Nand Flash BlockNbr = 1024
Nand Flash PlaneNbr = 1

test NAND_Reset.
Nand Flash reset is HAL_OK.

test erase a block.
erase block is HAL_OK.

Nand Flash Read_ID is HAL_OK.
Nand Flash ID = AD-F1-00-1D


write natural numbers into a page is HAL_OK。

Read_Status() find out whether read, program or erase operation is completed,
and whether the program or erase operation is completed successfully.
NAND memory read status is 0x40.
NAND memory read status is NAND_READY.

Read a written page, each byte shows natural numbers.
00,01,02,03,04,05,06,07,08,09,0A,0B,0C,0D,0E,0F,10,11,12,13,14,15,16,17,18,19,1A,1B,1C,1D,1E,1F,20,21,22,23,24,25,26,27,28,29,2A,2B,2C,2D,2E,2F,30,31,32,33,34,35,36,37,38,39,3A,3B,3C,3D,3E,3F,

Read a page that has not been written, each byte shows 0xFF.
FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,FF,

2、完整的代码

可以通过作者发布的GITHUB链接,下载完整的代码。

wenchm/Demo15_11_H743_FMC_NAND_FlASH: H743 via FMC expand NAND FlASH,logic driver mapping to physic address https://github.com/wenchm/Demo15_11_H743_FMC_NAND_FlASH

相关推荐
@good_good_study3 小时前
STM32 定时器PWM配置函数及实验
stm32·单片机
三佛科技-134163842124 小时前
KP32511SGA固定12V输出小家电电源芯片 典型应用电路
单片机·嵌入式硬件
xingzhemengyou15 小时前
STM32启动流程
stm32·单片机·嵌入式硬件
aduzhe5 小时前
int32 - int32MAX 出现异常
c语言·stm32
youcans_5 小时前
【动手学STM32G4】(4)STM32G431之ADC与DAC
stm32·单片机·嵌入式硬件·数据采集·串口通信
boneStudent8 小时前
Day32:SPI 配置与使用
stm32·单片机·嵌入式硬件
逆小舟9 小时前
【RTOS】处理中断
单片机·嵌入式硬件
ACP广源盛139246256739 小时前
GSV1015@ACP#1015/2015产品规格详解及产品应用分享
单片机·嵌入式硬件·音视频
三品吉他手会点灯10 小时前
STM32F103学习笔记-19-SysTick-系统定时器(第1节)-功能框图讲解和优先级配置
笔记·stm32·单片机·嵌入式硬件·学习