cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F7 sometimes receives 0x00 from erased Flash memory connected over QuadSPI

ALanz.2198
Associate

I'm using the STM32F779BI microcontroller with a connected 64MB NOR-Flash memory (MT25QL512ABB). The memory is connected via the Quad-SPI interface. To erase, program and read the memory i use the mt25ql512abb.c file out of the STM32Cube_FW_G4_V1.1.0/Drivers/BSP/Components/mt25ql512abb folder from the STM32Cube firmware package. I can erase, program and read the memory registers. But sometimes on a random address the MT25QL512ABB_ReadSTR() method (see below) returns 0x00 instead of the programmed value. If i read at the same address again the correct value is returned.

/* Read/Write Array Commands (3/4 Byte Address Command Set) *********************/
/**
  * @brief  Reads an amount of data from the QSPI memory on STR mode.
  *         SPI/DPI/QPI; 1-1-1/1-1-2/1-2-2/1-1-4/1-4-4/2-2-2/4-4-4
  * @param  Ctx Component object pointer
  * @param  Mode Interface mode
  * @param  AddressSize Address size
  * @param  pData Pointer to data to be read
  * @param  ReadAddr Read start address
  * @param  Size Size of data to read
  * @retval QSPI memory status
  */
int32_t MT25QL512ABB_ReadSTR(QSPI_HandleTypeDef *Ctx, MT25QL512ABB_Interface_t Mode, MT25QL512ABB_AddressSize_t AddressSize, uint8_t *pData, uint32_t ReadAddr, uint32_t Size)
{
  QSPI_CommandTypeDef s_command;
 
  /* Initialize the read command */
  switch(Mode)
  {
  case MT25QL512ABB_SPI_1I2O_MODE :          /* 1-1-2 commands */
    s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
    s_command.Instruction     = (AddressSize == MT25QL512ABB_3BYTES_SIZE) ? MT25QL512ABB_1I2O_FAST_READ_CMD : MT25QL512ABB_4_BYTE_ADDR_1I2O_FAST_READ_CMD;
    s_command.AddressMode     = QSPI_ADDRESS_1_LINE;
    s_command.DummyCycles     = 8;
    s_command.DataMode        = QSPI_DATA_2_LINES;
    break;
 
  case MT25QL512ABB_SPI_2IO_MODE :           /* 1-2-2 commands */
    s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
    s_command.Instruction     = (AddressSize == MT25QL512ABB_3BYTES_SIZE) ? MT25QL512ABB_2IO_FAST_READ_CMD : MT25QL512ABB_4_BYTE_ADDR_2IO_FAST_READ_CMD;
    s_command.AddressMode     = QSPI_ADDRESS_2_LINES;
    s_command.DummyCycles     = 8;
    s_command.DataMode        = QSPI_DATA_2_LINES;
    break;
 
  case MT25QL512ABB_SPI_1I4O_MODE :          /* 1-1-4 commands */
    s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
    s_command.Instruction     = (AddressSize == MT25QL512ABB_3BYTES_SIZE) ? MT25QL512ABB_1I4O_FAST_READ_CMD : MT25QL512ABB_4_BYTE_ADDR_1I4O_FAST_READ_CMD;
    s_command.AddressMode     = QSPI_ADDRESS_1_LINE;
    s_command.DummyCycles     = 8;
    s_command.DataMode        = QSPI_DATA_4_LINES;
    break;
 
  case MT25QL512ABB_SPI_4IO_MODE :           /* 1-4-4 commands */
    s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
    s_command.Instruction     = (AddressSize == MT25QL512ABB_3BYTES_SIZE) ? MT25QL512ABB_4IO_FAST_READ_CMD : MT25QL512ABB_4_BYTE_ADDR_4IO_FAST_READ_CMD;
    s_command.AddressMode     = QSPI_ADDRESS_4_LINES;
    s_command.DummyCycles     = 10;
    s_command.DataMode        = QSPI_DATA_4_LINES;
    break;
 
  case MT25QL512ABB_DPI_MODE :               /* 2-2-2 commands */
    s_command.InstructionMode = QSPI_INSTRUCTION_2_LINES;
    s_command.Instruction     = (AddressSize == MT25QL512ABB_3BYTES_SIZE) ? MT25QL512ABB_2IO_FAST_READ_CMD : MT25QL512ABB_4_BYTE_ADDR_2IO_FAST_READ_CMD;
    s_command.AddressMode     = QSPI_ADDRESS_2_LINES;
    s_command.DummyCycles     = 8;
    s_command.DataMode        = QSPI_DATA_2_LINES;
    break;
 
  case MT25QL512ABB_QPI_MODE :               /* 4-4-4 commands */
    s_command.InstructionMode = QSPI_INSTRUCTION_4_LINES;
    s_command.Instruction     = (AddressSize == MT25QL512ABB_3BYTES_SIZE) ? MT25QL512ABB_4IO_FAST_READ_CMD : MT25QL512ABB_4_BYTE_ADDR_4IO_FAST_READ_CMD;
    s_command.AddressMode     = QSPI_ADDRESS_4_LINES;
    s_command.DummyCycles     = 10;
    s_command.DataMode        = QSPI_DATA_4_LINES;
    break;
 
  case MT25QL512ABB_SPI_MODE :               /* 1-1-1 commands, Power on H/W default setting */
  default :
    s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
    s_command.Instruction     = (AddressSize == MT25QL512ABB_3BYTES_SIZE) ? MT25QL512ABB_FAST_READ_CMD : MT25QL512ABB_4_BYTE_ADDR_FAST_READ_CMD;
    s_command.AddressMode     = QSPI_ADDRESS_1_LINE;
    s_command.DummyCycles     = 8;
    s_command.DataMode        = QSPI_DATA_1_LINE;
    break;
  }
 
  s_command.AddressSize       = (AddressSize == MT25QL512ABB_3BYTES_SIZE) ? QSPI_ADDRESS_24_BITS : QSPI_ADDRESS_32_BITS;
  s_command.Address           = ReadAddr;
  s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
  s_command.NbData            = Size;
  s_command.DdrMode           = QSPI_DDR_MODE_DISABLE;
  s_command.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;
  s_command.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;
 
  /* Configure the command */
  if (HAL_QSPI_Command(Ctx, &s_command, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    return MT25QL512ABB_ERROR;
  }
 
  /* Reception of the data */
  if (HAL_QSPI_Receive(Ctx, pData, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    return MT25QL512ABB_ERROR;
  }
 
  return MT25QL512ABB_OK;
}

The MT25QL512ABB_ReadSTR() method uses the following HAL_QSPI_Receive method. This method is polling the Transmission Complete Flag (TCF) and the FIFO Threshold Flag (FTF). If one of them is set the QUADSPI data register is read out. I have tracked this method and i have seen that the method only returns 0x00 if the Transmission Complete Flag QSPI_FLAG_TC is set. In this case the FIFO level (FLEVEL) in the QUADSPI status register (QUADSPI_SR) is zero and so it is clear that the function returns 0x00. If the FIFO Threshold Flag (QSPI_FLAG_FT) is set the function returns the correct register value.

/**
  * @brief Receive an amount of data in blocking mode 
  * @param hqspi QSPI handle
  * @param pData pointer to data buffer
  * @param Timeout  Time out duration
  * @note   This function is used only in Indirect Read Mode
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_QSPI_Receive(QSPI_HandleTypeDef *hqspi, uint8_t *pData, uint32_t Timeout)
{
  HAL_StatusTypeDef status = HAL_OK;
  uint32_t tickstart = HAL_GetTick();
  uint32_t addr_reg = READ_REG(hqspi->Instance->AR);
  __IO uint32_t *data_reg = &hqspi->Instance->DR;
 
  /* Process locked */
  __HAL_LOCK(hqspi);
  
  if(hqspi->State == HAL_QSPI_STATE_READY)
  {
    hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;
    if(pData != NULL )
    {
      /* Update state */
      hqspi->State = HAL_QSPI_STATE_BUSY_INDIRECT_RX;
    
      /* Configure counters and size of the handle */
      hqspi->RxXferCount = READ_REG(hqspi->Instance->DLR) + 1;
      hqspi->RxXferSize = READ_REG(hqspi->Instance->DLR) + 1;
      hqspi->pRxBuffPtr = pData;
 
      /* Configure QSPI: CCR register with functional as indirect read */
      MODIFY_REG(hqspi->Instance->CCR, QUADSPI_CCR_FMODE, QSPI_FUNCTIONAL_MODE_INDIRECT_READ);
 
      /* Start the transfer by re-writing the address in AR register */
      WRITE_REG(hqspi->Instance->AR, addr_reg);
      
      while(hqspi->RxXferCount > 0)
      {
        /* Wait until FT or TC flag is set to read received data */
        status = QSPI_WaitFlagStateUntilTimeout(hqspi, (QSPI_FLAG_FT | QSPI_FLAG_TC), SET, tickstart, Timeout);
 
        if  (status != HAL_OK)
        { 
          break;
        }
 
        *hqspi->pRxBuffPtr++ = *(__IO uint8_t *)data_reg;
        hqspi->RxXferCount--;
      }
    
      if (status == HAL_OK)
      {
        /* Wait until TC flag is set to go back in idle state */
        status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_TC, SET, tickstart, Timeout);
 
        if  (status == HAL_OK)
        {
          /* Clear Transfer Complete bit */
          __HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_TC);
          
#if defined(QSPI1_V1_0)
         /* Workaround - Extra data written in the FIFO at the end of a read transfer */
         status = HAL_QSPI_Abort(hqspi);
#endif /* QSPI_V1_0 */  
        }
      }
 
      /* Update QSPI state */
      hqspi->State = HAL_QSPI_STATE_READY;    
    }
    else
    {
      hqspi->ErrorCode |= HAL_QSPI_ERROR_INVALID_PARAM;
      status = HAL_ERROR;
    }
  }
  else
  {
    status = HAL_BUSY;
  }
  
  /* Process unlocked */
  __HAL_UNLOCK(hqspi);
 
  return status;
}

Does anyone have an idea what the cause of the problem might be?

0 REPLIES 0