Question
Debugging NAND flash system infinitely hanging
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;
}