cancel
Showing results for 
Search instead for 
Did you mean: 

Problems with custom external loader for W25Q16 spi flash.

AksultanK
Associate II

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 

1 ACCEPTED SOLUTION

Accepted Solutions
AksultanK
Associate II

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.

View solution in original post

9 REPLIES 9
AksultanK
Associate II

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 III

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.

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.

Thanks a lot, @AksultanK.

I really appreciate your help.

I would update you with the outcome.

Hello AksultanK,

We got it working and can upload and verify data with this loader file.

Thanks again for your help.

We are now working on using it along with Toughgfx. Hope to get it working soon.

Great! Glad I could help. Please share the results. ​

Neolithic
Associate III

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.

Topic as own thread. STM32 model not specified. https://community.st.com/s/question/0D53W00002HW5CtSAL/how-to-perform-w25q16-fast-read-dual-output-

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

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