Skip to main content
ALanz.2198
Visitor II
December 9, 2019
Question

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

  • December 9, 2019
  • 0 replies
  • 602 views

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?

This topic has been closed for replies.