2025-04-21 8:44 PM
I have a custom designed PCB board where I have used STM32L56 and W25Q256 along with other components. First, I was using SPI for interfacing but it was taking so much time when writing/reading MBs file. So I have to opt for QSPI now. L5 doesn't have specific QSPI, but using OSPI we can configure it as Quad SPI.
So, my questions are
1) what is difference between QSPI and OSPI as QSPI (command and working mechanism)
2) will this code work for OSPI as QSPI
3) if you have any test code for OSPI as QSPI, I can test and will modify it according to my needs
Looking forward to your response
Below are my configurations, code files with changes accordingly.
void testQSPI(){ OSPI_RegularCmdTypeDef s_command = {0}; /*uint8_t pData[3]; uint8_t wData[0x100]; uint8_t rData[0x100];*/ uint8_t pData[3]; uint8_t wData[0x100]; uint8_t rData[0x100]; memset(pData, 0x00, sizeof(pData)); memset(wData, 0x00, sizeof(wData)); memset(wData, 0x00, sizeof(wData)); uint32_t i; printf("***************QuadSPi Example*******************************\r\n"); BSP_QSPI_Init(); BSP_QSPI_Erase_Chip(); /*##-2-Read Device ID Test ###########################################*/ /* Read Manufacture/Device ID */ s_command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; s_command.Instruction = READ_ID_CMD; s_command.AddressMode = HAL_OSPI_ADDRESS_1_LINE; s_command.AddressSize = HAL_OSPI_ADDRESS_24_BITS; s_command.Address = 0x000000; s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = HAL_OSPI_DATA_1_LINE; s_command.DummyCycles = 0; s_command.NbData = 2; s_command.DQSMode = HAL_OSPI_DQS_DISABLE; // s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } if (HAL_OSPI_Receive(&hospi1, pData, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } printf("SPI I/0 Read Device ID : 0x%2X 0x%2X\r\n",pData[0],pData[1]); /* Read Manufacture/Device ID Dual I/O*/ s_command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; s_command.Instruction = DUAL_READ_ID_CMD; s_command.AddressMode = HAL_OSPI_ADDRESS_2_LINES; s_command.AddressSize = HAL_OSPI_ADDRESS_24_BITS; s_command.Address = 0x000000; s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_2_LINES; s_command.AlternateBytesSize= HAL_OSPI_ALTERNATE_BYTES_8_BITS; s_command.AlternateBytes = 0; s_command.DataMode = HAL_OSPI_DATA_2_LINES; s_command.DummyCycles = 0; s_command.NbData = 2; s_command.DQSMode = HAL_OSPI_DQS_DISABLE; // s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } if (HAL_OSPI_Receive(&hospi1, pData, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } printf("Dual I/O Read Device ID : 0x%2X 0x%2X\r\n",pData[0],pData[1]); /* Read Manufacture/Device ID Quad I/O*/ s_command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; s_command.Instruction = QUAD_READ_ID_CMD; s_command.AddressMode = HAL_OSPI_ADDRESS_4_LINES; s_command.AddressSize = HAL_OSPI_ADDRESS_24_BITS; s_command.Address = 0x000000; s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_4_LINES; s_command.AlternateBytesSize= HAL_OSPI_ALTERNATE_BYTES_8_BITS; s_command.AlternateBytes = 0x00; s_command.DataMode = HAL_OSPI_DATA_4_LINES; s_command.DummyCycles = 4; s_command.NbData = 2; s_command.DQSMode = HAL_OSPI_DQS_DISABLE; // s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } if (HAL_OSPI_Receive(&hospi1, pData, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } printf("Quad I/O Read Device ID : 0x%2X 0x%2X\r\n",pData[0],pData[1]); /* Read JEDEC ID */ s_command.InstructionMode = HAL_OSPI_INSTRUCTION_1_LINE; s_command.Instruction = READ_JEDEC_ID_CMD; s_command.AddressMode = HAL_OSPI_ADDRESS_NONE; s_command.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = HAL_OSPI_DATA_1_LINE; s_command.DummyCycles = 0; s_command.NbData = 3; s_command.DQSMode = HAL_OSPI_DQS_DISABLE; // s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD; if (HAL_OSPI_Command(&hospi1, &s_command, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } if (HAL_OSPI_Receive(&hospi1, pData, HAL_OSPI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } printf("Read JEDEC ID : 0x%2X 0x%2X 0x%2X\r\n\r\n",pData[0],pData[1],pData[2]); /*##-3-QSPI Erase/Write/Read Test ###########################################*/ /* fill buffer */ for(i =0;i<0x100;i ++) { wData[i] = i*2; rData[i] = 0; } if(BSP_QSPI_Erase_Block(0) == QSPI_OK) printf(" QSPI Erase Block ok\r\n"); else Error_Handler(); if(BSP_QSPI_Write(wData,0x00,0x100)== QSPI_OK) printf(" QSPI Write ok\r\n"); else Error_Handler(); if(BSP_QSPI_Read(rData,0x00,0x100)== QSPI_OK) printf(" QSPI Read ok\r\n\r\n"); else Error_Handler(); printf("QSPI Read Data : \r\n"); for(i =0;i<0x100;i++) printf("0x%02X ",rData[i]); printf("\r\n\r\n"); for(i =0;i<0x100;i++) if(rData[i] != wData[i])printf("0x%02X 0x%02X ",wData[i],rData[i]); printf("\r\n\r\n"); /* check date */ if(memcmp(wData,rData,0x100) == 0 ) printf(" W25Q128FV QuadSPI Test OK\r\n"); else printf(" W25Q128FV QuadSPI Test False\r\n"); }
Solved! Go to Solution.
2025-04-22 4:30 AM
Hello @NajeebUllahKhan;
1- Are my configurations ok according to W25Q256JV?
To check your configuration, I recommend you to take a look at AN5050 Table 8. STM32CubeMX - Configuration of OCTOSPI parameters. This table explains how to configure the OCTOSPI parameter settings.
2- Memory Type is Micron or Macronix?
The memory type has no impact in Quad-SPI mode. So you can choose any memory type.
When using a octo-SPI mode, you simply need to look at the data ordering in the memory datasheet and then select the one that matches it in the STM32 OCTOSPI configuration. The micron (and compatible memories) use D0/D1 ordering while Macronix (and compatible memories) use D1/D0 data ordering.
Please take a look at this FAQ Overall FAQs for QUADSPI/OCTOSPI/HSPI/XSPI - STMicroelectronics Community
3- Device Size will be 23 or 24 as my flash is 32MB?
The size of the Quad memory in bytes and expressed in 2^n. The datasheet of the W25Q256JV is 256MBits = 32Mbytes = 0x200 0000. We see the bit 25 is set meaning 2^25 = 32 MBytes. In STM32CubeMx we set the Device Size field to 25.
I hope this answer your request.
Thank you.
Kaouthar
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.
2025-04-22 1:14 AM - edited 2025-04-22 1:16 AM
Hello @NajeebUllahKhan;
The OctoSPI interface is fully configurable and supports two, four or eight data lines: Single-SPI (traditional SPI), Dual-SPI, Quad-SPI and Octo-SPI.
For Quad memory connected to the OCTOSPI interface code example, I recommend you to take a look at AN5050 precisely sections 7.2 OCTOSPI configuration with STM32CubeMX and III. Quad-SPI PSRAM in Regular-command protocol example.
I advise you to refer to this code example and get inspired to configure your own project to satisfy your needs.
Thank you.
Kaouthar
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.
2025-04-22 4:10 AM
I am using Winbond W25Q256JV 32MB and STM32L562CEU6 UFQFPN48 which has OSPI with following options (Disable, Single SPI, Dual SPI, Quad SPI) and I selected Quad SPI.
I have attached my configuration below in picture from CubemX. I have some questions.
1) Are my configurations ok according to W25Q256JV?
2) Memory Type is Micron or Macronix?
3) Device Size will be 23 or 24 as my flash is 32MB?
2025-04-22 4:30 AM
Hello @NajeebUllahKhan;
1- Are my configurations ok according to W25Q256JV?
To check your configuration, I recommend you to take a look at AN5050 Table 8. STM32CubeMX - Configuration of OCTOSPI parameters. This table explains how to configure the OCTOSPI parameter settings.
2- Memory Type is Micron or Macronix?
The memory type has no impact in Quad-SPI mode. So you can choose any memory type.
When using a octo-SPI mode, you simply need to look at the data ordering in the memory datasheet and then select the one that matches it in the STM32 OCTOSPI configuration. The micron (and compatible memories) use D0/D1 ordering while Macronix (and compatible memories) use D1/D0 data ordering.
Please take a look at this FAQ Overall FAQs for QUADSPI/OCTOSPI/HSPI/XSPI - STMicroelectronics Community
3- Device Size will be 23 or 24 as my flash is 32MB?
The size of the Quad memory in bytes and expressed in 2^n. The datasheet of the W25Q256JV is 256MBits = 32Mbytes = 0x200 0000. We see the bit 25 is set meaning 2^25 = 32 MBytes. In STM32CubeMx we set the Device Size field to 25.
I hope this answer your request.
Thank you.
Kaouthar
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.
2025-04-25 3:52 AM
Thank you so much for detailed explanation, it helped a lot in understanding things related to OSPI.
So, I have to use OSPI instructions with Quad Data Lines because I am configuring OSPI not QSPI right?
And do these OSPI configuration works reliable with W25Q which is QSPI based?
Can I get an example related to exact STML562CE specified uC for OSPI with Single SPI, Dual SPI, Quad SPI to get some help in creating my own algorithm?
Looking forward to kind response...
2025-04-25 4:16 AM
Hello @NajeebUllahKhan;
Yes, you need to use the OSPI Hal drivers.
For the OCTOSPI interface configured in QUAD mode example, I recommend you to take a look at AN5050 precisely Table 7. STM32CubeMX - Configuration of OCTOSPI signals and mode, Table 8. STM32CubeMX - Configuration of OCTOSPI parameters and III. Quad-SPI PSRAM in Regular-command protocol example.
The III. Quad-SPI PSRAM in Regular-command protocol example section explains how to configure the OCTOSPI1 in Indirect/Memory-mapped mode and how to configure the external Quad-SPI PSRAM AP Memory allowing communication in STR Quad-SPI mode.
You can get inspired from this example to configure your own project.
I hope this help you.
If your initial question is answered please click on Accept as Solution on the reply which answered your question.
If you have another question, please create a new post.
Thank you for your contribution in ST Community.
Kaouthar
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.
2025-04-25 5:18 AM - edited 2025-04-27 11:35 PM
Hi @KDJEM.1
OK, now I got some idea about how to configure and how to use OSPI in Quad Mode. Now what I need is, I have W25Q256JV and STM32L562CEU6 with 38 Pin Package and have OSPI (Single SPI, Dual SPI and Quad SPI option only). I want to interface it with normal operation (QSPI_ResetMemory, QSPI_AutoPollingMemReady, QSPI_WriteEnable, QSPI_Configuration, MemConfiguration, BSP_QSPI_Erase_Chip, BSP_QSPI_Write, BSP_QSPI_Read) funtions, with first reset the memory, then Autopoll to read reg to get memory ready, then write enable to write, then Configuration function to configure it for quad mode QE bit.
2025-04-27 11:33 PM - edited 2025-04-27 11:35 PM
Hi @KDJEM.1
I have W25Q256JV and STM32L562CEU6 with 38 Pin Package and have OSPI (Single SPI, Dual SPI and Quad SPI option only). Below is my Clock Settings, OSPI (Quad SPI) with Quad Lines Settings and Error Status during Write Enable and main.c file.
Kindly check and let me what is wrong so it's going into Error Handler every time on Write Enable.
If any basic drivers are available for OSPI in Quad Mode for Read/Write/Erase.
Looking forward to your kind help...
static void WriteEnable(OSPI_HandleTypeDef *hospi) {
OSPI_RegularCmdTypeDef sCommand;
OSPI_AutoPollingTypeDef sConfig;
HAL_StatusTypeDef ret;
/* Enable write operations ------------------------------------------ */
sCommand.OperationType = HAL_OSPI_OPTYPE_COMMON_CFG;
sCommand.FlashId = HAL_OSPI_FLASH_ID_1;
sCommand.Instruction = 0x06; // Use standard Write Enable command for Quad mode
sCommand.InstructionMode = HAL_OSPI_INSTRUCTION_4_LINES; // Use 4-line instruction mode
sCommand.InstructionSize = HAL_OSPI_INSTRUCTION_8_BITS; // 8-bit instruction size
sCommand.InstructionDtrMode = HAL_OSPI_INSTRUCTION_DTR_DISABLE;
sCommand.AddressMode = HAL_OSPI_ADDRESS_NONE;
sCommand.AlternateBytesMode = HAL_OSPI_ALTERNATE_BYTES_NONE;
sCommand.DataMode = HAL_OSPI_DATA_NONE;
sCommand.DummyCycles = 0;
sCommand.DQSMode = HAL_OSPI_DQS_DISABLE;
sCommand.SIOOMode = HAL_OSPI_SIOO_INST_EVERY_CMD;
ret = HAL_OSPI_Command(hospi, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
if (ret != HAL_OK) {
// Log the error here
Error_Handler();
}
/* Configure automatic polling mode to wait for write enabling ---- */
sCommand.Instruction = 0x05; // Read the status register command for Quad mode
sCommand.Address = 0x0;
sCommand.AddressMode = HAL_OSPI_ADDRESS_4_LINES; // Use 4-line address mode
sCommand.AddressSize = HAL_OSPI_ADDRESS_24_BITS; // Standard 3-byte address size
sCommand.AddressDtrMode = HAL_OSPI_ADDRESS_DTR_DISABLE;
sCommand.DataMode = HAL_OSPI_DATA_4_LINES; // Use 4-line data mode
sCommand.DataDtrMode = HAL_OSPI_DATA_DTR_DISABLE;
sCommand.NbData = 1; // 1 byte to read from status register
sCommand.DummyCycles = 8;
ret = HAL_OSPI_Command(hospi, &sCommand, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
if (ret != HAL_OK) {
// Log the error here
Error_Handler();
}
ret = HAL_OSPI_AutoPolling(hospi, &sConfig, HAL_OSPI_TIMEOUT_DEFAULT_VALUE);
if (ret != HAL_OK) {
// Log the error here
Error_Handler(); /* every time goes into error handler here */
}
/* Polling finished successfully */
}