cancel
Showing results for 
Search instead for 
Did you mean: 

W25Q256 write protection

Thomas8607
Senior

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(&reg1, 1) != HAL_OK) {
		return HAL_ERROR;
	}
	if (W25Q_Read_Status_Registers(&reg2, 2) != HAL_OK) {
	   return HAL_ERROR;
	}
	if (W25Q_Read_Status_Registers(&reg3, 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;
}

 

 

6 REPLIES 6

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.

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

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

https://community.st.com/t5/stm32-mcus-products/stm32h743-external-loader/m-p/639422/highlight/true#M235411

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

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 *)&reg_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);
}

 

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.

 

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

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:

https://community.st.com/t5/stm32-mcus-embedded-software/problem-with-nor-flash-w25q512-cannot-erase-sector-chip/td-p/665883

 

Thank you!