2019-12-09 12:00 AM
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?