【JokerのZYNQ7020】FLASH_TEST。

软件环境:vivado 2017.4 硬件平台:XC7Z020


在实际项目中,写好的ZYNQ工程在debug测试完毕之后,固化到FLASH往往是最后一步,然而,在固化的过程中,往往并不都是一次就能成功的,而固化不成功的原因也很多,最直接的排查手段就是可以先做一下FLASH的读写测试,看下FLASH的访问是否正常。

这里以镁光N25Q128为例子,说下常规FLASH的操作和测试过程,工程这边没什么特别需要注意的,用的是之前测试uartlite的工程,接口是QSPI Flash的。

首先打开flash手册,可以看到有这么一段比较重要的说明:

可以看出,flash是从1写到0,也就是说,擦除后的flash应该是全FF,然后写数据时候,往对应bit写0即可; 总字节数16MB,包含256个sectors(每sector 64K),相当于4096个subsectors(每个subsectors 4K),或65536个page(每个page 256B)。以框图描述如下:

 主要还是要记住sector有256个,包括65536个page,每个page 256B,每个地址代表1B。

 搞清楚存储的结构之后,下一个要关心的就是读写等操作指令了,下面只是列举了其中一部分,不同厂商,不同容量的话,需要注意有些指令是有可能不一样的:

另外,在使用fast read时候,需要注意,上来的数据中,首先是dummy bytes:

 写的话就直接按照指令+地址+数据的格式就好:

先上代码:

#include "xparameters.h"	/* SDK generated parameters */
#include "xqspips.h"		/* QSPI device driver */
#include "xil_printf.h"
#include "sleep.h"
/************************** Constant Definitions *****************************/

/*
 * The following constants map to the XPAR parameters created in the
 * xparameters.h file. They are defined here such that a user can easily
 * change all the needed parameters in one place.
 */
#define QSPI_DEVICE_ID		XPAR_XQSPIPS_0_DEVICE_ID

/*
 * The following constants define the commands which may be sent to the FLASH
 * device.
 */
#define WRITE_STATUS_CMD	0x01
#define WRITE_CMD			0x02
#define READ_CMD			0x03
#define WRITE_DISABLE_CMD	0x04
#define READ_STATUS_CMD		0x05
#define WRITE_ENABLE_CMD	0x06
#define FAST_READ_CMD		0x0B
#define DUAL_READ_CMD		0x3B
#define QUAD_READ_CMD		0x6B
#define BULK_ERASE_CMD		0xC7
#define	SEC_ERASE_CMD		0xD8
#define READ_ID				0x9F

/*
 * The following constants define the offsets within a FlashBuffer data
 * type for each kind of data.  Note that the read data offset is not the
 * same as the write data because the QSPI driver is designed to allow full
 * duplex transfers such that the number of bytes received is the number
 * sent and received.
 */
#define COMMAND_OFFSET		0 /* FLASH instruction */
#define ADDRESS_1_OFFSET	1 /* MSB byte of address to read or write */
#define ADDRESS_2_OFFSET	2 /* Middle byte of address to read or write */
#define ADDRESS_3_OFFSET	3 /* LSB byte of address to read or write */
#define DATA_OFFSET		    4 /* Start of Data for Read/Write */
#define DUMMY_OFFSET		4 /* Dummy byte offset for fast, dual and quad reads */
#define DUMMY_SIZE		    1 /* Number of dummy bytes for fast, dual and quad reads */
#define RD_ID_SIZE			4 /* Read ID command + 3 bytes ID response */
#define BULK_ERASE_SIZE		1 /* Bulk Erase command size */
#define SEC_ERASE_SIZE		4 /* Sector Erase command + Sector address */

/*
 * The following constants specify the extra bytes which are sent to the
 * FLASH on the QSPI interface, that are not data, but control information
 * which includes the command and address
 */
#define OVERHEAD_SIZE		4

/*
 * The following constants specify the page size, sector size, and number of
 * pages and sectors for the FLASH.  The page size specifies a max number of
 * bytes that can be written to the FLASH with a single transfer.
 */
#define SECTOR_SIZE		0x10000//65536
#define NUM_SECTORS		0x100//256
#define NUM_PAGES		0x10000//65536
#define PAGE_SIZE		256

/*
 * Number of flash pages to be written.
 */
#define PAGE_COUNT		65536

/*
 * Flash address to which data is ot be written.
 */
#define TEST_ADDRESS		0x00000000//0x00055000
#define UNIQUE_VALUE		0x05
/*
 * The following constants specify the max amount of data and the size of the
 * the buffer required to hold the data and overhead to transfer the data to
 * and from the FLASH.
 */
#define MAX_DATA		PAGE_COUNT * PAGE_SIZE

/**************************** Type Definitions *******************************/

/***************** Macros (Inline Functions) Definitions *********************/

/************************** Function Prototypes ******************************/

int FlashErase(XQspiPs *QspiPtr, u32 Address, u32 ByteCount);

void FlashWrite(XQspiPs *QspiPtr, u32 Address, u32 ByteCount, u8 Command);

void FlashRead(XQspiPs *QspiPtr, u32 Address, u32 ByteCount, u8 Command);

int FlashReadID(void);

int QspiFlashPolledExample(XQspiPs *QspiInstancePtr, u16 QspiDeviceId);

/************************** Variable Definitions *****************************/

/*
 * The instances to support the device drivers are global such that they
 * are initialized to zero each time the program runs. They could be local
 * but should at least be static so they are zeroed.
 */
static XQspiPs QspiInstance;

/*
 * The following variable allows a test value to be added to the values that
 * are written to the FLASH such that unique values can be generated to
 * guarantee the writes to the FLASH were successful
 */
int Test = 5;

/*
 * The following variables are used to read and write to the flash and they
 * are global to avoid having large buffers on the stack
 */
u8 ReadBuffer[MAX_DATA + DATA_OFFSET + DUMMY_SIZE];
u8 WriteBuffer[PAGE_SIZE + DATA_OFFSET];

/*****************************************************************************/
/**
*
* Main function to call the QSPI Flash example.
*
* @param	None
*
* @return	XST_SUCCESS if successful, otherwise XST_FAILURE.
*
* @note		None
*
******************************************************************************/
#define FLASH_TEST_ADDRESS0			0x00000000

int System_init_startup (void);
int qspi_flash_id(void);
int qspi_ease_entire_flash(void);
int Spi_Blank_Check(u32 StartAddr, u32 NoByteToRead);
int qspi_flash_write(void);
int qspi_flash_read(void);

static int qspi_init_flag=0;
static u32 Address = FLASH_TEST_ADDRESS0;

int main(void)
{
	int Status;
	int Cnt;
	int choice, exit_flag = 0;
	u32 SectCount=1, StartAddr, NoByteToRead;

	if (qspi_init_flag ==0)
	{
		Status = System_init_startup();

		if (Status != XST_SUCCESS) {
			return XST_FAILURE;
		}
		else
			qspi_init_flag=1;
	}

	StartAddr = FLASH_TEST_ADDRESS0;
	NoByteToRead = 512;
	SectCount = 512;

	while(exit_flag != 1)
	{
		print("\n\r*******************************************************************\n\r");
		print("\n\rChoose from options below: \r\n");
		print("1: Read Quad SPI flash ID\r\n");
		print("2: Erase Quad SPI flash\r\n");
		print("3: Blank Check Quad SPI flash\r\n");
		print("4: Write Quad SPI flash\r\n");
		print("5: Read Quad SPI flash\r\n");
		print("\n\r*******************************************************************\n\r");

		choice = inbyte();
		if (isalpha(choice)) {
			choice = toupper(choice);
		}

		switch(choice)
		{
			case '1':
			{
				print("\n\r\t Read Quad SPI flash ID\t\r\n");
				qspi_flash_id();
			}
			break;

			case '2':
			{
				print("Entire flash erase (Bulk Erase)\r\n");
				FlashErase(&QspiInstance, TEST_ADDRESS, MAX_DATA);
				print("Entire flash erase finish!\r\n");
			}
			break;

			case '3':
			{
				print ("\n\rQuad SPI flash Blank Check:\n\r");

				xil_printf("\r\n\r\nStart Address \t= 0x%08x\n\rEnd Address \t= 0x%08x\n\r", StartAddr,(TEST_ADDRESS + MAX_DATA));
				print ("\n\rPerforming Blank Check operation...\n\r");
				Status = Spi_Blank_Check(TEST_ADDRESS, MAX_DATA);
				if (Status != XST_SUCCESS) {
					print("\n\r\n\r\t\tBlank Check Operation Fail!.\r\n");
				}else
				{
					print("\n\r\n\rBlank Check Operation Completed without error.\r\n");
				}
			}
			break;

			case '4':
			{
				print ("\n\rWrite Quad SPI flash:\n\r");
				qspi_flash_write();
			}
			break;

			case '5':
			{
				print ("\n\rRead Quad SPI flash:\n\r");
				qspi_flash_read();
			}
			break;

			default:break;
		}
	}
}

int System_init_startup (void)
{
	int Status;
	XQspiPs_Config *QspiConfig;

	QspiConfig = XQspiPs_LookupConfig(QSPI_DEVICE_ID);
	if (NULL == QspiConfig) {
		return XST_FAILURE;
	}

	Status = XQspiPs_CfgInitialize(&QspiInstance, QspiConfig,
					QspiConfig->BaseAddress);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	XQspiPs_SetOptions(&QspiInstance, XQSPIPS_MANUAL_START_OPTION |
			XQSPIPS_FORCE_SSELECT_OPTION |
			XQSPIPS_HOLD_B_DRIVE_OPTION);

	XQspiPs_SetClkPrescaler(&QspiInstance, XQSPIPS_CLK_PRESCALE_8);

	XQspiPs_SetSlaveSelect(&QspiInstance);

	return XST_SUCCESS;
}

int qspi_flash_id(void)
{
	int Status;

	if (qspi_init_flag ==0)
	{
		Status = System_init_startup ();
		if (Status != XST_SUCCESS) {
			return XST_FAILURE;
		}
		else
			qspi_init_flag=1;

	}
	Status = FlashReadID();
	if(Status != XST_SUCCESS) {
		return XST_FAILURE;
	}
	return XST_SUCCESS;
}

int Spi_Blank_Check(u32 StartAddr, u32 NoByteToRead)
{
	int Status;
	int remaind_int, NoOfPage;
	u32 Index,StartOffsetAddr;
	StartOffsetAddr = StartAddr;
	if (qspi_init_flag ==0)
	{
		Status = System_init_startup ();
		if (Status != XST_SUCCESS) {
		} else qspi_init_flag=1;

	}
	NoOfPage = (NoByteToRead/PAGE_SIZE);
	remaind_int = (NoByteToRead - ( NoOfPage * PAGE_SIZE));

	if (remaind_int != 0) {
		NoOfPage = (NoOfPage+1);
	}
	xil_printf("\n\rPerforming Blank Check Operation...\n\rStart Address\t= 0x%08x\n\rEnd Address\t= 0x%08x\n\rNumber Of Pages\t= 0x%08x\n\r", StartOffsetAddr, NoByteToRead, NoOfPage);
	while (NoOfPage !=0)
	{
		memset(ReadBuffer, 0x00, sizeof(ReadBuffer));
		FlashRead(&QspiInstance, StartOffsetAddr, PAGE_SIZE, FAST_READ_CMD);

		xil_printf("\nStartOffsetAddr %x:",StartOffsetAddr);
		for(Index = 0; Index < PAGE_SIZE; Index++)
		{
			if(ReadBuffer[Index + DATA_OFFSET + DUMMY_SIZE] != 0xFF)
			{
				xil_printf("Blank Check Fail at Address:0x%x = 0x%x\r\n", (TEST_ADDRESS + Index), (ReadBuffer[Index + DATA_OFFSET + DUMMY_SIZE]));
					return XST_FAILURE;
			} else
			{
				xil_printf(".");
			}
		}
		NoOfPage--;
		StartOffsetAddr = (StartOffsetAddr + PAGE_SIZE);
	}
	return XST_SUCCESS;
}

int qspi_flash_write(void)
{
	int Page;
	int Count;
	u8 UniqueValue;

	print ("\n\rWriteBuffer:");
	for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < PAGE_SIZE;
			 Count++, UniqueValue++) {
			WriteBuffer[DATA_OFFSET + Count] = (u8)(UniqueValue);
			xil_printf (" 0x%x ",WriteBuffer[DATA_OFFSET + Count]);
		}

	for (Page = 0; Page < 5; Page++) {
			FlashWrite(&QspiInstance, (Page * PAGE_SIZE) + TEST_ADDRESS,PAGE_SIZE, WRITE_CMD);
			usleep(500000);
		}

	return XST_SUCCESS;
}

int qspi_flash_read(void)
{
	int Cnt;

	memset(ReadBuffer, 0x00, sizeof(ReadBuffer));
	FlashRead(&QspiInstance, TEST_ADDRESS, (5 * PAGE_SIZE) , FAST_READ_CMD);

	for(Cnt = 0; Cnt < (5 * PAGE_SIZE); Cnt++)
	{
		xil_printf(" 0x%x ", (ReadBuffer[Cnt + DATA_OFFSET + DUMMY_SIZE]));
	}

	return XST_SUCCESS;
}

/*****************************************************************************/
/**
*
* This function writes to the  serial FLASH connected to the QSPI interface.
* All the data put into the buffer must be in the same page of the device with
* page boundaries being on 256 byte boundaries.
*
* @param	QspiPtr is a pointer to the QSPI driver component to use.
* @param	Address contains the address to write data to in the FLASH.
* @param	ByteCount contains the number of bytes to write.
* @param	Command is the command used to write data to the flash. QSPI
*		device supports only Page Program command to write data to the
*		flash.
*
* @return	None.
*
* @note		None.
*
******************************************************************************/
void FlashWrite(XQspiPs *QspiPtr, u32 Address, u32 ByteCount, u8 Command)
{
	u8 WriteEnableCmd = { WRITE_ENABLE_CMD };
	u8 ReadStatusCmd[] = { READ_STATUS_CMD, 0 };  /* must send 2 bytes */
	u8 FlashStatus[2];

	/*
	 * Send the write enable command to the FLASH so that it can be
	 * written to, this needs to be sent as a seperate transfer before
	 * the write
	 */
	XQspiPs_PolledTransfer(QspiPtr, &WriteEnableCmd, NULL,
				sizeof(WriteEnableCmd));


	/*
	 * Setup the write command with the specified address and data for the
	 * FLASH
	 */
	WriteBuffer[COMMAND_OFFSET]   = Command;
	WriteBuffer[ADDRESS_1_OFFSET] = (u8)((Address & 0xFF0000) >> 16);
	WriteBuffer[ADDRESS_2_OFFSET] = (u8)((Address & 0xFF00) >> 8);
	WriteBuffer[ADDRESS_3_OFFSET] = (u8)(Address & 0xFF);

	/*
	 * Send the write command, address, and data to the FLASH to be
	 * written, no receive buffer is specified since there is nothing to
	 * receive
	 */
	XQspiPs_PolledTransfer(QspiPtr, WriteBuffer, NULL,
				ByteCount + OVERHEAD_SIZE);

	/*
	 * Wait for the write command to the FLASH to be completed, it takes
	 * some time for the data to be written
	 */
	while (1) {
		/*
		 * Poll the status register of the FLASH to determine when it
		 * completes, by sending a read status command and receiving the
		 * status byte
		 */
		XQspiPs_PolledTransfer(QspiPtr, ReadStatusCmd, FlashStatus,
					sizeof(ReadStatusCmd));

		/*
		 * If the status indicates the write is done, then stop waiting,
		 * if a value of 0xFF in the status byte is read from the
		 * device and this loop never exits, the device slave select is
		 * possibly incorrect such that the device status is not being
		 * read
		 */
		if ((FlashStatus[1] & 0x01) == 0) {
			break;
		}
	}
}

/*****************************************************************************/
/**
*
* This function reads from the  serial FLASH connected to the
* QSPI interface.
*
* @param	QspiPtr is a pointer to the QSPI driver component to use.
* @param	Address contains the address to read data from in the FLASH.
* @param	ByteCount contains the number of bytes to read.
* @param	Command is the command used to read data from the flash. QSPI
*		device supports one of the Read, Fast Read, Dual Read and Fast
*		Read commands to read data from the flash.
*
* @return	None.
*
* @note		None.
*
******************************************************************************/
void FlashRead(XQspiPs *QspiPtr, u32 Address, u32 ByteCount, u8 Command)
{
	/*
	 * Setup the write command with the specified address and data for the
	 * FLASH
	 */
	WriteBuffer[COMMAND_OFFSET]   = Command;
	WriteBuffer[ADDRESS_1_OFFSET] = (u8)((Address & 0xFF0000) >> 16);
	WriteBuffer[ADDRESS_2_OFFSET] = (u8)((Address & 0xFF00) >> 8);
	WriteBuffer[ADDRESS_3_OFFSET] = (u8)(Address & 0xFF);

	if ((Command == FAST_READ_CMD) || (Command == DUAL_READ_CMD) ||
	    (Command == QUAD_READ_CMD)) {
		ByteCount += DUMMY_SIZE;
	}
	/*
	 * Send the read command to the FLASH to read the specified number
	 * of bytes from the FLASH, send the read command and address and
	 * receive the specified number of bytes of data in the data buffer
	 */
	XQspiPs_PolledTransfer(QspiPtr, WriteBuffer, ReadBuffer,
				ByteCount + OVERHEAD_SIZE);
}

/*****************************************************************************/
/**
*
* This function erases the sectors in the  serial FLASH connected to the
* QSPI interface.
*
* @param	QspiPtr is a pointer to the QSPI driver component to use.
* @param	Address contains the address of the first sector which needs to
*		be erased.
* @param	ByteCount contains the total size to be erased.
*
* @return	None.
*
* @note		None.
*
******************************************************************************/
int FlashErase(XQspiPs *QspiPtr, u32 Address, u32 ByteCount)
{
	u8 WriteEnableCmd = { WRITE_ENABLE_CMD };
	u8 ReadStatusCmd[] = { READ_STATUS_CMD, 0 };  /* must send 2 bytes */
	u8 FlashStatus[2];
	int Sector;

	/*
	 * If erase size is same as the total size of the flash, use bulk erase
	 * command
	 */
	if (ByteCount == (NUM_SECTORS * SECTOR_SIZE)) {
		/*
		 * Send the write enable command to the FLASH so that it can be
		 * written to, this needs to be sent as a seperate transfer
		 * before the erase
		 */
		XQspiPs_PolledTransfer(QspiPtr, &WriteEnableCmd, NULL,
				  sizeof(WriteEnableCmd));

		/*
		 * Setup the bulk erase command
		 */
		WriteBuffer[COMMAND_OFFSET]   = BULK_ERASE_CMD;

		/*
		 * Send the bulk erase command; no receive buffer is specified
		 * since there is nothing to receive
		 */
		XQspiPs_PolledTransfer(QspiPtr, WriteBuffer, NULL,
					BULK_ERASE_SIZE);

		/*
		 * Wait for the erase command to the FLASH to be completed
		 */
		while (1) {
			/*
			 * Poll the status register of the device to determine
			 * when it completes, by sending a read status command
			 * and receiving the status byte
			 */
			XQspiPs_PolledTransfer(QspiPtr, ReadStatusCmd,
						FlashStatus,
						sizeof(ReadStatusCmd));

			/*
			 * If the status indicates the write is done, then stop
			 * waiting; if a value of 0xFF in the status byte is
			 * read from the device and this loop never exits, the
			 * device slave select is possibly incorrect such that
			 * the device status is not being read
			 */
			if ((FlashStatus[1] & 0x01) == 0) {
				break;
			}
		}

		return XST_SUCCESS;
	}

	/*
	 * If the erase size is less than the total size of the flash, use
	 * sector erase command
	 */
	for (Sector = 0; Sector < ((ByteCount / SECTOR_SIZE) + 1); Sector++) {
		/*
		 * Send the write enable command to the SEEPOM so that it can be
		 * written to, this needs to be sent as a seperate transfer
		 * before the write
		 */
		XQspiPs_PolledTransfer(QspiPtr, &WriteEnableCmd, NULL,
					sizeof(WriteEnableCmd));

		/*
		 * Setup the write command with the specified address and data
		 * for the FLASH
		 */
		WriteBuffer[COMMAND_OFFSET]   = SEC_ERASE_CMD;
		WriteBuffer[ADDRESS_1_OFFSET] = (u8)(Address >> 16);
		WriteBuffer[ADDRESS_2_OFFSET] = (u8)(Address >> 8);
		WriteBuffer[ADDRESS_3_OFFSET] = (u8)(Address & 0xFF);

		/*
		 * Send the sector erase command and address; no receive buffer
		 * is specified since there is nothing to receive
		 */
		XQspiPs_PolledTransfer(QspiPtr, WriteBuffer, NULL,
					SEC_ERASE_SIZE);

		/*
		 * Wait for the sector erse command to the FLASH to be completed
		 */
		while (1) {
			/*
			 * Poll the status register of the device to determine
			 * when it completes, by sending a read status command
			 * and receiving the status byte
			 */
			XQspiPs_PolledTransfer(QspiPtr, ReadStatusCmd,
						FlashStatus,
						sizeof(ReadStatusCmd));

			/*
			 * If the status indicates the write is done, then stop
			 * waiting, if a value of 0xFF in the status byte is
			 * read from the device and this loop never exits, the
			 * device slave select is possibly incorrect such that
			 * the device status is not being read
			 */
			if ((FlashStatus[1] & 0x01) == 0) {
				break;
			}
		}

		Address += SECTOR_SIZE;
	}

	return XST_SUCCESS;
}

/*****************************************************************************/
/**
*
* This function reads serial FLASH ID connected to the SPI interface.
*
* @param	None.
*
* @return	XST_SUCCESS if read id, otherwise XST_FAILURE.
*
* @note		None.
*
******************************************************************************/
int FlashReadID(void)
{
	int Status;

	/*
	 * Read ID in Auto mode.
	 */
	WriteBuffer[COMMAND_OFFSET]   = READ_ID;
	WriteBuffer[ADDRESS_1_OFFSET] = 0x23;		/* 3 dummy bytes */
	WriteBuffer[ADDRESS_2_OFFSET] = 0x08;
	WriteBuffer[ADDRESS_3_OFFSET] = 0x09;

	Status = XQspiPs_PolledTransfer(&QspiInstance, WriteBuffer, ReadBuffer,
				RD_ID_SIZE);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	xil_printf("FlashID=0x%x 0x%x 0x%x\n\r", ReadBuffer[1], ReadBuffer[2],
		   ReadBuffer[3]);
	if ( (ReadBuffer[1] == 0x20))
			 {
				 xil_printf("\n\rManufacturer ID:\t0x%x\t:= MICRON\n\r", ReadBuffer[1]);
				 if ( (ReadBuffer[2] == 0xBA))
				 {
					 xil_printf("Memory Type:\t\t0x%x\t:= N25Q 3V0\n\r", ReadBuffer[2]);
				 }
				 else
				 {
					 if ((ReadBuffer[2] == 0xBB))
					 	 {
						 	 xil_printf("Memory Type:\t\t0x%x\t:= N25Q 1V8\n\r", ReadBuffer[2]);
					 	 } else xil_printf("Memory Type:\t\t0x%x\t:= QSPI Data\n\r", ReadBuffer[2]);
				 }
				 if ((ReadBuffer[3] == 0x18))
				 	 {
					 xil_printf("Memory Capacity:\t0x%x\t:= 128Mbit\n\r", ReadBuffer[3]);
				 	 }
				 	 else if ( (ReadBuffer[3] == 0x19))
				 	 	 {
				 		 	 xil_printf("Memory Capacity:\t0x%x\t:= 256Mbit\n\r", ReadBuffer[3]);
				 	 	 }
				 	 	 else if ((ReadBuffer[3] == 0x20))
				 	 	 	 {
					 	 	 	 xil_printf("Memory Capacity:\t0x%x\t:= 512Mbit\n\r", ReadBuffer[3]);
				 			 }
				 	 	 	 else if ((ReadBuffer[3] == 0x21))
				 			 	 {
				 	 	 		 	 xil_printf("Memory Capacity:\t0x%x\t:= 1024Mbit\n\r", ReadBuffer[3]);
				 			 	 	 }
			 }
			 else if ((ReadBuffer[1] == 0x01))
			 {
				 xil_printf("\n\rManufacturer ID: \tSPANSION\n\r");
				 if ((ReadBuffer[3] == 0x18))
				  	 {
				 	 	 xil_printf("Memory Capacity\t=\t256Mbit\n\r");
				  	 }
				  	 else if ((ReadBuffer[3] == 0x19))
				  	 	 {
				  	 	 	 xil_printf("Memory Capacity\t=\t512Mbit\n\r");
				 		 }
				  	 	 else if ((ReadBuffer[3] == 0x20))
					 		{
				  	 	 	 	 xil_printf("Memory Capacity\t=\t1024Mbit\n\r");

					 			 	 }
			 }
			 else if ((ReadBuffer[1] == 0xEF))
			 		 {
			 			 xil_printf("\n\rManufacturer ID\t=\tWINBOND\n\r");
			 			 if ((ReadBuffer[3] == 0x18))
			 			  	 {
			 			 	 	 xil_printf("Memory Capacity\t=\t128Mbit\n\r");
			 			  	 }
			 }

	return XST_SUCCESS;
}

 下面对代码进行简要的说明:

1.代码总共包含5个功能,读ID、整片擦除、空白检测、写入数据、读取数据,通过串口进行交互

2.代码最开始#define _CMD相关的指令和OFFSET、SIZE配置等参数,需要根据实际使用的片子来进行调整,保证跟手册一致,否则有可能无法正常进行测试

3.读、写测试均测试5个page,起始地址由代码中的TEST_ADDRESS来指定

4.在System_init_startup()中完成了QSPI接口的初始化,通过XQspiPs_SetOptions()来设置参数,通过XQspiPs_SetClkPrescaler()来设置时钟的分频

5.如果待测的是1Gb那种大容量flash,一定注意要把FlashWrite()和FlashRead()函数接口中的地址长度改掉,当前使用的是3字节地址

6.不同厂商不同芯片不同读取指令,dummy bytes个数可能会不同,如果懒得查手册,最好实际读取时候打断点,来确定最开始的dummy bytes个数

7.在写flash时,注意要有小的间隔,否则有可能写入的数据完全不正确

接下来展示实测结果:

读ID:

 整片擦除:

此时回读前5个page:

进行空白检测:

然后再向前5个page循环写入从5开始的递增数:

此时回读新写入后的5个page,可见:

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
11-15 700

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值