Skip to main content
Gpapa.1
Associate
March 31, 2022
Solved

Can't write on external flash w25q128jv

  • March 31, 2022
  • 3 replies
  • 2479 views

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 */

This topic has been closed for replies.
Best answer by Gpapa.1

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

3 replies

MM..1
Super User
March 31, 2022

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...

Tesla DeLorean
Guru
March 31, 2022

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 (See Profile) Up vote any posts that you find helpful, it shows what's working..
Gpapa.1
Gpapa.1AuthorBest answer
Associate
April 1, 2022

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