Skip to main content
Associate
February 22, 2025
Question

STM32G473 QSPI indirect read times out at higher frequencies

I have a custom board with an STM32G473 running at 170MHz. I have the QSPI peripheral running correctly in indirect mode when the pre-scaler has a value of 5 (so ~23MHz) but when I decrease the pre-scaler any further all HAL_QSPI_Receive calls end up failing silently. I've tracked it down to the QSPI_WaitFlagStateUntilTimeout returning an error due to what seems like a timeout. Here's a snippet of my initialization code:

 

	flashSPI.Instance = QUADSPI;
	flashSPI.Init.ClockPrescaler = 2;
	flashSPI.Init.FifoThreshold = 1;
	flashSPI.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_NONE;
	flashSPI.Init.FlashSize = 27;
	flashSPI.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_1_CYCLE;
	flashSPI.Init.ClockMode = QSPI_CLOCK_MODE_0;
	flashSPI.Init.FlashID = QSPI_FLASH_ID_1;
	flashSPI.Init.DualFlash = QSPI_DUALFLASH_DISABLE;

	 __HAL_RCC_QSPI_CLK_ENABLE();
	 __HAL_RCC_GPIOA_CLK_ENABLE();
	 __HAL_RCC_GPIOB_CLK_ENABLE();

	// Initialize pins
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
	GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
	GPIO_InitStruct.Alternate = GPIO_AF10_QUADSPI;

	// Configure NCS pin
	GPIO_InitStruct.Pin = QSPI_NCS_Pin;
	GPIO_InitStruct.Pull = GPIO_PULLUP;
	HAL_GPIO_Init(QSPI_NCS_Port, &GPIO_InitStruct);

	GPIO_InitStruct.Pin = QSPI_CLK_Pin;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	HAL_GPIO_Init(QSPI_CLK_Port, &GPIO_InitStruct);

	GPIO_InitStruct.Pin = QSPI_IO3_Pin;
	HAL_GPIO_Init(QSPI_IO3_Port, &GPIO_InitStruct);

	GPIO_InitStruct.Pin = QSPI_IO2_Pin;
	HAL_GPIO_Init(QSPI_IO2_Port, &GPIO_InitStruct);

	GPIO_InitStruct.Pin = QSPI_IO1_Pin;
	HAL_GPIO_Init(QSPI_IO1_Port, &GPIO_InitStruct);

	GPIO_InitStruct.Pin = QSPI_IO0_Pin;
	HAL_GPIO_Init(QSPI_IO0_Port, &GPIO_InitStruct);

	__HAL_RCC_QSPI_FORCE_RESET();
	__HAL_RCC_QSPI_RELEASE_RESET();
	if(HAL_QSPI_Init(&flashSPI) != HAL_OK) return FC_ERROR;

	// Enable interrupts
	HAL_NVIC_SetPriority(QUADSPI_IRQn, 1, 0);
	HAL_NVIC_EnableIRQ(QUADSPI_IRQn);

	// Check device ID and manufacturer ID
	uint8_t jedec[3] = {0};
	getJEDEC(jedec);
	uint16_t deviceID = (jedec[1] << 8) | (jedec[2]);
	if(jedec[0] != WINBOND_MFR_ID || deviceID != W25N02KV_DEVICE_ID) return FC_ERROR;

 

I tried implementing the "QUADSPI internal timing criticality" fix in the errata but haven't had any luck. Are there certain parameters I'm missing?

This topic has been closed for replies.

7 replies

Tesla DeLorean
Guru
February 23, 2025

Show the actual code that's failing, and ignoring the error codes.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
ethanleepAuthor
Associate
February 23, 2025

This is the function that fails:

 

// Get the JEDEC ID with a 3 byte array
FC_STATUS flashDriver::getJEDEC(uint8_t *jedec) {
	QSPI_CommandTypeDef command = {0};

	command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
	command.Instruction = READ_JEDC_CMD;
	command.DataMode = QSPI_DATA_1_LINE;
	command.DummyCycles = 8;
	command.NbData = 3;

	if(HAL_QSPI_Command(&flashSPI, &command, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) return FC_ERROR;

	if(HAL_QSPI_Receive(&flashSPI, jedec, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) return FC_ERROR;

	return FC_OK;
}

 

 HAL_QSPI_Command executes as expected but HAL_QSPI_Receive returns all zeroes and takes the whole timeout duration. 

Tesla DeLorean
Guru
February 23, 2025

Does it return an error?

 hqspi->State = HAL_QSPI_STATE_ERROR; 
 hqspi->ErrorCode |= HAL_QSPI_ERROR_TIMEOUT; 

 

Can't say I've fiddled with the clock prescaler, but this has worked for me on the G4's

 

//****************************************************************************

static uint8_t BSP_QSPI_ReadStatus(QSPI_HandleTypeDef *hqspi, uint32_t Reg, uint32_t *pStatusReg)
{
 QSPI_CommandTypeDef sCommand = {0};
 uint32_t data = 0;

 sCommand.NbData = 1;

 switch(Reg)
 {
 case 0 : sCommand.Instruction = READ_STATUS_REG1_CMD; break; // REG1 RDSR 0x05
 case 1 : sCommand.Instruction = READ_STATUS_REG2_CMD; break; // REG2 EQIO 0x35 !1
 case 2 : sCommand.Instruction = READ_STATUS_REG3_CMD; break; // REG3 RDCR
 case 0x9F : // READID
 sCommand.Instruction = 0x9F;
 sCommand.NbData = 3;
 break;
 }

 sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
 sCommand.AddressMode = QSPI_ADDRESS_NONE;
 sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
 sCommand.DataMode = QSPI_DATA_1_LINE;
 sCommand.DummyCycles = 0;

 sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
 sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
 sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;

 /* Send the command */
 if (HAL_QSPI_Command(hqspi, &sCommand, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
 {
 return(QSPI_ERROR);
 }

 if (HAL_QSPI_Receive(hqspi, (void *)&data, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
 {
 return(QSPI_ERROR);
 }

 if (pStatusReg)
 *pStatusReg = data;

 return(QSPI_OK);
}

//****************************************************************************

 

 

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
ethanleepAuthor
Associate
February 23, 2025

HAL_QSPI_Receive returns HAL_ERROR, which I missed before. Sorry about that. Looking at the debugger, the QSPI peripheral exits with an ErrorCode of 1 but State is still HAL_QSPI_STATE_READY.

 

I gave your code a shot and I'm hitting the same issue, still works when the pre-scaler is 5 however. 

Tesla DeLorean
Guru
February 23, 2025

TBH I don't know what mechanical dependencies it has on the speed. It just clocks the bus, it doesn't really have any expectations on the response, if you clock too fast you'll just get gibberish back, or it won't accept the command, in which case you'll just clock back pin states.

At higher speeds, and high slew rates, you're apt to get a lot of ringing.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
Associate III
April 11, 2025

@Tesla DeLorean Could you let me know how to get rid of my issue, https://community.st.com/t5/stm32-mcus-touchgfx-and-gui/regarding-external-loader-with-at25q128a-nor-flash/td-p/790941 ,  it would be glad if you could help me out, I have been working on this since from three months.

Thank you,

Tesla DeLorean
Guru
April 11, 2025

3 Months? If I provide a solution it's got to be worth something?  https://paypal.me/cliveone

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