2024-12-18 01:25 AM
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:
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.
QSPI Configuration:
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;
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; }
Dummy Cycles:
Status and Flag Registers:
Any insights, recommendations, or solutions from the community would be highly appreciated!
2024-12-18 03:10 AM
Hello @Mohammed Eshaq,
Which STM32H7 are you using?
The dummy cycle must be configured depending on the memory datasheet.
As mentioned in the memory datasheet, for erase operation, the dummy cycle is equal to 0.
Are you using 4-BYTE 4KB SUBSECTOR ERASE 0x21 operation?
Before 0x21 operation, the WRITE ENABLE command must be issued first. Also, 0x21 operation support only 4 address bytes as mentioned in the above table.
I recommend you to refer to QSPI_MemoryMappedDual example and check your configuration and settings. This example describes how to erase part of the QSPI memory, write data in IT mode and access to QSPI memory in memory-mapped dual mode. This example has been tested with STM32H747I-EVALUATION BOARD and MT25TL01G memory.
Did you find an issue when using 4KB SUBSECTOR ERASE 0x20 operation?
I hope this help you!
Thank you.
Kaouthar
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
2024-12-18 04:41 AM
You did realize that the flash device is a two-stacked die device, didn't you? I've always resisted to use these devices as the handling is prone to cause difficulties: the handling of inter-die communication varies across manufacturers and is sometimes not clearly documented. So, are you sure you can already write and read the *entire* memory? I.e. full 128MBytes of random data? In particular, status register must be read twice to retrieve both status registers (of both dies).
2024-12-18 08:39 AM
A 128MB device is going to need to be in 4-byte (32-bit) addressing mode. The 3-byte (24-bit) is only good to 16MB/128Mb
Two die mode requires you loop reading the Flag Status Register twice, and BOTH must flag ready. You can't use AutoPolling of the Status Register on one die.
Erasing can fail/complete immediately if the BP (block protection) bits are set in the Status Register, there's also a failure flag in the Flag Status Register.
There isn't a Mass Erase, you must erase each die, selected via the address
Used the 01G, 02G and 04G parts on STM32's, work fine.
Dummy Cycles, memory and STM32 need a consistent view of this, the memory will expect you to respect the setting it had internally.