其实是为了测试我这个新买的好杜邦新.
接入的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****/