cancel
Showing results for 
Search instead for 
Did you mean: 

Problem with NOR Flash W25Q512 cannot erase sector / chip

duchuylee
Associate II

Hello,
I have been trying to make a driver for the Winbond W25Q512JV, It's works normally ( I can read/write data, erase sector/chip, can write image as external flash loader with Touchgfx) until one day I could no longer erase sectors or full chips ( My chip has been erased no more than 100 times). When erasing, it doesn't report any errors, it just responds to a successful erase very quickly (~ 0.5s) , almost immediately (previously it took ~ 140 seconds to erase a full chip). When I read back these memory areas, they are not equal to 0xFF. I understand that erase has not been performed yet.
I checked by reading the registers status: reg1 = 0xFE, reg2 = 0x02, reg3 = 0x03 and compare with datasheet, it mean bit SRL = 0, SRP = 1, WEL = 1, TB = 1, BP[3-0] = 1 => My chip into protection state

duchuylee_1-1713893705439.png

duchuylee_0-1713893524850.png

I use STM32H723 on OSPI2 running with QSPI mode, how can i resolve this problem? please give me solution. Thank you for your help



1 ACCEPTED SOLUTION

Accepted Solutions
duchuylee
Associate II

Hi @Tesla DeLorean , @Pavel A. 
Sorry for the late reply, I just had a long vacation so I'm just now starting again with this project.
I tried to remember that, before, I set the clock for OSPI at 200MHz, with clock prescaler = 2 (~100Mhz), W25Q512JV worked well, no problems occurred. But after that, I adjusted the clock for OSPI to 275MHz (maximum with stm32h723), with the prescaler clock still = 2 (~137MHz) (because I also used OSPI1 for Octo RAM APS12808L-3OBM so I adjusted the frequency This number is to test the responsiveness of external RAM).
At this time, W25Q512JV loaded and deleted a few times and then got the above error.
It seems that the OSPI frequency exceeding the response level of the W25Q512JV caused the initial configuration of the status register to wrong, leading to the chip entering the OTP state, this cannot be undone like Mr @Pavel A.  mentioned.
I replaced the W25Q512JV chip with a newer chip, set the OSPI clock to 200MHz, with clock prescaler = 2 (~100Mhz) and it seems to work fine, no problems yet (at least until now). I will continue to update if that issue repeats.
Thank you for your help.

View solution in original post

9 REPLIES 9
Pavel A.
Evangelist III

When erasing, it doesn't report any errors, it just responds to a successful erase very quickly (~ 0.5s) , almost immediately (previously it took ~ 140 seconds

Look for conditions that prevent erase: protected sectors/areas, read-only password, etc.

 

I'm not sure how you did that or how to clear. One of the bits (SRL) perhaps via a power cycle. The rest you'll need to clear the bits and Write Status Register 1.

 

Failing that you'll need to remove and replace the device, and perhaps ponder hard about what you were doing to get into this state.

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

Hi @Pavel A. , @Tesla DeLorean 
Thanks for the help, as I mentioned above,  SRL = 0, SRP = 1 and I have voltage measurement on W25Q512: Vcc = 3.29V (normal), /WP = 0V, Compare with the table above, W25Q512 into hardware protected: "When /WP pin is low the Status Register locked and cannot be written to". But I used W25Q512 in QSPI mode, the pin /WP as IO2, can only be controlled by QSPI instructions software
Below is my code to erase chip, It was working fine until I got above error:

HAL_StatusTypeDef W25Qxx_OSPI_ResetChip(OSPI_HandleTypeDef* hospi)

{

    OSPI_RegularCmdTypeDef sCommand={0};



    /* Enable Reset --------------------------- */

/* Common Commands*/

sCommand.OperationType      = HAL_OSPI_OPTYPE_COMMON_CFG; /* Common configuration (indirect or auto-polling mode) */

sCommand.FlashId            = HAL_OSPI_FLASH_ID_1; /* Set The OCTO SPI Flash ID */

sCommand.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE; /* Disable Instruction DDR/DTR Mode */

sCommand.AddressDtrMode      = HAL_OSPI_ADDRESS_DTR_DISABLE; /* Disable Address DDR/DTR Mode */

sCommand.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; /* Disable Data DDR/DTR Mode */

sCommand.DQSMode            = HAL_OSPI_DQS_DISABLE; /* Disable Data Strobe */

sCommand.SIOOMode          = HAL_OSPI_SIOO_INST_EVERY_CMD; /* SIOO Mode: Send instruction on every transaction */

sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; /* Disable Alternate Bytes Mode */

sCommand.AlternateBytes = HAL_OSPI_ALTERNATE_BYTES_NONE; /* Alternate Bytes = 0 */

sCommand.AlternateBytesSize = HAL_OSPI_ALTERNATE_BYTES_NONE; /* Alternate Bytes Size = 0 */

sCommand.AlternateBytesDtrMode = HAL_OSPI_ALTERNATE_BYTES_DTR_DISABLE; /* Disable Alternate Bytes DDR/DTR Mode */

sCommand.InstructionMode    = HAL_OSPI_INSTRUCTION_1_LINE; /* Instruction on a single line */

sCommand.InstructionSize    = HAL_OSPI_INSTRUCTION_8_BITS; /* 8-bit Instruction */

#if((USE_W25Qxx == USE_W25Q512) || (USE_W25Qxx == USE_W25Q256))

sCommand.AddressSize = HAL_OSPI_ADDRESS_32_BITS; /* 32-bit Address */

#elif((USE_W25Qxx == USE_W25Q128) || (USE_W25Qxx == USE_W25Q64))

sCommand.AddressSize = HAL_OSPI_ADDRESS_24_BITS; /* 24-bit Address */

#endif

/* Instruction */

sCommand.Instruction = W25QXX_ENABLE_RST_CMD; /* What We Do? */

/* Address */

sCommand.AddressMode        = HAL_OSPI_ADDRESS_NONE; /* Define Address Lines: No Address */

sCommand.Address = 0; /* Byte Address */

/* Data */

sCommand.DataMode          = HAL_OSPI_DATA_NONE; /* Define Data Lines: No Data */

sCommand.DummyCycles        = 0; /* Bytes Send With No Data */

sCommand.NbData            = 0; /* Bytes Send With Data */



if (HAL_OSPI_Command(hospi, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)

{

return HAL_ERROR;

}



    /* Reset Device --------------------------- */

/* Common Commands*/

sCommand.OperationType      = HAL_OSPI_OPTYPE_COMMON_CFG; /* Common configuration (indirect or auto-polling mode) */

sCommand.FlashId            = HAL_OSPI_FLASH_ID_1; /* Set The OCTO SPI Flash ID */

sCommand.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE; /* Disable Instruction DDR/DTR Mode */

sCommand.AddressDtrMode      = HAL_OSPI_ADDRESS_DTR_DISABLE; /* Disable Address DDR/DTR Mode */

sCommand.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE; /* Disable Data DDR/DTR Mode */

sCommand.DQSMode            = HAL_OSPI_DQS_DISABLE; /* Disable Data Strobe */

sCommand.SIOOMode          = HAL_OSPI_SIOO_INST_EVERY_CMD; /* SIOO Mode: Send instruction on every transaction */

sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; /* Disable Alternate Bytes Mode */

sCommand.AlternateBytes = HAL_OSPI_ALTERNATE_BYTES_NONE; /* Alternate Bytes = 0 */

sCommand.AlternateBytesSize = HAL_OSPI_ALTERNATE_BYTES_NONE; /* Alternate Bytes Size = 0 */

sCommand.AlternateBytesDtrMode = HAL_OSPI_ALTERNATE_BYTES_DTR_DISABLE; /* Disable Alternate Bytes DDR/DTR Mode */

sCommand.InstructionMode    = HAL_OSPI_INSTRUCTION_1_LINE; /* Instruction on a single line */

sCommand.InstructionSize    = HAL_OSPI_INSTRUCTION_8_BITS; /* 8-bit Instruction */

#if((USE_W25Qxx == USE_W25Q512) || (USE_W25Qxx == USE_W25Q256))

sCommand.AddressSize = HAL_OSPI_ADDRESS_32_BITS; /* 32-bit Address */

#elif((USE_W25Qxx == USE_W25Q128) || (USE_W25Qxx == USE_W25Q64))

sCommand.AddressSize = HAL_OSPI_ADDRESS_24_BITS; /* 24-bit Address */

#endif

/* Instruction */

sCommand.Instruction = W25QXX_RESET_CMD; /* What We Do? */

/* Address */

sCommand.AddressMode        = HAL_OSPI_ADDRESS_NONE; /* Define Address Lines: No Address */

sCommand.Address = 0; /* Byte Address */

/* Data */

sCommand.DataMode          = HAL_OSPI_DATA_NONE; /* Define Data Lines: No Data */

sCommand.DummyCycles        = 0; /* Bytes Send With No Data */

sCommand.NbData            = 0; /* Bytes Send With Data */



if (HAL_OSPI_Command(hospi, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)

{

return HAL_ERROR;

}

return HAL_OK;

}

I also attached W25Q512 library files below, please help me check it 
@Tesla DeLorean  "Failing that you'll need to remove and replace the device, and perhaps ponder hard about what you were doing to get into this state." => I can replace by new chip, but I'm afraid this will happen again.
Thank you so much

That looks to Reset not Erase

Get the QE enabled so the pin states are for data, not write protect. Enable the pins with an internal pull-up so they aren't low or floating.

Clear the BPx and COM bits.

Mass Erase will fail immediately if any sectors are protected. It doesn't generate an "Error" as there's not way/method to report that. Watch for it taking less than a second, rather than 100's of seconds

>> I can replace by new chip, but I'm afraid this will happen again.

Sure, but approach this as a validation exercise. Try simple interactions and test incrementally, so you can observe it working, and understand exactly what you did to make it fail if you do so again. If you understand WHY it happened you might have a better idea how to reverse/undo the situation.

Perhaps wire up a ZIF socket so you can swap between devices.

Try to fix by clearing the protection bits in SR1. Write that code first.

Not seeing anything glaring in your code, but do make sure you clear auto variables like sCommand, in EVERY instance, so there's not chance of picking up random content from the existing stack frame.

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

Hi @Tesla DeLorean 
Thank you for your quick reply
>> That looks to Reset not Erase => Oh sorry for my bad, I copied the wrong function:

HAL_StatusTypeDef W25Qxx_OSPI_Erase_Chip(OSPI_HandleTypeDef* hospi)
{
	OSPI_RegularCmdTypeDef sCommand={0};
	//uint8_t reg3=0, w_reg3=0;
	uint32_t tick_start = 0, tick_end = 0;
	tick_start = HAL_GetTick();
    /* Erasing Sequence ---------------------------------*/
	/* Common Commands*/
	sCommand.OperationType      		= HAL_OSPI_OPTYPE_COMMON_CFG; 				/* Common configuration (indirect or auto-polling mode) */
	sCommand.FlashId            		= HAL_OSPI_FLASH_ID_1; 						/* Set The OCTO SPI Flash ID */
	sCommand.InstructionDtrMode 		= HAL_OSPI_INSTRUCTION_DTR_DISABLE; 		/* Disable Instruction DDR/DTR Mode */
	sCommand.AddressDtrMode     		= HAL_OSPI_ADDRESS_DTR_DISABLE; 			/* Disable Address DDR/DTR Mode */
	sCommand.DataDtrMode				    = HAL_OSPI_DATA_DTR_DISABLE; 				/* Disable Data DDR/DTR Mode */
	sCommand.DQSMode            		= HAL_OSPI_DQS_DISABLE; 					/* Disable Data Strobe */
	sCommand.SIOOMode          			= HAL_OSPI_SIOO_INST_EVERY_CMD; 			/* SIOO Mode: Send instruction on every transaction */
	sCommand.AlternateBytesMode 		= HAL_OSPI_ALTERNATE_BYTES_NONE; 			/* Disable Alternate Bytes Mode */
	sCommand.AlternateBytes				  = HAL_OSPI_ALTERNATE_BYTES_NONE; 			/* Alternate Bytes = 0 */
	sCommand.AlternateBytesSize			= HAL_OSPI_ALTERNATE_BYTES_NONE; 			/* Alternate Bytes Size = 0 */
	sCommand.AlternateBytesDtrMode		= HAL_OSPI_ALTERNATE_BYTES_DTR_DISABLE; 	/* Disable Alternate Bytes DDR/DTR Mode */
	sCommand.InstructionMode   			= HAL_OSPI_INSTRUCTION_1_LINE;				/* Instruction on a single line */
	sCommand.InstructionSize    		= HAL_OSPI_INSTRUCTION_8_BITS;				/* 8-bit Instruction */
#if((USE_W25Qxx == USE_W25Q512) || (USE_W25Qxx == USE_W25Q256))
	sCommand.AddressSize 						= HAL_OSPI_ADDRESS_32_BITS;					/* 32-bit Address */
#elif((USE_W25Qxx == USE_W25Q128) || (USE_W25Qxx == USE_W25Q64))
	sCommand.AddressSize 						= HAL_OSPI_ADDRESS_24_BITS;					/* 24-bit Address */
#endif
	/* Instruction */
	sCommand.Instruction 				    = W25QXX_CHIP_ERASE_CMD;						/* What We Do? */
	/* Address */
	sCommand.AddressMode       			= HAL_OSPI_ADDRESS_NONE;					/* Define Address Lines: No Address */
	sCommand.Address					      = 0;										/* Byte Address */
	/* Data */
	sCommand.DataMode          			= HAL_OSPI_DATA_NONE;						/* Define Data Lines: No Data */
	sCommand.DummyCycles       			= 0;										/* Bytes Send With No Data */
	sCommand.NbData            			= 1;										/* Bytes Send With Data */

	if (W25Qxx_OSPI_WriteEnable(hospi) != HAL_OK)
	{
		return HAL_ERROR;
	}

	if (HAL_OSPI_Command(hospi, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		return HAL_ERROR;
	}

	while (W25Qxx_IsBusy(hospi)==HAL_ERROR)
	{
		HAL_Delay(1);
	}

	if (W25Qxx_OSPI_AutoPollingMemReady(hospi) != HAL_OK)
	{
		return HAL_ERROR;
	}
	tick_end = HAL_GetTick();
	printf("Erase all chip OK in %0.4f s.\r\n", (double)(tick_end - tick_start) / 1000);
	return HAL_OK;
}

>> Clear the BPx and COM bits => I have try to clear BPx, but when read again reg1, those bit back to 1 (CMP = 0, WPS = 0)
>> Get the QE enabled so the pin states are for data, not write protect. Enable the pins with an internal pull-up so they aren't low or floating. => I read reg2 = 0x02 mean QE = 1, but I measure WP = 0V => Is there anything wrong here? Can I config WP pin of GPIO on STM32H723 to internal pull up first?
>> Try to fix by clearing the protection bits in SR1. Write that code first. => Yeah, I will try to make it

>> make sure you clear auto variables like sCommand, in EVERY instance, so there's not chance of picking up random content from the existing stack frame => This is good idea too
Thank you for support

duchuylee
Associate II

Hi @Tesla DeLorean 
I tried all the solutions above, but when I read SRP, results are always returned 1, it causes nor flash to enter hardware protected mode (WP/IO2 is always in state 0 when idle in QSPI mode), I cannot erase/write any memory area, including the status register. I tried to find a way to clear this bit back to 0, but it seems that the datasheet for the W25Q512JV does not mention how to clear this bit. ☹️
Can you give me any advice?
Thank you!

Pavel A.
Evangelist III

If you managed to set OTP bits, this cannot be undone, by design (( 

Recommend to lock the status byte (or whatever it is called) early, before starting of the main app - to prevent any dangerous changes until next power cycle.

 

Not sure, if there are individual pages locked these might need to be cleared. Not clear to me how these might be enumerated or how they would have been set initially. 

In this situation I'd start with a fresh part and do very basic interactions with it. Check the initial state. Report it at each startup. When confident it is work enable additional functionality. Test and proceed until it fails again, and keep a log of the things you did or tested so you might pin down the interactions that resulted in failure so a) you don't repeat them and b) you can ponder the ways to undo or unwind what you did.

 

Edit: One possible course of action to pin-point involved sectors would be to do a pass at 64KB, doing erases, see which fail or complete instantly, and once narrowed down there repeat at 4KB sectors. Map out what is/isn't protected.

At the very least it would be something to query WInbond more directly with.

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

Hi @Tesla DeLorean , @Pavel A. 
Sorry for the late reply, I just had a long vacation so I'm just now starting again with this project.
I tried to remember that, before, I set the clock for OSPI at 200MHz, with clock prescaler = 2 (~100Mhz), W25Q512JV worked well, no problems occurred. But after that, I adjusted the clock for OSPI to 275MHz (maximum with stm32h723), with the prescaler clock still = 2 (~137MHz) (because I also used OSPI1 for Octo RAM APS12808L-3OBM so I adjusted the frequency This number is to test the responsiveness of external RAM).
At this time, W25Q512JV loaded and deleted a few times and then got the above error.
It seems that the OSPI frequency exceeding the response level of the W25Q512JV caused the initial configuration of the status register to wrong, leading to the chip entering the OTP state, this cannot be undone like Mr @Pavel A.  mentioned.
I replaced the W25Q512JV chip with a newer chip, set the OSPI clock to 200MHz, with clock prescaler = 2 (~100Mhz) and it seems to work fine, no problems yet (at least until now). I will continue to update if that issue repeats.
Thank you for your help.