cancel
Showing results for 
Search instead for 
Did you mean: 

Can't write on external flash w25q128jv

Gpapa.1
Associate

I am trying to initialize my W25Q128jv External Flash in my project, but I am not able to write on it and I think it could be because of the Memory Mapping Mode but I really don't know. For this project I will need my QUADSPI when I will add TouchGFX to save some items, but for now I am only trying to do a for cycle to verify that it works and its performance. If I disable MemoryMappingMode to write, it goes in HardFault.

uint32_t *flashbuffer = (uint32_t*)0x90000000;
const uint32_t size = 1000;
 
int begin = HAL_GetTick();
  for(i = 0; i < size; i++)
    {
      flashbuffer[i]=i;
    }
int end = HAL_GetTick();

Here is MX_QUADSPI_Init

static void MX_QUADSPI_Init(void)
{
 
  /* USER CODE BEGIN QUADSPI_Init 0 */
 
  /* USER CODE END QUADSPI_Init 0 */
 
  /* USER CODE BEGIN QUADSPI_Init 1 */
 
  /* USER CODE END QUADSPI_Init 1 */
  /* QUADSPI parameter configuration*/
  hqspi.Instance = QUADSPI;
  hqspi.Init.ClockPrescaler = 1;
  hqspi.Init.FifoThreshold = 4;
  hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
  hqspi.Init.FlashSize = 23;
  hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_6_CYCLE;
  hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;
  hqspi.Init.FlashID = QSPI_FLASH_ID_1;
  hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE;
  if (HAL_QSPI_Init(&hqspi) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN QUADSPI_Init 2 */
  BSP_QSPI_Init();
  /* USER CODE END QUADSPI_Init 2 */
}

And here is my initialization

uint8_t BSP_QSPI_Init(void)
{
	QSPI_CommandTypeDef s_command;
	uint8_t value = W25Q128JV_FSR_QE;
 
  /* QSPI memory reset */
  if (QSPI_ResetMemory() != QSPI_OK)
  {
    return QSPI_NOT_SUPPORTED;
  }
 
	/* Enable write operations */
	if (QSPI_WriteEnable() != QSPI_OK)
	{
		return QSPI_ERROR;
	}
 
	/* Set status register for Quad Enable,the Quad IO2 and IO3 pins are enable */
	s_command.InstructionMode   = QSPI_INSTRUCTION_1_LINE;
  s_command.Instruction       = WRITE_STATUS_REG2_CMD;
  s_command.AddressMode       = QSPI_ADDRESS_NONE;
  s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
  s_command.DataMode          = QSPI_DATA_1_LINE;
  s_command.DummyCycles       = 0;
  s_command.NbData            = 1;
  s_command.DdrMode           = QSPI_DDR_MODE_DISABLE;
  s_command.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;
  s_command.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;
	/* Configure the command */
  if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    return QSPI_ERROR;
  }
	/* Transmit the data */
	if (HAL_QSPI_Transmit(&hqspi, &value, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
  {
    return QSPI_ERROR;
  }
 
  /* automatic polling mode to wait for memory ready */
  if (QSPI_AutoPollingMemReady(W25Q128JV_WRITE_STATUS_REG_TIME_MS) != QSPI_OK)
  {
    return QSPI_ERROR;
  }
  BSP_QSPI_MemoryMappedMode();
  return QSPI_OK;
}
/*BSP_QSPI_Init*/

And here my driver

static uint8_t QSPI_WriteEnable(void) {
 
    QSPI_CommandTypeDef sCommand;
    QSPI_AutoPollingTypeDef sConfig;
 
    /* Enable write operations ------------------------------------------ */
    sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
    sCommand.Instruction = 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_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
 
        return (QSPI_ERROR);
    }
 
    /* Configure automatic polling mode to wait for write enabling ---- */
    sConfig.Match = W25Q128JV_FSR_WREN;
    sConfig.Mask = W25Q128JV_FSR_WREN;
    sConfig.MatchMode = QSPI_MATCH_MODE_AND;
    sConfig.StatusBytesSize = 1;
    sConfig.Interval = 0x10;
    sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
 
    sCommand.Instruction = READ_STATUS_REG1_CMD;
    sCommand.DataMode = QSPI_DATA_1_LINE;
    sCommand.NbData = 1;
 
    if (HAL_QSPI_AutoPolling(&hqspi, &sCommand, &sConfig, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
 
        return (QSPI_ERROR);
    }
 
    return (QSPI_OK);
 
} /* QSPI_WriteEnable */
 
static uint8_t BSP_QSPI_Write(const uint8_t * pData, uint32_t WriteAddr, uint32_t Size) {
 
    QSPI_CommandTypeDef s_command;
    uint32_t end_addr, current_size, current_addr;
 
    /* Calculation of the size between the write address and the end of the page */
    current_addr = 0U;
 
    while (current_addr <= WriteAddr) {
 
        current_addr += W25Q128JV_PAGE_SIZE;
    }
 
    current_size = current_addr - WriteAddr;
 
    /* Check if the size of the data is less than the remaining place in the page */
    if (current_size > Size) {
 
        current_size = Size;
    }
 
    /* Initialize the address variables */
    current_addr = WriteAddr;
    end_addr = WriteAddr + Size;
 
    /* Initialize the program command */
    s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
    s_command.Instruction = QUAD_INPUT_PAGE_PROG_CMD;
    s_command.AddressMode = QSPI_ADDRESS_1_LINE;
    s_command.AddressSize = QSPI_ADDRESS_24_BITS;
    s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
    s_command.DataMode = QSPI_DATA_4_LINES;
    s_command.DummyCycles = 0;
    s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
    s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
    s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
 
    /* Perform the write page by page */
    do {
        s_command.Address = current_addr;
        s_command.NbData = current_size;
 
        /* Enable write operations */
        QSPI_WriteEnable();
 
        /* Configure the command */
        if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
 
            return (QSPI_ERROR);
        }
 
        /* Transmission of the data */
        if (HAL_QSPI_Transmit(&hqspi, (uint8_t *)((uint32_t)pData), HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
 
            return (QSPI_ERROR);
        }
 
        /* Configure automatic polling mode to wait for end of program */
        if (QSPI_AutoPollingMemReady(HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) {
 
            return (QSPI_ERROR);
        }
 
        /* Update the address and size variables for next page programming */
        current_addr += current_size;
        pData += current_size;
        current_size = ((current_addr + W25Q128JV_PAGE_SIZE) > end_addr) ? (end_addr - current_addr) : W25Q128JV_PAGE_SIZE;
 
    } while (current_addr < end_addr);
 
    return (QSPI_OK);
 
} /* BSP_QSPI_Write */
 
uint8_t BSP_QSPI_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size) {
 
    QSPI_CommandTypeDef s_command;
 
    /* Initialize the read command */
    s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
    s_command.Instruction = READ_CMD;
    s_command.AddressMode = QSPI_ADDRESS_1_LINE;
    s_command.AddressSize = QSPI_ADDRESS_24_BITS;
    s_command.Address = ReadAddr;
    s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
    s_command.DataMode = QSPI_DATA_1_LINE;
    s_command.DummyCycles = 0;
    s_command.NbData = Size;
    s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
    s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
    s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
 
    /* Configure the command */
    if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
 
        return (QSPI_ERROR);
    }
 
    /* Reception of the data */
    if (HAL_QSPI_Receive(&hqspi, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
 
        return (QSPI_ERROR);
    }
 
    return (QSPI_OK);
 
} /* BSP_QSPI_Read */
 

static void BSP_QSPI_MemoryMappedMode(void) {
 
    QSPI_CommandTypeDef s_command;
    QSPI_MemoryMappedTypeDef s_mem_mapped_cfg;
 
    /* Configure the command for the read instruction */
    s_command.Instruction = QUAD_INOUT_FAST_READ_CMD;
    s_command.Address = 0U;
    s_command.AlternateBytes = 0xF0;
    s_command.AddressSize = QSPI_ADDRESS_24_BITS;
    s_command.AlternateBytesSize = QSPI_ALTERNATE_BYTES_8_BITS;
    s_command.DummyCycles = W25Q128JV_DUMMY_CYCLES_READ_QUAD;
    s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
    s_command.AddressMode = QSPI_ADDRESS_4_LINES;
    s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_4_LINES;
    s_command.DataMode = QSPI_DATA_4_LINES;
    s_command.NbData = 0U;
    s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
    s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
    s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
 
    /* Configure the memory mapped mode */
    s_mem_mapped_cfg.TimeOutPeriod = 0;
    s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;
 
    if (HAL_QSPI_MemoryMapped(&hqspi, &s_command, &s_mem_mapped_cfg) != HAL_OK) {
 
        Error_Handler();
    }
 
} /* BSP_QSPI_MemoryMappedMode */

1 ACCEPTED SOLUTION

Accepted Solutions
Gpapa.1
Associate

Thanks for your suggestions. I used the two functions Write and Read, and disabling the Memory Mapping Mode it works. Thank you again!

View solution in original post

3 REPLIES 3
MM..1
Chief II

If i good understand in memory mapped mode is read only , cant write.

And in your question i dont see where is returned QSPI_ERROR...

That's not how you write to this type of NOR Flash memory.

Memory Mapped mode here does not support writing.

If you access un-mapped/un-decoded memory on a Cortex-Mx it will Hard Fault / Bus Fault.

Writing of this type of memory is done in direct command mode, with specific commands, which you then wait on completion. See BSP_QSPI_Write()

Pull a manual/data-sheet for the W25Q128 parts and review it.

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

Thanks for your suggestions. I used the two functions Write and Read, and disabling the Memory Mapping Mode it works. Thank you again!