embeddedsw/XilinxProcessorIPLib/drivers/iicps/examples/xiicps_eeprom_intr_example.c
P L Sai Krishna a1f6e45ede iicps: Modified the examples to support peripheral tests.
This patch modifies the examples such that these examples
will run smoothly in peripheral tests.
Modified the API prototypes.
Added TESTAPP macro checks.

Signed-off-by: P L Sai Krishna <lakshmis@xilinx.com>
Reviewed-by: Punnaiah Choudary Kalluri <punnaia@xilinx.com>
2015-08-18 12:23:28 +05:30

623 lines
17 KiB
C

/******************************************************************************
*
* Copyright (C) 2010 - 2014 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 xiicps_eeprom_intr_example.c
*
* This file consists of a interrutp mode design example which uses the Xilinx
* PS IIC device and XIicPs driver to exercise the EEPROM.
*
* The XIicPs_MasterSend() API is used to transmit the data and the
* XIicPs_MasterRecv() API is used to receive the data.
*
* The example is tested with a 2Kb/8Kb serial IIC EEPROM (ST M24C02/M24C08).
* The WP pin of this EEPROM is hardwired to ground on the HW in which this
* was tested.
*
* The AddressType should be u8 as the address pointer in the on-board
* EEPROM is 1 bytes.
*
* This code assumes that no Operating System is being used.
*
* @note
*
* None.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- ---------------------------------------------------------
* 1.00a sdm 03/15/10 First release
* 1.01a sg 04/13/12 Added MuxInit function for initializing the IIC Mux
* on the ZC702 board and to configure it for accessing
* the IIC EEPROM.
* Updated to use usleep instead of delay loop
* 1.04a hk 09/03/13 Removed GPIO code to pull MUX out of reset - CR#722425.
* 2.3 sk 10/07/14 Removed multiple initializations for read buffer.
*
* </pre>
*
******************************************************************************/
/***************************** Include Files *********************************/
#include "xparameters.h"
#include "sleep.h"
#include "xiicps.h"
#include "xscugic.h"
#include "xil_exception.h"
#include "xil_printf.h"
#include "xplatform_info.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 IIC_DEVICE_ID XPAR_XIICPS_0_DEVICE_ID
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
#define IIC_INTR_ID XPAR_XIICPS_0_INTR
/*
* The following constant defines the address of the IIC Slave device on the
* IIC bus. Note that since the address is only 7 bits, this constant is the
* address divided by 2.
*/
#define IIC_SLAVE_ADDR 0x54
#define IIC_SCLK_RATE 100000
#define IIC_MUX_ADDRESS 0x74
/*
* The page size determines how much data should be written at a time.
* The write function should be called with this as a maximum byte count.
*/
#define MAX_SIZE 32
#define PAGE_SIZE_16 16
#define PAGE_SIZE_32 32
/*
* The Starting address in the IIC EEPROM on which this test is performed.
*/
#define EEPROM_START_ADDRESS 0
/**************************** Type Definitions *******************************/
/*
* The AddressType should be u8 as the address pointer in the on-board
* EEPROM is 1 byte.
*/
typedef u16 AddressType;
/***************** Macros (Inline Functions) Definitions *********************/
/************************** Function Prototypes ******************************/
int IicPsEepromIntrExample(XScuGic *InterruptController, XIicPs *IicInstance,
u16 DeviceId, u16 IntrId);
static int EepromWriteData(XIicPs *IicInstance, u16 ByteCount);
static int MuxInit(XIicPs *IicInstance);
static int EepromReadData(XIicPs *IicInstance, u8 *BufferPtr, u16 ByteCount);
static int SetupInterruptSystem(XScuGic *InterruptController,
XIicPs * IicInstPtr, u16 IntrId);
static void Handler(void *CallBackRef, u32 Event);
/************************** Variable Definitions *****************************/
#ifndef TESTAPP_GEN
XIicPs IicInstance; /* The instance of the IIC device. */
XScuGic InterruptController; /* The instance of the Interrupt Controller. */
#endif
u32 Platform;
/*
* Write buffer for writing a page.
*/
u8 WriteBuffer[sizeof(AddressType) + MAX_SIZE];
u8 ReadBuffer[MAX_SIZE]; /* Read buffer for reading a page. */
volatile u8 TransmitComplete; /* Flag to check completion of Transmission */
volatile u8 ReceiveComplete; /* Flag to check completion of Reception */
volatile u32 TotalErrorCount;
/************************** Function Definitions *****************************/
/*****************************************************************************/
/**
* Main function to call the Iic EEPROM interrupt example.
*
* @param None.
*
* @return XST_SUCCESS if successful else XST_FAILURE.
*
* @note None.
*
******************************************************************************/
#ifndef TESTAPP_GEN
int main(void)
{
int Status;
xil_printf("IIC EEPROM Interrupt Example Test \r\n");
/*
* Run the Iic EEPROM interrupt mode example.
*/
Status = IicPsEepromIntrExample(&InterruptController, &IicInstance,
IIC_DEVICE_ID, IIC_INTR_ID);
if (Status != XST_SUCCESS) {
xil_printf("IIC EEPROM Interrupt Example Test Failed\r\n");
return XST_FAILURE;
}
xil_printf("Successfully ran IIC EEPROM Interrupt Example Test\r\n");
return XST_SUCCESS;
}
#endif
/*****************************************************************************/
/**
* This function writes, reads, and verifies the data to the IIC EEPROM. It
* does the write as a single page write, performs a buffered read.
*
* @param None.
*
* @return XST_SUCCESS if successful else XST_FAILURE.
*
* @note None.
*
******************************************************************************/
int IicPsEepromIntrExample(XScuGic *InterruptController, XIicPs *IicInstance,
u16 DeviceId, u16 IntrId)
{
u32 Index;
int Status;
XIicPs_Config *ConfigPtr; /* Pointer to configuration data */
AddressType Address = EEPROM_START_ADDRESS;
int WrBfrOffset;
int PageSize;
/*
* Initialize the IIC driver so that it is ready to use.
*/
ConfigPtr = XIicPs_LookupConfig(DeviceId);
if (ConfigPtr == NULL) {
return XST_FAILURE;
}
Status = XIicPs_CfgInitialize(IicInstance, ConfigPtr,
ConfigPtr->BaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Setup the Interrupt System.
*/
Status = SetupInterruptSystem(InterruptController, IicInstance, IntrId);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Setup the handlers for the IIC that will be called from the
* interrupt context when data has been sent and received, specify a
* pointer to the IIC driver instance as the callback reference so
* the handlers are able to access the instance data.
*/
XIicPs_SetStatusHandler(IicInstance, (void *) IicInstance, Handler);
/*
* Set the IIC serial clock rate.
*/
XIicPs_SetSClk(IicInstance, IIC_SCLK_RATE);
/*
* Set the channel value in IIC Mux if
* it is Zynq platform
*/
Platform = XGetPlatform_Info();
if(Platform == XPLAT_ZYNQ) {
Status = MuxInit(IicInstance);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
}
/*
* Initialize the data to write and the read buffer.
*/
if (Platform == XPLAT_ZYNQ) {
PageSize = PAGE_SIZE_16;
WriteBuffer[0] = (u8) (Address);
WrBfrOffset = 1;
} else {
PageSize = PAGE_SIZE_32;
WriteBuffer[0] = (u8) (Address >> 8);
WriteBuffer[1] = (u8) (Address);
WrBfrOffset = 2;
}
for (Index = 0; Index < PageSize; Index++) {
WriteBuffer[WrBfrOffset + Index] = 0xFF;
ReadBuffer[Index] = 0;
}
/*
* Write to the EEPROM.
*/
Status = EepromWriteData(IicInstance, WrBfrOffset + PageSize);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Read from the EEPROM.
*/
Status = EepromReadData(IicInstance, ReadBuffer, PageSize);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Verify the data read against the data written.
*/
for (Index = 0; Index < PageSize; Index++) {
if (ReadBuffer[Index] != WriteBuffer[Index + WrBfrOffset]) {
return XST_FAILURE;
}
}
/*
* Initialize the data to write and the read buffer.
*/
if (Platform == XPLAT_ZYNQ) {
WriteBuffer[0] = (u8) (Address);
WrBfrOffset = 1;
} else {
WriteBuffer[0] = (u8) (Address >> 8);
WriteBuffer[1] = (u8) (Address);
WrBfrOffset = 2;
}
for (Index = 0; Index < PageSize; Index++) {
WriteBuffer[WrBfrOffset + Index] = Index + 10;
ReadBuffer[Index] = 0;
}
/*
* Write to the EEPROM.
*/
Status = EepromWriteData(IicInstance, WrBfrOffset + PageSize);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Read from the EEPROM.
*/
Status = EepromReadData(IicInstance, ReadBuffer, PageSize);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Verify the data read against the data written.
*/
for (Index = 0; Index < PageSize; Index++) {
if (ReadBuffer[Index] != WriteBuffer[Index + WrBfrOffset]) {
return XST_FAILURE;
}
}
return XST_SUCCESS;
}
/*****************************************************************************/
/**
* This function writes a buffer of data to the IIC serial EEPROM.
*
* @param ByteCount contains the number of bytes in the buffer to be
* written.
*
* @return XST_SUCCESS if successful else XST_FAILURE.
*
* @note The Byte count should not exceed the page size of the EEPROM as
* noted by the constant PAGE_SIZE.
*
******************************************************************************/
static int EepromWriteData(XIicPs *IicInstance, u16 ByteCount)
{
TransmitComplete = FALSE;
/*
* Send the Data.
*/
XIicPs_MasterSend(IicInstance, WriteBuffer,
ByteCount, IIC_SLAVE_ADDR);
/*
* Wait for the entire buffer to be sent, letting the interrupt
* processing work in the background, this function may get
* locked up in this loop if the interrupts are not working
* correctly.
*/
while (TransmitComplete == FALSE) {
if (0 != TotalErrorCount) {
return XST_FAILURE;
}
}
/*
* Wait until bus is idle to start another transfer.
*/
while (XIicPs_BusIsBusy(IicInstance));
/*
* Wait for a bit of time to allow the programming to complete
*/
usleep(250000);
return XST_SUCCESS;
}
/*****************************************************************************/
/**
* This function reads data from the IIC serial EEPROM into a specified buffer.
*
* @param BufferPtr contains the address of the data buffer to be filled.
* @param ByteCount contains the number of bytes in the buffer to be read.
*
* @return XST_SUCCESS if successful else XST_FAILURE.
*
* @note None.
*
******************************************************************************/
static int EepromReadData(XIicPs *IicInstance, u8 *BufferPtr, u16 ByteCount)
{
int Status;
AddressType Address = EEPROM_START_ADDRESS;
int WrBfrOffset;
/*
* Position the Pointer in EEPROM.
*/
if (Platform == XPLAT_ZYNQ) {
WriteBuffer[0] = (u8) (Address);
WrBfrOffset = 1;
} else {
WriteBuffer[0] = (u8) (Address >> 8);
WriteBuffer[1] = (u8) (Address);
WrBfrOffset = 2;
}
Status = EepromWriteData(IicInstance, WrBfrOffset);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
ReceiveComplete = FALSE;
/*
* Receive the Data.
*/
XIicPs_MasterRecv(IicInstance, BufferPtr,
ByteCount, IIC_SLAVE_ADDR);
while (ReceiveComplete == FALSE) {
if (0 != TotalErrorCount) {
return XST_FAILURE;
}
}
/*
* Wait until bus is idle to start another transfer.
*/
while (XIicPs_BusIsBusy(IicInstance));
return XST_SUCCESS;
}
/******************************************************************************/
/**
*
* This function setups the interrupt system such that interrupts can occur
* for the IIC.
*
* @param IicPsPtr contains a pointer to the instance of the Iic
* which is going to be connected to the interrupt controller.
*
* @return XST_SUCCESS if successful, otherwise XST_FAILURE.
*
* @note None.
*
*******************************************************************************/
static int SetupInterruptSystem(XScuGic *InterruptController, XIicPs *IicPsPtr,
u16 IntrId)
{
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(InterruptController, 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_IRQ_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
InterruptController);
/*
* 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(InterruptController, IntrId,
(Xil_InterruptHandler)XIicPs_MasterInterruptHandler,
(void *)IicPsPtr);
if (Status != XST_SUCCESS) {
return Status;
}
/*
* Enable the interrupt for the Iic device.
*/
XScuGic_Enable(InterruptController, IntrId);
/*
* Enable interrupts in the Processor.
*/
Xil_ExceptionEnable();
return XST_SUCCESS;
}
/*****************************************************************************/
/**
*
* This function is the handler which performs processing to handle data events
* from the IIC. It is called from an interrupt context such that the amount
* of processing performed should be minimized.
*
* This handler provides an example of how to handle data for the IIC and
* is application specific.
*
* @param CallBackRef contains a callback reference from the driver, in
* this case it is the instance pointer for the IIC driver.
* @param Event contains the specific kind of event that has occurred.
* @param EventData contains the number of bytes sent or received for sent
* and receive events.
*
* @return None.
*
* @note None.
*
*******************************************************************************/
void Handler(void *CallBackRef, u32 Event)
{
/*
* All of the data transfer has been finished.
*/
if (0 != (Event & XIICPS_EVENT_COMPLETE_RECV)){
ReceiveComplete = TRUE;
} else if (0 != (Event & XIICPS_EVENT_COMPLETE_SEND)) {
TransmitComplete = TRUE;
} else if (0 == (Event & XIICPS_EVENT_SLAVE_RDY)){
/*
* If it is other interrupt but not slave ready interrupt, it is
* an error.
* Data was received with an error.
*/
TotalErrorCount++;
}
}
/*****************************************************************************/
/**
* This function initializes the IIC MUX to select EEPROM.
*
* @param None.
*
* @return XST_SUCCESS if pass, otherwise XST_FAILURE.
*
* @note None.
*
****************************************************************************/
static int MuxInit(XIicPs *IicInstance)
{
u8 WriteBuffer;
u8 MuxIicAddr = IIC_MUX_ADDRESS;
u8 Buffer = 0;
/*
* Channel select value for EEPROM.
*/
WriteBuffer = 0x04;
TransmitComplete = FALSE;
/*
* Send the Data.
*/
XIicPs_MasterSend(IicInstance, &WriteBuffer,1, MuxIicAddr);
while (TransmitComplete == FALSE) {
if (0 != TotalErrorCount) {
return XST_FAILURE;
}
}
/*
* Wait until bus is idle to start another transfer.
*/
while (XIicPs_BusIsBusy(IicInstance));
ReceiveComplete = FALSE;
/*
* Receive the Data.
*/
XIicPs_MasterRecv(IicInstance, &Buffer,1, MuxIicAddr);
while (ReceiveComplete == FALSE) {
if (0 != TotalErrorCount) {
return XST_FAILURE;
}
}
/*
* Wait until bus is idle to start another transfer.
*/
while (XIicPs_BusIsBusy(IicInstance));
return XST_SUCCESS;
}