cancel
Showing results for 
Search instead for 
Did you mean: 

QSPI Problem with AutoPolling with MX25L512 nor flash

ACHAB.1
Associate

Hi,

I'm trying to implement Macronix MX25L512 with STM32L476, FATFS and USB MSC.

I don't understand why but AutoPolling function timeout.

According to the code below, QSPI_Driver_init() is the first function called. QSPI_ResetMemory return QSPI_OK, but QSPI_EnterMemory_QPI return an error when the AutoPolling function is called. If I skip this function, the same problem occurs when the autopolling function is called in the QSPI_WriteEnable function. That is so weird...

I code this driver with the help of BSP driver from this repo : https://github.com/STMicroelectronics/STM32CubeF7/tree/master/Drivers/BSP/STM32F7308-Discovery

Here, a bit of my code, but I attaching complete C files.

If anyone could help me it would be great !

Thanks in advance

uint8_t QSPI_Driver_init() {
	if (QSPI_ResetMemory(&hqspi) != QSPI_OK) {
		return QSPI_NOT_SUPPORTED;
	}
 
	/* Put QSPI memory in QPI mode */
	if (QSPI_EnterMemory_QPI(&hqspi) != QSPI_OK) {
		return QSPI_NOT_SUPPORTED;
	}
 
	/* Set the QSPI memory in 4-bytes address mode */
	if (QSPI_EnterFourBytesAddress(&hqspi) != QSPI_OK) {
		return QSPI_NOT_SUPPORTED;
	}
 
	/* Configuration of the dummy cycles on QSPI memory side */
	if (QSPI_Configure_Dummy(&hqspi) != QSPI_OK) {
		return QSPI_NOT_SUPPORTED;
	}
 
	/* Configuration of the Output driver strength on memory side */
	if (QSPI_OutDrvStrengthCfg(&hqspi) != QSPI_OK) {
		return QSPI_NOT_SUPPORTED;
	}
	qspi_init_state = 1;
	return QSPI_OK;
}
........
static uint8_t QSPI_EnterMemory_QPI(QSPI_HandleTypeDef *_hqspi) {
	QSPI_CommandTypeDef sCommand;
	QSPI_AutoPollingTypeDef sConfig;
 
	/* Enable QPI operations ------------------------------------------ */
	sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
	sCommand.Instruction = QPI_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) {
		return QSPI_ERROR;
	}
 
	/* Configure automatic polling mode to wait for QPI enabling ---- */
	sConfig.Match = MX25L512_SR_QUADEN;
	sConfig.Mask = MX25L512_SR_QUADEN|MX25L512_SR_WIP;
	sConfig.MatchMode = QSPI_MATCH_MODE_AND;
	sConfig.StatusBytesSize = 1;
	sConfig.Interval = 0x10;
	sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
 
	sCommand.InstructionMode = QSPI_INSTRUCTION_4_LINES;
	sCommand.Instruction = READ_STATUS_REG_CMD;
	sCommand.DataMode = QSPI_DATA_4_LINES;
 
	if (HAL_QSPI_AutoPolling(_hqspi, &sCommand, &sConfig,
	HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
		return QSPI_ERROR;
	}
 
	return QSPI_OK;
}
 
static uint8_t QSPI_ResetMemory(QSPI_HandleTypeDef *_hqspi) {
	QSPI_CommandTypeDef sCommand;
	QSPI_AutoPollingTypeDef sConfig;
	uint8_t reg = 0;
 
	sCommand.InstructionMode = QSPI_INSTRUCTION_4_LINES;
	sCommand.Instruction = RESET_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) {
		return QSPI_ERROR;
	}
 
	/* Send the reset memory command */
	sCommand.Instruction = RESET_MEMORY_CMD;
	if (HAL_QSPI_Command(_hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE)
			!= HAL_OK) {
		return QSPI_ERROR;
	}
 
	/* Send command RESET command in SPI mode */
	/* Initialize the reset enable command */
	sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
	sCommand.Instruction = RESET_ENABLE_CMD;
	/* Send the command */
	if (HAL_QSPI_Command(_hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE)
			!= HAL_OK) {
		return QSPI_ERROR;
	}
	/* Send the reset memory command */
	sCommand.Instruction = RESET_MEMORY_CMD;
 
	if (HAL_QSPI_Command(_hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE)
			!= HAL_OK) {
		return QSPI_ERROR;
	}
 
	/* After reset CMD, 1000ms requested if QSPI memory SWReset occured during full chip erase operation */
	HAL_Delay(1000);
 
	/* Configure automatic polling mode to wait the WIP bit=0 */
	sConfig.Match = 0;
	sConfig.Mask = MX25L512_SR_WIP;
	sConfig.MatchMode = QSPI_MATCH_MODE_AND;
	sConfig.StatusBytesSize = 1;
	sConfig.Interval = 0x10;
	sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
 
	sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
	sCommand.Instruction = READ_STATUS_REG_CMD;
	sCommand.DataMode = QSPI_DATA_1_LINE;
 
	if (HAL_QSPI_AutoPolling(_hqspi, &sCommand, &sConfig,
	HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
		return QSPI_ERROR;
	}
 
	/* Initialize the reading of status register */
	sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
	sCommand.Instruction = READ_STATUS_REG_CMD;
	sCommand.AddressMode = QSPI_ADDRESS_NONE;
	sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
	sCommand.DataMode = QSPI_DATA_1_LINE;
	sCommand.DummyCycles = 0;
	sCommand.NbData = 1;
	sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
	sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
	sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
 
	/* Configure the command */
	if (HAL_QSPI_Command(_hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE)
			!= HAL_OK) {
		return QSPI_ERROR;
	}
 
	/* Reception of the data */
	if (HAL_QSPI_Receive(_hqspi, &reg, HAL_QPSI_TIMEOUT_DEFAULT_VALUE)
			!= HAL_OK) {
		return QSPI_ERROR;
	}
 
	/* Enable write operations, command in 1 bit */
	/* 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) {
		return QSPI_ERROR;
	}
 
	/* Configure automatic polling mode to wait for write enabling */
	sConfig.Match = MX25L512_SR_WREN;
	sConfig.Mask = MX25L512_SR_WREN;
	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;
 
	if (HAL_QSPI_AutoPolling(_hqspi, &sCommand, &sConfig,
	HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
		return QSPI_ERROR;
	}
 
	/* Update the configuration register with new dummy cycles */
	sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
	sCommand.Instruction = WRITE_STATUS_CONFIG_REG_CMD;
	sCommand.AddressMode = QSPI_ADDRESS_NONE;
	sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
	sCommand.DataMode = QSPI_DATA_1_LINE;
	sCommand.DummyCycles = 0;
	sCommand.NbData = 2; //1
	sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
	sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
	sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
 
	/* Enable the Quad IO on the QSPI memory (Non-volatile bit) */
	reg |= 0x40;
 
	/* Configure the command */
	if (HAL_QSPI_Command(_hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE)
			!= HAL_OK) {
		return QSPI_ERROR;
	}
 
	/* Transmission of the data */
	if (HAL_QSPI_Transmit(_hqspi, &reg, HAL_QPSI_TIMEOUT_DEFAULT_VALUE)
			!= HAL_OK) {
		return QSPI_ERROR;
	}
 
	/* 40ms  Write Status/Configuration Register Cycle Time */
	HAL_Delay(40);
 
	return QSPI_OK;
}
 
........
 
static uint8_t QSPI_WriteEnable(QSPI_HandleTypeDef *_hqspi) {
	QSPI_CommandTypeDef sCommand;
	QSPI_AutoPollingTypeDef sConfig;
 
	sCommand.InstructionMode = QSPI_INSTRUCTION_4_LINES;
	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) {
		return QSPI_ERROR;
	}
 
	/* Configure automatic polling mode to wait for write enabling ---- */
	sConfig.Match = MX25L512_SR_WREN;
	sConfig.Mask = MX25L512_SR_WREN;
	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_4_LINES;
	if (HAL_QSPI_AutoPolling(_hqspi, &sCommand, &sConfig,
	HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
		return QSPI_ERROR;
	}
 
	return QSPI_OK;
}
 
........

1 REPLY 1

Should really clear the auto/local variables for consistent/predictable behaviour.

You use instruction width inconsistently. Should really try and track what mode you're in at any given point as the instruction set/expectations shift.

Double check if you're enabling the 4-pins (QE) vs actually going into Quad Mode for everything, I lack the patience to go through the data sheet, code and include files here.

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