xilisf: Added examples to test QSPIPSU interface.

This patch add polled and interrupt examples to test
QSPIPSU flash interface.

Signed-off-by: P L Sai Krishna <lakshmis@xilinx.com>
Reviewed-by: Harini Katakam <harinik@xilinx.com>
This commit is contained in:
P L Sai Krishna 2015-08-07 21:41:41 +05:30 committed by Nava kishore Manne
parent 37e2397703
commit 2d669b2c21
2 changed files with 1298 additions and 0 deletions

View file

@ -0,0 +1,740 @@
/******************************************************************************
*
* Copyright (C) 2012 - 2015 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
/*****************************************************************************/
/**
*
* @file xilisf_qspipsu_flash_intr_example.c
*
*
* This file contains a design example using the XILISF Library in
* interrupt mode with a serial FLASH device. This examples performs
* some transfers in Auto mode and Manual start mode, to illustrate the modes
* available.
* The hardware which this example runs on, must have a serial FLASH (Numonyx
* N25Q, Winbond W25Q, or Spansion S25FL) for it to run. This example has been
* tested with the Numonyx Serial Flash (N25Q128).
*
* @note
*
* None.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- --- -------- -----------------------------------------------
* 5.4 sk 08/07/15 First release
*
*</pre>
*
******************************************************************************/
/***************************** Include Files *********************************/
#include "xparameters.h" /**< EDK generated parameters */
#include "xscugic.h" /**< Interrupt controller device driver */
#include "xil_exception.h"
#include "xil_printf.h"
#include <xilisf.h> /**< Serial Flash Library header file */
/************************** Constant Definitions *****************************/
/** @name Device ID's
*
* @{
*/
/*
* 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_XQSPIPSU_0_DEVICE_ID
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
#define QSPI_INTR_ID XPAR_XQSPIPS_0_INTR
/*@}*/
/**
* 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 DATA_OFFSET 5 /**< Data byte offset for fast, dual
and quad reads */
#define DUMMY_SIZE 1 /**< Number of dummy bytes for fast,
dual and quad reads */
/**
* 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 NUM_PAGES 0x10000 /**< Number of Pages in the flash */
#define PAGE_SIZE 256 /**< Page Size for Read/Write Operation */
/**
* Number of flash pages to be written.
*/
#define PAGE_COUNT 16 /**< Number of Pages for
Read/Write Operation */
/*
* Max page size to initialize write and read buffer
*/
#define MAX_PAGE_SIZE 1024
/**
* Flash address to which data is to be written.
*/
#define TEST_ADDRESS 0x0080000 /**< Test Address in the flash */
#define UNIQUE_VALUE 0x05 /**< Unique Value for Test */
/**
* 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 /**< Max Data Calculated by
multiplying Page count and Page Size*/
/**
* The following constant defines the slave select signal that is used to
* to select the FLASH device on the QSPI bus, this signal is typically
* connected to the chip select of the device
*/
#define FLASH_QSPI_SELECT 0x01
#define INTR_MODE 1 /**< Interrupt Mode Enable */
/**************************** Type Definitions *******************************/
/***************** Macros (Inline Functions) Definitions *********************/
/************************** Function Prototypes ******************************/
static int QspiSetupIntrSystem(XScuGic *IntcInstancePtr,
XQspiPsu *QspiInstancePtr, u16 QspiIntrId);
static void QspiDisableIntrSystem(XScuGic *IntcInstancePtr, u16 QspiIntrId);
void XilIsf_Handler(void *CallBackRef, u32 StatusEvent, unsigned int ByteCount);
int FlashErase(XIsf *InstancePtr, u32 Address, u32 ByteCount);
int FlashWrite(XIsf *InstancePtr, u32 Address, u32 ByteCount, u8 Command);
int FlashRead(XIsf *InstancePtr, u32 Address, u32 ByteCount, u8 Command);
int QspiFlashIntrExample(XScuGic *IntcInstancePtr, XQspiPsu *QspiInstancePtr,
u16 QspiDeviceId, u16 QspiIntrId);
u32 SectorMask(u32 SectorSize);
/************************** 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 XScuGic IntcInstance;
static XQspiPsu QspiInstance;
static XIsf Isf;
/**
* The following variables are shared between non-interrupt processing and
* interrupt processing such that they must be global.
*/
volatile int TransferInProgress;
/**
* The following variable tracks any errors that occur during interrupt
* processing
*/
int ErrorCount;
/**
* 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 eeprom and they
* are global to avoid having large buffers on the stack
*/
u8 ReadBuffer[(PAGE_COUNT * MAX_PAGE_SIZE) + (DATA_OFFSET + DUMMY_SIZE)*8] __attribute__ ((aligned(64)));
u8 WriteBuffer[(PAGE_COUNT * MAX_PAGE_SIZE) + DATA_OFFSET];
u8 IsfWriteBuffer[PAGE_SIZE + XISF_CMD_SEND_EXTRA_BYTES];/**< IsfWrite Buffer
used in XilISF Initialization */
/*****************************************************************************/
/**
*
* Main function to call the QSPIPSU Flash example.
*
* @return XST_SUCCESS if successful, otherwise XST_FAILURE.
*
* @note None
*
******************************************************************************/
int main(void)
{
int Status;
xil_printf("QSPIPSU FLASH Interrupt Example Test \r\n");
/*
* Run the QSPIPSU Interrupt example.
*/
Status = QspiFlashIntrExample(&IntcInstance, &QspiInstance,
QSPI_DEVICE_ID, QSPI_INTR_ID);
if (Status != XST_SUCCESS) {
xil_printf("QSPIPSU FLASH Interrupt Example Test Failed\r\n");
return XST_FAILURE;
}
xil_printf("Successfully ran QSPIPSU FLASH Interrupt Example Test\r\n");
return XST_SUCCESS;
}
/****************************************************************************/
/**
* The purpose of this function is to illustrate how to use the XQspiPsu
* device driver in interrupt mode. This function writes and reads data
* from a serial FLASH.
*
* @param IntcInstancePtr is the instance of the interrupt
* @param QspiInstancePtr is the Pointer to the qspipsu driver instance
* @param QspiDeviceId is the Device ID of qspipsu
* @param QspiIntrId is the interrupt ID for QSPIPSU driver
*
* @return XST_SUCCESS if successful else XST_FAILURE.
*
* @note
*
* This function calls other functions which contain loops that may be infinite
* if interrupts are not working such that it may not return. If the device
* slave select is not correct and the device is not responding on bus it will
* read a status of 0xFF for the status register as the bus is pulled up.
*
*****************************************************************************/
int QspiFlashIntrExample(XScuGic *IntcInstancePtr, XQspiPsu *QspiInstancePtr,
u16 QspiDeviceId, u16 QspiIntrId)
{
int Status;
u8 *BufferPtr;
u8 UniqueValue;
int Count;
int Page;
XQspiPsu_Config *ConfigPtr; /* Pointer to Configuration ROM data */
u32 Options;
/*
* Lookup the device configuration in the temporary CROM table. Use this
* configuration info down below when initializing this component.
*/
ConfigPtr = XQspiPsu_LookupConfig(QspiDeviceId);
if (ConfigPtr == NULL) {
return XST_DEVICE_NOT_FOUND;
}
Status = XQspiPsu_CfgInitialize(QspiInstancePtr, ConfigPtr,
ConfigPtr->BaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Set the QSPI options
*/
Options = XQSPIPSU_MANUAL_START_OPTION;
Status = XIsf_SetSpiConfiguration(&Isf, QspiInstancePtr,
Options, XISF_SPI_PRESCALER);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/* Initialize the XILISF Library */
XIsf_Initialize(&Isf, QspiInstancePtr, FLASH_QSPI_SELECT,
IsfWriteBuffer);
XIsf_SetTransferMode(&Isf, XISF_INTERRUPT_MODE);
/*
* Connect the Qspipsu device to the interrupt subsystem such that
* interrupts can occur. This function is application specific
*/
Status = QspiSetupIntrSystem(IntcInstancePtr, QspiInstancePtr,
QspiIntrId);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Setup the handler for the QSPI that will be called from the
* interrupt context when an QSPI status occurs, specify a pointer to
* the QSPI driver instance as the callback reference so the handler is
* able to access the instance data
*/
XIsf_SetStatusHandler(&Isf, QspiInstancePtr,
(XQspiPsu_StatusHandler) XilIsf_Handler);
/*
* Initialize the write buffer for a pattern to write to the FLASH
* and the read buffer to zero so it can be verified after the read,
* the test value that is added to the unique value allows the value
* to be changed in a debug environment to guarantee
*/
for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < PAGE_SIZE;
Count++, UniqueValue++) {
WriteBuffer[Count] = (u8)(UniqueValue + Test);
}
memset(ReadBuffer, 0x00, sizeof(ReadBuffer));
Status = FlashErase(&Isf, TEST_ADDRESS, MAX_DATA);
if(Status != XST_SUCCESS){
return XST_FAILURE;
}
/*
* Write the data in the write buffer to the serial FLASH a page at a
* time, starting from TEST_ADDRESS
*/
for (Page = 0; Page < PAGE_COUNT; Page++) {
FlashWrite(&Isf, (Page * PAGE_SIZE) + TEST_ADDRESS,
PAGE_SIZE, XISF_WRITE);
}
/*
* Read the contents of the FLASH from TEST_ADDRESS, using Normal Read
* command
*/
FlashRead(&Isf, TEST_ADDRESS, MAX_DATA, XISF_QUAD_OP_FAST_READ);
/*
* Setup a pointer to the start of the data that was read into the read
* buffer and verify the data read is the data that was written
*/
BufferPtr = ReadBuffer;
for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < MAX_DATA;
Count++, UniqueValue++) {
if (BufferPtr[Count] != (u8)(UniqueValue + Test)) {
return XST_FAILURE;
}
}
QspiDisableIntrSystem(IntcInstancePtr, QspiIntrId);
return XST_SUCCESS;
}
/*****************************************************************************/
/**
* This function is the handler which performs processing for the QSPIPSU driver.
* It is called from an interrupt context such that the amount of processing
* performed should be minimized. It is called when a transfer of QSPI data
* completes or an error occurs.
*
* This handler provides an example of how to handle QSPIPSU interrupts but is
* application specific.
*
* @param CallBackRef is a reference passed to the handler.
* @param StatusEvent is the status of the QSPIPSU .
* @param ByteCount is the number of bytes transferred.
*
* @return None
*
* @note None.
*
******************************************************************************/
void XilIsf_Handler(void *CallBackRef, u32 StatusEvent, unsigned int ByteCount)
{
/*
* Indicate the transfer on the QSPI bus is no longer in progress
* regardless of the status event
*/
TransferInProgress = FALSE;
/*
* If the event was not transfer done, then track it as an error
*/
if (StatusEvent != XST_SPI_TRANSFER_DONE) {
ErrorCount++;
}
}
/*****************************************************************************/
/**
*
* This function writes to the serial FLASH connected to the QSPIPSU interface.
* The FLASH contains a 256 byte write buffer which can be filled and then a
* write is automatically performed by the device. 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 InstancePtr is a pointer to the XIsf 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.
*
* @return None.
*
* @note None.
*
******************************************************************************/
int FlashWrite(XIsf *InstancePtr, u32 Address, u32 ByteCount, u8 Command)
{
XIsf_WriteParam WriteParam;
int Status;
WriteParam.Address = Address;
WriteParam.NumBytes = ByteCount;
WriteParam.WritePtr = WriteBuffer;
/*
* Perform the Write operation.
*/
TransferInProgress = TRUE;
Status = XIsf_Write(&Isf, Command, (void*) &WriteParam);
if(Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Wait till the Transfer is complete and check if there are any errors
* in the transaction.
*/
while(TransferInProgress);
if(ErrorCount != 0) {
return XST_FAILURE;
}
return XST_SUCCESS;
}
/*****************************************************************************/
/**
* This function reads from the serial FLASH connected to the
* QSPIPSU interface.
*
* @param InstancePtr is a pointer to the XIsf 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.
*
* @return None.
*
* @note None.
*
******************************************************************************/
int FlashRead(XIsf *InstancePtr, u32 Address, u32 ByteCount, u8 Command)
{
XIsf_ReadParam ReadParam;
int Status;
/*
* Set the
* - Address in the Serial Flash where the data is to be read from.
* - Number of bytes to be read from the Serial Flash.
* - Read Buffer to which the data is to be read.
*/
ReadParam.Address = Address;
ReadParam.NumBytes = ByteCount;
ReadParam.ReadPtr = ReadBuffer;
/*
* Perform the Read operation.
*/
TransferInProgress = TRUE;
Status = XIsf_Read(&Isf, Command, (void*) &ReadParam);
if(Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Wait till the Transfer is complete and check if there are any errors
* in the transaction.
*/
while(TransferInProgress);
if(ErrorCount != 0) {
return XST_FAILURE;
}
return XST_SUCCESS;
}
/*****************************************************************************/
/**
*
* This function erases the sectors in the serial FLASH connected to the
* QSPIPSU interface.
*
* @param InstancePtr is a pointer to the XIsf 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(XIsf *InstancePtr, u32 Address, u32 ByteCount)
{
int Status;
int Sector;
u32 NumSect;
u32 SectorSize;
u32 NumSectors;
u32 Sector_Mask;
SectorSize = Isf.SectorSize;
NumSectors = Isf.NumSectors;
/* Get the sector mask value */
Sector_Mask = SectorMask(SectorSize);
/*
* If erase size is same as the total size of the flash, use bulk erase
* command
*/
if (ByteCount == (NumSectors * SectorSize)) {
/*
* Perform the Bulk Erase operation.
*/
TransferInProgress = TRUE;
Status = XIsf_Erase(InstancePtr, XISF_BULK_ERASE, Address);
if(Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Wait till the Transfer is complete and check if there
* are any errors in the transaction.
*/
while(TransferInProgress);
if(ErrorCount != 0) {
return XST_FAILURE;
}
}
/*
* Calculate no. of sectors to erase based on byte count
*/
NumSect = ByteCount/SectorSize + 1;
/*
* If ByteCount to k sectors,
* but the address range spans from N to N+k+1 sectors, then
* increment no. of sectors to be erased
*/
if( ((Address + ByteCount) & Sector_Mask) ==
((Address + (NumSect * SectorSize)) &
Sector_Mask) ) {
NumSect++;
}
/*
* If the erase size is less than the total size of the flash, use
* sector erase command
*/
for (Sector = 0; Sector < NumSect; Sector++) {
/*
* Perform the Bulk Erase operation.
*/
TransferInProgress = TRUE;
Status = XIsf_Erase(InstancePtr, XISF_SECTOR_ERASE, Address);
if(Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Wait till the Transfer is complete and check if there
* are any errors in the transaction.
*/
while(TransferInProgress);
if(ErrorCount != 0) {
return XST_FAILURE;
}
Address += SectorSize;
}
return XST_SUCCESS;
}
/*****************************************************************************/
/**
*
* This function setups the interrupt system for an Qspipsu device.
*
* @param IntcInstancePtr is a pointer to the instance of the Intc device.
* @param QspiInstancePtr is a pointer to the instance of the Qspipsu device.
* @param QspiIntrId is the interrupt Id for an QSPIPSU device.
*
* @return XST_SUCCESS if successful, otherwise XST_FAILURE.
*
* @note None.
*
******************************************************************************/
static int QspiSetupIntrSystem(XScuGic *IntcInstancePtr,
XQspiPsu *QspiInstancePtr, u16 QspiIntrId)
{
int Status;
XScuGic_Config *IntcConfig; /* Instance of the interrupt controller */
Xil_ExceptionInit();
/*
* Initialize the interrupt controller driver so that it is ready to
* use.
*/
IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
if (NULL == IntcConfig) {
return XST_FAILURE;
}
Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,
IntcConfig->CpuBaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Connect the interrupt controller interrupt handler to the hardware
* interrupt handling logic in the processor.
*/
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
IntcInstancePtr);
/*
* Connect the device driver handler that will be called when an
* interrupt for the device occurs, the handler defined above performs
* the specific interrupt processing for the device.
*/
Status = XScuGic_Connect(IntcInstancePtr, QspiIntrId,
(Xil_ExceptionHandler)XQspiPsu_InterruptHandler,
(void *)QspiInstancePtr);
if (Status != XST_SUCCESS) {
return Status;
}
/*
* Enable the interrupt for the Qspi device.
*/
XScuGic_Enable(IntcInstancePtr, QspiIntrId);
/*
* Enable interrupts in the Processor.
*/
Xil_ExceptionEnable();
return XST_SUCCESS;
}
/*****************************************************************************/
/**
*
* This function disables the interrupts that occur for the Qspipsu device.
*
* @param IntcInstancePtr is the pointer to an INTC instance.
* @param QspiIntrId is the interrupt Id for an QSPIPSU device.
*
* @return None.
*
* @note None.
*
******************************************************************************/
static void QspiDisableIntrSystem(XScuGic *IntcInstancePtr, u16 QspiIntrId)
{
/*
* Disable the interrupt for the QSPI device.
*/
XScuGic_Disable(IntcInstancePtr, QspiIntrId);
/*
* Disconnect and disable the interrupt for the Qspi device.
*/
XScuGic_Disconnect(IntcInstancePtr, QspiIntrId);
}
/*****************************************************************************/
/**
*
* This function calculates the sector mask based upon the sector size value
*
*
* @param SectorSize is the size of the sector of the flash
* available on the board.
*
* @return will return the sector mask after calculation.
*
* @note None.
*
******************************************************************************/
u32 SectorMask(u32 SectorSize){
u32 Mask;
switch(SectorSize){
case 0x10000:
Mask = 0xFFFF0000;
break;
case 0x20000:
Mask = 0xFFFE0000;
break;
case 0x40000:
Mask = 0xFFFC0000;
break;
case 0x80000:
Mask = 0xFFF80000;
break;
default:
break;
}
return Mask;
}

View file

@ -0,0 +1,558 @@
/******************************************************************************
*
* Copyright (C) 2012 - 2015 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
/*****************************************************************************/
/**
*
* @file xilisf_qspipsu_flash_polled_example.c
*
*
* This file contains a design example using the XILISF Library in
* interrupt mode with a serial FLASH device. This examples performs
* some transfers in Auto mode and Manual start mode, to illustrate the modes
* available.
* The hardware which this example runs on, must have a serial FLASH (Numonyx
* N25Q, Winbond W25Q, or Spansion S25FL) for it to run. This example has been
* tested with the Numonyx Serial Flash (N25Q128).
*
* @note
*
* None.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- --- -------- -----------------------------------------------
* 5.4 sk 08/07/15 First Release.
*
*</pre>
*
******************************************************************************/
/***************************** Include Files *********************************/
#include "xparameters.h" /* EDK generated parameters */
#include "xscugic.h" /* Interrupt controller device driver */
#include "xil_exception.h"
#include "xil_printf.h"
#include "xilisf.h" /* Serial Flash Library header file */
/************************** Constant Definitions *****************************/
/** @name Device ID's
*
* @{
*/
/*
* 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_XQSPIPSU_0_DEVICE_ID
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
#define QSPI_INTR_ID XPAR_XQSPIPS_0_INTR
/*@}*/
/**
* 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 DATA_OFFSET 5 /**< Data byte offset for fast, dual
and quad reads */
#define DUMMY_SIZE 1 /**< Number of dummy bytes for fast,
dual and quad reads */
/**
* The following constants specify the page size and number of
* pages for the FLASH. The page size specifies a max number of
* bytes that can be written to the FLASH with a single transfer.
*/
#define NUM_PAGES 0x10000 /**< Number of Pages in the flash */
#define PAGE_SIZE 256 /**< Page Size for Read/Write Operation */
/**
* Number of flash pages to be written.
*/
#define PAGE_COUNT 2 /**< Number of Pages for r/w Operation */
/*
* Max page size to initialize write and read buffer
*/
#define MAX_PAGE_SIZE 1024
/**
* Flash address to which data is ot be written.
*/
#define TEST_ADDRESS 0x1000000 /**< Test Address in the flash */
#define UNIQUE_VALUE 0x08 /**< Unique Value for Test */
/**
* 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 /**< Max Data Calculated by
multiplying Page count and Page Size */
/**
* The following constant defines the slave select signal that is used to
* to select the FLASH device on the QSPI bus, this signal is typically
* connected to the chip select of the device
*/
#define FLASH_QSPI_SELECT 0x01 /**< Interrupt Mode Enable */
/**************************** Type Definitions *******************************/
/***************** Macros (Inline Functions) Definitions *********************/
/************************** Function Prototypes ******************************/
int FlashErase(XIsf *InstancePtr, u32 Address, u32 ByteCount);
int FlashWrite(XIsf *InstancePtr, u32 Address, u32 ByteCount,
u8 Command);
int FlashRead(XIsf *InstancePtr, u32 Address, u32 ByteCount,
u8 Command);
int QspiFlashPollExample(XScuGic *IntcInstancePtr, XQspiPsu *QspiInstancePtr,
u16 QspiDeviceId, u16 QspiIntrId);
static u32 SectorMask(u32 SectorSize);
/************************** 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 XScuGic IntcInstance;
static XQspiPsu QspiInstance;
static XIsf Isf;
static XQspiPsu_Config *ConfigPtr; /**< Pointer to Configuration ROM data */
/**
* The following variables are shared between non-interrupt processing and
* interrupt processing such that they must be global.
*/
volatile int TransferInProgress;
/**
* 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_Polled = 7;
/**
* The following variables are used to read and write to the eeprom and they
* are global to avoid having large buffers on the stack
*/
u8 ReadBuffer[(PAGE_COUNT * MAX_PAGE_SIZE) + (DATA_OFFSET + DUMMY_SIZE)*8] __attribute__ ((aligned(64)));
u8 WriteBuffer[(PAGE_COUNT * MAX_PAGE_SIZE) + DATA_OFFSET];
u8 IsfWriteBuffer[PAGE_SIZE + XISF_CMD_SEND_EXTRA_BYTES];/**< IsfWrite Buffer
used in XilISF Initialization */
/*****************************************************************************/
/**
*
* Main function to call the QSPI Flash example.
*
* @return XST_SUCCESS if successful, otherwise XST_FAILURE.
*
* @note None
*
******************************************************************************/
int main(void)
{
int Status;
xil_printf("QSPIPSU FLASH Polling Example Test \r\n");
/*
* Run the Qspipsu Interrupt example.
*/
Status = QspiFlashPollExample(&IntcInstance, &QspiInstance,
QSPI_DEVICE_ID, QSPI_INTR_ID);
if (Status != XST_SUCCESS) {
xil_printf("QSPIPSU FLASH Polling Example Test Failed\r\n");
return XST_FAILURE;
}
xil_printf("Successfully ran QSPIPSU FLASH Polling Example Test\r\n");
return XST_SUCCESS;
}
/****************************************************************************/
/**
* The purpose of this function is to illustrate how to use the XQspiPsu
* device driver in interrupt mode. This function writes and reads data
* from a serial FLASH.
*
* @return XST_SUCCESS if successful else XST_FAILURE.
*
* @note
*
* This function calls other functions which contain loops that may be infinite
* if interrupts are not working such that it may not return. If the device
* slave select is not correct and the device is not responding on bus it will
* read a status of 0xFF for the status register as the bus is pulled up.
*
*****************************************************************************/
int QspiFlashPollExample(XScuGic *IntcInstancePtr, XQspiPsu *QspiInstancePtr,
u16 QspiDeviceId, u16 QspiIntrId)
{
u8 *BufferPtr;
u8 UniqueValue;
int Count;
int Page;
int Status;
u32 Options;
/*
* Lookup the device configuration in the temporary CROM table. Use this
* configuration info down below when initializing this component.
*/
ConfigPtr = XQspiPsu_LookupConfig(QspiDeviceId);
if (ConfigPtr == NULL) {
return XST_DEVICE_NOT_FOUND;
}
Status = XQspiPsu_CfgInitialize(QspiInstancePtr, ConfigPtr,
ConfigPtr->BaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Set the QSPI options
*/
Options = XQSPIPSU_MANUAL_START_OPTION;
XIsf_SetSpiConfiguration(&Isf, QspiInstancePtr, Options,
XISF_SPI_PRESCALER);
/* Initialize the XILISF Library */
XIsf_Initialize(&Isf, QspiInstancePtr, FLASH_QSPI_SELECT,
IsfWriteBuffer);
/*
* Initialize the write buffer for a pattern to write to the FLASH
* and the read buffer to zero so it can be verified after the read,
* the test value that is added to the unique value allows the value
* to be changed in a debug environment to guarantee
*/
for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < PAGE_SIZE;
Count++, UniqueValue++) {
WriteBuffer[Count] = (u8)(UniqueValue + Test_Polled);
}
memset(ReadBuffer, 0x00, sizeof(ReadBuffer));
Status = FlashErase(&Isf, TEST_ADDRESS, MAX_DATA);
if(Status != XST_SUCCESS){
return XST_FAILURE;
}
/*
* Write the data in the write buffer to the serial FLASH a page at a
* time, starting from TEST_ADDRESS
*/
for (Page = 0; Page < PAGE_COUNT; Page++) {
Status = FlashWrite(&Isf,
(Page * PAGE_SIZE) + TEST_ADDRESS, PAGE_SIZE,
XISF_WRITE);
if(Status != XST_SUCCESS){
return XST_FAILURE;
}
}
/******************************************************
******************QUAD OP FAST READ*******************
******************************************************/
/*
* Read the contents of the FLASH from TEST_ADDRESS, using QUAD IO
* Fast Read command
*/
Status = FlashRead(&Isf, TEST_ADDRESS, MAX_DATA,
XISF_QUAD_OP_FAST_READ);
if(Status != XST_SUCCESS){
return XST_FAILURE;
}
/*
* Setup a pointer to the start of the data that was read into the read
* buffer and verify the data read is the data that was written
*/
BufferPtr = ReadBuffer;
for (UniqueValue = UNIQUE_VALUE, Count = 0; Count < MAX_DATA;
Count++, UniqueValue++) {
if (BufferPtr[Count] != (u8)(UniqueValue + Test_Polled)) {
return XST_FAILURE;
}
}
return XST_SUCCESS;
}
/*****************************************************************************/
/**
*
* This function writes to the serial FLASH connected to the QSPIPSU interface.
* The FLASH contains a 256 byte write buffer which can be filled and then a
* write is automatically performed by the device. 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 InstancePtr is a pointer to the XIsf 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.
*
* @return None.
*
* @note None.
*
******************************************************************************/
int FlashWrite(XIsf *InstancePtr, u32 Address, u32 ByteCount,
u8 Command)
{
XIsf_WriteParam WriteParam;
int Status;
WriteParam.Address = Address;
WriteParam.NumBytes = ByteCount;
WriteParam.WritePtr = WriteBuffer;
/*
* Perform the Write operation.
*/
Status = XIsf_Write(&Isf, Command, (void*) &WriteParam);
if(Status != XST_SUCCESS) {
return XST_FAILURE;
}
return XST_SUCCESS;
}
/*****************************************************************************/
/**
* This function reads from the serial FLASH connected to the
* QSPIPSU interface.
*
* @param InstancePtr is a pointer to the XIsf 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.
*
* @return None.
*
* @note None.
*
******************************************************************************/
int FlashRead(XIsf *InstancePtr, u32 Address, u32 ByteCount, u8 Command)
{
XIsf_ReadParam ReadParam;
int Status;
/*
* Set the
* - Address in the Serial Flash where the data is to be read from.
* - Number of bytes ReadParam.NumDummyBytesto be read from the Serial Flash.
* - Read Buffer to which the data is to be read.
*/
ReadParam.Address = Address;
ReadParam.NumBytes = ByteCount;
ReadParam.ReadPtr = ReadBuffer;
/*
* Perform the Read operation.
*/
Status = XIsf_Read(&Isf, Command, (void*) &ReadParam);
if(Status != XST_SUCCESS) {
return XST_FAILURE;
}
return XST_SUCCESS;
}
/*****************************************************************************/
/**
*
* This function erases the sectors in the serial FLASH connected to the
* QSPIPSU interface.
*
* @param InstancePtr is a pointer to the XIsf 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(XIsf *InstancePtr, u32 Address, u32 ByteCount)
{
int Status;
int Sector;
u32 NumSect;
u32 SectorSize;
u32 NumSectors;
u32 Sector_Mask;
/*
* Get the value of Sector Size and Number of Sectors for the flash
*/
SectorSize = Isf.SectorSize;
NumSectors = Isf.NumSectors;
/* Get the sector mask value */
Sector_Mask = SectorMask(SectorSize);
/*
* If erase size is same as the total size of the flash, use bulk erase
* command
*/
if (ByteCount == (NumSectors * SectorSize)) {
if(InstancePtr->SpiInstPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_STACKED){
XQspiPsu_SelectFlash(InstancePtr->SpiInstPtr,
XQSPIPSU_SELECT_FLASH_CS_LOWER, XQSPIPSU_SELECT_FLASH_BUS_LOWER);
}
/*
* Call Bulk erase
*/
Status = XIsf_Erase(InstancePtr,
XISF_BULK_ERASE, Address);
if(Status != XST_SUCCESS) {
return XST_FAILURE;
}
if(InstancePtr->SpiInstPtr->Config.ConnectionMode == XQSPIPSU_CONNECTION_MODE_STACKED){
XQspiPsu_SelectFlash(InstancePtr->SpiInstPtr,
XQSPIPSU_SELECT_FLASH_CS_UPPER, XQSPIPSU_SELECT_FLASH_BUS_LOWER);
/*
* Call Bulk erase
*/
Status = XIsf_Erase(InstancePtr,
XISF_BULK_ERASE, Address);
if(Status != XST_SUCCESS) {
return XST_FAILURE;
}
}
return Status;
}
/*
* Calculate no. of sectors to erase based on byte count
*/
NumSect = ByteCount/SectorSize + 1;
/*
* If ByteCount to k sectors,
* but the address range spans from N to N+k+1 sectors, then
* increment no. of sectors to be erased
*/
if( ((Address + ByteCount) & Sector_Mask) ==
((Address + (NumSect * SectorSize)) &
Sector_Mask) ) {
NumSect++;
}
/*
* If the erase size is less than the total size of the flash, use
* sector erase command
*/
for (Sector = 0; Sector < NumSect; Sector++) {
/*
* Perform the Sector Erase operation.
*/
Status = XIsf_Erase(InstancePtr, XISF_SECTOR_ERASE, Address);
if(Status != XST_SUCCESS) {
return XST_FAILURE;
}
Address += SectorSize;
}
return XST_SUCCESS;
}
/*****************************************************************************/
/**
*
* This function calculates the sector mask based upon the sector size value
*
*
* @param SectorSize is the size of the sector of the flash
* available on the board.
*
* @return will return the sector mask after calculation.
*
* @note None.
*
******************************************************************************/
u32 SectorMask(u32 SectorSize){
u32 Mask;
switch(SectorSize){
case 0x10000:
Mask = 0xFFFF0000;
break;
case 0x20000:
Mask = 0xFFFE0000;
break;
case 0x40000:
Mask = 0xFFFC0000;
break;
case 0x80000:
Mask = 0xFFF80000;
break;
default:
break;
}
return Mask;
}