【H27U4G8F2E.c】
#include <stdio.h>
#include <stm32f4xx.h>
#include "H27U4G8F2E.h"
NAND_HandleTypeDef hnand;
void H27U4G8F2E_Init(void)
{
FMC_NAND_PCC_TimingTypeDef timing;
GPIO_InitTypeDef gpio;
NAND_DeviceConfigTypeDef config;
NAND_IDTypeDef id;
__HAL_RCC_FMC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
// PD6: FMC_NWAIT
gpio.Alternate = GPIO_AF12_FMC;
gpio.Mode = GPIO_MODE_AF_OD;
gpio.Pin = GPIO_PIN_6;
gpio.Pull = GPIO_PULLUP;
gpio.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(GPIOD, &gpio);
// PD0~1: FMC_D2~3, PD4: FMC_NOE, PD5: FMC_NWE, PD11: FMC_CLE, PD12: FMC_ALE, PD14~15: FMC_D0~1
gpio.Mode = GPIO_MODE_AF_PP;
gpio.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_14 | GPIO_PIN_15;
gpio.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOD, &gpio);
// PE7~10: FMC_D4~7
gpio.Pin = GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10;
HAL_GPIO_Init(GPIOE, &gpio);
// PG9: FMC_NCE3
gpio.Pin = GPIO_PIN_9;
HAL_GPIO_Init(GPIOG, &gpio);
hnand.Instance = FMC_NAND_DEVICE;
hnand.Init.EccComputation = FMC_NAND_ECC_DISABLE;
hnand.Init.ECCPageSize = FMC_NAND_ECC_PAGE_SIZE_2048BYTE;
hnand.Init.MemoryDataWidth = FMC_NAND_PCC_MEM_BUS_WIDTH_8;
hnand.Init.NandBank = FMC_NAND_BANK3;
hnand.Init.TARSetupTime = 0;
hnand.Init.TCLRSetupTime = 0;
hnand.Init.Waitfeature = FMC_NAND_PCC_WAIT_FEATURE_ENABLE;
timing.HiZSetupTime = 0;
timing.HoldSetupTime = 0;
timing.SetupTime = 6;
timing.WaitSetupTime = 3;
HAL_NAND_Init(&hnand, &timing, &timing);
HAL_NAND_Read_ID(&hnand, &id);
printf("NAND ID: %#x %#x %#x %#x\n", id.Maker_Id, id.Device_Id, id.Third_Id, id.Fourth_Id);
config.BlockNbr = 4096;
config.BlockSize = 64;
config.ExtraCommandEnable = DISABLE;
config.PageSize = 2048;
config.PlaneNbr = 1;
config.PlaneSize = config.BlockNbr;
config.SpareAreaSize = 4; // 實際大小爲64
HAL_NAND_ConfigDevice(&hnand, &config);
}
【main.c】
#include <stdio.h>
#include <stm32f4xx.h>
#include <string.h>
#include "common.h"
#include "H27U4G8F2E.h"
static uint8_t buffer[2048];
static void test(void)
{
int i;
uint32_t ecc[2];
NAND_AddressTypeDef addr;
memset(buffer, 0, sizeof(buffer));
addr.Plane = 0;
addr.Block = 0;
addr.Page = 2;
HAL_NAND_ECC_Enable(&hnand);
HAL_NAND_Read_Page_8b(&hnand, &addr, buffer, 1);
HAL_NAND_GetECC(&hnand, &ecc[0], HAL_MAX_DELAY);
HAL_NAND_ECC_Disable(&hnand);
HAL_NAND_Read_SpareArea_8b(&hnand, &addr, (uint8_t *)&ecc[1], 1);
printf("ECC=%#x, %#x\n", ecc[0], ecc[1]);
if (ecc[0] != ecc[1])
printf("ECC error!\n");
for (i = 0; i < sizeof(buffer); i++)
{
if (buffer[10] != 0x8a || (i != 10 && buffer[i] != (i & 0xff)))
printf("(%d) buffer[%#x]=%#x\n", i, i, buffer[i]);
}
}
static void write_test(void)
{
int i;
uint32_t ecc;
NAND_AddressTypeDef addr;
for (i = 0; i < sizeof(buffer); i++)
{
buffer[i] = i & 0xff;
if (i == 10)
buffer[i] |= 0x80;
}
addr.Plane = 0;
addr.Block = 0;
addr.Page = 2;
HAL_NAND_ECC_Enable(&hnand);
HAL_NAND_Write_Page_8b(&hnand, &addr, buffer, 1);
HAL_NAND_GetECC(&hnand, &ecc, HAL_MAX_DELAY);
HAL_NAND_ECC_Disable(&hnand);
HAL_NAND_Write_SpareArea_8b(&hnand, &addr, (uint8_t *)&ecc, 1);
printf("written! ECC=%#x\n", ecc);
}
int main(void)
{
HAL_Init();
clock_init();
usart_init(115200);
printf("STM32F429IG NAND\n");
printf("SystemCoreClock=%u\n", SystemCoreClock);
H27U4G8F2E_Init();
//write_test();
while (1)
{
test();
test();
HAL_Delay(500);
}
}
初始化NAND Flash時,禁用ECC。
計算ECC校驗碼前先打開ECC,讀取一個2KB的數據塊,獲取ECC校驗值,然後關閉ECC。
當這2KB的數據爲00 01 02 03 04 05 .............. FE FF 00 01 02 ............... FE FF時,ECC校驗碼剛好是0
但是如果讓第10個字節爲0x8a,則ECC校驗碼爲0x5555666a