Block Erase Function Issue with MT25QL01GBBB NOR Flash on STM32 MCU
Description:
I am currently working on interfacing the MT25QL01GBBB NOR Flash memory with an STM32 MCU using the STM HAL QSPI library. While most operations such as read, write, and basic commands work successfully, I am encountering an issue with the block erase function.
The block erase operation does not seem to function as expected. After executing the block erase command, the memory contents remain unchanged. Additionally, modifying the dummy cycles in the erase function impacts the communication stability with the NOR flash chip. Specifically:
- Dummy cycle = 1: Erase function is sent, but the memory is not cleared.
- Dummy cycle = 0: Communication with the chip fails, resulting in status register and other commands returning incorrect values.
Despite following the MT25QL01GBBB datasheet closely, the block erase functionality is not performing as intended. Below are the details of my setup and the code being used.
Setup:
- Microcontroller: STM32 (STM32 H7 series)
- QSPI Flash: MT25QL01GBBB. Both MCU and Flash are on the same PCB.
- IDE and Toolchain: STM32CubeIDE with STM32 HAL drivers
- Communication Mode: QPI (Quad Peripheral Interface)
- Addressing Mode: 3-Byte and 4 Byte Addressing (tried both)
- Library Used: I have taken the library for this chip MT25QL512ABB, and matched it to the MT25QL01GBBB datasheet. The opcodes are pretty much the same except for one (whole chip erase cmd).
QSPI Configuration:
- Clock Prescaler: Configured for 80 MHz SPI clock (tried for much lower frequencies as well).
- QSPI Command Timeouts: 5 seconds (HAL_QSPI_TIMEOUT_DEFAULT_VALUE).
- Write Enable: Enabled and verified before erase.
QSPI is inialized as follows:
hqspi.Instance = QUADSPI;
hqspi.Init.ClockPrescaler = 2;
hqspi.Init.FifoThreshold = 16;
hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
hqspi.Init.FlashSize = 26;
hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_8_CYCLE; // Tried other values as well
hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;
hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE;
Code Snippet for Block Erase:
This are snippets from my driver program:
ret=MT25QL01GBBB_EnterQPIMode(&hqspi);
if (ret != MT25QL01GBBB_OK)
printf("MT25QL01GBBB Error\r\n");
else
printf("Entered QPI Mode\r\n");
MT25QL01GBBB_Interface_t mode = MT25QL01GBBB_QPI_MODE;
ret=MT25QL01GBBB_Exit4BytesAddressMode(&hqspi, mode);
if (ret != MT25QL01GBBB_OK)
printf("MT25QL01GBBB Error\r\n");
else
printf("3-Bytes Address Mode\r\n");
MT25QL01GBBB_AddressSize_t size = MT25QL01GBBB_3BYTES_SIZE;
printf("=== Erase ===\r\n");
ret=MT25QL01GBBB_WriteEnable(&hqspi, mode, MT25QL01GBBB_DUALFLASH_DISABLE);
if(ret!=MT25QL01GBBB_OK)
printf("MT25QL01GBBB Error\r\n");
else
printf("Write Enabled\r\n");
ret=MT25QL01GBBB_ReadStatusRegister(&hqspi, mode, MT25QL01GBBB_DUALFLASH_DISABLE, ®8);
if(ret!=MT25QL01GBBB_OK)
printf("MT25QL01GBBB Error\r\n");
else
printf("Status REG: %X\r\n", REG8);
ret=MT25QL01GBBB_ReadFlagStatusRegister(&hqspi, mode, MT25QL01GBBB_DUALFLASH_DISABLE, ®8);
if(ret!=MT25QL01GBBB_OK)
printf("MT25QL01GBBB Error\r\n");
else
printf("Flag Status REG: %X\r\n", REG8);
ret=MT25QL01GBBB_BlockErase(&hqspi, mode, size, address, MT25QL01GBBB_ERASE_4K);
if(ret!=MT25QL01GBBB_OK)
printf("Erase Error\r\n");
else
printf("Erased @ 0x%X\r\n", address);
HAL_Delay(5000); // Experimenting. Added after frustration
ret=MT25QL01GBBB_ReadStatusRegister(&hqspi, mode, MT25QL01GBBB_DUALFLASH_DISABLE, ®8);
if(ret!=MT25QL01GBBB_OK)
printf("MT25QL01GBBB Error\r\n");
else
printf("\033[0;31mStatus REG: %X\033[0m\r\n", REG8);
ret=MT25QL01GBBB_ReadFlagStatusRegister(&hqspi, mode, MT25QL01GBBB_DUALFLASH_DISABLE, ®8);
if(ret!=MT25QL01GBBB_OK)
printf("MT25QL01GBBB Error\r\n");
else
printf("Flag Status REG: %X\r\n", REG8);
HAL_Delay(1000); // Experimenting
// As per the datasheet, if the erase command goes through the enable latch is disabled automatically, and the busy latch goes high, but they don't!
ret=MT25QL01GBBB_WriteDisable(&hqspi, mode);
if(ret!=MT25QL01GBBB_OK)
printf("MT25QL01GBBB Error\r\n");
else
printf("Write Disabled\r\n");
ret=MT25QL01GBBB_ReadStatusRegister(&hqspi, mode, MT25QL01GBBB_DUALFLASH_DISABLE, ®8);
if(ret!=MT25QL01GBBB_OK)
printf("MT25QL01GBBB Error\r\n");
else
printf("Status REG: %X\r\n", REG8);
ret=MT25QL01GBBB_ReadFlagStatusRegister(&hqspi, mode, MT25QL01GBBB_DUALFLASH_DISABLE, ®8);
if(ret!=MT25QL01GBBB_OK)
printf("MT25QL01GBBB Error\r\n");
else
printf("Flag Status REG: %X\r\n", REG8);
printf("=== Done erasing ===\r\n");Here is the code I am using in the library for the block erase function:
int32_t MT25QL01GBBB_BlockErase(QSPI_HandleTypeDef *Ctx, MT25QL01GBBB_Interface_t Mode, MT25QL01GBBB_AddressSize_t AddressSize, uint32_t BlockAddress, MT25QL01GBBB_Erase_t BlockSize) {
int32_t ret = MT25QL01GBBB_OK;
QSPI_CommandTypeDef s_command;
/* Initialize the erase command */
switch(BlockSize) {
case MT25QL01GBBB_ERASE_32K:
s_command.Instruction = (AddressSize == MT25QL01GBBB_3BYTES_SIZE) ? MT25QL01GBBB_SUBSECTOR_ERASE_32K_CMD : MT25QL01GBBB_4_BYTE_ADDR_SUBSECTOR_ERASE_32K_CMD;
break;
case MT25QL01GBBB_ERASE_64K:
s_command.Instruction = (AddressSize == MT25QL01GBBB_3BYTES_SIZE) ? MT25QL01GBBB_SECTOR_ERASE_64K_CMD : MT25QL01GBBB_4_BYTE_ADDR_SECTOR_ERASE_64K_CMD;
break;
case MT25QL01GBBB_ERASE_4K:
default:
s_command.Instruction = (AddressSize == MT25QL01GBBB_3BYTES_SIZE) ? MT25QL01GBBB_SUBSECTOR_ERASE_4K_CMD : MT25QL01GBBB_4_BYTE_ADDR_SUBSECTOR_ERASE_4K_CMD;
break;
}
s_command.InstructionMode = (Mode == MT25QL01GBBB_QPI_MODE) ? QSPI_INSTRUCTION_4_LINES : QSPI_INSTRUCTION_1_LINE;
s_command.AddressMode = QSPI_ADDRESS_4_LINES;
s_command.AddressSize = QSPI_ADDRESS_24_BITS;
s_command.Address = BlockAddress;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DummyCycles = 1; // Originally set to 0, which causes communication issues.
s_command.DataMode = QSPI_DATA_NONE;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
/* Send the command */
if (HAL_QSPI_Command(Ctx, &s_command, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
ret = MT25QL01GBBB_ERROR;
}
return ret;
}Observations:
Dummy Cycles:
- Setting DummyCycles = 1 allows communication but does not erase memory content, however, we can still get the values for the flag/status register and read memory locations.
- Setting DummyCycles = 0 results in a communication failure. Can't read any of the above!
Status and Flag Registers:
- Status Register (0x05): Shows Write Enable Latch active during the erase process.
- Flag Status Register (0x70): Shows Ready Bit after erase operation, but the content remains unchanged.
Questions for the Community:
- Dummy Cycles: Could there be an issue with the number of dummy cycles specified in the HAL library or the command configuration?
- Addressing Mode: Is there a possibility that the 3-byte addressing mode is causing this issue with the block erase command?
- Driver Compatibility: Are there known limitations or adjustments required for the STM32 HAL QSPI library to support the MT25QL01GBBB erase functionality?
- Erase Procedure: Are there any additional steps required (e.g., specific configurations for MT25QL01GBBB) before or after executing the erase command?
Any insights, recommendations, or solutions from the community would be highly appreciated!
