2019-07-31 02:23 PM
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:
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++;
}
Solved! Go to Solution.
2019-08-02 12:54 PM
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;
}
2019-07-31 06:15 PM
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.
2019-08-01 12:08 AM
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.
2019-08-01 01:12 AM
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
2019-08-01 01:42 PM
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, ®, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK)
{
return 0;
}
return reg;
}
2019-08-01 02:38 PM
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;
}
2019-08-01 03:35 PM
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.
2019-08-02 04:24 AM
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?
2019-08-02 12:54 PM
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;
}