cancel
Showing results for 
Search instead for 
Did you mean: 

Memory Mapped QSPI reads nonsensical data

shabbir.hussain
Associate III

I am using a STM32F746zg uc connected to a W25Q80 Flash memory. In my initialization I erase a page then memory map the flash and then I read a pointer to that address. I expect to read 0xFF as the flash has just been erased, however I read 0x88. I'm not sure what is causing this behavior. Have I improperly wired the flash or is this an issue with my code (see snippets below)?

More Info:

  1. I'm using Cube IDE and created the project using Cube MX.
  2. I am able to properly read the manufacturer and device ID so I know that atleast vcc, gnd, cs, clk, io0 are wired properly.
  3. I followed the cubef7 example for memory mapped qspi as closely as possible

int EraseSector(QSPI_HandleTypeDef* hqspi, QSPI_CommandTypeDef* sCommand, QSPI_AutoPollingTypeDef* sConfig, uint32_t addr)
{
	sCommand->Instruction = SECTOR_ERASE_CMD;
	sCommand->AddressMode = QSPI_ADDRESS_1_LINE;
	sCommand->Address     = addr;
	sCommand->DataMode    = QSPI_DATA_NONE;
	sCommand->DummyCycles = 0;
 
   if (HAL_QSPI_Command(hqspi, sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
   {
	   return 0;
   }
 
	/* Configure automatic polling mode to wait for memory ready ------ */
	 sCommand->InstructionMode   = QSPI_INSTRUCTION_1_LINE;
	 sCommand->Instruction       = READ_STATUS_REG_CMD;
	 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           = 0x00;
	 sConfig->Mask            = 0x01;
	 sConfig->MatchMode       = QSPI_MATCH_MODE_AND;
	 sConfig->StatusBytesSize = 1;
	 sConfig->Interval        = 0x10;
	 sConfig->AutomaticStop   = QSPI_AUTOMATIC_STOP_ENABLE;
 
	 if (HAL_QSPI_AutoPolling(hqspi, sCommand, sConfig, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	 {
		 return 0;
	 }
 
	 return 1;
}
int SetMemoryMap(QSPI_HandleTypeDef* hqspi, QSPI_CommandTypeDef* sCommand)
{
	// Memory Map the External flash
	QSPI_MemoryMappedTypeDef s_mem_mapped_cfg;
 
	/* Configure the command for the read instruction */
	sCommand->InstructionMode   = QSPI_INSTRUCTION_4_LINES;
	sCommand->Instruction       = QUAD_OUT_FAST_READ_CMD;
	sCommand->AddressMode       = QSPI_ADDRESS_4_LINES;
	sCommand->DataMode          = QSPI_DATA_4_LINES;
	sCommand->DummyCycles = DUMMY_CLOCK_CYCLES_READ_QUAD;
 
 	/* Configure the memory mapped mode */
 	s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;
 	s_mem_mapped_cfg.TimeOutPeriod     = 0;
 
 	if (HAL_QSPI_MemoryMapped(hqspi, sCommand, &s_mem_mapped_cfg) != HAL_OK)
 	{
 		return 0;
 	}
 
 	return 1;
}
      /* Reading Sequence ------------------------------------------------ */
	  __IO uint8_t *qspi_addr = (__IO uint8_t *)(0x90000000);
	  for (int idx = 0; idx < BUFFERSIZE; idx++)
	  {
		if (*qspi_addr != aTxBuffer[idx])
	    {
			 HAL_GPIO_TogglePin(GPIOB, LD3_Pin);
		}
		qspi_addr++;
	  }

1 ACCEPTED SOLUTION

Accepted Solutions
shabbir.hussain
Associate III

I've solved my issue thanks to @Andreas Bolsch​  and @Community member​ 

The problems were due to the fact that the flash expects a 24 bit address and I was just supplying an 8-bit address. The fix is in the command settings specified in the HAL command config to set the address size to 24 bit. The working code to map memory is pasted below in case someone stumbles upon this issue.

int SetMemoryMap(QSPI_HandleTypeDef* hqspi, QSPI_CommandTypeDef* sCommand)
{
	// Memory Map the External flash
	QSPI_MemoryMappedTypeDef s_mem_mapped_cfg;
 
	/* Configure the command for the read instruction */
	sCommand->InstructionMode   = QSPI_INSTRUCTION_1_LINE;
	sCommand->Instruction       = QUAD_OUT_FAST_READ_CMD;
	sCommand->AddressMode       = QSPI_ADDRESS_1_LINE;
	sCommand->AddressSize		= QSPI_ADDRESS_24_BITS;
	sCommand->DataMode          = QSPI_DATA_4_LINES;
	sCommand->DummyCycles = DUMMY_CLOCK_CYCLES_READ_QUAD;
 
 	/* Configure the memory mapped mode */
 	s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;
 	s_mem_mapped_cfg.TimeOutPeriod     = 0;
 
 	if (HAL_QSPI_MemoryMapped(hqspi, sCommand, &s_mem_mapped_cfg) != HAL_OK)
 	{
 		return 0;
 	}
 
 	return 1;
}

View solution in original post

8 REPLIES 8

I think by default the part is not in Quad mode.

Try using the non-mapped Single, Double and Quad reads prior to trying mapped.

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

This particular chip doesn't have a 'pure' quad mode at all. Even for the quad-I/O instructions, the instruction byte must be send in 1-line mode (in contrary to your 'sCommand->InstructionMode = QSPI_INSTRUCTION_4_LINES;' in SetMemoryMap), only address and data can be transferred in quad mode. It's a rather old design ...

Moreover, before using the quad-I/O-instructions, the non-volatile QE bit in the status register 2 must be set (in 1-line-mode, of-course) once. And watch out for the rather peculiar features of the 'Write status register' instruction for this device.

Even with a 1-bit instruction and address, a linear mapped read of the array can run at 66 or 100 MBps​ on a F7 running at 200 MHz

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

I tried this. I read 0xFF which is expected after erasing the memory. My next step is to read back something I wrote in.

int ReadData(QSPI_HandleTypeDef* hqspi, QSPI_CommandTypeDef* sCommand, uint32_t addr)
{
	 uint8_t reg;
 
	 /* Read Volatile Configuration register --------------------------- */
	 sCommand->InstructionMode   = QSPI_INSTRUCTION_1_LINE;
	 sCommand->Instruction       = READ_CMD;
	 sCommand->AddressMode       = QSPI_ADDRESS_1_LINE;
	 sCommand->Address			 = addr;
	 sCommand->DataMode          = QSPI_DATA_1_LINE;
	 sCommand->DummyCycles       = 0;
	 sCommand->SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;
	 sCommand->NbData            = 1;
 
	 if (HAL_QSPI_Command(hqspi, sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	 {
		 return 0;
	 }
 
	 if (HAL_QSPI_Receive(hqspi, &reg, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	 {
		 return 0;
	 }
 
 
	 return reg;
}

I've enabled the QE status register but I I'm still reading 0x88 during memory mapped read. This time I set the QE to enable and read it back to check, then I memory map. Below is how I set the QE bit and the new memory map code.

Is there anything else I can try?

int EnableVolatileReg(QSPI_HandleTypeDef* hqspi, QSPI_CommandTypeDef* sCommand)
{
	/* Write Volatile Configuration register */
	 sCommand->InstructionMode   = QSPI_INSTRUCTION_1_LINE;
	 sCommand->Instruction       = WRITE_ENABLE_VOL_STATUS_REG;
	 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;
	 sCommand->NbData            = 1;
 
	 if (HAL_QSPI_Command(hqspi, sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	 {
		 return 0;
	 }
	 return 1;
 
}
 
int GetStatusReg(QSPI_HandleTypeDef* hqspi, QSPI_CommandTypeDef* sCommand, QSPI_AutoPollingTypeDef* sConfig, uint8_t* reg)
{
	 sCommand->InstructionMode   = QSPI_INSTRUCTION_1_LINE;
	 sCommand->Instruction       = READ_STATUS_REG_CMD;
	 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;
	 sCommand->NbData            = 1;
 
	 if (HAL_QSPI_Command(hqspi, sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	 {
		 return 0;
	 }
 
	 if (HAL_QSPI_Receive(hqspi, reg, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	 {
		 return 0;
	 }
 
	 sCommand->InstructionMode   = QSPI_INSTRUCTION_1_LINE;
	 sCommand->Instruction       = READ_STATUS_REG2_CMD;
	 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;
	 sCommand->NbData            = 1;
 
	 if (HAL_QSPI_Command(hqspi, sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	 {
		 return 0;
	 }
 
	 if (HAL_QSPI_Receive(hqspi, reg+1, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	 {
		 return 0;
	 }
 
}
 
int SetQERegister(QSPI_HandleTypeDef* hqspi, QSPI_CommandTypeDef* sCommand, QSPI_AutoPollingTypeDef* sConfig)
{
	 uint8_t reg[] = {0,0};
 
	 // Set Write enable For volatile reg
	 EnableVolatileReg(hqspi, sCommand);
 
	 // Get current Register values
	 GetStatusReg(hqspi, sCommand, sConfig, reg);
 
	 // Write enable
	 EnableWrite(hqspi, sCommand, sConfig);
 
 
	 // Enable Quad Mode
	 reg[1] ^= 0x02; // set bit 2 to high
 
	 //Write Register values
	 sCommand->InstructionMode   = QSPI_INSTRUCTION_1_LINE;
	 sCommand->Instruction       = WRITE_STATUS_REG_CMD;
	 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;
	 sCommand->NbData            = 2;
 
	 if (HAL_QSPI_Command(hqspi, sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	 {
		 return 0;
	 }
 
	if (HAL_QSPI_Transmit(hqspi, reg, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
	{
		return 0;
	}
 
 	// reset the reg variables to confirm a good read
	reg[0] = 0;
	reg[1] = 0;
 
	 // Readback the status reg
	 GetStatusReg(hqspi, sCommand, sConfig, reg);
 
	 // register is already set
	 if(reg[1] & 0x02)
	 {
		 return 1;
	 }
	 else
	 {
		 return 0;
	 }
}
 
int SetMemoryMap(QSPI_HandleTypeDef* hqspi, QSPI_CommandTypeDef* sCommand)
{
	// Memory Map the External flash
	QSPI_MemoryMappedTypeDef s_mem_mapped_cfg;
 
	/* Configure the command for the read instruction */
	sCommand->InstructionMode   = QSPI_INSTRUCTION_1_LINE;
	sCommand->Instruction       = QUAD_OUT_FAST_READ_CMD;
	sCommand->AddressMode       = QSPI_ADDRESS_4_LINES;
	sCommand->DataMode          = QSPI_DATA_4_LINES;
	sCommand->DummyCycles = DUMMY_CLOCK_CYCLES_READ_QUAD;
 
 	/* Configure the memory mapped mode */
 	s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;
 	s_mem_mapped_cfg.TimeOutPeriod     = 0;
 
 	if (HAL_QSPI_MemoryMapped(hqspi, sCommand, &s_mem_mapped_cfg) != HAL_OK)
 	{
 		return 0;
 	}
 
 	return 1;
}

I'd recommend just ORing the bit, toggling it is probably unhelpful or counter productive. Not reviewed your chip specs, beyond noting QE=0 by default.

// Enable Quad Mode

reg[1] |= 0x02; // set bit 1 to high

I have a board with dual 25SF041 chips, I can use one or the pair together. This chip by default doesn't have QE=1, so the quad pins/commands don't work. The string of 88 88 88 88 is reminiscent of what I was seeing, but I don't have it in my shared notes.

1-bit and 2-bit modes worked properly, so could validate the read/write across the whole array.

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

Did you really check that QE was successfully set? Your SetQERegister can't work as desired: A write to status register takes up to 15 ms to complete! And, as already mentioned above, don't toggle the QE bit, just set it to '1'. This has to be done only once, as it's a non-volatile setting, so don't set it unconditionally but only when it's still '0'.

What's WRITE_ENABLE_VOL_STATUS_REG? For writing to the status register*S*, the usual WRITE_ENABLE instruction is required, nothing else.

Did you check that all GPIOs involved are set properly to AF and that the correct AF number is selected? Any activity on the IO3, IO2 pins? After setting QSPI to memory mapped mode, did you check that the QSPI registers are properly initialized? Verify in particular CR and CCR against reference manual. BUSY bit set, any errror flag in SR set?

shabbir.hussain
Associate III

I've solved my issue thanks to @Andreas Bolsch​  and @Community member​ 

The problems were due to the fact that the flash expects a 24 bit address and I was just supplying an 8-bit address. The fix is in the command settings specified in the HAL command config to set the address size to 24 bit. The working code to map memory is pasted below in case someone stumbles upon this issue.

int SetMemoryMap(QSPI_HandleTypeDef* hqspi, QSPI_CommandTypeDef* sCommand)
{
	// Memory Map the External flash
	QSPI_MemoryMappedTypeDef s_mem_mapped_cfg;
 
	/* Configure the command for the read instruction */
	sCommand->InstructionMode   = QSPI_INSTRUCTION_1_LINE;
	sCommand->Instruction       = QUAD_OUT_FAST_READ_CMD;
	sCommand->AddressMode       = QSPI_ADDRESS_1_LINE;
	sCommand->AddressSize		= QSPI_ADDRESS_24_BITS;
	sCommand->DataMode          = QSPI_DATA_4_LINES;
	sCommand->DummyCycles = DUMMY_CLOCK_CYCLES_READ_QUAD;
 
 	/* Configure the memory mapped mode */
 	s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;
 	s_mem_mapped_cfg.TimeOutPeriod     = 0;
 
 	if (HAL_QSPI_MemoryMapped(hqspi, sCommand, &s_mem_mapped_cfg) != HAL_OK)
 	{
 		return 0;
 	}
 
 	return 1;
}