2019-04-04 12:18 AM
Our board is using an STM32H753 MCU with QSPI Serial Flash IS25WQ040. Quad SPI was enabled in CubeMX and I see the QSPI functions in stm32h7xx_hal_qspi.c.
I'm just trying to get a Qspi_Test function called from main working that is currently getting stuck. Here is the code from HAL_QSPI_AutoPolling function:
if(hqspi->State == HAL_QSPI_STATE_READY)
{
hqspi->ErrorCode = HAL_QSPI_ERROR_NONE;
/* Update state */
hqspi->State = HAL_QSPI_STATE_BUSY_AUTO_POLLING;
/* Wait till BUSY flag reset */
status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_BUSY, RESET, tickstart, Timeout);
if (status == HAL_OK)
{
/* Configure QSPI: PSMAR register with the status match value */
WRITE_REG(hqspi->Instance->PSMAR, cfg->Match);
/* Configure QSPI: PSMKR register with the status mask value */
WRITE_REG(hqspi->Instance->PSMKR, cfg->Mask);
/* Configure QSPI: PIR register with the interval value */
WRITE_REG(hqspi->Instance->PIR, cfg->Interval);
/* Configure QSPI: CR register with Match mode and Automatic stop enabled
(otherwise there will be an infinite loop in blocking mode) */
MODIFY_REG(hqspi->Instance->CR, (QUADSPI_CR_PMM | QUADSPI_CR_APMS),
(cfg->MatchMode | QSPI_AUTOMATIC_STOP_ENABLE));
/* Call the configuration function */
cmd->NbData = cfg->StatusBytesSize;
QSPI_Config(hqspi, cmd, QSPI_FUNCTIONAL_MODE_AUTO_POLLING);
/* Wait until SM flag is set to go back in idle state */
status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_SM, SET, tickstart, Timeout);
if (status == HAL_OK)
{
__HAL_QSPI_CLEAR_FLAG(hqspi, QSPI_FLAG_SM);
/* Update state */
hqspi->State = HAL_QSPI_STATE_READY;
}
}
}
The problem is the following line of code where the status is always 1 instead of 0:
/* Wait until SM flag is set to go back in idle state */
status = QSPI_WaitFlagStateUntilTimeout(hqspi, QSPI_FLAG_SM, SET, tickstart, Timeout);
I'm not sure what the original developer did in terms of adding/modifying after the CubeMX generation, so if there is a chunk of code expected to be added by user and not CubeMX, that is most likely what I'm missing.
Any chance there is a simple and obvious cause for never setting the SM flag? Is there a minimal example project that I compare against for what is missing?
Thanks
2019-04-16 06:33 PM
I'm still stuck on getting QSPI flash initialization working. I don't know if this problem is a configuration issue or a process/order-of-operations issue. Any advice pointing where to look next is greatly appreciated.
The problem is that the HAL_QSPI_Autopolling function times out. The flash is a 4Mb IS25WQ040.
main.c calls MX_QUADSPI_Init();. That appears to return successfully.
void MX_QUADSPI_Init(void)
{
hqspi.Instance = QUADSPI;
hqspi.Init.ClockPrescaler = 4;
hqspi.Init.FifoThreshold = 4;
hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_NONE;
hqspi.Init.FlashSize = 22; // 22|24|25 see above
hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_1_CYCLE;
hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;
hqspi.Init.FlashID = QSPI_FLASH_ID_1;
hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE;
if (HAL_QSPI_Init(&hqspi) != HAL_OK)
{
Error_Handler();
}
}
void HAL_QSPI_MspInit(QSPI_HandleTypeDef* qspiHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(qspiHandle->Instance==QUADSPI)
{
/* USER CODE BEGIN QUADSPI_MspInit 0 */
/* USER CODE END QUADSPI_MspInit 0 */
/* QUADSPI clock enable */
__HAL_RCC_QSPI_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
/**QUADSPI GPIO Configuration
PG6 ------> QUADSPI_BK1_NCS
PF7 ------> QUADSPI_BK1_IO2
PF10 ------> QUADSPI_CLK
PD13 ------> QUADSPI_BK1_IO3
PD12 ------> QUADSPI_BK1_IO1
PD11 ------> QUADSPI_BK1_IO0
*/
GPIO_InitStruct.Pin = WICED_QSPI_PIN_CS_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF10_QUADSPI;
HAL_GPIO_Init(WICED_QSPI_PIN_CS_GPIO_Port, &GPIO_InitStruct);
GPIO_InitStruct.Pin = WICED_QSPI_PIN_D2_Pin|WICED_QSPI_PIN_CLK_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF9_QUADSPI;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
GPIO_InitStruct.Pin = WICED_QSPI_PIN_D3_Pin|WICED_QSPI_PIN_D1_Pin|WICED_QSPI_PIN_D0_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF9_QUADSPI;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
/* QUADSPI interrupt Init */
HAL_NVIC_SetPriority(QUADSPI_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(QUADSPI_IRQn);
/* USER CODE BEGIN QUADSPI_MspInit 1 */
/* USER CODE END QUADSPI_MspInit 1 */
}
}
So then I call a function to test QSPI:
HAL_StatusTypeDef Qspi_Test(QSPI_HandleTypeDef *hqspi)
{
QSPI_CommandTypeDef sCommand;
uint32_t address = 0;
uint16_t index;
__IO uint8_t step = 0;
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
sCommand.AddressSize = QSPI_ADDRESS_24_BITS;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
while(1)
{
switch(step)
{
case 0:
CmdCplt = 0;
/* Initialize Reception buffer --------------------------------------- */
for (index = 0; index < BUFFER_SIZE; index++)
{
aRxBuffer[index] = 0;
}
printf("QSPI Enable write operations before\r\n");
/* Enable write operations ------------------------------------------- */
QSPI_WriteEnable(hqspi);
printf("QSPI Enable write operations finished\r\n");
/* Erasing Sequence -------------------------------------------------- */
sCommand.Instruction = SECTOR_ERASE_CMD;
sCommand.AddressMode = QSPI_ADDRESS_1_LINE;
sCommand.Address = address;
sCommand.DataMode = QSPI_DATA_NONE;
sCommand.DummyCycles = 0;
if (HAL_QSPI_Command_IT(hqspi, &sCommand) != HAL_OK)
{
printf("case0: HAL_QSPI_Command_IT Error_Handler\r\n");
Error_Handler();
}
step++;
break;
case 1:
if(CmdCplt != 0)
{
CmdCplt = 0;
StatusMatch = 0;
/* Configure automatic polling mode to wait for end of erase ------- */
QSPI_AutoPollingMemReady(hqspi);
step++;
}
break;
case 2:
if(StatusMatch != 0)
{
StatusMatch = 0;
TxCplt = 0;
/* Enable write operations ----------------------------------------- */
QSPI_WriteEnable(hqspi);
/* Writing Sequence ------------------------------------------------ */
sCommand.Instruction = QUAD_IN_FAST_PROG_CMD;
sCommand.AddressMode = QSPI_ADDRESS_1_LINE;
sCommand.DataMode = QSPI_DATA_4_LINES;
sCommand.NbData = BUFFER_SIZE;
if (HAL_QSPI_Command(hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
printf("case2: HAL_QSPI_Command Error_Handler\r\n");
Error_Handler();
}
if (HAL_QSPI_Transmit_IT(hqspi, (uint8_t*)aTxBuffer) != HAL_OK)
{
printf("case2: HAL_QSPI_Transmit_IT Error_Handler\r\n");
Error_Handler();
}
step++;
}
break;
case 3:
if(TxCplt != 0)
{
TxCplt = 0;
StatusMatch = 0;
/* Configure automatic polling mode to wait for end of program ----- */
QSPI_AutoPollingMemReady(hqspi);
step++;
}
break;
case 4:
if(StatusMatch != 0)
{
StatusMatch = 0;
RxCplt = 0;
/* Configure Volatile Configuration register (with new dummy cycles) */
QSPI_DummyCyclesCfg(hqspi);
/* Reading Sequence ------------------------------------------------ */
sCommand.Instruction = QUAD_OUT_FAST_READ_CMD;
sCommand.DummyCycles = DUMMY_CLOCK_CYCLES_READ_QUAD;
if (HAL_QSPI_Command(hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
printf("case4: HAL_QSPI_Command Error_Handler\r\n");
Error_Handler();
}
if (HAL_QSPI_Receive_IT(hqspi, (uint8_t*)aRxBuffer) != HAL_OK)
{
printf("case4: HAL_QSPI_Receive_IT Error_Handler\r\n");
Error_Handler();
}
step++;
}
break;
case 5:
if (RxCplt != 0)
{
RxCplt = 0;
/* Result comparison ----------------------------------------------- */
for (index = 0; index < BUFFER_SIZE; index++)
{
if (aRxBuffer[index] != aTxBuffer[index])
{
printf("case5: Fail\r\n");
Fail();
}
}
address += QSPI_PAGE_SIZE;
if(address >= QSPI_END_ADDR)
{
address = 0;
}
step = 0;
}
break;
default :
printf("default case: Error_Handler\r\n");
Error_Handler();
}
}
}
And it doesn't return from case 0's "QSPI_WriteEnable(hqspi);" In that function, its timing out from HAL_QSPI_AutoPolling function.
void QSPI_WriteEnable(QSPI_HandleTypeDef *hqspi)
{
QSPI_CommandTypeDef sCommand;
QSPI_AutoPollingTypeDef sConfig;
/* Enable write operations ------------------------------------------ */
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
sCommand.Instruction = WRITE_ENABLE_CMD;
sCommand.AddressMode = QSPI_ADDRESS_NONE;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
sCommand.DataMode = QSPI_DATA_NONE;
sCommand.DummyCycles = 0;
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
if (HAL_QSPI_Command(hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
printf("HAL_QSPI_Command: Error_Handler\r\n");
Error_Handler();
}
/* Configure automatic polling mode to wait for write enabling ---- */
sConfig.Match = 0x02;
sConfig.Mask = 0x02;
sConfig.MatchMode = QSPI_MATCH_MODE_AND;
sConfig.StatusBytesSize = 1;
sConfig.Interval = 0x10;
sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
sCommand.Instruction = READ_STATUS_REG_CMD;
sCommand.DataMode = QSPI_DATA_1_LINE;
//sCommand.DataMode = QSPI_DATA_4_LINES;
if (HAL_QSPI_AutoPolling(hqspi, &sCommand, &sConfig, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
printf("HAL_QSPI_AutoPolling: Error_Handler\r\n");
Error_Handler();
}
}
Any help or suggestions greatly appreciated.
2019-04-16 07:31 PM
Ok, now i'm really confused. Connected up my Saleae logic analyzer to the flash chip and two things immediately stand out to me:
Since MX_QUADSPI_Init runs without hitting the Error_Handler(), I'm expecting my QSPI clock to be running from that point. Is this an incorrect assumption?
Thanks
2019-04-16 09:24 PM
If I change:
if (HAL_QSPI_Command(hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
if (HAL_QSPI_AutoPolling(hqspi, &sCommand, &sConfig, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
to
if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
if (HAL_QSPI_AutoPolling(&hqspi, &sCommand, &sConfig, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
It doesn't wait 5 seconds to timeout, it fails sooner (HAL_QSPI_Command only fails when using &hqspi and not hqspi). And I really thought that was the problem. I'm pretty sure it needs the ampersand. Right?
2019-09-19 12:53 AM
I just had a similar issue.
At last i discovered, that the defines for my QSPI pins where defined wrong in a header file.
2020-10-12 08:15 AM
Hello All,
I am facing the same issue - HAL_QSPI_AutoPolling () fails with timeout error. I have checked QSPI pins as per schematic and found correct. Before, this HAL_QSPI_AutoPolling function, I have successfully read Status Register 2 and also Write Enable command does not return with any error. So, I think Pinwise, it is okay. I have increased timeout value to 10000 from default 5000; just to give some more time.
But still behavior has not changed !
Can we replace this with simple reading Status Register and check that required bit?
Any hint or guidance is appreciated. I am really stuck with this error?
Thanks and Regards
2020-10-12 08:30 AM
My Error is resolved by replacing:
s_command.SIOOMode = QSPI_SIOO_INST_ONLY_FIRST_CMD;
with
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
for write enable command after which I called AutoPolling function.
2020-10-12 09:43 AM
>>Can we replace this with simple reading Status Register and check that required bit?
Yes, the hardware provides for a great deal of flexibility in how you interact with it, the functions here supposedly provide an optimal way, but not the only way.
Some memory devices permit a continuous stream to be read from the same register, others might not, you'd need to check the datasheet for the specific parts involved.