cancel
Showing results for 
Search instead for 
Did you mean: 

Debugging NAND flash system infinitely hanging

chris7777
Associate II
I'm trying to interface with a W25N NAND flash chip on an STM32H7, over QSPI. I've only got consistent output out of the reads, and even then, I notice the system hangs forever and can't accept anymore input after a read. Everything else will hang immediately, even a print statement to the terminal at the top of the function won't appear, and the whole system hangs.
 
From some similar issues I found online, I thought it would be a timing issue, and so I tried to implement a status register check. That's my first function in my excerpt below. However, this function couldn't even run alone without again hanging the system (meaning something else is causing the resets, program, clear, and even status check to hang). What else could be the issue that stops everything from running?
 
Any advice much appreciated. Thanks very much in advance.

uint8_t W25N_status(void) {
    QSPI_CommandTypeDef cmd = {0};
    uint8_t status;

    cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE;
    cmd.AddressMode = QSPI_ADDRESS_1_LINE;
    cmd.AddressSize = QSPI_ADDRESS_8_BITS;
    cmd.Address = 0xC0;;
    cmd.DataMode = QSPI_DATA_1_LINE;
    cmd.NbData = 1;
    cmd.Instruction = 0x0F;     // read status register
    if (HAL_QSPI_Command(&hqspi1, &cmd, HAL_MAX_DELAY) != HAL_OK)
        return 0xFF;

    if (HAL_QSPI_Receive(&hqspi1, &status, HAL_MAX_DELAY) != HAL_OK)
        return 0xFF;

    return status;
}


uint8_t W25N_reset(void) {
    QSPI_CommandTypeDef cmd = {0};

    cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE;
    cmd.AddressMode = QSPI_ADDRESS_NONE;
    cmd.DataMode = QSPI_DATA_NONE;

    cmd.Instruction = 0x66;     // enable reset
    if (HAL_QSPI_Command(&hqspi1, &cmd, HAL_MAX_DELAY) != HAL_OK)
        return 1;

    cmd.Instruction = 0x99;     // reset
    if (HAL_QSPI_Command(&hqspi1, &cmd, HAL_MAX_DELAY) != HAL_OK)
        return 1;

    HAL_Delay(5);             // delay to allow full reset (tRST is max 500ums)
    return 0;
}


uint32_t W25N_read_id(void) {
    QSPI_CommandTypeDef cmd = {0};
    uint8_t read_data[3];

    cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE;
    cmd.AddressMode = QSPI_ADDRESS_NONE;
    cmd.DataMode = QSPI_DATA_1_LINE;
    cmd.DummyCycles = 8;
    cmd.NbData = 3;
    cmd.Instruction = 0x9F;     // read JEDEC id

    if (HAL_QSPI_Command(&hqspi1, &cmd, HAL_MAX_DELAY) != HAL_OK)
        return 0xFFFFFFFF;

    if (HAL_QSPI_Receive(&hqspi1, read_data, HAL_MAX_DELAY) != HAL_OK)
        return 0xFFFFFFFF;

    return (read_data[0] << 16) | (read_data[1] << 8) | read_data[2];
}


uint8_t W25N_read(uint32_t start_page, uint16_t offset, uint32_t size, uint8_t *data) {

    // load flash page
    QSPI_CommandTypeDef cmd = {0};
    cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE;
    cmd.AddressMode = QSPI_ADDRESS_1_LINE;
    cmd.AddressSize = QSPI_ADDRESS_24_BITS;
    cmd.DataMode = QSPI_DATA_NONE;
    cmd.Instruction = 0x13;
    cmd.Address = start_page;

    if (HAL_QSPI_Command(&hqspi1, &cmd, HAL_MAX_DELAY) != HAL_OK)
        return 1;

    // HAL_Delay(5);

    // read flash segment
    cmd = {0};
    cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE;
    cmd.AddressMode = QSPI_ADDRESS_1_LINE;
    cmd.AddressSize = QSPI_ADDRESS_16_BITS;
    cmd.DataMode = QSPI_DATA_4_LINES;
    cmd.DummyCycles = 8;
    cmd.NbData = size;
    cmd.Instruction = 0x6B;
    cmd.Address = offset;

    if (HAL_QSPI_Command(&hqspi1, &cmd, HAL_MAX_DELAY) != HAL_OK)
        return 1;

    if (HAL_QSPI_Receive(&hqspi1, data, HAL_MAX_DELAY) != HAL_OK)
        return 1;

    return 0;
}


uint8_t W25N_block_erase(uint32_t block) {
    QSPI_CommandTypeDef cmd = {0};
    cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE;
    cmd.AddressMode = QSPI_ADDRESS_NONE ;
    cmd.DataMode = QSPI_DATA_NONE;
    cmd.Instruction = 0x06;     // write enable

    if (HAL_QSPI_Command(&hqspi1, &cmd, HAL_MAX_DELAY) != HAL_OK)
        return 1;

    cmd = {0};
    cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE;
    cmd.AddressMode = QSPI_ADDRESS_1_LINE;
    cmd.DataMode = QSPI_DATA_NONE;
    cmd.AddressSize = QSPI_ADDRESS_24_BITS;
    cmd.Address = block * 64;
    cmd.Instruction = 0xD8;     // block reset

    if (HAL_QSPI_Command(&hqspi1, &cmd, HAL_MAX_DELAY) != HAL_OK)
        return 1;

    HAL_Delay(10);  // delay to allow full reset (tBE is max 10ms)
    return 0;
}


uint8_t W25N_program_data(uint32_t page, uint16_t offset, uint16_t size, uint8_t *data) {
    QSPI_CommandTypeDef cmd = {0};
    cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE;
    cmd.AddressMode = QSPI_ADDRESS_NONE ;
    cmd.DataMode = QSPI_DATA_NONE;
    cmd.Instruction = 0x06;     // write enable

    if (HAL_QSPI_Command(&hqspi1, &cmd, HAL_MAX_DELAY) != HAL_OK)
        return 1;

    cmd = {0};
    cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE;
    cmd.AddressMode = QSPI_ADDRESS_1_LINE;
    cmd.DataMode = QSPI_DATA_4_LINES;
    cmd.AddressSize = QSPI_ADDRESS_16_BITS;
    cmd.Address = offset;
    cmd.NbData = size;
    cmd.Instruction = 0x34;     // Quad Random Load Program Data

    if (HAL_QSPI_Command(&hqspi1, &cmd, HAL_MAX_DELAY) != HAL_OK)
        return 1;

    if (HAL_QSPI_Transmit(&hqspi1, data, HAL_MAX_DELAY) != HAL_OK)
        return 1;

    cmd = {0};
    cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE;
    cmd.AddressMode = QSPI_ADDRESS_1_LINE;
    cmd.AddressSize = QSPI_ADDRESS_24_BITS;
    cmd.DataMode = QSPI_DATA_NONE;
    cmd.Address = page;
    cmd.Instruction = 0x10;     // program execute

    if (HAL_QSPI_Command(&hqspi1, &cmd, HAL_MAX_DELAY) != HAL_OK)
        return 1;
   
    return 0;
}
1 REPLY 1
Saket_Om
ST Employee

Hello @chris7777 

Don’t use HAL_MAX_DELAY while debugging. If QSPI flags never complete, the HAL will block forever and it looks like the whole MCU hung. Use a short timeout and check the returned error code.

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