Difference between revisions of "Serial Flash - W25Qxxx QuadSPI"

From Stm32World Wiki
Jump to navigation Jump to search
(10 intermediate revisions by the same user not shown)
Line 1: Line 1:
[[Category:STM32]][[Category:USB]][[Category:STM32 Hardware]][[Category:STM32 Development]]{{metadesc|QuadSPI Flash (W25Q128)}}
+
[[Category:STM32]][[Category:STM32 Hardware]][[Category:STM32 Development]]{{metadesc|QuadSPI Flash (W25Q128) information}}
 +
Serial flash IC's are quite common.  They are typically named M25Qxxx where M is the manufacturer (W is for Winbond) and xxx is the size in bits.  So the "W25Q128JV" is a Winbond flash with 128 bits = 16 MB.
 +
 
 +
== Pinout ==
 +
 
 +
The serial flash IC's typically have a pinout like:
 +
 
 +
[[File:Winbond W25Q128 Pins.png|600px]]
 +
 
 +
They can operate in either plain SPI mode (using DI and DO as MOSI/MISO) or so-called Quad SPI (4 data lines) using IO0-IO3.
 +
 
 +
== Memory Organisation ==
 +
 
 +
Internally the flash is organised like this:
 +
 
 +
[[File:Winbond W25Q128 Layout.png|800px]]
 +
 
 +
Bytes in the flash can be read/write individually, but before "writing" the address of the write needs to be "erased" (set to 0xff) and erase can only be done by "sector" (4kB in the above example -
  
 
== STM32L4 training - Hands-on QSPI ==
 
== STM32L4 training - Hands-on QSPI ==
  
https://www.youtube.com/watch?v=ElFH5JdtvYg
+
{{#ev:youtube|ElFH5JdtvYg}}
 +
 
 +
== Source Example ==
 +
 
 +
Working:
 +
 
 +
<pre>
 +
QSPI_CommandTypeDef sCommand;
 +
static uint8_t id[17] = { 0 };
 +
static uint8_t tx_buf[0x10] = "Ext Flash";
 +
static uint8_t rx_buf[0x10] = { 0 };
 +
 
 +
sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
 +
sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
 +
sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
 +
 
 +
/***** Read ID operation*****/
 +
sCommand.Instruction = 0x9F; //READ ID command code
 +
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; //Command line width
 +
sCommand.AddressMode = QSPI_ADDRESS_NONE; //Address line width. No address phase
 +
sCommand.DataMode = QSPI_DATA_1_LINE; //Data line width
 +
sCommand.NbData = 17; //Read the data length. ID length is 17 bytes
 +
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //No multiplexing byte stage
 +
sCommand.DummyCycles = 0; //No Dummy phase
 +
//Configuration command (when there is data stage, the command will be sent in the subsequent sending/receiving API call)
 +
if (HAL_QSPI_Command(&hqspi, &sCommand, 5000) != HAL_OK) {
 +
Error_Handler();
 +
}
 +
//Execute QSPI reception
 +
if (HAL_QSPI_Receive(&hqspi, id, 5000) != HAL_OK) {
 +
Error_Handler();
 +
}
 +
 
 +
/***** Write enable operation (need to make the external memory in the write enable state before block erasing) *****/
 +
sCommand.Instruction = 0x06; //Write enable command code
 +
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; //Command line width
 +
sCommand.AddressMode = QSPI_ADDRESS_NONE; //Address line width. No address phase
 +
sCommand.DataMode = QSPI_DATA_NONE; //Data line width. No data stage
 +
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //No multiplexing byte stage
 +
sCommand.DummyCycles = 0; //No Dummy phase
 +
//Configure sending command
 +
if (HAL_QSPI_Command(&hqspi, &sCommand, 5000) != HAL_OK) {
 +
Error_Handler();
 +
}
 +
 
 +
/***** Block erase operation*****/
 +
sCommand.Instruction = 0xD8; //Sector erase command code
 +
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; //Command line width
 +
sCommand.AddressMode = QSPI_ADDRESS_1_LINE; //Address line width. No address phase
 +
sCommand.AddressSize = QSPI_ADDRESS_24_BITS; //Address length
 +
sCommand.Address = 0; //Any address in the sector to be erased.
 +
sCommand.DataMode = QSPI_DATA_NONE; //Data line width. No data stage
 +
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //No multiplexing byte stage
 +
sCommand.DummyCycles = 0; //No Dummy phase
 +
//Configure sending command
 +
if (HAL_QSPI_Command(&hqspi, &sCommand, 5000) != HAL_OK) {
 +
Error_Handler();
 +
}
 +
HAL_Delay(3000); //Delay 3s. The unit is SysTick timer interrupt period
 +
 
 +
/***** Write enable operation (need to make the external memory in the write enable state before block erasing) *****/
 +
sCommand.Instruction = 0x06; //Write enable command code
 +
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; //Command line width
 +
sCommand.AddressMode = QSPI_ADDRESS_NONE; //Address line width. No address phase
 +
sCommand.DataMode = QSPI_DATA_NONE; //Data line width. No data stage
 +
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //No multiplexing byte stage
 +
sCommand.DummyCycles = 0; //No Dummy phase
 +
//Configure sending command
 +
if (HAL_QSPI_Command(&hqspi, &sCommand, 5000) != HAL_OK) {
 +
Error_Handler();
 +
}
 +
 
 +
/***** Four-wire fast write operation*****/
 +
sCommand.Instruction = 0x32; //Quick write command code with four lines
 +
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; //Command line width
 +
sCommand.AddressMode = QSPI_ADDRESS_1_LINE; //Address line width
 +
sCommand.AddressSize = QSPI_ADDRESS_24_BITS; //Address length
 +
sCommand.Address = 0; //Write the starting address
 +
sCommand.DataMode = QSPI_DATA_4_LINES; //Data line width
 +
sCommand.NbData = 10; //write data length
 +
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //No multiplexing byte stage
 +
sCommand.DummyCycles = 0; //No Dummy phase
 +
//Configuration command (when there is data stage, the command will be sent in the subsequent sending/receiving API call)
 +
if (HAL_QSPI_Command(&hqspi, &sCommand, 5000) != HAL_OK) {
 +
Error_Handler();
 +
}
 +
//Execute QSPI reception
 +
if (HAL_QSPI_Transmit(&hqspi, tx_buf, 5000) != HAL_OK) {
 +
Error_Handler();
 +
}
 +
HAL_Delay(5); //Delay 5ms. The unit is SysTick timer interrupt period
 +
 
 +
/***** Four-wire fast read operation*****/
 +
sCommand.Instruction = 0x6B; //Quick read command code with four lines
 +
sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; //Command line width
 +
sCommand.AddressMode = QSPI_ADDRESS_1_LINE; //Address line width
 +
sCommand.AddressSize = QSPI_ADDRESS_24_BITS; //Address length
 +
sCommand.Address = 0; //Start address
 +
sCommand.DataMode = QSPI_DATA_4_LINES; //Data line width
 +
sCommand.NbData = 10; //Read data length
 +
sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //No multiplexing byte stage
 +
sCommand.DummyCycles = 8; //Dummy phase. N25Q128A13EF840F
 +
 
 +
//Configuration command (when there is data stage, the command will be sent in the subsequent sending/receiving API call)
 +
if (HAL_QSPI_Command(&hqspi, &sCommand, 5000) != HAL_OK) {
 +
Error_Handler();
 +
}
 +
//Execute QSPI reception
 +
if (HAL_QSPI_Receive(&hqspi, rx_buf, 5000) != HAL_OK) {
 +
Error_Handler();
 +
}
 +
 
 +
</pre>
  
 
== Miscellaneous Links ==  
 
== Miscellaneous Links ==  
  
 
* [https://datasheet.lcsc.com/szlcsc/Winbond-Elec-W25Q128JVSIQTR_C97521.pdf W25Q128JV Datasheet]
 
* [https://datasheet.lcsc.com/szlcsc/Winbond-Elec-W25Q128JVSIQTR_C97521.pdf W25Q128JV Datasheet]
 +
* [https://datasheet.lcsc.com/lcsc/2106062244_GigaDevice-Semicon-Beijing-GD25Q128ESIG_C2758105.pdf GD25Q128E Datasheet]
 +
* [https://datasheet.lcsc.com/lcsc/1912111437_GigaDevice-Semicon-Beijing-GD25LQ64CSIGR_C395493.pdf GD25LQ64C Datasheet]
 
* [https://www.programmersought.com/article/39481457418/ LittleFS on SPI Flash (W28Q64)]
 
* [https://www.programmersought.com/article/39481457418/ LittleFS on SPI Flash (W28Q64)]
 
* [https://stackoverflow.com/questions/47610302/how-to-use-w25q16-flash-memory-in-stm32f4-with-hal-driver How to use W25Q16 FLASH memory in STM32F4 with HAL Driver?]
 
* [https://stackoverflow.com/questions/47610302/how-to-use-w25q16-flash-memory-in-stm32f4-with-hal-driver How to use W25Q16 FLASH memory in STM32F4 with HAL Driver?]
 +
* [https://www.st.com/resource/en/application_note/dm00227538-quadspi-interface-on-stm32-microcontrollers-and-microprocessors-stmicroelectronics.pdf Quad-SPI interface on STM32 microcontrollers and microprocessors]
 +
* [https://github.com/amvasil/stm32-qspi-fat-usb Github project putting fatfs on qspi flash]
 +
* [https://vivonomicon.com/2020/08/08/bare-metal-stm32-programming-part-12-using-quad-spi-flash-memory/ Bare metal QSPI Flash]

Revision as of 02:18, 12 July 2022

Serial flash IC's are quite common. They are typically named M25Qxxx where M is the manufacturer (W is for Winbond) and xxx is the size in bits. So the "W25Q128JV" is a Winbond flash with 128 bits = 16 MB.

Pinout

The serial flash IC's typically have a pinout like:

Winbond W25Q128 Pins.png

They can operate in either plain SPI mode (using DI and DO as MOSI/MISO) or so-called Quad SPI (4 data lines) using IO0-IO3.

Memory Organisation

Internally the flash is organised like this:

Winbond W25Q128 Layout.png

Bytes in the flash can be read/write individually, but before "writing" the address of the write needs to be "erased" (set to 0xff) and erase can only be done by "sector" (4kB in the above example -

STM32L4 training - Hands-on QSPI

Source Example

Working:

	QSPI_CommandTypeDef sCommand;
	static uint8_t id[17] = { 0 };
	static uint8_t tx_buf[0x10] = "Ext Flash";
	static uint8_t rx_buf[0x10] = { 0 };

	sCommand.DdrMode = QSPI_DDR_MODE_DISABLE;
	sCommand.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
	sCommand.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;

	/***** Read ID operation*****/
	sCommand.Instruction = 0x9F; //READ ID command code
	sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; //Command line width
	sCommand.AddressMode = QSPI_ADDRESS_NONE; //Address line width. No address phase
	sCommand.DataMode = QSPI_DATA_1_LINE; //Data line width
	sCommand.NbData = 17; //Read the data length. ID length is 17 bytes
	sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //No multiplexing byte stage
	sCommand.DummyCycles = 0; //No Dummy phase
	//Configuration command (when there is data stage, the command will be sent in the subsequent sending/receiving API call)
	if (HAL_QSPI_Command(&hqspi, &sCommand, 5000) != HAL_OK) {
		Error_Handler();
	}
	//Execute QSPI reception
	if (HAL_QSPI_Receive(&hqspi, id, 5000) != HAL_OK) {
		Error_Handler();
	}

	/***** Write enable operation (need to make the external memory in the write enable state before block erasing) *****/
	sCommand.Instruction = 0x06; //Write enable command code
	sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; //Command line width
	sCommand.AddressMode = QSPI_ADDRESS_NONE; //Address line width. No address phase
	sCommand.DataMode = QSPI_DATA_NONE; //Data line width. No data stage
	sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //No multiplexing byte stage
	sCommand.DummyCycles = 0; //No Dummy phase
	//Configure sending command
	if (HAL_QSPI_Command(&hqspi, &sCommand, 5000) != HAL_OK) {
		Error_Handler();
	}

	/***** Block erase operation*****/
	sCommand.Instruction = 0xD8; //Sector erase command code
	sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; //Command line width
	sCommand.AddressMode = QSPI_ADDRESS_1_LINE; //Address line width. No address phase
	sCommand.AddressSize = QSPI_ADDRESS_24_BITS; //Address length
	sCommand.Address = 0; //Any address in the sector to be erased.
	sCommand.DataMode = QSPI_DATA_NONE; //Data line width. No data stage
	sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //No multiplexing byte stage
	sCommand.DummyCycles = 0; //No Dummy phase
	//Configure sending command
	if (HAL_QSPI_Command(&hqspi, &sCommand, 5000) != HAL_OK) {
		Error_Handler();
	}
	HAL_Delay(3000); //Delay 3s. The unit is SysTick timer interrupt period

	/***** Write enable operation (need to make the external memory in the write enable state before block erasing) *****/
	sCommand.Instruction = 0x06; //Write enable command code
	sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; //Command line width
	sCommand.AddressMode = QSPI_ADDRESS_NONE; //Address line width. No address phase
	sCommand.DataMode = QSPI_DATA_NONE; //Data line width. No data stage
	sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //No multiplexing byte stage
	sCommand.DummyCycles = 0; //No Dummy phase
	//Configure sending command
	if (HAL_QSPI_Command(&hqspi, &sCommand, 5000) != HAL_OK) {
		Error_Handler();
	}

	/***** Four-wire fast write operation*****/
	sCommand.Instruction = 0x32; //Quick write command code with four lines
	sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; //Command line width
	sCommand.AddressMode = QSPI_ADDRESS_1_LINE; //Address line width
	sCommand.AddressSize = QSPI_ADDRESS_24_BITS; //Address length
	sCommand.Address = 0; //Write the starting address
	sCommand.DataMode = QSPI_DATA_4_LINES; //Data line width
	sCommand.NbData = 10; //write data length
	sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //No multiplexing byte stage
	sCommand.DummyCycles = 0; //No Dummy phase
	//Configuration command (when there is data stage, the command will be sent in the subsequent sending/receiving API call)
	if (HAL_QSPI_Command(&hqspi, &sCommand, 5000) != HAL_OK) {
		Error_Handler();
	}
	//Execute QSPI reception
	if (HAL_QSPI_Transmit(&hqspi, tx_buf, 5000) != HAL_OK) {
		Error_Handler();
	}
	HAL_Delay(5); //Delay 5ms. The unit is SysTick timer interrupt period

	/***** Four-wire fast read operation*****/
	sCommand.Instruction = 0x6B; //Quick read command code with four lines
	sCommand.InstructionMode = QSPI_INSTRUCTION_1_LINE; //Command line width
	sCommand.AddressMode = QSPI_ADDRESS_1_LINE; //Address line width
	sCommand.AddressSize = QSPI_ADDRESS_24_BITS; //Address length
	sCommand.Address = 0; //Start address
	sCommand.DataMode = QSPI_DATA_4_LINES; //Data line width
	sCommand.NbData = 10; //Read data length
	sCommand.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //No multiplexing byte stage
	sCommand.DummyCycles = 8; //Dummy phase. N25Q128A13EF840F

	//Configuration command (when there is data stage, the command will be sent in the subsequent sending/receiving API call)
	if (HAL_QSPI_Command(&hqspi, &sCommand, 5000) != HAL_OK) {
		Error_Handler();
	}
	//Execute QSPI reception
	if (HAL_QSPI_Receive(&hqspi, rx_buf, 5000) != HAL_OK) {
		Error_Handler();
	}

Miscellaneous Links