2023-12-25 10:12 AM
Hi,
I'm trying to run dual QSPI Flash with my own design STM32H750XBH6. Flashes are 256 mbit MX25L25645. Single mode 32 mb flash read, write and boot succesfully. However, when I switch to dual chip mode, i get a write error (constant 0XFF) on the 2nd chip after 0x93000001 (48 mb) adresses. (adress 0x90000000 to 0x92FFFFFF working very well. )
Solved! Go to Solution.
2023-12-26 10:22 AM - edited 2023-12-26 03:21 PM
Ok, but this isn't how it interleaves
/*modify buffer to enable quad mode*/ test_buffer[0] |= 0x40; /*set dummy cycles*/ test_buffer[1] |= 0xE0; test_buffer[2] |= 0x40; test_buffer[3] |= 0xE0;
The SR will need to be paired.
ie
test_buffer[0] = (test_buffer[0]) & 0xC3) | 0x40; // SR First Bank
test_buffer[1] = (test_buffer[1]) & 0xC3) | 0x40; // SR Second Bank
..
I would make sure the BP bits, which are sticky, are also cleared otherwise writes and erases can fail due to protection mechanics. This can be problematic when switching vendors as these bit definitions can be different. I've mostly seen myself locking Micron's by using Macronix code because the 0x40 is a Protection Bit in their context.
I'm also not sure you need to switch parts to use 4-Byte (32-bit) addressing mode, there are commands that explicitly define 3 or 4-byte .
For loaders, I'd keep them as simple as possible at the outset. You don't need to switch into the most exotic modes, performance is usually more to do with how fast the ST-LINK/V2 or V3 can shovel data across the interface.
In dual bank the page write can expand from 256 bytes to 512 bytes, as it interleaves between the two chips.
2023-12-25 10:37 AM
The polling method would need to span both devices. ie you'd need to read status registers as a pair of bytes.
2023-12-26 12:15 AM
Thank you for nice tips Tesla DeLorean. I tried to edit to code as you said. But still can't write to 16 mb above to 2nd flash. I think the second flash does not switch to 4 byte (32 bit) adress mode.
QSPI_WriteEnable;
/* Configure automatic polling mode to wait for write enabling ---- */
sConfig.Match = 0x0202;
sConfig.Mask = 0x0202;
sConfig.MatchMode = QSPI_MATCH_MODE_AND;
sConfig.StatusBytesSize = 2;
sConfig.Interval = 0x10;
sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
HAL_GPIO_TogglePin (GPIOE, GPIO_PIN_4);
sCommand.Instruction = READ_STATUS_REG_CMD;
sCommand.DataMode = QSPI_DATA_1_LINE;
if (HAL_QSPI_AutoPolling(&hqspi, &sCommand, &sConfig,
HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
QSPI_Configuration
/*modify buffer to enable quad mode*/
test_buffer[0] |= 0x40;
/*set dummy cycles*/
test_buffer[1] |= 0xE0;
test_buffer[2] |= 0x40;
test_buffer[3] |= 0xE0;
if (QSPI_WriteEnable() != HAL_OK) {
return HAL_ERROR;
}
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.Address = 0;
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
sCommand.NbData = 4;
if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE)
!= HAL_OK) {
return HAL_ERROR;
}
if (HAL_QSPI_Transmit(&hqspi, test_buffer,
HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
Error_Handler();
return HAL_ERROR;
}
AN4760 only show quad line read squenze to dual flash. How to 1 line write squenze to instruction code data write?
2023-12-26 01:15 AM
Hello @erdalturkekul
You may need to add HAL_QSPI_Command in QSPI_WriteEnable before configuring automatic polling mode to wait for reading out the values of configuration register.
You can refer to the example of cube.
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
2023-12-26 04:18 AM
@FBL still the same problem persist.
In MX25L25645 datasheet says; if using larger than 128 mbit adress, you must execute Enable4ByteMode command.
My CSP_QSPI_Enable4ByteMode func.;
uint8_t CSP_QSPI_Enable4ByteMode(void) {
QSPI_CommandTypeDef sCommand;
if (QSPI_WriteEnable() != HAL_OK) {
return HAL_ERROR;
}
sCommand.Instruction = ENTER_4BYTE_MODE_CMD;
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
sCommand.AddressMode = QSPI_ADDRESS_NONE;
sCommand.Address = 0;
sCommand.DataMode = QSPI_DATA_NONE;
sCommand.DummyCycles = 0;
if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE)
!= HAL_OK) {
return HAL_ERROR;
}
if (QSPI_AutoPollingMemReady() != HAL_OK) {
return HAL_ERROR;
}
return HAL_OK;
}
Is this function execute in lower and upper flash at same time?
.c and .h files attached
2023-12-26 10:22 AM - edited 2023-12-26 03:21 PM
Ok, but this isn't how it interleaves
/*modify buffer to enable quad mode*/ test_buffer[0] |= 0x40; /*set dummy cycles*/ test_buffer[1] |= 0xE0; test_buffer[2] |= 0x40; test_buffer[3] |= 0xE0;
The SR will need to be paired.
ie
test_buffer[0] = (test_buffer[0]) & 0xC3) | 0x40; // SR First Bank
test_buffer[1] = (test_buffer[1]) & 0xC3) | 0x40; // SR Second Bank
..
I would make sure the BP bits, which are sticky, are also cleared otherwise writes and erases can fail due to protection mechanics. This can be problematic when switching vendors as these bit definitions can be different. I've mostly seen myself locking Micron's by using Macronix code because the 0x40 is a Protection Bit in their context.
I'm also not sure you need to switch parts to use 4-Byte (32-bit) addressing mode, there are commands that explicitly define 3 or 4-byte .
For loaders, I'd keep them as simple as possible at the outset. You don't need to switch into the most exotic modes, performance is usually more to do with how fast the ST-LINK/V2 or V3 can shovel data across the interface.
In dual bank the page write can expand from 256 bytes to 512 bytes, as it interleaves between the two chips.
2023-12-26 11:40 AM
This should be closer to what's desired.
/*Enable quad mode and set dummy cycles count*/
uint8_t QSPI_Configuration(void)
{
QSPI_CommandTypeDef sCommand = { 0 };
uint8_t test_buffer[4] = { 0 };
// The QE bit enables the use of pins and extended quad command set
// Need to send QPI ENABLE (0x35) for 4-4-4, otherwise 1-1-x or 1-x-x assumed
// You Enable 4-BYTE Addressing Mode via Control Register
//sCommand.DataMode = QSPI_DATA_4_LINES; // Decide Which Mode You're In
sCommand.DataMode = QSPI_DATA_1_LINE;
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE;
sCommand.AddressMode = QSPI_ADDRESS_NONE;
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
sCommand.DummyCycles = 0;
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
/*read status register*/
sCommand.Instruction = READ_STATUS_REG_CMD; // 0x05
sCommand.NbData = 2;
if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE)
!= HAL_OK) {
return HAL_ERROR;
}
if (HAL_QSPI_Receive(&hqspi, (uint8_t *)(&test_buffer[0]),
HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return HAL_ERROR;
}
/*read configuration register*/
sCommand.Instruction = READ_CONFIGURATION_REG_CMD; // 0x15
sCommand.NbData = 2;
if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE)
!= HAL_OK) {
return HAL_ERROR;
}
if (HAL_QSPI_Receive(&hqspi, (uint8_t *)(&test_buffer[2]),
HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
return HAL_ERROR;
}
*/
/*modify buffer to enable quad mode*/
if (QSPI_WriteEnable() != HAL_OK) {
return HAL_ERROR;
}
test_buffer[0] = (test_buffer[0] & 0xC3) | 0x40; // Set QE, Clear BP
test_buffer[1] = (test_buffer[1] & 0xC3) | 0x40; // Set QE, Clear BP
test_buffer[2] |= 0xE0; // Dummy 8 (Single/Dual) / 10 (Quad)
test_buffer[3] |= 0xE0; // DC1,DC0,4-BYTE ENABLE
sCommand.Instruction = WRITE_STATUS_REG_CMD; // SR+CR or SR+SR+CR+CR in dual bank
sCommand.NbData = 4;
if (HAL_QSPI_Command(&hqspi, &sCommand, HAL_QPSI_TIMEOUT_DEFAULT_VALUE)
!= HAL_OK) {
return HAL_ERROR;
}
if (HAL_QSPI_Transmit(&hqspi, (uint8_t *)(&test_buffer[0]),
HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {
Error_Handler();
return HAL_ERROR;
}
return HAL_OK;
}
Would probably lean to using the Quad Command's rather than engage QPI mode, so Init() path can be optimized
2023-12-26 02:09 PM
@Tesla DeLorean thank you for your solutions!! :) now work fine
Yes, stlink V3 is the bottleneck when writing flash. Its takes about 15-20 minutes when 64 mb flash writing.
But, dual qspi MemoryMappedMode better than single flash. I can run to tgfx animated picture on the 1024 x 600 pixel lcd without any flicker or frezing. H7 series mcu most performing one. If there were no 256 mbyte limit, I would like to try two 1 gbit nor flash (with a little writing patience and more coffee breaks)
2023-12-26 03:47 PM
2x 1Gbit (128MB) will get you to the 256 MB ceiling for the 0x90000000..0x9FFFFFFF range
Are you using BGA24 parts?
You are getting to the limit of the SOIC16 NOR FLASH parts. With Micron beyond 1Gbit you're getting to stacked multi-die parts. The ready and die/mass erase mechanics get to be different.
2023-12-26 05:29 PM
Tentative Dual MX25L256 build for your platform (blind port as can't test)
What Part# for the 1Gbit? MX66L1G ?