2021-03-10 07:48 AM
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, ®, 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, ®, 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;
}
........
2021-03-10 08:21 AM
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.