cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
Contributor
Contributor
343 Views
Registered: ‎03-12-2018

How to change Updatable boot file in QSPI from PS (zynq 7000)

Jump to solution

Hello There,

My device is in QSPI mode, having a working Boot.bin programmed at 0x0 offset. When I switch on the system, it gets booted successfully and working. It has UDP based Ethernet functionality.

I have new updates for my system and want to update/change the Boot.bit present in QSPI 0x0 offset.

I'm able to receive Boot.bin file over Ethernet and put it on DDR memory and to verify it, I've written it into SD card and tried booting the system in SD card mode. It works fine. This tells me that the Boot file PS is receiving over Ethernet is the correct one (Just to be double sure I'm doing CRC after receiving the complete file in DDR).

Now I want to do same with QSPI, after receiving complete file in DDR, I'm writing it into QSPI memory from 0th Address (1 page at a time, i.e. 256 bytes). After writing, when I tried booting the system in QSPI mode, system is not getting booted.

Can anyone, help me with this.?

Idea is to boot the system in QSPI mode, when update comes over Ethernet, QSPI memory gets updated with the new Boot file, and after restarting the system, it should booted with new Boot.bin.

I'm using ZC7020 Evaluation Board from Xilinx. A quick response will be appreciated.

Thanks

Lokesh

 

 

 

0 Kudos
1 Solution

Accepted Solutions
Highlighted
Contributor
Contributor
75 Views
Registered: ‎03-12-2018

Re: How to change Updatable boot file in QSPI from PS (zynq 7000)

Jump to solution

Hi @stephenm,

Made lot of changes in to the code. And now I'm able to transfer the updated Boot.bin file in place of updatable Boot.bin present at offset 0x0.

Anyone who is trying the same, i.e. updating the boot file from PS, I'm sharing the snippets of my code, which will help then to get it working at ease. (Please find the attachment for my complete source code to understand the work in detail)

#include "xqspips.h"		/* QSPI device driver */

First let's understand how flash memory is written.

- You have to erase the memory before writing
- You can not write more than page size(i.e. 256) bytes at once to the flash memory
- If you have more data, you have to write page by page
- Because your FlashWrite() function uses a defined buffer (WriteBuffer), you have to copy the data to be written to that buffer before calling the function

Here, I'm using Sector Wise Erase & Write, along with Page Wise approach. 

PageSize = 256 bytes;

SectorSize = 4096 * PageSize;

NoOf_Sectors = totalWriteCount / SectorSize;  /**( equals to SectorSize)**/

NoOf_SubSector = totalWriteCount % (SectorSize * NoOf_Sector); /**( Less than SectorSize, but greater than PageSize)**/

NoOf_LastBytes = NoOf_SubSector % PageSize /**(Less than PageSize)**/

 

Follwoing Earse and Write Code snippet will explain everything in detail...

FlashReadID();
u32 nPage; u32 TotalPages = ReadCount / PAGE_SIZE; u32 nPages = 4096; u32 nSpiAddress = 0; // Flash start address u32 nOffset = 0, TotalOffset = 0; u32 *pSrcData, *pDestData; pSrcData = (u32 *)BOOT_FILE_DATA_DDR_ADDR; pDestData = (u32 *)BOOT_FILE_RX_DATA_DDR_ADDR; // Erase flash Sectors to be written u32 nMaxData = nPages * PAGE_SIZE; u32 nSectors = ReadCount / nMaxData; u32 nSubSector = ReadCount % (nMaxData * nSectors); u32 SRC_ADDR = BOOT_FILE_DATA_DDR_ADDR; for(int i = 0; i < nSectors; i++){ Status = FlashErase(QspiInstancePtr, nSpiAddress, nMaxData); if (Status != XST_SUCCESS) { xil_printf("Flash Erase : Failed \r\n"); return XST_FAILURE; } else { xil_printf("Flash Erase : Success : %d\r\n",i); } xil_printf("Writing Started.... \r\n"); for (nPage = 0; nPage < nPages; nPage++, nOffset += PAGE_SIZE, TotalOffset+= PAGE_SIZE) { memcpy(&WriteBuffer[DATA_OFFSET], (u8 *)(SRC_ADDR + nOffset), PAGE_SIZE); usleep(10); Status = FlashWrite(QspiInstancePtr, nSpiAddress + nOffset, PAGE_SIZE, WRITE_CMD); if (Status != XST_SUCCESS) { xil_printf("FlashWrite: Failed : nOffset = %d \r\n", nOffset); return XST_FAILURE; } usleep(10); } xil_printf("FlashWrite : Success :nOffset = %d, Sector = %d, TotalOFfset = %d \r\n", nOffset,i, TotalOffset); nSpiAddress += nMaxData; SRC_ADDR += nMaxData; nOffset = 0; }
// Erase flash SubSectors to be written
int new_nPages = nSubSector/PAGE_SIZE; int new_nMaxData = new_nPages * PAGE_SIZE; int nLast = nSubSector % PAGE_SIZE; if(nSubSector){ xil_printf("=== SUBSECTOR === %d\r\n",nSubSector); Status = FlashErase(QspiInstancePtr, nSpiAddress, nSubSector); if (Status != XST_SUCCESS) { xil_printf("Flash Erase : Failed \r\n"); return XST_FAILURE; } else { xil_printf("Flash Erase : Success \r\n"); } xil_printf("Writing Started.... \r\n"); for (nPage = 0; nPage < new_nPages; nPage++, nOffset += PAGE_SIZE, TotalOffset+= PAGE_SIZE) { memcpy(&WriteBuffer[DATA_OFFSET], (u8 *)(SRC_ADDR + nOffset), PAGE_SIZE); usleep(10); Status = FlashWrite(QspiInstancePtr, nSpiAddress + nOffset, PAGE_SIZE, WRITE_CMD); if (Status != XST_SUCCESS) { xil_printf("FlashWrite: Failed : nOffset = %d \r\n", nOffset); return XST_FAILURE; } usleep(10); } xil_printf("FlashWrite : Success :nOffset = %d, TotalOFfset = %d \r\n", nOffset, TotalOffset); nSpiAddress += new_nMaxData; SRC_ADDR += new_nMaxData; nOffset = 0; }
// Erase flash nLast to be written if (nLast) { xil_printf("=== nLast === %d\r\n",nLast); nSpiAddress = 0; xil_printf("SRC_ADDR = %x, nLast = %d, TotalOffset = %d \r\n",SRC_ADDR, nLast, TotalOffset); memset(&WriteBuffer[DATA_OFFSET + nLast], 0, PAGE_SIZE - nLast); memcpy(&WriteBuffer[DATA_OFFSET], (u8*)SRC_ADDR, nLast); Status = FlashWrite(QspiInstancePtr, nSpiAddress + TotalOffset, PAGE_SIZE, WRITE_CMD); if (Status != XST_SUCCESS) { xil_printf("FlashWrite: Failed : nOffset = %d \r\n", nOffset); } else{ xil_printf("FlashWrite : Success : TotalOFfset = %d\r\n", TotalOffset); } } xil_printf("Writing Done.... \r\n");

Reading the Written data from flash and comparing to verify

xil_printf("Reading Started.... \r\n");
	XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_LQSPI_MODE_OPTION | XQSPIPS_HOLD_B_DRIVE_OPTION);

	u32 Addr1;
	Addr1 = 0;

	u32 *Dest1;
	Dest1 = (u32 *)BOOT_FILE_RX_DATA_DDR_ADDR;

	u32 *Src1;
	Src1 = (u32 *)BOOT_FILE_DATA_DDR_ADDR;


	Status = XQspiPs_LqspiRead(QspiInstancePtr, ReadBuffer, Addr1 , ((nPages * PAGE_SIZE * nSectors) + nLast));
	if (Status == XST_SUCCESS) {
		xil_printf("Reading Done....1 \r\n");
	}
	else{
		xil_printf("Reading Failed....1 \r\n");
	}

	memcpy(Dest1, &ReadBuffer[COMMAND_OFFSET], ((nPages * PAGE_SIZE * nSectors)+nLast));

	xil_printf(" ReadCount = %d, nMaxData = %d,\r\n Total0ffset = %d, nLast = %d \r\n", ReadCount, nMaxData,TotalOffset,nLast);
	Status = CheckData((u8 *) Src1 , (u8 *) Dest1, ((nPages * PAGE_SIZE * nSectors)+ nLast));
	if (Status != XST_SUCCESS) {
		xil_printf("CMP 1 \r\n");
		return XST_FAILURE;
	}

 Hope this will help to all those who are working with same.

Thanks and Warm Regards,

Lokesh

 

  

View solution in original post

10 Replies
Highlighted
Moderator
Moderator
328 Views
Registered: ‎09-12-2007

Re: How to change Updatable boot file in QSPI from PS (zynq 7000)

Jump to solution

If you can boot uboot, then you can use the uboot to program the QSPI

  • sf probe 0 0 0
  • sf erase 0 <at least the size of your image>
  • sf write <location of your image in DDR> 0 <size of your image in hex>

 

0 Kudos
Highlighted
Contributor
Contributor
322 Views
Registered: ‎03-12-2018

Re: How to change Updatable boot file in QSPI from PS (zynq 7000)

Jump to solution

Thank you for your quick response.

I'm not using uboot. I'm working with Standalone.
System's Boot.bin consist of FSBL, Bitstream, cpu0.elf, cpu1.elf.

Thanks
Lokesh

0 Kudos
Highlighted
Moderator
Moderator
318 Views
Registered: ‎09-12-2007

Re: How to change Updatable boot file in QSPI from PS (zynq 7000)

Jump to solution

In that case you will need to use the tools to update the QSPI with your image. In SDK, there is a flash writer tool in the GUI

0 Kudos
Highlighted
Contributor
Contributor
310 Views
Registered: ‎03-12-2018

Re: How to change Updatable boot file in QSPI from PS (zynq 7000)

Jump to solution

Through tool it works.

But when I'm trying to update it through PS, as a update. Its not getting booted.

Thanks

Lokesh

0 Kudos
Highlighted
Moderator
Moderator
308 Views
Registered: ‎09-12-2007

Re: How to change Updatable boot file in QSPI from PS (zynq 7000)

Jump to solution

How are you doing this through the PS? you mean you are using the drivers to write to the QSPI?

Are you making sure to erase first? 

0 Kudos
Highlighted
Contributor
Contributor
293 Views
Registered: ‎03-12-2018

Re: How to change Updatable boot file in QSPI from PS (zynq 7000)

Jump to solution

YEs, I'm using QSPI driver for Erase and write. Total file size is about 4.5MB.

I'm using the following command for Erasing.

TEST_ADDRESS = 0x0; 
ReadCount = 4.5MB;

Status = FlashErase(QspiInstancePtr, TEST_ADDRESS, ReadCount);

For Writing I'm executing following code...here 

int PageSize = 256;
u32 NoOfPages = (ReadCount / 256) + 3; xil_printf("NoOfPages = %d\r\n",NoOfPages);  for ( PageNo = 0; PageNo < NoOfPages; PageNo++) { FlashWrite(QspiInstancePtr, (PageNo * PAGE_SIZE) + TEST_ADDRESS, PAGE_SIZE, WRITE_CMD); }

I'm writing Page wise, as it seems that complete 4.5MB is not getting written in one go. is it.??

 

Thanks

Lokesh

 

0 Kudos
Highlighted
Contributor
Contributor
227 Views
Registered: ‎03-12-2018

Re: How to change Updatable boot file in QSPI from PS (zynq 7000)

Jump to solution

Hi @stephenm ,

I've updated my QSPI code as follows..

	u32 nPage;
	u32 nPages = ReadCount / PAGE_SIZE;
	u32 nLast = ReadCount % PAGE_SIZE;
	u32 nSpiAddress = 0; // Flash start address
	u32 nOffset = 0;
	u32 *pSrcData;
//	pSrcData = SDreadBuffer;
	pSrcData = (u32 *)BOOT_FILE_DATA_DDR_ADDR; // This is place I've read the Boot file from Ethernet


	// Erase flash pages to be written
	u32 nMaxData = ReadCount;
	if (nLast){
	    nMaxData += PAGE_SIZE;
	}

	Status = FlashErase(QspiInstancePtr, nSpiAddress, nMaxData);
	if (Status != XST_SUCCESS) {
		xil_printf("Flash Erase : Failed \r\n");
	} else {
		xil_printf("Flash Erase : Success \r\n");
	}

	xil_printf("Writing Started.... \r\n");
	for (nPage = 0; nPage < nPages; nPage++, nOffset += PAGE_SIZE)
	{
	    memcpy(&WriteBuffer[DATA_OFFSET], pSrcData + nOffset, PAGE_SIZE);
	    FlashWrite(QspiInstancePtr, nSpiAddress + nOffset, PAGE_SIZE, WRITE_CMD);
	}
	if (nLast)
	{
	    // Clear unused memory
		xil_printf("nLast = %d, nOffset = %d \r\n",nLast, nOffset);
	    memset(&WriteBuffer[DATA_OFFSET + nLast], 0, PAGE_SIZE - nLast);
	    // If the memory must be preserved, it must be read and stored before erasing
	    //  and copied back here
	    //memcpy(&WriteBuffer[DATA_OFFSET], pPreserved, PAGE_SIZE);
	    memcpy(&WriteBuffer[DATA_OFFSET], pSrcData + nOffset, nLast);
	    FlashWrite(QspiInstancePtr, nSpiAddress + nOffset, PAGE_SIZE, WRITE_CMD);
	}

	xil_printf("Writing Done.... \r\n");

I need your input on this.

Thanks

Lokesh

0 Kudos
Highlighted
Moderator
Moderator
191 Views
Registered: ‎09-12-2007

Re: How to change Updatable boot file in QSPI from PS (zynq 7000)

Jump to solution
0 Kudos
Highlighted
Contributor
Contributor
100 Views
Registered: ‎03-12-2018

Re: How to change Updatable boot file in QSPI from PS (zynq 7000)

Jump to solution

Hi @stephenm ,

Now for the test purpose, I'm writing 4MB of known data into DDR, writing that data into QSPI Flash and reading it back, just to check the written data is correct or not?

After reading the data , when I compare the data with existing, after 1058048 bytes comparison is failing.

Thanks

Lokesh

 

 

0 Kudos
Highlighted
Contributor
Contributor
76 Views
Registered: ‎03-12-2018

Re: How to change Updatable boot file in QSPI from PS (zynq 7000)

Jump to solution

Hi @stephenm,

Made lot of changes in to the code. And now I'm able to transfer the updated Boot.bin file in place of updatable Boot.bin present at offset 0x0.

Anyone who is trying the same, i.e. updating the boot file from PS, I'm sharing the snippets of my code, which will help then to get it working at ease. (Please find the attachment for my complete source code to understand the work in detail)

#include "xqspips.h"		/* QSPI device driver */

First let's understand how flash memory is written.

- You have to erase the memory before writing
- You can not write more than page size(i.e. 256) bytes at once to the flash memory
- If you have more data, you have to write page by page
- Because your FlashWrite() function uses a defined buffer (WriteBuffer), you have to copy the data to be written to that buffer before calling the function

Here, I'm using Sector Wise Erase & Write, along with Page Wise approach. 

PageSize = 256 bytes;

SectorSize = 4096 * PageSize;

NoOf_Sectors = totalWriteCount / SectorSize;  /**( equals to SectorSize)**/

NoOf_SubSector = totalWriteCount % (SectorSize * NoOf_Sector); /**( Less than SectorSize, but greater than PageSize)**/

NoOf_LastBytes = NoOf_SubSector % PageSize /**(Less than PageSize)**/

 

Follwoing Earse and Write Code snippet will explain everything in detail...

FlashReadID();
u32 nPage; u32 TotalPages = ReadCount / PAGE_SIZE; u32 nPages = 4096; u32 nSpiAddress = 0; // Flash start address u32 nOffset = 0, TotalOffset = 0; u32 *pSrcData, *pDestData; pSrcData = (u32 *)BOOT_FILE_DATA_DDR_ADDR; pDestData = (u32 *)BOOT_FILE_RX_DATA_DDR_ADDR; // Erase flash Sectors to be written u32 nMaxData = nPages * PAGE_SIZE; u32 nSectors = ReadCount / nMaxData; u32 nSubSector = ReadCount % (nMaxData * nSectors); u32 SRC_ADDR = BOOT_FILE_DATA_DDR_ADDR; for(int i = 0; i < nSectors; i++){ Status = FlashErase(QspiInstancePtr, nSpiAddress, nMaxData); if (Status != XST_SUCCESS) { xil_printf("Flash Erase : Failed \r\n"); return XST_FAILURE; } else { xil_printf("Flash Erase : Success : %d\r\n",i); } xil_printf("Writing Started.... \r\n"); for (nPage = 0; nPage < nPages; nPage++, nOffset += PAGE_SIZE, TotalOffset+= PAGE_SIZE) { memcpy(&WriteBuffer[DATA_OFFSET], (u8 *)(SRC_ADDR + nOffset), PAGE_SIZE); usleep(10); Status = FlashWrite(QspiInstancePtr, nSpiAddress + nOffset, PAGE_SIZE, WRITE_CMD); if (Status != XST_SUCCESS) { xil_printf("FlashWrite: Failed : nOffset = %d \r\n", nOffset); return XST_FAILURE; } usleep(10); } xil_printf("FlashWrite : Success :nOffset = %d, Sector = %d, TotalOFfset = %d \r\n", nOffset,i, TotalOffset); nSpiAddress += nMaxData; SRC_ADDR += nMaxData; nOffset = 0; }
// Erase flash SubSectors to be written
int new_nPages = nSubSector/PAGE_SIZE; int new_nMaxData = new_nPages * PAGE_SIZE; int nLast = nSubSector % PAGE_SIZE; if(nSubSector){ xil_printf("=== SUBSECTOR === %d\r\n",nSubSector); Status = FlashErase(QspiInstancePtr, nSpiAddress, nSubSector); if (Status != XST_SUCCESS) { xil_printf("Flash Erase : Failed \r\n"); return XST_FAILURE; } else { xil_printf("Flash Erase : Success \r\n"); } xil_printf("Writing Started.... \r\n"); for (nPage = 0; nPage < new_nPages; nPage++, nOffset += PAGE_SIZE, TotalOffset+= PAGE_SIZE) { memcpy(&WriteBuffer[DATA_OFFSET], (u8 *)(SRC_ADDR + nOffset), PAGE_SIZE); usleep(10); Status = FlashWrite(QspiInstancePtr, nSpiAddress + nOffset, PAGE_SIZE, WRITE_CMD); if (Status != XST_SUCCESS) { xil_printf("FlashWrite: Failed : nOffset = %d \r\n", nOffset); return XST_FAILURE; } usleep(10); } xil_printf("FlashWrite : Success :nOffset = %d, TotalOFfset = %d \r\n", nOffset, TotalOffset); nSpiAddress += new_nMaxData; SRC_ADDR += new_nMaxData; nOffset = 0; }
// Erase flash nLast to be written if (nLast) { xil_printf("=== nLast === %d\r\n",nLast); nSpiAddress = 0; xil_printf("SRC_ADDR = %x, nLast = %d, TotalOffset = %d \r\n",SRC_ADDR, nLast, TotalOffset); memset(&WriteBuffer[DATA_OFFSET + nLast], 0, PAGE_SIZE - nLast); memcpy(&WriteBuffer[DATA_OFFSET], (u8*)SRC_ADDR, nLast); Status = FlashWrite(QspiInstancePtr, nSpiAddress + TotalOffset, PAGE_SIZE, WRITE_CMD); if (Status != XST_SUCCESS) { xil_printf("FlashWrite: Failed : nOffset = %d \r\n", nOffset); } else{ xil_printf("FlashWrite : Success : TotalOFfset = %d\r\n", TotalOffset); } } xil_printf("Writing Done.... \r\n");

Reading the Written data from flash and comparing to verify

xil_printf("Reading Started.... \r\n");
	XQspiPs_SetOptions(QspiInstancePtr, XQSPIPS_LQSPI_MODE_OPTION | XQSPIPS_HOLD_B_DRIVE_OPTION);

	u32 Addr1;
	Addr1 = 0;

	u32 *Dest1;
	Dest1 = (u32 *)BOOT_FILE_RX_DATA_DDR_ADDR;

	u32 *Src1;
	Src1 = (u32 *)BOOT_FILE_DATA_DDR_ADDR;


	Status = XQspiPs_LqspiRead(QspiInstancePtr, ReadBuffer, Addr1 , ((nPages * PAGE_SIZE * nSectors) + nLast));
	if (Status == XST_SUCCESS) {
		xil_printf("Reading Done....1 \r\n");
	}
	else{
		xil_printf("Reading Failed....1 \r\n");
	}

	memcpy(Dest1, &ReadBuffer[COMMAND_OFFSET], ((nPages * PAGE_SIZE * nSectors)+nLast));

	xil_printf(" ReadCount = %d, nMaxData = %d,\r\n Total0ffset = %d, nLast = %d \r\n", ReadCount, nMaxData,TotalOffset,nLast);
	Status = CheckData((u8 *) Src1 , (u8 *) Dest1, ((nPages * PAGE_SIZE * nSectors)+ nLast));
	if (Status != XST_SUCCESS) {
		xil_printf("CMP 1 \r\n");
		return XST_FAILURE;
	}

 Hope this will help to all those who are working with same.

Thanks and Warm Regards,

Lokesh

 

  

View solution in original post