Serial Flash - W25Qxxx QuadSPI

From Stm32World
(Redirected from QuadSPI)
Jump to navigation Jump to search

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