cancel
Showing results for 
Search instead for 
Did you mean: 

OSPI as QSPI on L5 with W25Q256

NajeebUllahKhan
Associate II

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");

}

 

NajeebUllahKhan_0-1745293350492.pngNajeebUllahKhan_1-1745293359047.png

 

 

1 ACCEPTED SOLUTION

Accepted Solutions
KDJEM.1
ST Employee

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.

KDJEM1_1-1745321311205.png

 

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

KDJEM1_0-1745320771222.png

 

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.

View solution in original post

7 REPLIES 7
KDJEM.1
ST Employee

Hello @NajeebUllahKhan;

 

The OctoSPI interface is fully configurable and supports two, four or eight data linesSingle-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.

NajeebUllahKhan
Associate II

@KDJEM.1

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?

Capture.PNG

KDJEM.1
ST Employee

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.

KDJEM1_1-1745321311205.png

 

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

KDJEM1_0-1745320771222.png

 

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.

NajeebUllahKhan
Associate II

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

KDJEM.1
ST Employee

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.

KDJEM1_0-1745579315320.png

KDJEM1_1-1745579368377.png

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.

NajeebUllahKhan
Associate II

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.

NajeebUllahKhan
Associate II

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

}

1.PNG

2.PNG

3.PNG