cancel
Showing results for 
Search instead for 
Did you mean: 

Is it a bug in NAND FMC read_page or write_page that works fine?

Arman Ilmak
Senior

Hey guys.

After having a lot of problems i had with fmc and nand flash finally i made it work.

But when i was looking at HAL_NAND_Read_Page_8b hal function i saw that instead of using CMD_AREA for read command 0x00 it uses ADDR_AREA. But read and write page works fine.

Is it a bug or something that i dont know?

Here is the function:

HAL_StatusTypeDef HAL_NAND_Write_Page_8b(NAND_HandleTypeDef *hnand, NAND_AddressTypeDef *pAddress, uint8_t *pBuffer,
                                         uint32_t NumPageToWrite)
{
  uint32_t index;
  uint32_t tickstart;
  uint32_t deviceaddress;
  uint32_t numpageswritten = 0U;
  uint32_t nandaddress;
  uint32_t nbpages = NumPageToWrite;
  uint8_t *buff = pBuffer;
 
  /* Check the NAND controller state */
  if (hnand->State == HAL_NAND_STATE_BUSY)
  {
    return HAL_BUSY;
  }
  else if (hnand->State == HAL_NAND_STATE_READY)
  {
    /* Process Locked */
    __HAL_LOCK(hnand);
 
    /* Update the NAND controller state */
    hnand->State = HAL_NAND_STATE_BUSY;
 
    /* Identify the device address */
    deviceaddress = NAND_DEVICE;
 
    /* NAND raw address calculation */
    nandaddress = ARRAY_ADDRESS(pAddress, hnand);
 
    /* Page(s) write loop */
    while ((nbpages != 0U) && (nandaddress < ((hnand->Config.BlockSize) * (hnand->Config.BlockNbr))))
    {
      /* Send write page command sequence */
      *(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_AREA_A;
      __DSB();
      *(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_WRITE0;
      __DSB();
 
      /* Cards with page size <= 512 bytes */
      if ((hnand->Config.PageSize) <= 512U)
      {
        if (((hnand->Config.BlockSize) * (hnand->Config.BlockNbr)) <= 65535U)
        {
          *(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
          __DSB();
          *(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
          __DSB();
          *(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
          __DSB();
        }
        else /* ((hnand->Config.BlockSize)*(hnand->Config.BlockNbr)) > 65535 */
        {
          *(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
          __DSB();
          *(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
          __DSB();
          *(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
          __DSB();
          *(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_3RD_CYCLE(nandaddress);
          __DSB();
        }
      }
      else /* (hnand->Config.PageSize) > 512 */
      {
        if (((hnand->Config.BlockSize) * (hnand->Config.BlockNbr)) <= 65535U)
        {
          *(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
          __DSB();
          *(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
          __DSB();
          *(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
          __DSB();
          *(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
          __DSB();
        }
        else /* ((hnand->Config.BlockSize)*(hnand->Config.BlockNbr)) > 65535 */
        {
          *(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
          __DSB();
          *(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;
          __DSB();
          *(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandaddress);
          __DSB();
          *(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandaddress);
          __DSB();
          *(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = ADDR_3RD_CYCLE(nandaddress);
          __DSB();
        }
      }
 
      /* Write data to memory */
      for (index = 0U; index < hnand->Config.PageSize; index++)
      {
        *(__IO uint8_t *)deviceaddress = *buff;
        buff++;
        __DSB();
      }
 
      *(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = NAND_CMD_WRITE_TRUE1;
      __DSB();
 
      /* Get tick */
      tickstart = HAL_GetTick();
 
      /* Read status until NAND is ready */
      while (HAL_NAND_Read_Status(hnand) != NAND_READY)
      {
        if ((HAL_GetTick() - tickstart) > NAND_WRITE_TIMEOUT)
        {
          /* Update the NAND controller state */
          hnand->State = HAL_NAND_STATE_ERROR;
 
          /* Process unlocked */
          __HAL_UNLOCK(hnand);
 
          return HAL_TIMEOUT;
        }
      }
 
      /* Increment written pages number */
      numpageswritten++;
 
      /* Decrement pages to write */
      nbpages--;
 
      /* Increment the NAND address */
      nandaddress = (uint32_t)(nandaddress + 1U);
    }
 
    /* Update the NAND controller state */
    hnand->State = HAL_NAND_STATE_READY;
 
    /* Process unlocked */
    __HAL_UNLOCK(hnand);
  }
  else
  {
    return HAL_ERROR;
  }
 
  return HAL_OK;
}

2 REPLIES 2
Arman Ilmak
Senior

I mean this line of code:

*(__IO uint8_t *)((uint32_t)(deviceaddress | ADDR_AREA)) = 0x00U;

should be rewrite as:

*(__IO uint8_t *)((uint32_t)(deviceaddress | CMD_AREA)) = 0x00U;

 or not.

I suppose it depends on the specific NAND ICs it's designed to work with.

Sector zero on NAND's tends to be a special case, as it's always supposed to be readable (error-free) and regardless of the size/geometry of the NAND array.

Best to code a solution based on the parts you're using, and a thorough reading and understanding of the data sheet.

I don't know how well this is currently tested/maintained, nor the broadness of the NAND support. ST uses to own a NAND fab, I think they sold it or spun it out to Micron or Numonyx (2008)

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..