其实是为了测试我这个新买的好杜邦新.
接入的NAND是K91FG080U0E,包含1024 Blocks,每个Block包含 64 Pages,每个Page包含2K Bytes数据空间 + 64 Bytes冗余空间,总大小=1024 Blocks x 64 Pages x (2K+ 64) B = (1024 + 32) MBits = 1G Bits.
先用Cube生成工程,把CPU时钟设置成216MHz这个应该不用多说了.
然后把USART3绑定在PD9,PD8.
然后引脚排列真的乱啊,在芯片上是相邻的引脚,却不一定排针上相邻.
所以也不用想着走线是否等长,没有这么一回事.引脚有这么几个.
- I/O0 ~ I/O7:用于输入地址/数据/命令/输出数据,接线无难度.
- CLE:命令锁存使能,在输入命令之前,要先在模式寄存器中,设置CLE使能,接FMC_CLE引脚.
- ALE:地址锁存使能,在输入地址之前,要先在模式寄存器中,设置ALE使能,接FMC_ALE引脚.
- CE#:芯片使能,在操作Nand Flash之前,要先选中此芯片,才能操作,接FMC_NCE引脚.
- RE#:读使能,在读取数据之前,要先使RE#有效,接FMC_NOE引脚.
- WE#:写使能,在写取数据之前,要先使WE#有效,接FMC_NWE引脚.
- R/B#:就绪/忙,主要用于在发送完编程/擦除命令后,检测这些操作是否完成,忙,表示编程/擦除操作仍在进行中,就绪表示操作完成.接FMC_NWAIT引脚.
然后配置好速度,因为不等长的,所以速度估计比手册要慢一些,我的测试程序如下.
用低格方式鉴别Flash,很好的是我这Flash竟然没坏块.
/* Includes ------------------------------------------------------------------*/ #include "main.h" #include "stm32f7xx_hal.h" /* USER CODE BEGIN Includes */ #include <string.h> /* USER CODE END Includes */ /* Private variables ---------------------------------------------------------*/ UART_HandleTypeDef huart3; NAND_HandleTypeDef hnand1; /* USER CODE BEGIN PV */ /* Private variables ---------------------------------------------------------*/ NAND_IDTypeDef NAND_ID; NAND_AddressTypeDef WriteReadAddr; #define NAND_PAGE_SIZE ((uint16_t)0x0800) /* 2 * 1024 bytes per page w/o Spare Area */ #define NAND_BLOCK_SIZE ((uint16_t)0x0040) /* 64 pages per block */ #define NAND_ZONE_SIZE ((uint16_t)0x0400) /* 1024 Block per zone */ #define NAND_SPARE_AREA_SIZE ((uint16_t)0x0040) /* last 64 bytes as spare area */ #define NAND_MAX_ZONE ((uint16_t)0x0001) /* 1 zones of 1024 block */ static uint8_t TxBuffer [NAND_PAGE_SIZE]; static uint8_t RxBuffer [NAND_PAGE_SIZE]; uint16_t i, j; uint16_t block = 0, page = 0; uint16_t status; uint8_t bad = 0; uint8_t bad_t[1024] = {0x00}; uint16_t bad_cnt = 0; /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); void Error_Handler(void); static void MX_GPIO_Init(void); static void MX_FMC_Init(void); static void MX_USART3_UART_Init(void); /* USER CODE BEGIN PFP */ /* Private function prototypes -----------------------------------------------*/ /* USER CODE END PFP */ /* USER CODE BEGIN 0 */ int fputc(int ch, FILE *f) { /* Place your implementation of fputc here */ /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */ HAL_UART_Transmit(&huart3, (uint8_t *)&ch, 1, 0xFFFF); return ch; } /* USER CODE END 0 */ int main(void) { /* USER CODE BEGIN 1 */ HAL_StatusTypeDef res; /* USER CODE END 1 */ /* MCU Configuration----------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* Configure the system clock */ SystemClock_Config(); /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_FMC_Init(); MX_USART3_UART_Init(); /* USER CODE BEGIN 2 */ printf(" NandFlash Example "); // HAL_NAND_Reset(&hnand1); /* Read the NAND memory ID */ res = HAL_NAND_Read_ID(&hnand1, &NAND_ID); printf(" NandID %d ", res); printf("Nand Flash ID = 0x%02X,0x%02X,0x%02X,0x%02X ", NAND_ID.Maker_Id, NAND_ID.Device_Id, NAND_ID.Third_Id, NAND_ID.Fourth_Id ); /* NAND memory address to write to */ WriteReadAddr.Plane = 0x00; WriteReadAddr.Block = 0x00; WriteReadAddr.Page = 0x00; /* Fill the buffer to send */ for (i = 0; i < NAND_ZONE_SIZE; i++ ) { WriteReadAddr.Block = i; res = HAL_NAND_Erase_Block(&hnand1, &WriteReadAddr); } /* Erase the NAND first Block */ HAL_Delay(100); WriteReadAddr.Plane = 0x00; WriteReadAddr.Block = 0x00; WriteReadAddr.Page = 0x00; while(1) { printf("check 0xff now "); for (i = 0; i < NAND_ZONE_SIZE; i++ ) { WriteReadAddr.Block = i; res = HAL_NAND_Erase_Block(&hnand1, &WriteReadAddr); } for(block = 0; block < 1024; block++) { bad = 0; for(page = 0; page < 64; page++) { WriteReadAddr.Block = block; WriteReadAddr.Page = page; /* Read data from FMC NAND memory */ HAL_NAND_Read_Page(&hnand1, &WriteReadAddr, RxBuffer, 1); for(j = 0; j < 2048; j++) { if(RxBuffer[j] != 0xFF) { /* if(RxBuffer[j] != 0x00) if(RxBuffer[j] != 0x30) if(RxBuffer[j] != 0x55) if(RxBuffer[j] != 0xAA) printf("0x%02X ",RxBuffer[j]); */ bad = 1; } } } if(bad) { bad_t[block] = 0x01; printf("bad blk = %d ", block); bad_cnt++; } else { bad_t[block] = 0x00; } } printf("check 0xaa now "); for (i = 0; i < NAND_ZONE_SIZE; i++ ) { WriteReadAddr.Block = i; res = HAL_NAND_Erase_Block(&hnand1, &WriteReadAddr); } for(block = 0; block < 1024; block++) { bad = 0; if(bad_t[block] == 0x00) { for(page = 0; page < 64; page++) { WriteReadAddr.Block = block; WriteReadAddr.Page = page; for (i = 0; i < NAND_PAGE_SIZE; i++ ) { TxBuffer[i] = 0xAA; } HAL_NAND_Write_Page(&hnand1, &WriteReadAddr, TxBuffer, 1); HAL_Delay(1); /* Read data from FMC NAND memory */ HAL_NAND_Read_Page(&hnand1, &WriteReadAddr, RxBuffer, 1); for(j = 0; j < 2048; j++) { if(RxBuffer[j] != 0xAA) { //printf("0x%02X ",TxBuffer[j]); bad = 1; } } } if(bad) { bad_t[block] = 0x01; printf("bad blk = %d ", block); bad_cnt++; } else { bad_t[block] = 0x00; } } } printf("check 0xaa now "); for (i = 0; i < NAND_ZONE_SIZE; i++ ) { WriteReadAddr.Block = i; res = HAL_NAND_Erase_Block(&hnand1, &WriteReadAddr); } for(block = 0; block < 1024; block++) { bad = 0; if(bad_t[block] == 0x00) { for(page = 0; page < 64; page++) { WriteReadAddr.Block = block; WriteReadAddr.Page = page; for (i = 0; i < NAND_PAGE_SIZE; i++ ) { TxBuffer[i] = 0x55; } HAL_NAND_Write_Page(&hnand1, &WriteReadAddr, TxBuffer, 1); HAL_Delay(1); /* Read data from FMC NAND memory */ HAL_NAND_Read_Page(&hnand1, &WriteReadAddr, RxBuffer, 1); for(j = 0; j < 2048; j++) { if(RxBuffer[j] != 0x55) { //printf("0x%02X ",TxBuffer[j]); bad = 1; } } } if(bad) { bad_t[block] = 0x01; printf("bad blk = %d ", block); bad_cnt++; } else { bad_t[block] = 0x00; } } } printf("check 0x00 now "); for (i = 0; i < NAND_ZONE_SIZE; i++ ) { WriteReadAddr.Block = i; res = HAL_NAND_Erase_Block(&hnand1, &WriteReadAddr); } for(block = 0; block < 1024; block++) { bad = 0; if(bad_t[block] == 0x00) { for(page = 0; page < 64; page++) { WriteReadAddr.Block = block; WriteReadAddr.Page = page; for (i = 0; i < NAND_PAGE_SIZE; i++ ) { TxBuffer[i] = 0x00; } HAL_NAND_Write_Page(&hnand1, &WriteReadAddr, TxBuffer, 1); HAL_Delay(1); /* Read data from FMC NAND memory */ HAL_NAND_Read_Page(&hnand1, &WriteReadAddr, RxBuffer, 1); for(j = 0; j < 2048; j++) { if(RxBuffer[j] != 0x00) { bad = 1; } } } if(bad) { bad_t[block] = 0x01; printf("bad blk = %d ", block); bad_cnt++; } else { bad_t[block] = 0x00; } } } printf("bad cnt = %d ", bad_cnt); while(1) { } } /* USER CODE END 2 */ } /** System Clock Configuration */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct; RCC_ClkInitTypeDef RCC_ClkInitStruct; RCC_PeriphCLKInitTypeDef PeriphClkInitStruct; /**Configure the main internal regulator output voltage */ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); /**Initializes the CPU, AHB and APB busses clocks */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = 16; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; RCC_OscInitStruct.PLL.PLLM = 8; RCC_OscInitStruct.PLL.PLLN = 216; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLQ = 2; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /**Activate the Over-Drive mode */ if (HAL_PWREx_EnableOverDrive() != HAL_OK) { Error_Handler(); } /**Initializes the CPU, AHB and APB busses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_7) != HAL_OK) { Error_Handler(); } PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USART3; PeriphClkInitStruct.Usart3ClockSelection = RCC_USART3CLKSOURCE_PCLK1; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { Error_Handler(); } /**Configure the Systick interrupt time */ HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / 1000); /**Configure the Systick */ HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); /* SysTick_IRQn interrupt configuration */ HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); } /* USART3 init function */ static void MX_USART3_UART_Init(void) { huart3.Instance = USART3; huart3.Init.BaudRate = 115200; huart3.Init.WordLength = UART_WORDLENGTH_7B; huart3.Init.StopBits = UART_STOPBITS_1; huart3.Init.Parity = UART_PARITY_NONE; huart3.Init.Mode = UART_MODE_TX_RX; huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart3.Init.OverSampling = UART_OVERSAMPLING_16; huart3.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; huart3.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; if (HAL_UART_Init(&huart3) != HAL_OK) { Error_Handler(); } } /* FMC initialization function */ static void MX_FMC_Init(void) { FMC_NAND_PCC_TimingTypeDef ComSpaceTiming; /** Perform the NAND1 memory initialization sequence */ hnand1.Instance = FMC_NAND_DEVICE; /* hnand1.Init */ hnand1.Init.NandBank = FMC_NAND_BANK3; hnand1.Init.Waitfeature = FMC_NAND_WAIT_FEATURE_ENABLE; hnand1.Init.MemoryDataWidth = FMC_NAND_MEM_BUS_WIDTH_8; hnand1.Init.EccComputation = FMC_NAND_ECC_ENABLE; hnand1.Init.ECCPageSize = FMC_NAND_ECC_PAGE_SIZE_512BYTE; hnand1.Init.TCLRSetupTime = 0; hnand1.Init.TARSetupTime = 0; /* hnand1.Config */ hnand1.Config.PageSize = 2048; hnand1.Config.SpareAreaSize = 64; hnand1.Config.BlockSize = 64; hnand1.Config.BlockNbr = 64; hnand1.Config.PlaneNbr = 1; hnand1.Config.PlaneSize = 1024; hnand1.Config.ExtraCommandEnable = DISABLE; /* ComSpaceTiming */ ComSpaceTiming.SetupTime = 10; ComSpaceTiming.WaitSetupTime = 4; ComSpaceTiming.HoldSetupTime = 4; ComSpaceTiming.HiZSetupTime = 10; if (HAL_NAND_Init(&hnand1, &ComSpaceTiming, &ComSpaceTiming) != HAL_OK) { Error_Handler(); } } /** Pinout Configuration */ static void MX_GPIO_Init(void) { /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOE_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); } /* USER CODE BEGIN 4 */ /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @param None * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler */ /* User can add his own implementation to report the HAL error return state */ while(1) { } /* USER CODE END Error_Handler */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d ", file, line) */ /* USER CODE END 6 */ } #endif /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/