cancel
Showing results for 
Search instead for 
Did you mean: 

Block Erase Function Issue with MT25QL01GBBB NOR Flash on STM32 MCU

Mohammed Eshaq
Associate III

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:

  1. Microcontroller: STM32 (STM32 H7 series)
  2. QSPI Flash: MT25QL01GBBB. Both MCU and Flash are on the same PCB.
  3. IDE and Toolchain: STM32CubeIDE with STM32 HAL drivers
  4. Communication Mode: QPI (Quad Peripheral Interface)
  5. Addressing Mode: 3-Byte and 4 Byte Addressing (tried both)
  6. 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).
  7. 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, &REG8);
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, &REG8);
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, &REG8);
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, &REG8);
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, &REG8);

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, &REG8);
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:

  1. 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!
  2. 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:

  1. Dummy Cycles: Could there be an issue with the number of dummy cycles specified in the HAL library or the command configuration?
  2. Addressing Mode: Is there a possibility that the 3-byte addressing mode is causing this issue with the block erase command?
  3. Driver Compatibility: Are there known limitations or adjustments required for the STM32 HAL QSPI library to support the MT25QL01GBBB erase functionality?
  4. 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!

3 REPLIES 3
KDJEM.1
ST Employee

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.

KDJEM1_0-1734518939005.png

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.

Andreas Bolsch
Lead II

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).

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.

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