Skip to main content
AksultanK
Associate II
May 1, 2021
Solved

Problems with custom external loader for W25Q16 spi flash.

  • May 1, 2021
  • 9 replies
  • 4187 views

Hello everyone, I've got custom-made board with STM32F407VE and W25Q16 SPI flash with TFT Display installed.

So I've decided to develop my own external loader for SPI flash for storing images in my TouchGFX project. I've managed to read data from flash with st-link utility and stm32cube programmer but encountered some problems.

  1. Somehow I can erase one sector at a time. But if I decide to erase multiple sectors, only the first sector in sequence will be erased. This works in st-link utility.
  2. In STM32CubeProgrammer, erase functions doesn't work at all, but I can read the data in memory.

And because of these issues I can't write data to flash, And I don't even know if write function will work, and I still need to figure out how to use it in TouchGFX project.

Edit: It turned out I'm able to erase one sector in stm32cubeprogrammer if I don't do anything except erasing after connecting. If I touch anything before erase command, It fails. Still can't erase multiple sectors at once.

Please help…

Here are my functions I found in st-link utility folder (stm32cubeprogrammer has the same source code).

The sector erase for external loader:

int SectorErase (uint32_t EraseStartAddress ,uint32_t EraseEndAddress)
{
	 EraseStartAddress &= 0x0FFFFFFF;
	 EraseEndAddress &= 0x0FFFFFFF;
 __set_PRIMASK(0); 
 EraseStartAddress = EraseStartAddress - EraseStartAddress % w25qxx.SectorSize;
 while (EraseEndAddress>=EraseStartAddress)
 {
	 W25qxx_EraseSector(EraseStartAddress);
 EraseStartAddress += w25qxx.SectorSize;
 }
 __set_PRIMASK(1); //enable interrupts
 return 1;
}

Erase sector funtion for spi flash

void W25qxx_EraseSector(uint32_t SectorAddr)
{
	while(w25qxx.Lock==1)
		W25qxx_Delay(1);
	w25qxx.Lock=1;
	#if (_W25QXX_DEBUG==1)
	uint32_t	StartTime=HAL_GetTick();	
	printf("w25qxx EraseSector %d Begin...\r\n",SectorAddr);
	#endif
	W25qxx_WaitForWriteEnd();
	//SectorAddr = SectorAddr * w25qxx.SectorSize;
 W25qxx_WriteEnable();
 HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_RESET);
 W25qxx_Spi(0x20);
	if(w25qxx.ID>=W25Q256) W25qxx_Spi((SectorAddr & 0xFF000000) >> 24);
 
 W25qxx_Spi((SectorAddr & 0xFF0000) >> 16);
 W25qxx_Spi((SectorAddr & 0xFF00) >> 8);
 W25qxx_Spi(SectorAddr & 0xFF);
 
 HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_SET);
 W25qxx_WaitForWriteEnd();
	#if (_W25QXX_DEBUG==1)
	printf("w25qxx EraseSector done after %d ms\r\n",HAL_GetTick()-StartTime);
	#endif
	W25qxx_Delay(1);
	w25qxx.Lock=0;
}

Write function for external loader:

int Write (uint32_t Address, uint32_t Size, uint8_t* buffer)
{
 W25qxx_WriteByte(buffer, Address, Size);
 return 1;
}

Write function flash

void W25qxx_WriteByte(uint8_t *pBuffer, uint32_t WriteAddr_inBytes, uint32_t ByteNum)
{
	while(w25qxx.Lock==1)
		W25qxx_Delay(1);
	w25qxx.Lock=1;
	#if (_W25QXX_DEBUG==1)
	uint32_t	StartTime=HAL_GetTick();
	printf("w25qxx WriteByte 0x%02X at address %d begin...",pBuffer,WriteAddr_inBytes);
	#endif
	W25qxx_WaitForWriteEnd();
 W25qxx_WriteEnable();
 HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_RESET);
 W25qxx_Spi(0x02);
	if(w25qxx.ID>=W25Q256)
		W25qxx_Spi((WriteAddr_inBytes & 0xFF000000) >> 24);
 W25qxx_Spi((WriteAddr_inBytes & 0xFF0000) >> 16);
 W25qxx_Spi((WriteAddr_inBytes & 0xFF00) >> 8);
 W25qxx_Spi(WriteAddr_inBytes & 0xFF);
 //W25qxx_Spi(pBuffer);
 HAL_SPI_Transmit(&_W25QXX_SPI,pBuffer,ByteNum,5000);
	HAL_GPIO_WritePin(_W25QXX_CS_GPIO,_W25QXX_CS_PIN,GPIO_PIN_SET);
 W25qxx_WaitForWriteEnd();
	#if (_W25QXX_DEBUG==1)
	printf("w25qxx WriteByte done after %d ms\r\n",HAL_GetTick()-StartTime);
	#endif
	w25qxx.Lock=0;
}

Here's CubeProgrammer erase fail screenshot

0693W00000AN5JxQAL.png 

This topic has been closed for replies.
Best answer by AksultanK

Solved.

Init() function called every time before other functions. So SystemClockConfig was called several times, causing a hard fault. I've removed it from Init and erase, read and write operations work fine, but it looks like verify isn't working correctly.

9 replies

AksultanK
AksultanKAuthorBest answer
Associate II
May 14, 2021

Solved.

Init() function called every time before other functions. So SystemClockConfig was called several times, causing a hard fault. I've removed it from Init and erase, read and write operations work fine, but it looks like verify isn't working correctly.

KBhon.1
Associate II
June 21, 2021

Hello @AksultanK​ ,

Good Day!

We have been working on exactly the same configuration and we found that no one has yet implemented an external loader for SPI flash (no Quad).

We are also facing similar issues.

Our loader isn't even able to communicate with the SPI flash.

Could you please share your loader_src and Dev_info files with me?

Thanking You.

AksultanK
AksultanKAuthor
Associate II
June 21, 2021

Sure, here is archive with the CubeIDE project. But please be aware, there are some lines that I have no clue what they do. At some point I just started copying lines from examples in hope it will work, so it's a not the best example, but it works somehow. Still couldn't make it work in TouchGFX.

KBhon.1
Associate II
June 22, 2021

Thanks a lot, @AksultanK.

I really appreciate your help.

I would update you with the outcome.

Neolithic
Associate III
May 28, 2023

Hi,

I have been trying to program W25Q16 external flash for Fast Read Dual Out mode. In this mode, basically both the lines MISO and MOSI become input for the host (STM32 in this case) and data can be read at double the speed. My SPI is running at 40MHz and in Normal read mode with DMA I am getting the correct bandwidth. I am able to read out 20KB in roughly 4.150 milliseconds.

Now, when i try to send the instruction to perform Fast Read Dual Output as mentioned in page 30 of this user manual https://datasheet.lcsc.com/lcsc/1912111437_Winbond-Elec-W25Q128JVSIQ_C113767.pdf

I start getting incorrect Data. I have written some predefined values to 512Byte space in flash for the comparison. When I do a normal read, as mentioned above, the data stays correct. However, with Fast Read Dual Out, the data gets corrupted.

What i am not able to understand is that, does it require special steps to configure GPIOs before we do fast read dual output? Or am i missing anything specific which is not mentioned in the manual. If you have already done something similar, kindly guide me. My SPI initialization values are:

inSPIHandle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;

inSPIHandle->Init.CLKPhase = SPI_PHASE_1EDGE;

inSPIHandle->Init.CLKPolarity = SPI_POLARITY_LOW;

inSPIHandle->Init.CRCPolynomial = SPI_CRCPR_CRCPOLY;

inSPIHandle->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED;

inSPIHandle->Init.DataSize = SPI_DATASIZE_8BIT;

inSPIHandle->Init.Direction = SPI_DIRECTION_2LINES;

inSPIHandle->Init.FirstBit = SPI_FIRSTBIT_MSB;

inSPIHandle->Init.Mode = SPI_MODE_MASTER;

inSPIHandle->Init.NSS = SPI_NSS_SOFT;

inSPIHandle->Init.TIMode = SPI_TIMODE_DISABLE;

I will be looking forward to your reply.

Tesla DeLorean
Guru
May 28, 2023
Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
Neolithic
Associate III
May 29, 2023

I have asked in multiple places in the hope that people who have experience with this flash, might have already done it.