2024-09-10 05:26 AM
Hi!
Why can i not disable the protection? I use W25Q256. I can't write and erase the flash ic.
The programming was working, but suddenly an error occurred during download. Here I noticed that the bits of SR 1 went to 1 and I can't reset them.
What could be the problem that I can't find?
I attached the picture from the readed registers.
Thank you!
Here is my code:
/* Enable Quad Mode & Set Dummy Cycles Count */
HAL_StatusTypeDef W25Q_QSPI_Configuration() {
uint8_t reg1 = 0, reg2 = 0, reg3 = 0;
uint8_t w_reg1 = 0, w_reg2 = 0, w_reg3 = 0;
if (W25Q_Read_Status_Registers(®1, 1) != HAL_OK) {
return HAL_ERROR;
}
if (W25Q_Read_Status_Registers(®2, 2) != HAL_OK) {
return HAL_ERROR;
}
if (W25Q_Read_Status_Registers(®3, 3) != HAL_OK) {
return HAL_ERROR;
}
#if W25Q_FLASH_SIZE > 0x1000000
// If ADP != 1
if(!((reg3 >> 1) & 0b1)) { // Check 1.bit
w_reg3 = reg3 | (1 << 1); // Set ADP 1.bit
}
// If ADS != 1
if(reg3 & 0b1) { // Check ADS 0.bit
W25Q_Enter4ByteMode(1); // Enter 4byte mode
}
#else
// If ADS != 1
if(((reg3 >> 0) & 1)) { // Check 0.bit
// Enter 4 byte mode
W25Q_Enter4ByteMode(0); // Exit 4byte mode
}
#endif
w_reg1 = 0x0; //reg1;
w_reg2 = reg2 | W25Q_SR_Quad_Enable;
w_reg3 = reg3 | 0xA9;
if (W25Q_Write_Status_Registers(w_reg1, 1) != HAL_OK) {
return HAL_ERROR;
}
if (W25Q_Write_Status_Registers(w_reg2, 2) != HAL_OK) {
return HAL_ERROR;
}
if (W25Q_Write_Status_Registers(w_reg3, 3) != HAL_OK) {
return HAL_ERROR;
}
return HAL_OK;
}
2024-09-10 06:17 AM
Some of the older parts SR1 and SR2 must write as a pair.
The high order bit in SR1 clears via a power cycle, once set you can't change the other bits.
Yes, need to clear the BPx bits and COM
Seen a number of people jam up the parts this way.
2024-09-10 07:11 AM
Can you help me with what exactly I have to do to make the ic work again, what is the solution to this error? I tried quite a few things but it didn't work. Thanks
2024-09-10 07:57 PM
2024-09-11 02:52 AM
Thank you for the link, but
I rewrote the code into my program, but when I read the registers back, all the bits are still 1. I can't set them to 0.
I also defined W25Q256 so that the status register is 16 bits, but it is not good.
I don't know what else could be wrong and why it happened at all.
/* QSPI Initial Function */
HAL_StatusTypeDef W25Q_QSPI_Init(void) {
hqspi.Instance = QUADSPI;
if (HAL_QSPI_DeInit(&hqspi) != HAL_OK) {
return HAL_ERROR;
}
MX_QUADSPI_Init();
if (W25Q_QSPI_ResetChip() != HAL_OK) {
return HAL_ERROR;
}
if (W25Q_QSPI_Configuration() != HAL_OK) {
return HAL_ERROR;
}
if (W25Q_QSPI_AutoPollingMemReady() != HAL_OK) {
return HAL_ERROR;
}
if (W25Q_QSPI_WriteEnable() != HAL_OK) {
return HAL_ERROR;
}
return HAL_OK;
}
/* Reset Chip Function */
HAL_StatusTypeDef W25Q_QSPI_ResetChip() {
QSPI_CommandTypeDef sCommand = {0};
/* Enable Reset --------------------------- */
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
sCommand.Instruction = W25Q_ENABLE_RST_CMD; /* Reset command enable */
sCommand.AddressMode = QSPI_ADDRESS_NONE;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
sCommand.DataMode = QSPI_DATA_NONE;
sCommand.DummyCycles = 0;
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return HAL_ERROR;
}
/* Reset execute */
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
sCommand.Instruction = W25Q_RESET_CMD; /* Reset command execute */
sCommand.AddressMode = QSPI_ADDRESS_NONE;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
sCommand.DataMode = QSPI_DATA_NONE;
sCommand.DummyCycles = 0;
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return HAL_ERROR;
}
for (uint32_t temp = 0; temp < 500000; temp++) {
__NOP();
}
return HAL_OK;
}
/* Write Enable Function */
HAL_StatusTypeDef W25Q_QSPI_WriteEnable() {
QSPI_CommandTypeDef sCommand = { 0 };
QSPI_AutoPollingTypeDef sConfig = { 0 };
/* Enable write operations ------------------------------------------ */
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
sCommand.Instruction = W25Q_WRITE_ENABLE_CMD;
sCommand.AddressMode = QSPI_ADDRESS_NONE;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
sCommand.DataMode = QSPI_DATA_NONE;
sCommand.DummyCycles = 0;
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return HAL_ERROR;
}
/* Configure automatic polling mode to wait for write enabling ---- */
sConfig.Match = 0x02U;
sConfig.Mask = 0x02U;
sConfig.MatchMode = QSPI_MATCH_MODE_AND;
sConfig.StatusBytesSize = 1;
sConfig.Interval = W25Q_AUTOPOLLING_INTERVAL_TIME;
sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
sCommand.Instruction = W25Q_READ_SR1_CMD;
sCommand.DataMode = QSPI_DATA_1_LINE;
if (HAL_QSPI_AutoPolling(&hqspi, &sCommand, &sConfig, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return HAL_ERROR;
}
return HAL_OK;
}
/* Auto Polling Memory Function */
HAL_StatusTypeDef W25Q_QSPI_AutoPollingMemReady() {
QSPI_CommandTypeDef sCommand = { 0 };
QSPI_AutoPollingTypeDef sConfig = { 0 };
/* Configure automatic polling mode to wait for memory ready ------ */
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
sCommand.Instruction = W25Q_READ_SR1_CMD; /* Register 1 reading */
sCommand.AddressMode = QSPI_ADDRESS_NONE;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
sCommand.DataMode = QSPI_DATA_1_LINE;
sCommand.DummyCycles = 0;
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
sConfig.Match = 0x00U;
sConfig.Mask = 0x01U;
sConfig.MatchMode = QSPI_MATCH_MODE_AND;
sConfig.StatusBytesSize = 1;
sConfig.Interval = W25Q_AUTOPOLLING_INTERVAL_TIME;
sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
if (HAL_QSPI_AutoPolling(&hqspi, &sCommand, &sConfig, HAL_MAX_DELAY) != HAL_OK) {
return HAL_ERROR;
}
return HAL_OK;
}
/* Write Status Registers Function */
HAL_StatusTypeDef W25Q_Write_Status_Registers(uint32_t reg_data, uint8_t reg_num)
{
QSPI_CommandTypeDef sCommand = {0};
sCommand.NbData = 1;
switch(reg_num)
{
#if 1 // WINBOND
case 1 : // REG1
sCommand.Instruction = W25Q_WRITE_SR1_CMD;
sCommand.NbData = 2; // REG1 and REG2 as 16-bit
break;
#else
case 1 : sCommand.Instruction = W25Q_WRITE_SR1_CMD; break; // REG1
case 2 : sCommand.Instruction = W25Q_WRITE_SR2_CMD; break; // REG2
case 3 : sCommand.Instruction = W25Q_WRITE_SR3_CMD; break; // REG3
#endif
default:
return(HAL_ERROR);
}
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
sCommand.AddressMode = QSPI_ADDRESS_NONE;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
sCommand.DataMode = QSPI_DATA_1_LINE;
sCommand.DummyCycles = 0;
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
/* Enable write operations */
if (W25Q_QSPI_WriteEnable() != HAL_OK)
{
return(HAL_ERROR);
}
/* Send the command */
if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return(HAL_ERROR);
}
/* Transmission of the data */
if (HAL_QSPI_Transmit(&hqspi, (void *)®_data, HAL_QSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return(HAL_ERROR);
}
return(HAL_OK);
}
// Enable Quad Mode
HAL_StatusTypeDef W25Q_QSPI_Configuration() // WINBOND
{
uint32_t Id, Reg1, Reg2;
if (W25Q_Read_Status_Registers(&Id, 0x9F) == HAL_OK)
{
Id &= 0xFFFF;
if ((Id != 0x40EF) && (Id != 0x60EF)) // WINBOND CHECK
return(HAL_ERROR);
}
else
{
return(HAL_ERROR);
}
if (W25Q_Read_Status_Registers(&Reg1, 1) != HAL_OK)
return(HAL_ERROR);
if (W25Q_Read_Status_Registers(&Reg2, 2) != HAL_OK)
return(HAL_ERROR);
// Unfudge parts where invalid MICRON, MACRONIX and WINBOND sequences have been registered
#if defined(USE_W25Q256) || defined(USE_W25Q512) || defined(USE_W25Q01) || defined(USE_W25Q02)
if (((Reg2 & 0x42) != 0x02) || ((Reg1 & 0x3C) != 0))
{
Reg2 |= 2; // Set QE
Reg2 &= ~0x40; // COM=0
Reg1 &= ~0x3C; // Clear BP0,BP1,BP2,BP3
#else
if (((Reg2 & 0x42) == 0) || ((Reg1 & 0x1C) != 0)) // W25Q64 / W25Q128
{
Reg2 |= 2; // Set QE
Reg2 &= ~0x40; // COM = 0
Reg1 &= ~0x1C; // Clear BP0,BP1,BP2
#endif
if (W25Q_Write_Status_Registers(((Reg2 << 8) | Reg1), 1) != HAL_OK) // WINBOND WRITES BOTH
return(HAL_ERROR);
/* Configure automatic polling mode to wait the memory is ready */
if (W25Q_QSPI_AutoPollingMemReady() != HAL_OK)
{
//puts("Fail Quad");
return(HAL_ERROR);
}
if (W25Q_Read_Status_Registers(&Reg1, 1) != HAL_OK)
return(HAL_ERROR);
if (W25Q_Read_Status_Registers(&Reg2, 2) != HAL_OK)
return(HAL_ERROR);
}
return(HAL_OK);
}
2024-09-11 09:35 AM - edited 2024-09-11 09:37 AM
Like I said, once the high order bit of SR1 (SRP) gets set, perhaps by other code you run, perhaps by the /WP pin state, it locks the part until power cycled. I've skimmed the data sheets a couple of times and don't have a clear read of exactly what is happening. Perhaps you can find a Winbond FAE to have a discussion with?
You can't change the status register if it's implicitly locked.
Perhaps you can switch out for a new part? And then tread more carefully, or identify where you're locking it up?
Watch that the memory IC is in the correct modes for the commands/methods being used to talk to it. Writing several megabytes in the wrong modes may result in patterns which are misinterpreted.
2024-09-11 11:01 AM
My SRL is low, SRP is high I will try pull up the WP pin with an external resistor. This is hardware unprotect, so i try reset the BP bits. Maybe.
If i can't i will change to a new flash ic.
I used this flash ic at 120Mhz, so it was maybe go to wrong bit settings. I will set to 100Mhz.
I read it here:
Thank you!