【方法】STM32F429IG單片機FMC計算NAND Flash ECC校驗碼

【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

發佈了78 篇原創文章 · 獲贊 39 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章