cancel
Showing results for 
Search instead for 
Did you mean: 

QSPI_FLAG_SM timing out on QSPI flash test

MRex
Associate III

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

7 REPLIES 7
MRex
Associate III

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.

MRex
Associate III

Ok, now i'm really confused. Connected up my Saleae logic analyzer to the flash chip and two things immediately stand out to me:

  1. I don't see the CLK toggling. I don't know how the other signals are showing negative edges at the same time without a clock. I've checked my wire lead to the flash and looks well soldered... but the code seems to be calling the functions to enable the QSPI clock in the HAL_QSPI_MspInit, so clock should be running.
  2. IO2, which is active low Write Protect, goes low and stays low. So I can see how it is getting stuck in QSPI_WriteEnable(hspi). IO2 and IO3 both have 10K pull-ups externally connected to them.

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

0690X000008AcelQAC.png

MRex
Associate III

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?

bitlischieber
Associate III

I just had a similar issue.

At last i discovered, that the defines for my QSPI pins where defined wrong in a header file.

PDChauhan
Associate II

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

PDChauhan
Associate II

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.

>>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.

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