diff --git a/XilinxProcessorIPLib/drivers/iic/data/iic.mdd b/XilinxProcessorIPLib/drivers/iic/data/iic.mdd new file mode 100755 index 00000000..79f2dd4c --- /dev/null +++ b/XilinxProcessorIPLib/drivers/iic/data/iic.mdd @@ -0,0 +1,68 @@ +############################################################################## +# +# (c) Copyright 2005-2014 Xilinx, Inc. All rights reserved. +# +# This file contains confidential and proprietary information of Xilinx, Inc. +# and is protected under U.S. and international copyright and other +# intellectual property laws. +# +# DISCLAIMER +# This disclaimer is not a license and does not grant any rights to the +# materials distributed herewith. Except as otherwise provided in a valid +# license issued to you by Xilinx, and to the maximum extent permitted by +# applicable law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL +# FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS, +# IMPLIED, OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF +# MERCHANTABILITY, NON-INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; +# and (2) Xilinx shall not be liable (whether in contract or tort, including +# negligence, or under any other theory of liability) for any loss or damage +# of any kind or nature related to, arising under or in connection with these +# materials, including for any direct, or any indirect, special, incidental, +# or consequential loss or damage (including loss of data, profits, goodwill, +# or any type of loss or damage suffered as a result of any action brought by +# a third party) even if such damage or loss was reasonably foreseeable or +# Xilinx had been advised of the possibility of the same. +# +# CRITICAL APPLICATIONS +# Xilinx products are not designed or intended to be fail-safe, or for use in +# any application requiring fail-safe performance, such as life-support or +# safety devices or systems, Class III medical devices, nuclear facilities, +# applications related to the deployment of airbags, or any other applications +# that could lead to death, personal injury, or severe property or +# environmental damage (individually and collectively, "Critical +# Applications"). Customer assumes the sole risk and liability of any use of +# Xilinx products in Critical Applications, subject only to applicable laws +# and regulations governing limitations on product liability. +# +# THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE +# AT ALL TIMES. +# +# MODIFICATION HISTORY: +# +# Ver Who Date Changes +# -------- ------ -------- -------------------------------------------------- +# 3.0 adk 10/12/13 Removed support for xps_iic +############################################################################## +## @BEGIN_CHANGELOG EDK_M +## +## - Removed support for opb_iic +## +## @END_CHANGELOG + +## @BEGIN_CHANGELOG EDK_MS3 +## +## 06/16/10 sv Added support for axi_iic +## +## @END_CHANGELOG + +OPTION psf_version = 2.1; + +BEGIN driver iic + + OPTION supported_peripherals = (axi_iic); + OPTION driver_state = ACTIVE; + OPTION copyfiles = all; + OPTION VERSION = 3.1; + OPTION NAME = iic; + +END driver diff --git a/XilinxProcessorIPLib/drivers/iic/data/iic.tcl b/XilinxProcessorIPLib/drivers/iic/data/iic.tcl new file mode 100755 index 00000000..5508a87c --- /dev/null +++ b/XilinxProcessorIPLib/drivers/iic/data/iic.tcl @@ -0,0 +1,56 @@ +############################################################################### +# +# Copyright (C) 2004 - 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 THE +# XILINX CONSORTIUM 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. +# +# +# MODIFICATION HISTORY: +# Ver Who Date Changes +# -------- ------ -------- ------------------------------------ +# 3.0 adk 12/10/13 Updated as per the New Tcl API's +############################################################################## +## @BEGIN_CHANGELOG EDK_M +## Removed the local xdefine_canonical_xpars API as there is +## a common API in the tcl of the tools +## +## @END_CHANGELOG + +## @BEGIN_CHANGELOG EDK_LS3 +## Updated to handle the corner cases described in CR #518193 while +## generating canonical definitions +## +## @END_CHANGELOG + +#uses "xillib.tcl" + +proc generate {drv_handle} { + xdefine_include_file $drv_handle "xparameters.h" "XIic" "NUM_INSTANCES" "DEVICE_ID" "C_BASEADDR" "C_HIGHADDR" "C_TEN_BIT_ADR" "C_GPO_WIDTH" + xdefine_config_file $drv_handle "xiic_g.c" "XIic" "DEVICE_ID" "C_BASEADDR" "C_TEN_BIT_ADR" "C_GPO_WIDTH" + + xdefine_canonical_xpars $drv_handle "xparameters.h" "Iic" "DEVICE_ID" "C_BASEADDR" "C_HIGHADDR" "C_TEN_BIT_ADR" "C_GPO_WIDTH" +} diff --git a/XilinxProcessorIPLib/drivers/iic/data/iic_header.h b/XilinxProcessorIPLib/drivers/iic/data/iic_header.h new file mode 100644 index 00000000..9c153a8b --- /dev/null +++ b/XilinxProcessorIPLib/drivers/iic/data/iic_header.h @@ -0,0 +1,41 @@ +/****************************************************************************** +* +* Copyright (C) 2005 - 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 THE +* XILINX CONSORTIUM 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. +* +******************************************************************************/ +#ifndef IIC_HEADER_H /* prevent circular inclusions */ +#define IIC_HEADER_H /* by using protection macros */ + +#include "xil_types.h" +#include "xil_assert.h" +#include "xstatus.h" + +int IicSelfTestExample(u16 DeviceId); + +#endif diff --git a/XilinxProcessorIPLib/drivers/iic/data/iic_tapp.tcl b/XilinxProcessorIPLib/drivers/iic/data/iic_tapp.tcl new file mode 100755 index 00000000..1da4d080 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/iic/data/iic_tapp.tcl @@ -0,0 +1,140 @@ +############################################################################### +# +# Copyright (C) 2005 - 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 THE +# XILINX CONSORTIUM 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. +# +# MODIFICATION HISTORY: +# Ver Who Date Changes +# -------- ------ -------- ------------------------------------ +# 3.0 adk 12/10/13 Updated as per the New Tcl API's +############################################################################## + +## @BEGIN_CHANGELOG EDK_I +## +## - include header files +## +## @END_CHANGELOG + +## @BEGIN_CHANGELOG EDK_H +## +## - Added support for generation of multiple applications. +## All TCL procedures are now required to have a software +## project type as its first argument +## +## @END_CHANGELOG + +# Uses $XILINX_EDK/bin/lib/xillib_sw.tcl + +# ----------------------------------------------------------------- +# Software Project Types (swproj): +# 0 : MemoryTest - Calls basic memorytest routines from common driver dir +# 1 : PeripheralTest - Calls any existing polled_example and/or selftest +# ----------------------------------------------------------------- + +# ----------------------------------------------------------------- +# TCL Procedures: +# ----------------------------------------------------------------- + +proc gen_include_files {swproj mhsinst} { + if {$swproj == 0} { + return "" + } + if {$swproj == 1} { + set inc_file_lines {iic_header.h} + return $inc_file_lines + } +} + +proc gen_src_files {swproj mhsinst} { + if {$swproj == 0} { + return "" + } + if {$swproj == 1} { + set inc_file_lines {examples/xiic_selftest_example.c data/iic_header.h} + return $inc_file_lines + } +} + +proc gen_testfunc_def {swproj mhsinst} { + return "" +} + +proc gen_init_code {swproj mhsinst} { + return "" +} + +proc gen_testfunc_call {swproj mhsinst} { + + if {$swproj == 0} { + return "" + } + + set ipname [get_property NAME $mhsinst] + set deviceid [::hsi::utils::get_ip_param_name $mhsinst "DEVICE_ID"] + set stdout [get_property CONFIG.STDOUT [get_os]] + if { $stdout == "" || $stdout == "none" } { + set hasStdout 0 + } else { + set hasStdout 1 + } + + set testfunc_call "" + + if {${hasStdout} == 0} { + + append testfunc_call " + + { + int status; + + status = IicSelfTestExample(${deviceid}); + + }" + } else { + + append testfunc_call " + + { + int status; + + + print(\"\\r\\n Running IicSelfTestExample() for ${ipname}...\\r\\n\"); + + status = IicSelfTestExample(${deviceid}); + + if (status == 0) { + print(\"IicSelfTestExample PASSED\\r\\n\"); + } + else { + print(\"IicSelfTestExample FAILED\\r\\n\"); + } + }" + } + + return $testfunc_call +} diff --git a/XilinxProcessorIPLib/drivers/iic/examples/index.html b/XilinxProcessorIPLib/drivers/iic/examples/index.html new file mode 100755 index 00000000..1bdb9cfd --- /dev/null +++ b/XilinxProcessorIPLib/drivers/iic/examples/index.html @@ -0,0 +1,27 @@ + + +
+ + +Copyright � 1995-2014 Xilinx, Inc. All rights reserved.
+ + \ No newline at end of file diff --git a/XilinxProcessorIPLib/drivers/iic/examples/xiic_dynamic_eeprom_example.c b/XilinxProcessorIPLib/drivers/iic/examples/xiic_dynamic_eeprom_example.c new file mode 100644 index 00000000..84893a1c --- /dev/null +++ b/XilinxProcessorIPLib/drivers/iic/examples/xiic_dynamic_eeprom_example.c @@ -0,0 +1,666 @@ +/****************************************************************************** +* +* Copyright (C) 2006 - 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 THE +* XILINX CONSORTIUM 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 xiic_dynamic_eeprom_example.c +* +* This file consists of a Interrupt mode design example which uses the Xilinx +* IIC device and XIic driver to exercise the EEPROM in Dynamic controller mode. +* The XIic driver uses the complete FIFO functionality to transmit/receive data. +* +* This example writes/reads from the lower 256 bytes of the IIC EEPROMS. Please +* refer to the datasheets of the IIC EEPROM's for details about the internal +* addressing and page size of these devices. +* +* The XIic_DynMasterSend() API is used to transmit the data and +* XIic_DynMasterRecv() API is used to receive the data. +* +* This example is tested on ML300/ML310/ML403/ML501/ML507/ML510/ML605/SP601 and +* SP605 Xilinx boards. +* +* The ML310/ML410/ML510 boards have a on-board 64 Kb serial IIC EEPROM +* (Microchip 24LC64A). The WP pin of the IIC EEPROM is hardwired to ground on +* this board. +* +* The ML300 board has an on-board 32 Kb serial IIC EEPROM(Microchip 24LC32A). +* The WP pin of the IIC EEPROM has to be connected to ground for this example. +* The WP is connected to pin Y3 of the FPGA. +* +* The ML403 board has an on-board 4 Kb serial IIC EEPROM(Microchip 24LC04A). +* The WP pin of the IIC EEPROM is hardwired to ground on this board. +* +* The ML501/ML505/ML507/ML605/SP601/SP605 boards have an on-board 8 Kb serial +* IIC EEPROM(STM M24C08). The WP pin of the IIC EEPROM is hardwired to ground +* on these boards. +* +* The AddressType for ML300/ML310/ML410/ML510 boards should be u16 as the +* address pointer in the on board EEPROM is 2 bytes. +* +* The AddressType for ML403/ML501/ML505/ML507/ML605/SP601/SP605 boards should +* be u8 as the address pointer for the on board EEPROM is 1 byte. +* +* The 7 bit IIC Slave address of the IIC EEPROM on the ML300/ML310/ML403/ML410/ +* ML501/ML505/ML507/ML510 boards is 0x50. +* The 7 bit IIC Slave address of the IIC EEPROM on the ML605/SP601/SP605 boards +* is 0x54. +* Refer to the User Guide's of the respective boards for further information +* about the IIC slave address of IIC EEPROM's. +* +* The define EEPROM_ADDRESS in this file needs to be changed depending on +* the board on which this example is to be run. +* +* This code assumes that no Operating System is being used. +* +* @note +* +* None. +* +*+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- --------------------------------------------------------- +* 1.00a mta 04/13/06 Created. +* 2.00a ktn 11/17/09 Updated to use the HAL APIs. +* 2.01a ktn 03/17/10 Updated the information about the EEPROM's used on +* ML605/SP601/SP605 boards. Updated the example so that it +* can be used to access the entire IIC EEPROM for devices +* like M24C04/M24C08 that use LSB bits of the IIC device +* select code (IIC slave address) to specify the higher +* address bits of the EEPROM internal address. +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" +#include "xiic.h" +#include "xintc.h" +#include "xil_exception.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_IIC_0_DEVICE_ID +#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID +#define IIC_INTR_ID XPAR_INTC_0_IIC_0_VEC_ID + +/* + * 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. + * The 7 bit IIC Slave address of the IIC EEPROM on the ML300/ML310/ML403/ML510/ + * ML501/ML505/ML507/ML510 boards is 0x50. The 7 bit IIC Slave address of the + * IIC EEPROM on the ML605/SP601/SP605 boards is 0x54. + * Please refer the User Guide's of the respective boards for further + * information about the IIC slave address of IIC EEPROM's. + */ +#define EEPROM_ADDRESS 0x50 /* 0xA0 as an 8 bit number. */ + +/* + * The page size determines how much data should be written at a time. + * The ML310/ML300 board supports a page size of 32 and 16. + * The write function should be called with this as a maximum byte count. + */ +#define PAGE_SIZE 16 + +/* + * The Starting address in the IIC EEPROM on which this test is performed. + */ +#define EEPROM_TEST_START_ADDRESS 128 + +/**************************** Type Definitions *******************************/ + +/* + * The AddressType for ML300/ML310/ML410/ML510 boards should be u16 as the + * address pointer in the on board EEPROM is 2 bytes. + * The AddressType for ML403/ML501/ML505/ML507/ML605/SP601/SP605 boards should + * be u8 as the address pointer in the on board EEPROM is 1 bytes. + */ +typedef u8 AddressType; + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +int IicDynEepromExample(); + +int DynEepromWriteData(u16 ByteCount); + +int DynEepromReadData(u8 *BufferPtr, u16 ByteCount); + +static int SetupInterruptSystem(XIic *IicInstPtr); + +static void SendHandler(XIic *InstancePtr); + +static void ReceiveHandler(XIic *InstancePtr); + +static void StatusHandler(XIic *InstancePtr, int Event); + +/************************** Variable Definitions *****************************/ + +XIic IicInstance; /* The instance of the IIC device. */ +XIntc InterruptController; /* The instance of the Interrupt Controller. */ + +/* + * Write buffer for writing a page. + */ +u8 WriteBuffer[sizeof(AddressType) + PAGE_SIZE]; + +u8 ReadBuffer[PAGE_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 */ + +u8 EepromIicAddr; /* Variable for storing Eeprom IIC address */ + +/************************** Function Definitions *****************************/ + +/*****************************************************************************/ +/** +* +* Main function to call the Dynamic EEPROM example. +* +* @param None. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int main(void) +{ + int Status; + + /* + * Run the Dynamic EEPROM example. + */ + Status = IicDynEepromExample(); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* This function writes, reads, and verifies the data to the IIC EEPROM in +* Dynamic controller mode. 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 IicDynEepromExample() +{ + u8 Index; + int Status; + XIic_Config *ConfigPtr; /* Pointer to configuration data */ + AddressType Address = EEPROM_TEST_START_ADDRESS; + EepromIicAddr = EEPROM_ADDRESS; + + /* + * Initialize the IIC driver so that it is ready to use. + */ + ConfigPtr = XIic_LookupConfig(IIC_DEVICE_ID); + if (ConfigPtr == NULL) { + return XST_FAILURE; + } + + Status = XIic_CfgInitialize(&IicInstance, ConfigPtr, + ConfigPtr->BaseAddress); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + /* + * Initialize the Dynamic IIC core. + */ + Status = XIic_DynamicInitialize(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Setup the Interrupt System. + */ + Status = SetupInterruptSystem(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Set the Handlers for transmit and reception. + */ + XIic_SetSendHandler(&IicInstance, &IicInstance, + (XIic_Handler) SendHandler); + XIic_SetRecvHandler(&IicInstance, &IicInstance, + (XIic_Handler) ReceiveHandler); + XIic_SetStatusHandler(&IicInstance, &IicInstance, + (XIic_StatusHandler) StatusHandler); + + + /* + * Initialize the data to write and the read buffer. + */ + if (sizeof(Address) == 1) { + WriteBuffer[0] = (u8) (EEPROM_TEST_START_ADDRESS); + EepromIicAddr |= (EEPROM_TEST_START_ADDRESS >> 8) & 0x7; + } else { + WriteBuffer[0] = (u8) (EEPROM_TEST_START_ADDRESS >> 8); + WriteBuffer[1] = (u8) (EEPROM_TEST_START_ADDRESS); + ReadBuffer[Index] = 0; + } + + for (Index = 0; Index < PAGE_SIZE; Index++) { + WriteBuffer[sizeof(Address) + Index] = 0xFF; + ReadBuffer[Index] = 0; + } + + /* + * Set the Slave address. + */ + Status = XIic_SetAddress(&IicInstance, XII_ADDR_TO_SEND_TYPE, + EepromIicAddr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Write to the EEPROM. + */ + Status = DynEepromWriteData(sizeof(Address) + PAGE_SIZE); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Read from the EEPROM. + */ + Status = DynEepromReadData(ReadBuffer, PAGE_SIZE); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Verify the data read against the data written. + */ + for (Index = 0; Index < PAGE_SIZE; Index++) { + if (ReadBuffer[Index] != WriteBuffer[Index + sizeof(Address)]) { + return XST_FAILURE; + } + + ReadBuffer[Index] = 0; + } + + /* + * Initialize the data to write and the read buffer. + */ + if (sizeof(Address) == 1) { + WriteBuffer[0] = (u8) (EEPROM_TEST_START_ADDRESS); + } else { + WriteBuffer[0] = (u8) (EEPROM_TEST_START_ADDRESS >> 8); + WriteBuffer[1] = (u8) (EEPROM_TEST_START_ADDRESS); + ReadBuffer[Index] = 0; + } + + for (Index = 0; Index < PAGE_SIZE; Index++) { + WriteBuffer[sizeof(Address) + Index] = Index; + } + + /* + * Write to the EEPROM. + */ + Status = DynEepromWriteData(sizeof(Address) + PAGE_SIZE); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Read from the EEPROM. + */ + Status = DynEepromReadData(ReadBuffer, PAGE_SIZE); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Verify the data read against the data written. + */ + for (Index = 0; Index < PAGE_SIZE; Index++) { + if (ReadBuffer[Index] != WriteBuffer[Index + sizeof(Address)]) { + return XST_FAILURE; + } + + ReadBuffer[Index] = 0; + } + + 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. +* +******************************************************************************/ +int DynEepromWriteData(u16 ByteCount) +{ + int Status; + + /* + * Set the defaults. + */ + TransmitComplete = 1; + IicInstance.Stats.TxErrors = 0; + + /* + * Start the IIC device. + */ + Status = XIic_Start(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Send the Data. + */ + Status = XIic_DynMasterSend(&IicInstance, WriteBuffer, ByteCount); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the transmission is completed. + */ + while ((TransmitComplete) || (XIic_IsIicBusy(&IicInstance) == TRUE)) { + /* + * This condition is required to be checked in the case where we + * are writing two consecutive buffers of data to the EEPROM. + * The EEPROM takes about 2 milliseconds time to update the data + * internally after a STOP has been sent on the bus. + * A NACK will be generated in the case of a second write before + * the EEPROM updates the data internally resulting in a + * Transmission Error. + */ + if (IicInstance.Stats.TxErrors != 0) { + + + /* + * Enable the IIC device. + */ + Status = XIic_Start(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + + if (!XIic_IsIicBusy(&IicInstance)) { + /* + * Send the Data. + */ + Status = XIic_MasterSend(&IicInstance, + WriteBuffer, + ByteCount); + if (Status == XST_SUCCESS) { + IicInstance.Stats.TxErrors = 0; + } else { + + } + } + } + } + + /* + * Stop the IIC device. + */ + Status = XIic_Stop(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + 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. +* +******************************************************************************/ +int DynEepromReadData(u8 *BufferPtr, u16 ByteCount) +{ + int Status; + AddressType Address = EEPROM_TEST_START_ADDRESS; + /* + * Set the Defaults. + */ + ReceiveComplete = 1; + + /* + * Position the Pointer in EEPROM. + */ + Status = DynEepromWriteData(sizeof(Address)); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Start the IIC device. + */ + Status = XIic_Start(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Receive the Data. + */ + Status = XIic_DynMasterRecv(&IicInstance, BufferPtr, ByteCount); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till all the data is received. + */ + while ((ReceiveComplete) || (XIic_IsIicBusy(&IicInstance) == TRUE)) { + + } + + /* + * Stop the IIC device. + */ + Status = XIic_Stop(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} + + +/*****************************************************************************/ +/** +* This function setups the interrupt system so interrupts can occur for the +* IIC device. The function is application-specific since the actual system may +* or may not have an interrupt controller. The IIC device could be directly +* connected to a processor without an interrupt controller. The user should +* modify this function to fit the application. +* +* @param IicInstPtr contains a pointer to the instance of the IIC device +* which is going to be connected to the interrupt controller. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +static int SetupInterruptSystem(XIic *IicInstPtr) +{ + int Status; + + if (InterruptController.IsStarted == XIL_COMPONENT_IS_STARTED) { + return XST_SUCCESS; + } + + /* + * Initialize the interrupt controller driver so that it's ready to use. + */ + Status = XIntc_Initialize(&InterruptController, INTC_DEVICE_ID); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * 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 = XIntc_Connect(&InterruptController, IIC_INTR_ID, + (XInterruptHandler) XIic_InterruptHandler, + IicInstPtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Start the interrupt controller so interrupts are enabled for all + * devices that cause interrupts. + */ + Status = XIntc_Start(&InterruptController, XIN_REAL_MODE); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Enable the interrupts for the IIC device. + */ + XIntc_Enable(&InterruptController, IIC_INTR_ID); + + /* + * Initialize the exception table. + */ + Xil_ExceptionInit(); + + /* + * Register the interrupt controller handler with the exception table. + */ + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, + (Xil_ExceptionHandler) XIntc_InterruptHandler, + &InterruptController); + + /* + * Enable non-critical exceptions. + */ + Xil_ExceptionEnable(); + + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* This Send handler is called asynchronously from an interrupt +* context and indicates that data in the specified buffer has been sent. +* +* @param InstancePtr is not used, but contains a pointer to the IIC +* device driver instance which the handler is being called for. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void SendHandler(XIic *InstancePtr) +{ + TransmitComplete = 0; +} + +/*****************************************************************************/ +/** +* This Receive handler is called asynchronously from an interrupt +* context and indicates that data in the specified buffer has been Received. +* +* @param InstancePtr is not used, but contains a pointer to the IIC +* device driver instance which the handler is being called for. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void ReceiveHandler(XIic *InstancePtr) +{ + ReceiveComplete = 0; +} + +/*****************************************************************************/ +/** +* This Status handler is called asynchronously from an interrupt +* context and indicates the events that have occurred. +* +* @param InstancePtr is a pointer to the IIC driver instance for which +* the handler is being called for. +* @param Event indicates the condition that has occurred. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void StatusHandler(XIic *InstancePtr, int Event) +{ + +} diff --git a/XilinxProcessorIPLib/drivers/iic/examples/xiic_eeprom_example.c b/XilinxProcessorIPLib/drivers/iic/examples/xiic_eeprom_example.c new file mode 100644 index 00000000..59b9bce9 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/iic/examples/xiic_eeprom_example.c @@ -0,0 +1,818 @@ +/****************************************************************************** +* +* Copyright (C) 2006 - 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 THE +* XILINX CONSORTIUM 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 xiic_eeprom_example.c +* +* This file consists of a Interrupt mode design example which uses the Xilinx +* IIC device and XIic driver to exercise the EEPROM. The XIic driver uses the +* complete FIFO functionality to transmit/receive data. +* +* This example writes/reads from the lower 256 bytes of the IIC EEPROMS. Please +* refer to the datasheets of the IIC EEPROM's for details about the internal +* addressing and page size of these devices. +* +* The XIic_MasterSend() API is used to transmit the data and +* XIic_MasterRecv() API is used to receive the data. +* +* This example is tested on ML300/ML310/ML410/ML403/ML501/ML507/ML510/ML605/ +* SP601, SP605, KC705 , ZC702 and ZC706 Xilinx boards. +* +* The ML310/ML510/ML410 boards have a on-board 64 Kb serial IIC EEPROM +* (Microchip 24LC64A). The WP pin of the IIC EEPROM is hardwired to ground on +* this board. +* +* The ML300 board has an on-board 32 Kb serial IIC EEPROM(Microchip 24LC32A). +* The WP pin of the IIC EEPROM has to be connected to ground for this example. +* The WP is connected to pin Y3 of the FPGA. +* +* The ML403 board has an on-board 4 Kb serial IIC EEPROM(Microchip 24LC04A). +* The WP pin of the IIC EEPROM is hardwired to ground on this board. +* +* The ML501/ML505/ML507/ML605/SP601/SP605/KC705/ZC702/ZC706 boards have an +* on-board 8 Kb serial IIC EEPROM(STM M24C08). The WP pin of the IIC EEPROM is +* hardwired to ground on these boards. +* +* The AddressType for ML300/ML310/ML410/ML510 boards should be u16 as the +* address pointer in the on board EEPROM is 2 bytes. +* +* The AddressType for ML403/ML501/ML505/ML507/ML605/SP601/SP605/KC705/ZC702/ +* ZC706 boards should be u8 as the address pointer for the on board EEPROM +* is 1 byte. +* +* The 7 bit IIC Slave address of the IIC EEPROM on the ML300/ML310/ML403/ML410/ +* ML501/ML505/ML507/ML510 boards is 0x50. +* The 7 bit IIC Slave address of the IIC EEPROM on the ML605/SP601/SP605/KC705 +* /ZC702/ZC706 boards is 0x54. +* Refer to the User Guide's of the respective boards for further information +* about the IIC slave address of IIC EEPROM's. +* +* The define EEPROM_ADDRESS in this file needs to be changed depending on +* the board on which this example is to be run. This is the IIC address of the +* EEPROM. +* +* The define IIC_MUX_ADDRESS in this file needs to be changed depending on +* the board on which this example is to be run. This is the IIC address of the +* the MUX. +* +* The define IIC_MUX_ENABLE should be defined so that the IIC Mux initialization +* is done for the boards on the which the EEPROM is connected to an IIC Mux. +* The boards with a MUX are a KC705/ZC702/ZC706. +* +* The define IIC_EEPROM_CHANNEL needs to be changed depending on the Channel +* number of EEPROM for IIC Mux. On KC705 it is 0x08 and ZC702 is 0x04. Please +* refer the User Guide's of the respective boards for further information +* about the Channel number to use EEPROM. +* +* This code assumes that no Operating System is being used. +* +* +* @note +* +* None. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- --------------------------------------------------------- +* 1.00a mta 02/24/06 Created. +* 1.00a mta 04/05/07 Added support for microblaze. +* 2.00a ktn 11/17/09 Updated to use the HAL APIs and replaced call to +* XIic_Initialize API with XIic_LookupConfig and +* XIic_CfgInitialize. +* 2.01a ktn 03/17/10 Updated the information about the EEPROM's used on +* ML605/SP601/SP605 boards. Updated the example so that it +* can be used to access the entire IIC EEPROM for devices +* like M24C04/M24C08 that use LSB bits of the IIC device +* select code (IIC slave address) to specify the higher +* address bits of the EEPROM internal address. +* 2.02a bss 01/30/13 Updated for using the GIC in case of Zynq +* 2.06a bss 02/14/13 Added MuxInit API to support Zynq and KC705 boards and +* modified to use ScuGic in case of Zynq CR# 683509 +* +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" +#include "xiic.h" +#include "xil_exception.h" + +#ifdef XPAR_INTC_0_DEVICE_ID + #include "xintc.h" +#else + #include "xscugic.h" +#endif + +/************************** 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_IIC_0_DEVICE_ID + + + +#ifdef XPAR_INTC_0_DEVICE_ID + #define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID + #define IIC_INTR_ID XPAR_INTC_0_IIC_0_VEC_ID + #define INTC XIntc + #define INTC_HANDLER XIntc_InterruptHandler +#else + #define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID + #define IIC_INTR_ID XPAR_FABRIC_IIC_0_VEC_ID + #define INTC XScuGic + #define INTC_HANDLER XScuGic_InterruptHandler +#endif + + +/* + * 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. + * The 7 bit IIC Slave address of the IIC EEPROM on the ML300/ML310/ML403/ML410/ + * ML501/ML505/ML507/ML510 boards is 0x50. The 7 bit IIC Slave address of the + * IIC EEPROM on the ML605/SP601/SP605/KC705/ZC702/ZC706 boards is 0x54. + * Please refer the User Guide's of the respective boards for further + * information about the IIC slave address of IIC EEPROM's. + */ +#define EEPROM_ADDRESS 0x54 /* 0xA0 as an 8 bit number. */ + + +/* + * The IIC_MUX_ADDRESS defines the address of the IIC MUX device on the + * IIC bus. Note that since the address is only 7 bits, this constant is the + * address divided by 2. + * The IIC Slaves on the KC705/ZC702/ZC706 boards are connected to an + * IIC MUX. + * IIC_EEPROM_CHANNEL is the Channel number of EEPROM for IIC Mux. On KC705 it + * is 0x08 and ZC702 is 0x04.Please refer the User Guide's of the respective + * boards for further information about the Channel number to use EEPROM. + */ +#define IIC_MUX_ADDRESS 0x74 +#define IIC_EEPROM_CHANNEL 0x08 + +/* + * This define should be uncommented if there is IIC MUX on the board to which + * this EEPROM is connected. The boards that have IIC MUX are KC705/ZC702/ZC706. + */ +/* #define IIC_MUX_ENABLE */ + +/* + * The page size determines how much data should be written at a time. + * The ML310/ML300 board supports a page size of 32 and 16. + * The write function should be called with this as a maximum byte count. + */ +#define PAGE_SIZE 16 + +/* + * The Starting address in the IIC EEPROM on which this test is performed. + */ +#define EEPROM_TEST_START_ADDRESS 128 + +/**************************** Type Definitions *******************************/ + +/* + * The AddressType for ML300/ML310/ML410/ML510 boards should be u16 as the address + * pointer in the on board EEPROM is 2 bytes. + * The AddressType for ML403/ML501/ML505/ML507/ML605/SP601/SP605/KC705/ZC702 + * /ZC706 boards should be u8 as the address pointer in the on board EEPROM is + * 1 bytes. + */ +typedef u8 AddressType; + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +int IicEepromExample(); + +int EepromWriteData(u16 ByteCount); + +int EepromReadData(u8 *BufferPtr, u16 ByteCount); + +static int SetupInterruptSystem(XIic *IicInstPtr); + +static void SendHandler(XIic *InstancePtr); + +static void ReceiveHandler(XIic *InstancePtr); + +static void StatusHandler(XIic *InstancePtr, int Event); + +#ifdef IIC_MUX_ENABLE +static int MuxInit(void); +#endif +/************************** Variable Definitions *****************************/ + +XIic IicInstance; /* The instance of the IIC device. */ +INTC Intc; /* The instance of the Interrupt Controller Driver */ + +/* + * Write buffer for writing a page. + */ +u8 WriteBuffer[sizeof(AddressType) + PAGE_SIZE]; + +u8 ReadBuffer[PAGE_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 */ + +u8 EepromIicAddr; /* Variable for storing Eeprom IIC address */ + +/************************** Function Definitions *****************************/ + +/*****************************************************************************/ +/** +* Main function to call the High level EEPROM example. +* +* @param None. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int main(void) +{ + int Status; + + /* + * Run the EEPROM example. + */ + Status = IicEepromExample(); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* 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 IicEepromExample() +{ + u32 Index; + int Status; + XIic_Config *ConfigPtr; /* Pointer to configuration data */ + AddressType Address = EEPROM_TEST_START_ADDRESS; + EepromIicAddr = EEPROM_ADDRESS; + + /* + * Initialize the IIC driver so that it is ready to use. + */ + ConfigPtr = XIic_LookupConfig(IIC_DEVICE_ID); + if (ConfigPtr == NULL) { + return XST_FAILURE; + } + + Status = XIic_CfgInitialize(&IicInstance, ConfigPtr, + ConfigPtr->BaseAddress); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Setup the Interrupt System. + */ + Status = SetupInterruptSystem(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Set the Handlers for transmit and reception. + */ + XIic_SetSendHandler(&IicInstance, &IicInstance, + (XIic_Handler) SendHandler); + XIic_SetRecvHandler(&IicInstance, &IicInstance, + (XIic_Handler) ReceiveHandler); + XIic_SetStatusHandler(&IicInstance, &IicInstance, + (XIic_StatusHandler) StatusHandler); + + +#ifdef IIC_MUX_ENABLE + /* + * Initialize the IIC MUX on the boards on which the EEPROM + * are connected through the MUX. + */ + Status = MuxInit(); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + +#endif + + /* + * Initialize the data to write and the read buffer. + */ + if (sizeof(Address) == 1) { + WriteBuffer[0] = (u8) (EEPROM_TEST_START_ADDRESS); + EepromIicAddr |= (EEPROM_TEST_START_ADDRESS >> 8) & 0x7; + } else { + WriteBuffer[0] = (u8) (EEPROM_TEST_START_ADDRESS >> 8); + WriteBuffer[1] = (u8) (EEPROM_TEST_START_ADDRESS); + ReadBuffer[Index] = 0; + } + + for (Index = 0; Index < PAGE_SIZE; Index++) { + WriteBuffer[sizeof(Address) + Index] = 0xFF; + ReadBuffer[Index] = 0; + } + + /* + * Set the Slave address. + */ + Status = XIic_SetAddress(&IicInstance, XII_ADDR_TO_SEND_TYPE, + EepromIicAddr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + + /* + * Write to the EEPROM. + */ + Status = EepromWriteData(sizeof(Address) + PAGE_SIZE); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Read from the EEPROM. + */ + Status = EepromReadData(ReadBuffer, PAGE_SIZE); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Verify the data read against the data written. + */ + for (Index = 0; Index < PAGE_SIZE; Index++) { + if (ReadBuffer[Index] != WriteBuffer[Index + sizeof(Address)]) { + return XST_FAILURE; + } + + ReadBuffer[Index] = 0; + } + + /* + * Initialize the data to write and the read buffer. + */ + if (sizeof(Address) == 1) { + WriteBuffer[0] = (u8) (EEPROM_TEST_START_ADDRESS); + } else { + WriteBuffer[0] = (u8) (EEPROM_TEST_START_ADDRESS >> 8); + WriteBuffer[1] = (u8) (EEPROM_TEST_START_ADDRESS); + ReadBuffer[Index] = 0; + } + + for (Index = 0; Index < PAGE_SIZE; Index++) { + WriteBuffer[sizeof(Address) + Index] = Index; + ReadBuffer[Index] = 0; + } + + /* + * Write to the EEPROM. + */ + Status = EepromWriteData(sizeof(Address) + PAGE_SIZE); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Read from the EEPROM. + */ + Status = EepromReadData(ReadBuffer, PAGE_SIZE); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Verify the data read against the data written. + */ + for (Index = 0; Index < PAGE_SIZE; Index++) { + if (ReadBuffer[Index] != WriteBuffer[Index + sizeof(Address)]) { + return XST_FAILURE; + } + + ReadBuffer[Index] = 0; + } + + 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. +* +******************************************************************************/ +int EepromWriteData(u16 ByteCount) +{ + int Status; + + /* + * Set the defaults. + */ + TransmitComplete = 1; + IicInstance.Stats.TxErrors = 0; + + /* + * Start the IIC device. + */ + Status = XIic_Start(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Send the Data. + */ + Status = XIic_MasterSend(&IicInstance, WriteBuffer, ByteCount); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till the transmission is completed. + */ + while ((TransmitComplete) || (XIic_IsIicBusy(&IicInstance) == TRUE)) { + /* + * This condition is required to be checked in the case where we + * are writing two consecutive buffers of data to the EEPROM. + * The EEPROM takes about 2 milliseconds time to update the data + * internally after a STOP has been sent on the bus. + * A NACK will be generated in the case of a second write before + * the EEPROM updates the data internally resulting in a + * Transmission Error. + */ + if (IicInstance.Stats.TxErrors != 0) { + + + /* + * Enable the IIC device. + */ + Status = XIic_Start(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + + if (!XIic_IsIicBusy(&IicInstance)) { + /* + * Send the Data. + */ + Status = XIic_MasterSend(&IicInstance, + WriteBuffer, + ByteCount); + if (Status == XST_SUCCESS) { + IicInstance.Stats.TxErrors = 0; + } + else { + } + } + } + } + + /* + * Stop the IIC device. + */ + Status = XIic_Stop(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + 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. +* +******************************************************************************/ +int EepromReadData(u8 *BufferPtr, u16 ByteCount) +{ + int Status; + AddressType Address = EEPROM_TEST_START_ADDRESS; + + /* + * Set the Defaults. + */ + ReceiveComplete = 1; + + /* + * Position the Pointer in EEPROM. + */ + if (sizeof(Address) == 1) { + WriteBuffer[0] = (u8) (EEPROM_TEST_START_ADDRESS); + } + else { + WriteBuffer[0] = (u8) (EEPROM_TEST_START_ADDRESS >> 8); + WriteBuffer[1] = (u8) (EEPROM_TEST_START_ADDRESS); + } + + Status = EepromWriteData(sizeof(Address)); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Start the IIC device. + */ + Status = XIic_Start(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Receive the Data. + */ + Status = XIic_MasterRecv(&IicInstance, BufferPtr, ByteCount); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till all the data is received. + */ + while ((ReceiveComplete) || (XIic_IsIicBusy(&IicInstance) == TRUE)) { + + } + + /* + * Stop the IIC device. + */ + Status = XIic_Stop(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* This function setups the interrupt system so interrupts can occur for the +* IIC device. The function is application-specific since the actual system may +* or may not have an interrupt controller. The IIC device could be directly +* connected to a processor without an interrupt controller. The user should +* modify this function to fit the application. +* +* @param IicInstPtr contains a pointer to the instance of the IIC device +* which is going to be connected to the interrupt controller. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +static int SetupInterruptSystem(XIic *IicInstPtr) +{ + int Status; + +#ifdef XPAR_INTC_0_DEVICE_ID + + /* + * Initialize the interrupt controller driver so that it's ready to use. + */ + Status = XIntc_Initialize(&Intc, INTC_DEVICE_ID); + + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * 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 = XIntc_Connect(&Intc, IIC_INTR_ID, + (XInterruptHandler) XIic_InterruptHandler, + IicInstPtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Start the interrupt controller so interrupts are enabled for all + * devices that cause interrupts. + */ + Status = XIntc_Start(&Intc, XIN_REAL_MODE); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Enable the interrupts for the IIC device. + */ + XIntc_Enable(&Intc, IIC_INTR_ID); + +#else + + XScuGic_Config *IntcConfig; + + /* + * 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(&Intc, IntcConfig, + IntcConfig->CpuBaseAddress); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + XScuGic_SetPriorityTriggerType(&Intc, IIC_INTR_ID, + 0xA0, 0x3); + + /* + * Connect the interrupt handler that will be called when an + * interrupt occurs for the device. + */ + Status = XScuGic_Connect(&Intc, IIC_INTR_ID, + (Xil_InterruptHandler)XIic_InterruptHandler, + IicInstPtr); + if (Status != XST_SUCCESS) { + return Status; + } + + /* + * Enable the interrupt for the IIC device. + */ + XScuGic_Enable(&Intc, IIC_INTR_ID); + +#endif + + /* + * Initialize the exception table and register the interrupt + * controller handler with the exception table + */ + Xil_ExceptionInit(); + + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, + (Xil_ExceptionHandler)INTC_HANDLER, &Intc); + + /* Enable non-critical exceptions */ + Xil_ExceptionEnable(); + + + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* This Send handler is called asynchronously from an interrupt +* context and indicates that data in the specified buffer has been sent. +* +* @param InstancePtr is not used, but contains a pointer to the IIC +* device driver instance which the handler is being called for. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void SendHandler(XIic *InstancePtr) +{ + TransmitComplete = 0; +} + +/*****************************************************************************/ +/** +* This Receive handler is called asynchronously from an interrupt +* context and indicates that data in the specified buffer has been Received. +* +* @param InstancePtr is not used, but contains a pointer to the IIC +* device driver instance which the handler is being called for. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void ReceiveHandler(XIic *InstancePtr) +{ + ReceiveComplete = 0; +} + +/*****************************************************************************/ +/** +* This Status handler is called asynchronously from an interrupt +* context and indicates the events that have occurred. +* +* @param InstancePtr is a pointer to the IIC driver instance for which +* the handler is being called for. +* @param Event indicates the condition that has occurred. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void StatusHandler(XIic *InstancePtr, int Event) +{ + +} + +#ifdef IIC_MUX_ENABLE +/*****************************************************************************/ +/** +* This function initializes the IIC MUX to select EEPROM. +* +* @param None. +* +* @return XST_SUCCESS if pass, otherwise XST_FAILURE. +* +* @note None. +* +****************************************************************************/ +int MuxInit(void) +{ + + int Status; + /* + * Set the Slave address to the IIC MUC - PCA9543A. + */ + Status = XIic_SetAddress(&IicInstance, XII_ADDR_TO_SEND_TYPE, + IIC_MUX_ADDRESS); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + + /* + * Enabling all the channels + */ + WriteBuffer[0] = IIC_EEPROM_CHANNEL; + + Status = EepromWriteData(1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} +#endif diff --git a/XilinxProcessorIPLib/drivers/iic/examples/xiic_low_level_dynamic_eeprom_example.c b/XilinxProcessorIPLib/drivers/iic/examples/xiic_low_level_dynamic_eeprom_example.c new file mode 100644 index 00000000..b82c34cc --- /dev/null +++ b/XilinxProcessorIPLib/drivers/iic/examples/xiic_low_level_dynamic_eeprom_example.c @@ -0,0 +1,381 @@ +/****************************************************************************** +* +* Copyright (C) 2006 - 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 THE +* XILINX CONSORTIUM 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 xiic_low_level_dynamic_eeprom_example.c +* +* This file consists of a polled mode design example which uses the Xilinx +* IIC device in dynamic mode and low-level driver to exercise the EEPROM. +* +* The XIic_DynSend() API is used to transmit the data and XIic_DynRecv() API +* is used to receive the data. +* +* The example is tested on ML300/ML310/ML403/ML501/ML507/ML510 Xilinx boards. +* +* The ML310/ML410/ML510 boards have a on-board 64 Kb serial IIC EEPROM +* (Microchip 24LC64A). The WP pin of the IIC EEPROM is hardwired to ground on +* this board. +* +* The ML300 board has an on-board 32 Kb serial IIC EEPROM(Microchip 24LC32A). +* The WP pin of the IIC EEPROM has to be connected to ground for this example. +* The WP is connected to pin Y3 of the FPGA. +* +* The ML403 board has an on-board 4 Kb serial IIC EEPROM(Microchip 24LC04A). +* The WP pin of the IIC EEPROM is hardwired to ground on this board. +* +* The ML501/ML505/ML507/ML605/SP601/SP605 boards have an on-board 8 Kb serial +* IIC EEPROM(STM M24C08). The WP pin of the IIC EEPROM is hardwired to +* ground on these boards. +* +* The AddressType for ML300/ML310/ML410/ML510 boards should be u16 as the +* address pointer in the on board EEPROM is 2 bytes. +* +* The AddressType for ML403/ML501/ML505/ML507/ML605/SP601/SP605 boards should +* be u8 as the address pointer for the on board EEPROM is 1 byte. +* +* The 7 bit IIC Slave address of the IIC EEPROM on the ML300/ML310/ML410/ML403/ +* ML501/ML505/ML507/ML510 boards is 0x50. +* The 7 bit IIC Slave address of the IIC EEPROM on the ML605/SP601/SP605 boards +* is 0x54. +* Refer to the User Guide's of the respective boards for further information +* about the IIC slave address of IIC EEPROM's. +* +* The define EEPROM_ADDRESS in this file needs to be changed depending on +* the board on which this example is to be run. +* +* This code assumes that no Operating System is being used. +* +* @note +* +* None. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- --------------------------------------------------------- +* 1.00a mta 03/20/06 Created. +* 2.00a sdm 09/22/09 Converted all register accesses to 32 bit access. +* 2.01a ktn 03/17/10 Updated the information about the EEPROM's used on +* ML605/SP601/SP605 boards. Updated the example so that it +* can be used to access the entire IIC EEPROM for devices +* like M24C04/M24C08 that use LSB bits of the IIC device +* select code (IIC slave address) to specify the higher +* address bits of the EEPROM internal address. +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" +#include "xiic.h" +#include "xil_io.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_BASE_ADDRESS XPAR_IIC_0_BASEADDR + +/* + * The Starting address in the IIC EEPROM on which this test is performed. + */ +#define EEPROM_TEST_START_ADDRESS 0x80 + +/* + * 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. + * The 7 bit IIC Slave address of the IIC EEPROM on the ML300/ML310/ML403/ML410/ + * ML501/ML505/ML507/ML510 boards is 0x50. The 7 bit IIC Slave address of the IIC + * EEPROM on the ML605/SP601/SP605 boards is 0x54. + * Please refer the User Guide's of the respective boards for further + * information about the IIC slave address of IIC EEPROM's. + */ + #define EEPROM_ADDRESS 0x50 + +/* + * The page size determines how much data should be written at a time. + * The ML310/ML300 board supports a page size of 32 and 16. + * The write function should be called with this as a maximum byte count. + */ +#define PAGE_SIZE 16 + +#define IIC_SLAVE_ADDRESS 1 + +/**************************** Type Definitions *******************************/ + +/* + * The AddressType for ML300/ML310/ML410/ML510 boards should be u16 as the address + * pointer in the on board EEPROM is 2 bytes. + * The AddressType for ML403/ML501/ML505/ML507/ML605/SP601/SP605 boards should + * be u8 as the address pointer in the on board EEPROM is 1 bytes. + */ +typedef u8 AddressType; + +u8 EepromIicAddr; /* Variable for storing Eeprom IIC address */ + +/************************** Function Prototypes ******************************/ + +int IicLowLevelDynEeprom(); + +u8 EepromReadByte(u8 *BufferPtr, u8 ByteCount); +u8 EepromWriteByte(u8 *BufferPtr, u8 ByteCount); + +/************************** Variable Definitions *****************************/ + +u8 WriteBuffer[PAGE_SIZE]; /* Write buffer for writing a page. */ + +u8 ReadBuffer[PAGE_SIZE]; /* Read buffer for reading a page. */ + +/************************** Function Definitions *****************************/ + +/*****************************************************************************/ +/** +* Main function to call the low level Dynamic EEPROM example. +* +* @param None. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int main(void) +{ + int Status; + + /* + * Perform the Read and Write operation. + */ + Status = IicLowLevelDynEeprom(); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/****************************************************************************** +* +* The function uses the low level driver of IIC to read from the IIC EEPROM on +* the ML300/ML310 board. The addresses tested starts from 128. +* +* @param None. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int IicLowLevelDynEeprom() +{ + u8 BytesRead; + u8 BytesWritten; + u32 StatusReg; + u8 Index; + int Status; + EepromIicAddr = EEPROM_ADDRESS; + + /* + * Initialize the IIC Core. + */ + Status = XIic_DynInit(IIC_BASE_ADDRESS); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Make sure all the Fifo's are cleared and Bus is Not busy. + */ + while (((StatusReg = XIic_ReadReg(IIC_BASE_ADDRESS, + XIIC_SR_REG_OFFSET)) & + (XIIC_SR_RX_FIFO_EMPTY_MASK | + XIIC_SR_TX_FIFO_EMPTY_MASK | + XIIC_SR_BUS_BUSY_MASK)) != + (XIIC_SR_RX_FIFO_EMPTY_MASK | + XIIC_SR_TX_FIFO_EMPTY_MASK)) { + + } + + /* + * Initialize the data to written and the read buffer. + */ + for (Index = 0; Index < PAGE_SIZE; Index++) { + WriteBuffer[Index] = Index; + ReadBuffer[Index] = 0; + } + + /* + * Write to the EEPROM. + */ + BytesWritten = EepromWriteByte(WriteBuffer, PAGE_SIZE); + + /* + * Read from the EEPROM. + */ + BytesRead = EepromReadByte(ReadBuffer, PAGE_SIZE); + if (BytesRead != PAGE_SIZE) { + return XST_FAILURE; + } + + /* + * Verify the data read against the data written. + */ + for (Index = 0; Index < PAGE_SIZE; Index++) { + if (ReadBuffer[Index] != WriteBuffer[Index]) { + return XST_FAILURE; + } + + ReadBuffer[Index] = 0; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* This function writes a buffer of bytes to the IIC serial EEPROM. +* +* @param BufferPtr contains the address of the data to write. +* @param ByteCount contains the number of bytes in the buffer to be +* written. Note that this should not exceed the page size of the +* EEPROM as noted by the constant PAGE_SIZE. +* +* @return The number of bytes written, a value less than that which was +* specified as an input indicates an error. +* +* @note one. +* +******************************************************************************/ +u8 EepromWriteByte(u8 *BufferPtr, u8 ByteCount) +{ + u8 SentByteCount; + AddressType Address = EEPROM_TEST_START_ADDRESS; + u8 WriteBuffer[sizeof(Address) + PAGE_SIZE]; + u8 Index; + + /* + * A temporary write buffer must be used which contains both the address + * and the data to be written, put the address in first based upon the + * size of the address for the EEPROM + */ + if (sizeof(AddressType) == 2) { + WriteBuffer[0] = (u8) (Address >> 8); + WriteBuffer[1] = (u8) (Address); + } else if (sizeof(AddressType) == 1) { + WriteBuffer[0] = (u8) (Address); + EepromIicAddr |= (EEPROM_TEST_START_ADDRESS >> 8) & 0x7; + } + + /* + * Put the data in the write buffer following the address. + */ + for (Index = 0; Index < ByteCount; Index++) { + WriteBuffer[sizeof(Address) + Index] = BufferPtr[Index]; + } + + /* + * Write a page of data at the specified address to the EEPROM. + */ + SentByteCount = XIic_DynSend(IIC_BASE_ADDRESS, EepromIicAddr, + WriteBuffer, sizeof(Address) + PAGE_SIZE, + XIIC_STOP); + + /* + * Return the number of bytes written to the EEPROM. + */ + return SentByteCount - sizeof(Address); +} + +/****************************************************************************** +* +* This function reads a number of bytes 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. +* This value is constrained by the page size of the device such +* that up to 64K may be read in one call. +* +* @return The number of bytes read. A value less than the specified input +* value indicates an error. +* +* @note None. +* +******************************************************************************/ +u8 EepromReadByte(u8 *BufferPtr, u8 ByteCount) +{ + u8 ReceivedByteCount; + u8 SentByteCount; + u16 StatusReg; + AddressType Address = EEPROM_TEST_START_ADDRESS; + + /* + * Position the Read pointer to specific location in the EEPROM. + */ + do { + StatusReg = XIic_ReadReg(IIC_BASE_ADDRESS, XIIC_SR_REG_OFFSET); + if (!(StatusReg & XIIC_SR_BUS_BUSY_MASK)) { + SentByteCount = XIic_DynSend(IIC_BASE_ADDRESS, + EepromIicAddr, + (u8 *) &Address, + sizeof(Address), + XIIC_STOP); + } + + } while (SentByteCount != sizeof(Address)); + + StatusReg = XIic_ReadReg(IIC_BASE_ADDRESS, XIIC_SR_REG_OFFSET); + + while ((StatusReg & XIIC_SR_BUS_BUSY_MASK)) { + StatusReg = XIic_ReadReg(IIC_BASE_ADDRESS, XIIC_SR_REG_OFFSET); + } + + do { + /* + * Receive the data. + */ + ReceivedByteCount = XIic_DynRecv(IIC_BASE_ADDRESS, + EepromIicAddr, BufferPtr, + ByteCount); + } while (ReceivedByteCount != ByteCount); + + /* + * Return the number of bytes received from the EEPROM. + */ + return ReceivedByteCount; +} diff --git a/XilinxProcessorIPLib/drivers/iic/examples/xiic_low_level_eeprom_example.c b/XilinxProcessorIPLib/drivers/iic/examples/xiic_low_level_eeprom_example.c new file mode 100644 index 00000000..8a2b90a9 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/iic/examples/xiic_low_level_eeprom_example.c @@ -0,0 +1,515 @@ +/****************************************************************************** +* +* Copyright (C) 2002 - 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 THE +* XILINX CONSORTIUM 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 xiic_low_level_eeprom_example.c +* +* This file consists of a polled mode design example which uses the Xilinx +* IIC device and low-level driver to exercise the EEPROM. +* +* This example writes/reads from the lower 256 bytes of the IIC EEPROMS. Please +* refer to the datasheets of the IIC EEPROM's for details about the internal +* addressing and page size of these devices. +* +* The XIic_Send() API is used to transmit the data and XIic_Recv() API is used +* to receive the data. +* +* This example is tested on ML300/ML310/ML403/ML501/ML507/ML510/ML605/SP601 and +* SP605 Xilinx boards. +* +* The ML310/ML410/ML510 boards have a on-board 64 Kb serial IIC EEPROM +* (Microchip 24LC64A). The WP pin of the IIC EEPROM is hardwired to ground on +* this board. +* +* The ML300 board has an on-board 32 Kb serial IIC EEPROM(Microchip 24LC32A). +* The WP pin of the IIC EEPROM has to be connected to ground for this example. +* The WP is connected to pin Y3 of the FPGA. +* +* The ML403 board has an on-board 4 Kb serial IIC EEPROM(Microchip 24LC04A). +* The WP pin of the IIC EEPROM is hardwired to ground on this board. +* +* The ML501/ML505/ML507/ML605/SP601/SP605 boards have an on-board 8 Kb serial +* IIC EEPROM(STM M24C08). The WP pin of the IIC EEPROM is hardwired to +* ground on these boards. +* +* The AddressType for ML300/ML310/ML410/ML510 boards should be u16 as the +* address pointer in the on board EEPROM is 2 bytes. +* +* The AddressType for ML403/ML501/ML505/ML507/ML605/SP601/SP605 boards should +* be u8 as the address pointer for the on board EEPROM is 1 byte. +* +* The 7 bit IIC Slave address of the IIC EEPROM on the ML300/ML310/ML403/ML410/ +* ML501/ML505/ML507/ML510 boards is 0x50. +* The 7 bit IIC Slave address of the IIC EEPROM on the ML605/SP601/SP605 boards +* is 0x54. +* Refer to the User Guide's of the respective boards for further information +* about the IIC slave address of IIC EEPROM's. +* +* The define EEPROM_ADDRESS in this file needs to be changed depending on +* the board on which this example is to be run. +* +* This code assumes that no Operating System is being used. +* +* @note None +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00a jhl 09/10/03 Created +* 1.00a sv 05/09/05 Minor changes to comply to Doxygen and coding guidelines +* 1.00a mta 03/09/06 Minor updates due to changes in the low level driver for +* supporting repeated start functionality. +* 2.00a sdm 09/22/09 Converted all register accesses to 32 bit access and minor +* modifications as per coding guidelines. +* 2.01a ktn 03/17/10 Updated the information about the EEPROM's used on +* ML605/SP601/SP605 boards. Updated the example so that it +* can be used to access the entire IIC EEPROM for devices +* like M24C04/M24C08 that use LSB bits of the IIC device +* select code (IIC slave address) to specify the higher +* address bits of the EEPROM internal address. +* 2.01a sdm 06/13/11 Updated the example to flush the Tx FIFO when waiting for +* the previous command to be completed for CR612546. +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" +#include "xiic.h" +#include "xil_io.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_BASE_ADDRESS XPAR_IIC_0_BASEADDR + +/* + * 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. + * The 7 bit IIC Slave address of the IIC EEPROM on the ML300/ML310/ML403/ML410/ + * ML501/ML505/ML507/ML510 boards is 0x50. The 7 bit IIC Slave address of the + * IIC EEPROM on the ML605/SP601/SP605 boards is 0x54. + * Please refer the User Guide's of the respective boards for further + * information about the IIC slave address of IIC EEPROM's. + */ +#define EEPROM_ADDRESS 0x54 /* 0xA0 as an 8 bit number */ + +/* + * The page size determines how much data should be written at a time. + * The ML300 board supports a page size of 32 and 16 + * The write function should be called with this as a maximum byte count. + */ +#define PAGE_SIZE 16 + +/* + * The Starting address in the IIC EEPROM on which this test is performed + */ +#define EEPROM_TEST_START_ADDRESS 128 + + +/**************************** Type Definitions *******************************/ + +/* + * The AddressType for ML300/ML310/ML510 boards should be u16 as the address + * pointer in the on board EEPROM is 2 bytes. + * The AddressType for ML403/ML501/ML505/ML507/ML605/SP601/SP605 boards should + * be u8 as the address pointer in the on board EEPROM is 1 bytes. + */ +typedef u8 AddressType; + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + +int IicLowLevelEeprom(); + +int ReadWriteVerify(AddressType Address); + +unsigned EepromWriteByte(AddressType Address, u8 *BufferPtr, u16 ByteCount); + +unsigned EepromReadByte(AddressType Address, u8 *BufferPtr, u16 ByteCount); + +/************************** Variable Definitions **************************/ + +int ErrorCount; /* The Error Count */ + +u8 WriteBuffer[PAGE_SIZE]; /* Write buffer for writing a page */ +u8 ReadBuffer[PAGE_SIZE]; /* Read buffer for reading a page */ +u8 ReadBufferAll[PAGE_SIZE * 4]; /* Buffer used for reading all the data */ + +u8 EepromIicAddr; /* Variable for storing Eeprom IIC address */ + +/*****************************************************************************/ +/** +* Main function to call the low level EEPROM example. +* +* @param None. +* +* @return XST_SUCCESS if successful, XST_FAILURE if unsuccessful. +* +* @note None. +* +******************************************************************************/ +int main(void) +{ + int Status; + + /* + * Run the Low Level EEPROM example. + */ + Status = IicLowLevelEeprom(); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* The function uses the low level driver of IIC to read and write to the +* IIC EEPROM board. The addresses tested are from 128 to 192. +* +* @param None. +* +* @return XST_SUCCESS if successful, XST_FAILURE if unsuccessful. +* +* @note None. +* +****************************************************************************/ +int IicLowLevelEeprom() +{ + int Status; + unsigned BytesRead; + EepromIicAddr = EEPROM_ADDRESS; + + /* + * Read, write and verify a page of data at the specified address. + */ + Status = ReadWriteVerify(EEPROM_TEST_START_ADDRESS); + if (Status != XST_SUCCESS) { + ErrorCount++; + } + + /* + * Read, write and verify a page of data at the + * specified address + PAGE_SIZE. + */ + Status = ReadWriteVerify(EEPROM_TEST_START_ADDRESS + PAGE_SIZE); + if (Status != XST_SUCCESS) { + ErrorCount++; + } + + /* + * Read, write and verify a page of data at the + * specified address + (PAGE_SIZE * 3). + */ + Status = ReadWriteVerify(EEPROM_TEST_START_ADDRESS + (PAGE_SIZE * 3)); + if (Status != XST_SUCCESS) { + ErrorCount++; + } + + /* + * Read, write and verify a page of data at the + * specified address + (PAGE_SIZE * 2). + */ + Status = ReadWriteVerify(EEPROM_TEST_START_ADDRESS + (PAGE_SIZE * 2)); + if (Status != XST_SUCCESS) { + ErrorCount++; + } + + /* + * Read all the locations that were written in a single read, + * this data is not verified, only read to show that a larger + * amount of data can be read. + */ + BytesRead = EepromReadByte(EEPROM_TEST_START_ADDRESS, + ReadBufferAll, + PAGE_SIZE * 4); + if (BytesRead != PAGE_SIZE * 4) { + ErrorCount++; + } + + if (ErrorCount != 0x0) { + Status = XST_FAILURE; + } else { + Status = XST_SUCCESS; + } + + return Status; +} + +/*****************************************************************************/ +/** +* This function writes, reads, and verifies the read to the IIC EEPROM. It +* does the write as a single page write, performs a buffered read, and also +* performs byte reads. +* +* @param Address is the starting address of the page in the EEPROM device +* to which the data is to be written. +* +* @return XST_FAILURE if the test fails, XST_SUCCESS if the test passes. +* +* @note None. +* +****************************************************************************/ +int ReadWriteVerify(AddressType Address) +{ + unsigned BytesWritten; + unsigned BytesRead; + int Index; + + /* + * Initialize the data to written and the read buffer. + */ + for (Index = 0; Index < PAGE_SIZE; Index++) { + WriteBuffer[Index] = Index; + ReadBuffer[Index] = 0; + } + + /* + * Write to the EEPROM. + */ + BytesWritten = EepromWriteByte(Address, WriteBuffer, PAGE_SIZE); + if (BytesWritten != PAGE_SIZE) { + return XST_FAILURE; + } + + /* + * Read from the EEPROM. + */ + BytesRead = EepromReadByte(Address, ReadBuffer, PAGE_SIZE); + if (BytesRead != PAGE_SIZE) { + return XST_FAILURE; + } + + /* + * Verify the data read against the data written. + */ + for (Index = 0; Index < PAGE_SIZE; Index++) + { + if (ReadBuffer[Index] != WriteBuffer[Index]) { + return XST_FAILURE; + } + ReadBuffer[Index] = 0; + } + + /* + * Read each byte one at a time and verify. + */ + for (Index = 0; Index < PAGE_SIZE; Index++) + { + BytesRead = EepromReadByte(Address + Index, + &ReadBuffer[Index], 1); + if (BytesRead != 1) { + return XST_FAILURE; + } + + if (ReadBuffer[Index] != WriteBuffer[Index]) { + return XST_FAILURE; + } + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* This function writes a buffer of bytes to the IIC serial EEPROM. +* +* @param Address contains the address in the EEPROM to write to. +* @param BufferPtr contains the address of the data to write. +* @param ByteCount contains the number of bytes in the buffer to be written. +* Note that this should not exceed the page size of the EEPROM as +* noted by the constant PAGE_SIZE. +* +* @return The number of bytes written, a value less than that which was +* specified as an input indicates an error. +* +* @note None. +* +****************************************************************************/ +unsigned EepromWriteByte(AddressType Address, u8 *BufferPtr, u16 ByteCount) +{ + volatile unsigned SentByteCount; + volatile unsigned AckByteCount; + u8 WriteBuffer[sizeof(Address) + PAGE_SIZE]; + int Index; + + + /* + * A temporary write buffer must be used which contains both the address + * and the data to be written, put the address in first based upon the + * size of the address for the EEPROM. + */ + if (sizeof(AddressType) == 2) { + WriteBuffer[0] = (u8)(Address >> 8); + WriteBuffer[1] = (u8)(Address); + } else if (sizeof(AddressType) == 1) { + WriteBuffer[0] = (u8)(Address); + EepromIicAddr |= (EEPROM_TEST_START_ADDRESS >> 8) & 0x7; + } + + /* + * Put the data in the write buffer following the address. + */ + for (Index = 0; Index < ByteCount; Index++) { + WriteBuffer[sizeof(Address) + Index] = BufferPtr[Index]; + } + + /* + * Set the address register to the specified address by writing + * the address to the device, this must be tried until it succeeds + * because a previous write to the device could be pending and it + * will not ack until that write is complete. + */ + do { + SentByteCount = XIic_Send(IIC_BASE_ADDRESS, + EepromIicAddr, + (u8 *)&Address, sizeof(Address), + XIIC_STOP); + if (SentByteCount != sizeof(Address)) { + + /* Send is aborted so reset Tx FIFO */ + XIic_WriteReg(IIC_BASE_ADDRESS, XIIC_CR_REG_OFFSET, + XIIC_CR_TX_FIFO_RESET_MASK); + XIic_WriteReg(IIC_BASE_ADDRESS, XIIC_CR_REG_OFFSET, + XIIC_CR_ENABLE_DEVICE_MASK); + } + + } while (SentByteCount != sizeof(Address)); + + /* + * Write a page of data at the specified address to the EEPROM. + */ + SentByteCount = XIic_Send(IIC_BASE_ADDRESS, EepromIicAddr, + WriteBuffer, sizeof(Address) + PAGE_SIZE, + XIIC_STOP); + + /* + * Wait for the write to be complete by trying to do a write and + * the device will not ack if the write is still active. + */ + do { + AckByteCount = XIic_Send(IIC_BASE_ADDRESS, EepromIicAddr, + (u8 *)&Address, sizeof(Address), + XIIC_STOP); + if (AckByteCount != sizeof(Address)) { + + /* Send is aborted so reset Tx FIFO */ + XIic_WriteReg(IIC_BASE_ADDRESS, XIIC_CR_REG_OFFSET, + XIIC_CR_TX_FIFO_RESET_MASK); + XIic_WriteReg(IIC_BASE_ADDRESS, XIIC_CR_REG_OFFSET, + XIIC_CR_ENABLE_DEVICE_MASK); + } + + } while (AckByteCount != sizeof(Address)); + + + /* + * Return the number of bytes written to the EEPROM + */ + return SentByteCount - sizeof(Address); +} + +/*****************************************************************************/ +/** +* This function reads a number of bytes from the IIC serial EEPROM into a +* specified buffer. +* +* @param Address contains the address in the EEPROM to read from. +* @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. +* This value is not constrained by the page size of the device +* such that up to 64K may be read in one call. +* +* @return The number of bytes read. A value less than the specified input +* value indicates an error. +* +* @note None. +* +****************************************************************************/ +unsigned EepromReadByte(AddressType Address, u8 *BufferPtr, u16 ByteCount) +{ + volatile unsigned ReceivedByteCount; + u16 StatusReg; + + /* + * Set the address register to the specified address by writing + * the address to the device, this must be tried until it succeeds + * because a previous write to the device could be pending and it + * will not ack until that write is complete. + */ + do { + StatusReg = XIic_ReadReg(IIC_BASE_ADDRESS, XIIC_SR_REG_OFFSET); + if(!(StatusReg & XIIC_SR_BUS_BUSY_MASK)) { + ReceivedByteCount = XIic_Send(IIC_BASE_ADDRESS, + EepromIicAddr, + (u8 *)&Address, + sizeof(Address), + XIIC_STOP); + + if (ReceivedByteCount != sizeof(Address)) { + + /* Send is aborted so reset Tx FIFO */ + XIic_WriteReg(IIC_BASE_ADDRESS, + XIIC_CR_REG_OFFSET, + XIIC_CR_TX_FIFO_RESET_MASK); + XIic_WriteReg(IIC_BASE_ADDRESS, + XIIC_CR_REG_OFFSET, + XIIC_CR_ENABLE_DEVICE_MASK); + } + } + + } while (ReceivedByteCount != sizeof(Address)); + + /* + * Read the number of bytes at the specified address from the EEPROM. + */ + ReceivedByteCount = XIic_Recv(IIC_BASE_ADDRESS, EepromIicAddr, + BufferPtr, ByteCount, XIIC_STOP); + + /* + * Return the number of bytes read from the EEPROM. + */ + return ReceivedByteCount; +} diff --git a/XilinxProcessorIPLib/drivers/iic/examples/xiic_low_level_tempsensor_example.c b/XilinxProcessorIPLib/drivers/iic/examples/xiic_low_level_tempsensor_example.c new file mode 100644 index 00000000..e6a2b4e1 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/iic/examples/xiic_low_level_tempsensor_example.c @@ -0,0 +1,160 @@ +/****************************************************************************** +* +* Copyright (C) 2002 - 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 THE +* XILINX CONSORTIUM 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 xiic_low_level_tempsensor_example.c +* +* This file contains a polled mode design example which uses the Xilinx IIC +* device and low-level driver to execise the temperature sensor on the ML300 +* board. This example only performs read operations (receive) from the IIC +* temperature sensor of the platform. +* +* The XIic_Recv() API is used to receive the data. +* +* @note +* +* 7-bit addressing is used to access the tempsensor. +* +* None +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00a jhl 10/09/03 Initial Release +* 1.00a sv 05/09/05 Minor changes to comply to Doxygen and coding guidelines +* 1.00a mta 03/09/06 Minor updates due to changes in the low level driver for +* supporting repeated start functionality. +* 2.00a sdm 09/22/09 Minor modifications as per coding guidelines. +* +*+* +*****************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" +#include "xiic_l.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_BASE_ADDRESS XPAR_IIC_0_BASEADDR + + +/* + * The following constant defines the address of the IIC + * temperature sensor device on the IIC bus. Note that since + * the address is only 7 bits, this constant is the address divided by 2. + */ +#define TEMP_SENSOR_ONCHIP_ADDRESS 0x18 /* The actual address is 0x30 */ +#define TEMP_SENSOR_AMBIENT_ADDRESS 0x4B /* The actual address is 0x96 */ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + +int LowLevelTempSensorExample(u32 IicBaseAddress, + u8 TempSensorAddress, + u8 *TemperaturePtr); + +/************************** Variable Definitions *****************************/ + + +/*****************************************************************************/ +/** +* +* The purpose of this function is to illustrate how to use the IIC level 0 +* driver to read the temperature. +* +* @param None +* +* @return Always 0 +* +* @note +* +* The main function is returning an integer to prevent compiler warnings. +* +****************************************************************************/ +int main(void) +{ + u8 TemperaturePtr; + + /* + * Run the example, specify the Base Address that is generated in + * xparameters.h + */ + LowLevelTempSensorExample(IIC_BASE_ADDRESS, + TEMP_SENSOR_ONCHIP_ADDRESS, + &TemperaturePtr); + return 0; +} + +/*****************************************************************************/ +/** +* +* The function reads the temperature of the IIC temperature sensor on the +* IIC bus using the low-level driver. +* +* @param IicBaseAddress is the base address of the device. +* @param TempSensorAddress is the address of the Temperature Sensor device +* on the IIC bus. +* @param TemperaturePtr is the databyte read from the temperature sensor. +* +* @return The number of bytes read from the temperature sensor, normally one +* byte if successful. +* +* @note None. +* +****************************************************************************/ +int LowLevelTempSensorExample(u32 IicBaseAddress, + u8 TempSensorAddress, + u8 *TemperaturePtr) +{ + int ByteCount; + + ByteCount = XIic_Recv(IicBaseAddress, TempSensorAddress, + TemperaturePtr, 1, XIIC_STOP); + + + + return ByteCount; +} diff --git a/XilinxProcessorIPLib/drivers/iic/examples/xiic_multi_master_example.c b/XilinxProcessorIPLib/drivers/iic/examples/xiic_multi_master_example.c new file mode 100644 index 00000000..2ccaf23e --- /dev/null +++ b/XilinxProcessorIPLib/drivers/iic/examples/xiic_multi_master_example.c @@ -0,0 +1,504 @@ +/****************************************************************************** +* +* Copyright (C) 2006 - 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 THE +* XILINX CONSORTIUM 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 xiic_multi_master_example.c +* +* This file consists of a Interrupt mode design example which uses the Xilinx +* IIC device and XIic driver to exercise the EEPROM on the Xilinx boards in a +* Multi master mode. This example has been tested with an off-board external +* IIC Master connected on the IIC bus. +* +* This example writes/reads from the lower 256 bytes of the IIC EEPROMS. Please +* refer to the datasheets of the IIC EEPROM's for details about the internal +* addressing and page size of these devices. +* +* The XIic_MasterSend() API is used to transmit the data and XIic_MasterRecv() +* API is used to receive the data. +* +* The example is tested on ML300/ML310/ML403/ML501 Xilinx boards. +* +* The ML310/ML410/ML510 boards have a on-board 64 Kb serial IIC EEPROM +* (Microchip 24LC64A). The WP pin of the IIC EEPROM is hardwired to ground on +* this board. +* +* The ML300 board has an on-board 32 Kb serial IIC EEPROM(Microchip 24LC32A). +* The WP pin of the IIC EEPROM has to be connected to ground for this example. +* The WP is connected to pin Y3 of the FPGA. +* +* The ML403 board has an on-board 4 Kb serial IIC EEPROM(Microchip 24LC04A). +* The WP pin of the IIC EEPROM is hardwired to ground on this board. +* +* The ML501/ML505/ML507/ML605/SP601/SP605 boards have an on-board 8 Kb serial +* IIC EEPROM(STM M24C08). The WP pin of the IIC EEPROM is hardwired to +* ground on these boards. +* +* The AddressType for ML300/ML310/ML410/ML510 boards should be u16 as the +* address pointer in the on board EEPROM is 2 bytes. +* +* The AddressType for ML403/ML501/ML505/ML507/ML605/SP601/SP605 boards should +* be u8 as the address pointer for the on board EEPROM is 1 byte. +* +* The 7 bit IIC Slave address of the IIC EEPROM on the ML300/ML310/ML403/ML410/ +* ML501/ML505/ML507/ML510 boards is 0x50. +* The 7 bit IIC Slave address of the IIC EEPROM on the ML605/SP601/SP605 boards +* is 0x54. +* Refer to the User Guide's of the respective boards for further information +* about the IIC slave address of IIC EEPROM's. +* +* The define EEPROM_ADDRESS in this file needs to be changed depending on +* the board on which this example is to be run. +* This code assumes that no Operating System is being used. +* +* @note +* +* None. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00a mta 03/01/06 Created. +* 2.00a sdm 09/22/09 Converted all register accesses to 32 bit access. +* Updated to use the HAL APIs, replaced call to +* XIic_Initialize API with XIic_LookupConfig and +* XIic_CfgInitialize. +* 2.01a ktn 03/17/10 Updated the information about the EEPROM's used on +* ML605/SP601/SP605 boards. +* +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" +#include "xiic.h" +#include "xintc.h" +#include "xil_exception.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_IIC_0_DEVICE_ID +#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID +#define IIC_INTR_ID XPAR_INTC_0_IIC_0_VEC_ID + +/* + * 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. + * The 7 bit IIC Slave address of the IIC EEPROM on the ML300/ML310/ML403/ML501/ + * ML410/ML505/ML507/ML510 boards is 0x50. The 7 bit IIC Slave address of the + * IIC EEPROM on the ML605/SP601/SP605 boards is 0x54. + * Please refer the User Guide's of the respective boards for further + * information about the IIC slave address of IIC EEPROM's. + */ +#define EEPROM_ADDRESS 0x50 /* 0xA0 as an 8 bit number. */ + +/* + * The page size determines how much data should be written at a time. + * The ML300 board supports a page size of 32 and 16. + * The write function should be called with this as a maximum byte count. + */ +#define PAGE_SIZE 16 + +/* + * The Starting address in the IIC EEPROM on which this test is performed. + */ +#define EEPROM_TEST_START_ADDRESS 128 + +/**************************** Type Definitions *******************************/ + +/* + * The AddressType for ML300/ML310/ML410/ML510 boards should be u16 as the + * address pointer in the on board EEPROM is 2 bytes. + * The AddressType for ML403/ML501/ML505/ML507/ML605/SP601/SP605 boards should + * be u8 as the address pointer in the on board EEPROM is 1 bytes. + */ +typedef u8 AddressType; + + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +int IicMultiMasterExample(); + +static int SetupInterruptSystem(XIic *IicInstPtr); + +static void SendHandler(XIic *InstancePtr); +static void StatusHandler(XIic *InstancePtr, int Event); + +/************************** Variable Definitions *****************************/ + +XIic IicInstance; /* The instance of the IIC device. */ +XIntc InterruptController; /* The instance of the Interrupt Controller. */ + +/* + * Write buffer for writing a page. + */ +u8 WriteBuffer[sizeof(AddressType) + PAGE_SIZE]; + +volatile u8 TransmitComplete; +volatile u8 ReceiveComplete; +volatile u8 BusNotBusy; + +/************************** Function Definitions *****************************/ + +/*****************************************************************************/ +/** +* Main function to call the Multi Master example. +* +* @param None. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int main(void) +{ + int Status; + + /* + * Run the Multi master example. + */ + Status = IicMultiMasterExample(); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* This function writes the data to the IIC EEPROM. +* +* @param None. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +****************************************************************************/ +int IicMultiMasterExample() +{ + u8 Index; + int Status; + XIic_Config *ConfigPtr; /* Pointer to configuration data */ + AddressType Address = EEPROM_TEST_START_ADDRESS; + + /* + * Initialize the data to write and the read buffer. + */ + if (sizeof(Address) == 1) { + WriteBuffer[0] = (u8) (Address); + } + else { + WriteBuffer[0] = (u8) (Address >> 8); + WriteBuffer[1] = (u8) (Address); + } + for (Index = 0; Index < PAGE_SIZE; Index++) { + WriteBuffer[sizeof(Address) + Index] = 0xFF; + } + + /* + * Include the multi master functionality. + */ + XIic_MultiMasterInclude(); + + /* + * Initialize the IIC driver so that it is ready to use. + */ + ConfigPtr = XIic_LookupConfig(XPAR_IIC_0_DEVICE_ID); + if (ConfigPtr == NULL) { + return XST_FAILURE; + } + + Status = XIic_CfgInitialize(&IicInstance, ConfigPtr, + ConfigPtr->BaseAddress); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + + /* + * Setup the Interrupt System. + */ + Status = SetupInterruptSystem(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Set the Transmit and status handlers. + */ + XIic_SetSendHandler(&IicInstance, &IicInstance, + (XIic_Handler) SendHandler); + XIic_SetStatusHandler(&IicInstance, &IicInstance, + (XIic_StatusHandler) StatusHandler); + + /* + * Set the address of the slave. + */ + Status = XIic_SetAddress(&IicInstance, XII_ADDR_TO_SEND_TYPE, + EEPROM_ADDRESS); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + IicInstance.Stats.TxErrors = 0; + /* + * Set the defaults. + */ + TransmitComplete = 1; + + /* + * Start the IIC device. + */ + Status = XIic_Start(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Write to the EEPROM. + */ + XIic_MasterSend(&IicInstance, WriteBuffer, PAGE_SIZE); + + while (1) { + /* + * If arbitration is lost and some time later Bus if bus + * becomes free transmit the data. + */ + if (BusNotBusy) { + /* + * Start the IIC device. + */ + Status = XIic_Start(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Send the data. + */ + XIic_MasterSend(&IicInstance, WriteBuffer, PAGE_SIZE); + + /* + * Clear the Flag. + */ + BusNotBusy = 0; + } + + /* + * This condition is required to be checked in the case where we + * are writing two consecutive buffers of data to the EEPROM. + * The EEPROM takes about 2 milliseconds time to update the data + * internally after a STOP has been sent on the bus. + * A NACK will be generated in the case of a second write before + * the EEPROM updates the data internally resulting in a + * Transmission Error. + */ + if (IicInstance.Stats.TxErrors != 0) { + /* + * If the Slave didn't acknowledge then we should keep + * making attempts to transmit the data. + */ + IicInstance.Stats.TxErrors = 0; + /* + * Start the IIC device. + */ + Status = XIic_Start(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Send the data. + */ + XIic_MasterSend(&IicInstance, WriteBuffer, PAGE_SIZE); + } + + if ((!TransmitComplete) && + (XIic_IsIicBusy(&IicInstance) == FALSE)) + break; + } + + /* + * Stop the IIC device. + */ + Status = XIic_Stop(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/****************************************************************************/ +/** +* This function setups the interrupt system so interrupts can occur for the +* IIC. The function is application-specific since the actual system may or +* may not have an interrupt controller. The IIC device could be directly +* connected to a processor without an interrupt controller. The user should +* modify this function to fit the application. +* +* @param IicInstPtr contains a pointer to the instance of the IIC which +* is going to be connected to the interrupt controller. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +****************************************************************************/ +static int SetupInterruptSystem(XIic *IicInstPtr) +{ + int Status; + + if (InterruptController.IsStarted == XIL_COMPONENT_IS_STARTED) { + return XST_SUCCESS; + } + + /* + * Initialize the interrupt controller driver so that it's ready to use. + */ + Status = XIntc_Initialize(&InterruptController, INTC_DEVICE_ID); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * 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 = XIntc_Connect(&InterruptController, IIC_INTR_ID, + (XInterruptHandler) XIic_InterruptHandler, + IicInstPtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Start the interrupt controller so interrupts are enabled for all + * devices that cause interrupts. + */ + Status = XIntc_Start(&InterruptController, XIN_REAL_MODE); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Enable the interrupts for the IIC device. + */ + XIntc_Enable(&InterruptController, IIC_INTR_ID); + + + + /* + * Initialize the exception table. + */ + Xil_ExceptionInit(); + + /* + * Register the interrupt controller handler with the exception table. + */ + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, + (Xil_ExceptionHandler) XIntc_InterruptHandler, + &InterruptController); + + /* + * Enable non-critical exceptions. + */ + Xil_ExceptionEnable(); + + + + return XST_SUCCESS; +} + + +/*****************************************************************************/ +/** +* The Send handler is called asynchronously from an interrupt context and +* indicates that data in the specified buffer has been sent. +* +* @param InstancePtr is a pointer to the IIC driver instance for which +* the handler is being called for. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void SendHandler(XIic *InstancePtr) +{ + TransmitComplete = 0; +} + +/*****************************************************************************/ +/** +* The Status handler is called asynchronously from an interrupt context and +* indicates the events that have occured. +* +* @param InstancePtr is a pointer to the IIC driver instance for which +* the handler is being called for. +* @param Event indicates the condition that has occurred. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void StatusHandler(XIic *InstancePtr, int Event) +{ + if (Event == XII_ARB_LOST_EVENT) { + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, + XIIC_CR_ENABLE_DEVICE_MASK); + XIic_WriteIisr(InstancePtr->BaseAddress, XIIC_INTR_BNB_MASK); + XIic_WriteIier(InstancePtr->BaseAddress, XIIC_INTR_BNB_MASK); + InstancePtr->BNBOnly = TRUE; + } + else if (Event == XII_BUS_NOT_BUSY_EVENT) { + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, + 0x0); + BusNotBusy = 1; + } +} diff --git a/XilinxProcessorIPLib/drivers/iic/examples/xiic_repeated_start_example.c b/XilinxProcessorIPLib/drivers/iic/examples/xiic_repeated_start_example.c new file mode 100644 index 00000000..f1cf3d8d --- /dev/null +++ b/XilinxProcessorIPLib/drivers/iic/examples/xiic_repeated_start_example.c @@ -0,0 +1,535 @@ +/****************************************************************************** +* +* Copyright (C) 2006 - 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 THE +* XILINX CONSORTIUM 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 xiic_repeated_start_example.c +* +* This file consists of a interrupt mode design example to demonstrate the use +* of repeated start using the XIic driver. +* +* The XIic_MasterSend() API is used to transmit the data and XIic_MasterRecv() +* API is used to receive the data. +* +* The IIC devices that are present on the Xilinx boards donot support the +* repeated start option. These examples have been tested with an IIC +* device external to the boards. +* +* This code assumes that no Operating System is being used. +* +* @note +* +* None. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00a mta 02/20/06 Created. +* 2.00a sdm 09/22/09 Updated to use the HAL APIs, replaced call to +* XIic_Initialize API with XIic_LookupConfig and +* XIic_CfgInitialize. Updated the example with a +* fix for CR539763 where XIic_Start was being called +* instead of XIic_Stop. Added code for setting up the +* StatusHandler callback. +* +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" +#include "xiic.h" +#include "xintc.h" +#include "xil_exception.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_IIC_0_DEVICE_ID +#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID +#define IIC_INTR_ID XPAR_INTC_0_IIC_0_VEC_ID + +/* + * The following constant defines the address of the IIC + * device on the IIC bus. Note that since the address is only 7 bits, this + * constant is the address divided by 2. + */ +#define SLAVE_ADDRESS 0x70 /* 0xE0 as an 8 bit number. */ + +#define SEND_COUNT 16 +#define RECEIVE_COUNT 16 + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +int IicRepeatedStartExample(); +static int WriteData(u16 ByteCount); +static int ReadData(u8 *BufferPtr, u16 ByteCount); +static int SetupInterruptSystem(XIic *IicInstPtr); +static void SendHandler(XIic *InstancePtr); +static void ReceiveHandler(XIic *InstancePtr); +static void StatusHandler(XIic *InstancePtr, int Event); + +/************************** Variable Definitions *****************************/ + +XIic IicInstance; +XIntc InterruptController; + +u8 WriteBuffer[SEND_COUNT]; /* Write buffer for writing a page. */ +u8 ReadBuffer[RECEIVE_COUNT]; /* Read buffer for reading a page. */ + +volatile u8 TransmitComplete; +volatile u8 ReceiveComplete; + +/************************** Function Definitions *****************************/ + +/*****************************************************************************/ +/** +* Main function to call the Repeated Start example. +* +* @param None. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int main(void) +{ + int Status; + + /* + * Run the Repeated Start example. + */ + Status = IicRepeatedStartExample(); + if (Status != XST_SUCCESS) { + + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* This function writes and reads the data to the IIC Slave. +* +* @param None. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int IicRepeatedStartExample(void) +{ + u8 Index; + int Status; + XIic_Config *ConfigPtr; /* Pointer to configuration data */ + + /* + * Initialize the data to write and the read buffer. + */ + for (Index = 0; Index < SEND_COUNT; Index++) { + WriteBuffer[Index] = Index; + ReadBuffer[Index] = 0; + } + + /* + * Initialize the IIC driver so that it is ready to use. + */ + ConfigPtr = XIic_LookupConfig(XPAR_IIC_0_DEVICE_ID); + if (ConfigPtr == NULL) { + return XST_FAILURE; + } + + Status = XIic_CfgInitialize(&IicInstance, ConfigPtr, + ConfigPtr->BaseAddress); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Setup the Interrupt System. + */ + Status = SetupInterruptSystem(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Set the Transmit, Receive and Status handlers. + */ + XIic_SetSendHandler(&IicInstance, &IicInstance, + (XIic_Handler) SendHandler); + XIic_SetRecvHandler(&IicInstance, &IicInstance, + (XIic_Handler) ReceiveHandler); + XIic_SetStatusHandler(&IicInstance, &IicInstance, + (XIic_StatusHandler) StatusHandler); + + /* + * Set the Address of the Slave. + */ + Status = XIic_SetAddress(&IicInstance, XII_ADDR_TO_SEND_TYPE, + SLAVE_ADDRESS); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Write to the IIC Slave. + */ + Status = WriteData(SEND_COUNT); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Read from the IIC Slave. + */ + Status = ReadData(ReadBuffer, RECEIVE_COUNT); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* This function writes a buffer of data to IIC Slave. +* +* @param ByteCount contains the number of bytes in the buffer to be +* written. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +static int WriteData(u16 ByteCount) +{ + int Status; + int BusBusy; + + /* + * Set the defaults. + */ + TransmitComplete = 1; + + /* + * Start the IIC device. + */ + Status = XIic_Start(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Set the Repeated Start option. + */ + IicInstance.Options = XII_REPEATED_START_OPTION; + + /* + * Send the data. + */ + Status = XIic_MasterSend(&IicInstance, WriteBuffer, ByteCount); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till data is transmitted. + */ + while (TransmitComplete) { + + } + + /* + * This is for verification that Bus is not released and still Busy. + */ + BusBusy = XIic_IsIicBusy(&IicInstance); + + TransmitComplete = 1; + IicInstance.Options = 0x0; + + /* + * Send the Data. + */ + Status = XIic_MasterSend(&IicInstance, WriteBuffer, ByteCount); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till data is transmitted. + */ + while ((TransmitComplete) || (XIic_IsIicBusy(&IicInstance) == TRUE)) { + + } + + /* + * Stop the IIC device. + */ + Status = XIic_Stop(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* This function reads a data from the IIC Slave into a specified buffer. +* +* @param BufferPtr contains the address of the data buffer to be filled. +* @param ByteCount contains the number of bytes to be read. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +static int ReadData(u8 *BufferPtr, u16 ByteCount) +{ + int Status; + int BusBusy; + + /* + * Set the defaults. + */ + ReceiveComplete = 1; + + /* + * Start the IIC device. + */ + Status = XIic_Start(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Set the Repeated Start option. + */ + IicInstance.Options = XII_REPEATED_START_OPTION; + + /* + * Receive the data. + */ + Status = XIic_MasterRecv(&IicInstance, BufferPtr, ByteCount); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till all the data is received. + */ + while (ReceiveComplete) { + + } + + /* + * This is for verification that Bus is not released and still Busy. + */ + BusBusy = XIic_IsIicBusy(&IicInstance); + + ReceiveComplete = 1; + IicInstance.Options = 0x0; + + /* + * Receive the Data. + */ + Status = XIic_MasterRecv(&IicInstance, BufferPtr, ByteCount); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait till all the data is received. + */ + while ((ReceiveComplete) || (XIic_IsIicBusy(&IicInstance) == TRUE)) { + + } + + /* + * Stop the IIC device. + */ + Status = XIic_Stop(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* This function setups the interrupt system so interrupts can occur for the +* IIC. The function is application-specific since the actual system may or +* may not have an interrupt controller. The IIC device could be directly +* connected to a processor without an interrupt controller. The user should +* modify this function to fit the application. +* +* @param IicInstPtr contains a pointer to the instance of the IIC which +* is going to be connected to the interrupt controller. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +static int SetupInterruptSystem(XIic *IicInstPtr) +{ + int Status; + + if (InterruptController.IsStarted == XIL_COMPONENT_IS_STARTED) { + return XST_SUCCESS; + } + + /* + * Initialize the interrupt controller driver so that it's ready to use. + */ + Status = XIntc_Initialize(&InterruptController, INTC_DEVICE_ID); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * 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 = XIntc_Connect(&InterruptController, IIC_INTR_ID, + (XInterruptHandler) XIic_InterruptHandler, + IicInstPtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Start the interrupt controller so interrupts are enabled for all + * devices that cause interrupts. + */ + Status = XIntc_Start(&InterruptController, XIN_REAL_MODE); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Enable the interrupts for the IIC device. + */ + XIntc_Enable(&InterruptController, IIC_INTR_ID); + + /* + * Initialize the exception table. + */ + Xil_ExceptionInit(); + + /* + * Register the interrupt controller handler with the exception table. + */ + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, + (Xil_ExceptionHandler) XIntc_InterruptHandler, + &InterruptController); + + /* + * Enable non-critical exceptions. + */ + Xil_ExceptionEnable(); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* This Send handler is called asynchronously from an interrupt context and +* indicates that data in the specified buffer has been sent. +* +* @param InstancePtr is a pointer to the IIC driver instance for which +* the handler is being called for. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void SendHandler(XIic *InstancePtr) +{ + TransmitComplete = 0; +} + +/*****************************************************************************/ +/** +* This Receive handler is called asynchronously from an interrupt context and +* indicates that data in the specified buffer has been Received. +* +* @param InstancePtr is a pointer to the IIC driver instance for which +* the handler is being called for. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void ReceiveHandler(XIic *InstancePtr) +{ + ReceiveComplete = 0; +} + +/*****************************************************************************/ +/** +* This Status handler is called asynchronously from an interrupt +* context and indicates the events that have occurred. +* +* @param InstancePtr is a pointer to the IIC driver instance for which +* the handler is being called for. +* @param Event indicates the condition that has occurred. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void StatusHandler(XIic *InstancePtr, int Event) +{ + +} diff --git a/XilinxProcessorIPLib/drivers/iic/examples/xiic_selftest_example.c b/XilinxProcessorIPLib/drivers/iic/examples/xiic_selftest_example.c new file mode 100644 index 00000000..7fee704c --- /dev/null +++ b/XilinxProcessorIPLib/drivers/iic/examples/xiic_selftest_example.c @@ -0,0 +1,164 @@ +/****************************************************************************** +* +* Copyright (C) 2002 - 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 THE +* XILINX CONSORTIUM 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 xiic_selftest_example.c +* +* This file contains a example for using the IIC hardware device and +* XIic driver. +* +* @note +* +* None +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00a sv 05/09/05 Initial release for TestApp integration. +* 2.00a sdm 09/22/09 Updated to use the HAL APIs, replaced call to +* XIic_Initialize API with XIic_LookupConfig and +* XIic_CfgInitialize. Minor changes made as per +* coding guidelines. +*+* +*******************************************************************************/ + +#include "xparameters.h" +#include "xiic.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. + */ +#ifndef TESTAPP_GEN +#define IIC_DEVICE_ID XPAR_IIC_0_DEVICE_ID +#endif + +/**************************** Type Definitions ********************************/ + + +/***************** Macros (Inline Functions) Definitions **********************/ + + +/************************** Function Prototypes *******************************/ + +int IicSelfTestExample(u16 DeviceId); + +/************************** Variable Definitions ******************************/ + +/* + * The following are declared globally so they are zeroed and so they are + * easily accessible from a debugger. + */ +XIic Iic; /* The driver instance for IIC Device */ + + +/******************************************************************************/ +/** +* Main function to call the example. This function is not included if the +* example is generated from the TestAppGen test tool. +* +* @param None. +* +* @return XST_SUCCESS if successful, XST_FAILURE if unsuccessful. +* +* @note None. +* +******************************************************************************/ +#ifndef TESTAPP_GEN +int main(void) +{ + int Status; + + /* + * Run the example, specify the device ID that is generated in + * xparameters.h. + */ + Status = IicSelfTestExample(IIC_DEVICE_ID); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; + +} +#endif + +/*****************************************************************************/ +/** +* +* This function does a selftest on the IIC device and XIic driver as an +* example. +* +* @param DeviceId is the XPAR_
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00a mta 03/01/06 Created. +* 2.00a ktn 11/17/09 Updated to use the HAL APIs and replaced call to +* XIic_Initialize API with XIic_LookupConfig and +* XIic_CfgInitialize. Some of the macros have been +* renamed in the IIC driver and some renamed macros are +* used in this example. +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" +#include "xiic.h" +#include "xintc.h" +#include "xil_exception.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_IIC_0_DEVICE_ID +#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID +#define IIC_INTR_ID XPAR_INTC_0_IIC_0_VEC_ID + +/* + * The following constant defines the address of the IIC device on the IIC bus. + * Since the address is only 7 bits, this constant is the address divided by 2. + */ +#define SLAVE_ADDRESS 0x70 /* 0xE0 as an 8 bit number. */ + +#define RECEIVE_COUNT 25 +#define SEND_COUNT 25 + + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +int IicSlaveExample(); +int SlaveWriteData(u16 ByteCount); +int SlaveReadData(u8 *BufferPtr, u16 ByteCount); +static int SetupInterruptSystem(XIic * IicInstPtr); +static void StatusHandler(XIic *InstancePtr, int Event); +static void SendHandler(XIic *InstancePtr); +static void ReceiveHandler(XIic *InstancePtr); + +/************************** Variable Definitions *****************************/ + +XIic IicInstance; /* The instance of the IIC device. */ +XIntc InterruptController; /* The instance of the Interrupt Controller */ + + +u8 WriteBuffer[SEND_COUNT]; /* Write buffer for writing a page. */ +u8 ReadBuffer[RECEIVE_COUNT]; /* Read buffer for reading a page. */ + +volatile u8 TransmitComplete; +volatile u8 ReceiveComplete; + +volatile u8 SlaveRead; +volatile u8 SlaveWrite; + +/************************** Function Definitions *****************************/ + +/*****************************************************************************/ +/** +* Main function to call the IIC Slave example. +* +* @param None. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int main(void) +{ + int Status; + + /* + * Run the IIC Slave example. + */ + Status = IicSlaveExample(); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* This function writes and reads the data as a slave. The IIC master on the bus +* initiates the transfers. +* +* @param None. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int IicSlaveExample() +{ + int Status; + u8 Index; + XIic_Config *ConfigPtr; /* Pointer to configuration data */ + + + /* + * Initialize the IIC driver so that it is ready to use. + */ + ConfigPtr = XIic_LookupConfig(IIC_DEVICE_ID); + if (ConfigPtr == NULL) { + return XST_FAILURE; + } + + Status = XIic_CfgInitialize(&IicInstance, ConfigPtr, + ConfigPtr->BaseAddress); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Setup the Interrupt System. + */ + Status = SetupInterruptSystem(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Include the Slave functions. + */ + XIic_SlaveInclude(); + + /* + * Set the Transmit, Receive and Status Handlers. + */ + XIic_SetStatusHandler(&IicInstance, &IicInstance, + (XIic_StatusHandler) StatusHandler); + XIic_SetSendHandler(&IicInstance, &IicInstance, + (XIic_Handler) SendHandler); + XIic_SetRecvHandler(&IicInstance, &IicInstance, + (XIic_Handler) ReceiveHandler); + + /* + * Set the Address as a RESPOND type. + */ + Status = XIic_SetAddress(&IicInstance, XII_ADDR_TO_RESPOND_TYPE, + SLAVE_ADDRESS); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * The IIC Master on this bus should initiate the transfer + * and write data to the slave at this instance. + */ + SlaveReadData(ReadBuffer, RECEIVE_COUNT); + + for (Index = 0; Index < SEND_COUNT; Index++) { + WriteBuffer[Index] = Index; + } + + /* + * The IIC Master on this bus should initiate the transfer + * and read data from the slave. + */ + SlaveWriteData(SEND_COUNT); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* This function reads a buffer of bytes when the IIC Master on the bus writes +* data to the slave device. +* +* @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 +* +******************************************************************************/ +int SlaveReadData(u8 *BufferPtr, u16 ByteCount) +{ + int Status; + + /* + * Set the defaults. + */ + ReceiveComplete = 1; + + /* + * Start the IIC device. + */ + Status = XIic_Start(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Set the Global Interrupt Enable. + */ + XIic_IntrGlobalEnable(IicInstance.BaseAddress); + + /* + * Wait for AAS interrupt and completion of data reception. + */ + while ((ReceiveComplete) || (XIic_IsIicBusy(&IicInstance) == TRUE)) { + if (SlaveRead) { + XIic_SlaveRecv(&IicInstance, ReadBuffer, RECEIVE_COUNT); + SlaveRead = 0; + } + } + + /* + * Disable the Global Interrupt Enable. + */ + XIic_IntrGlobalDisable(IicInstance.BaseAddress); + + /* + * Stop the IIC device. + */ + Status = XIic_Stop(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* This function writes a buffer of bytes to the IIC bus when the IIC master +* initiates a read operation. +* +* @param ByteCount contains the number of bytes in the buffer to be +* written. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int SlaveWriteData(u16 ByteCount) +{ + int Status; + + /* + * Set the defaults. + */ + TransmitComplete = 1; + + /* + * Start the IIC device. + */ + Status = XIic_Start(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Set the Global Interrupt Enable. + */ + XIic_IntrGlobalEnable(IicInstance.BaseAddress); + + /* + * Wait for AAS interrupt and transmission to complete. + */ + while ((TransmitComplete) || (XIic_IsIicBusy(&IicInstance) == TRUE)) { + if (SlaveWrite) { + XIic_SlaveSend(&IicInstance, WriteBuffer, SEND_COUNT); + SlaveWrite = 0; + } + } + + /* + * Disable the Global Interrupt Enable bit. + */ + XIic_IntrGlobalDisable(IicInstance.BaseAddress); + + /* + * Stop the IIC device. + */ + Status = XIic_Stop(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/****************************************************************************/ +/** +* This Status handler is called asynchronously from an interrupt context and +* indicates the events that have occurred. +* +* @param InstancePtr is not used, but contains a pointer to the IIC +* device driver instance which the handler is being called for. +* @param Event indicates whether it is a request for a write or read. +* +* @return None. +* +* @note None. +* +****************************************************************************/ +static void StatusHandler(XIic *InstancePtr, int Event) +{ + /* + * Check whether the Event is to write or read the data from the slave. + */ + if (Event == XII_MASTER_WRITE_EVENT) { + /* + * Its a Write request from Master. + */ + SlaveRead = 1; + } else { + /* + * Its a Read request from the master. + */ + SlaveWrite = 1; + } +} + +/****************************************************************************/ +/** +* This Send handler is called asynchronously from an interrupt +* context and indicates that data in the specified buffer has been sent. +* +* @param InstancePtr is a pointer to the IIC driver instance for which +* the handler is being called for. +* +* @return None. +* +* @note None. +* +****************************************************************************/ +static void SendHandler(XIic *InstancePtr) +{ + TransmitComplete = 0; +} + +/****************************************************************************/ +/** +* This Receive handler is called asynchronously from an interrupt +* context and indicates that data in the specified buffer has been Received. +* +* @param InstancePtr is a pointer to the IIC driver instance for which +* the handler is being called for. +* +* @return None. +* +* @note None. +* +****************************************************************************/ +static void ReceiveHandler(XIic *InstancePtr) +{ + ReceiveComplete = 0; +} + +/****************************************************************************/ +/** +* This function setups the interrupt system so interrupts can occur for the +* IIC. The function is application-specific since the actual system may or +* may not have an interrupt controller. The IIC device could be directly +* connected to a processor without an interrupt controller. The user should +* modify this function to fit the application. +* +* @param IicInstPtr contains a pointer to the instance of the IIC which +* is going to be connected to the interrupt controller. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +****************************************************************************/ +static int SetupInterruptSystem(XIic * IicInstPtr) +{ + int Status; + + if (InterruptController.IsStarted == XIL_COMPONENT_IS_STARTED) { + return XST_SUCCESS; + } + + /* + * Initialize the interrupt controller driver so that it's ready to use. + */ + Status = XIntc_Initialize(&InterruptController, INTC_DEVICE_ID); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * 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 = XIntc_Connect(&InterruptController, IIC_INTR_ID, + (XInterruptHandler) XIic_InterruptHandler, + IicInstPtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Start the interrupt controller so interrupts are enabled for all + * devices that cause interrupts. + */ + Status = XIntc_Start(&InterruptController, XIN_REAL_MODE); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Enable the interrupts for the IIC device. + */ + XIntc_Enable(&InterruptController, IIC_INTR_ID); + + /* + * Initialize the exception table. + */ + Xil_ExceptionInit(); + + /* + * Register the interrupt controller handler with the exception table. + */ + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, + (Xil_ExceptionHandler) XIntc_InterruptHandler, + &InterruptController); + + /* + * Enable non-critical exceptions. + */ + Xil_ExceptionEnable(); + + + return XST_SUCCESS; +} diff --git a/XilinxProcessorIPLib/drivers/iic/examples/xiic_tempsensor_example.c b/XilinxProcessorIPLib/drivers/iic/examples/xiic_tempsensor_example.c new file mode 100644 index 00000000..bd225f30 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/iic/examples/xiic_tempsensor_example.c @@ -0,0 +1,394 @@ +/****************************************************************************** +* +* Copyright (C) 2006 - 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 THE +* XILINX CONSORTIUM 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 xiic_tempsensor_example.c +* +* This file contains an interrupt based design example which uses the Xilinx +* IIC device and driver to exercise the temperature sensor on the ML300 board. +* This example only performs read operations (receive) from the IIC temperature +* sensor of the platform. +* +* The XIic_MasterRecv() API is used to receive the data. +* +* This example assumes that there is an interrupt controller in the hardware +* system and the IIC device is connected to the interrupt controller. +* +* @note +* +* 7-bit addressing is used to access the tempsensor. +* +* None +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00a jhl 09/10/03 Created +* 1.00a sv 05/09/05 Minor changes to comply to Doxygen and coding guidelines +*+* +*****************************************************************************/ + +/***************************** Include Files ********************************/ + +#include "xparameters.h" +#include "xiic.h" +#include "xintc.h" +#include "xil_exception.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_IIC_0_DEVICE_ID +#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID +#define INTC_IIC_INTERRUPT_ID XPAR_INTC_0_IIC_0_VEC_ID + + +/* + * The following constant defines the address of the IIC + * temperature sensor device on the IIC bus. Note that since + * the address is only 7 bits, this constant is the address divided by 2. + */ +#define TEMP_SENSOR_ADDRESS 0x18 /* The actual address is 0x30 */ + + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ****************************/ + +int TempSensorExample(u16 IicDeviceId, u8 TempSensorAddress, + u8 *TemperaturePtr); + +static int SetupInterruptSystem(XIic *IicPtr); + +static void RecvHandler(void *CallbackRef, int ByteCount); + +static void StatusHandler(void *CallbackRef, int Status); + + +/************************** Variable Definitions **************************/ + +XIic Iic; /* The instance of the IIC device */ + +XIntc InterruptController; /* The instance of the Interrupt controller */ + +/* + * The following structure contains fields that are used with the callbacks + * (handlers) of the IIC driver. The driver asynchronously calls handlers + * when abnormal events occur or when data has been sent or received. This + * structure must be volatile to work when the code is optimized. + */ +volatile struct { + int EventStatus; + int RemainingRecvBytes; + int EventStatusUpdated; + int RecvBytesUpdated; +} HandlerInfo; + +/*****************************************************************************/ +/** +* +* The purpose of this function is to illustrate how to use the IIC driver to +* read the temperature. +* +* @param None +* +* @return XST_SUCCESS if successful, XST_FAILURE if unsuccessful +* +* @note None +* +*******************************************************************************/ +int main(void) +{ + int Status; + u8 TemperaturePtr; + + /* + * Call the TempSensorExample. + */ + Status = TempSensorExample(IIC_DEVICE_ID, TEMP_SENSOR_ADDRESS, + &TemperaturePtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; + +} + +/*****************************************************************************/ +/** +* The function reads the temperature of the IIC temperature sensor on the +* IIC bus. It initializes the IIC device driver and sets it up to communicate +* with the temperature sensor. This function does contain a loop that polls +* for completion of the IIC processing such that it may not return if +* interrupts or the hardware are not working. +* +* @param IicDeviceId is the XPAR_
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00a mta 03/01/06 Created. +* 2.00a ktn 11/17/09 Updated to use the HAL APIs and replaced call to +* XIic_Initialize API with XIic_LookupConfig and +* XIic_CfgInitialize. Made minor modifications as +* per coding guidelines. +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" +#include "xiic.h" +#include "xintc.h" +#include "xil_exception.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_IIC_0_DEVICE_ID +#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID +#define IIC_INTR_ID XPAR_INTC_0_IIC_0_VEC_ID + +/* + * The following constant defines the address of the IIC device on the IIC bus. + * Since the address is 10 bits, this constant is the address divided by 2. + */ +#define SLAVE_ADDRESS 0x270 /* 0x4E0 as an 10 bit number. */ +#define RECEIVE_COUNT 16 +#define SEND_COUNT 16 + + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +int IicTenBitAddrExample(); +int TenBitAddrWriteData(u16 ByteCount); +int TenBitAddrReadData(u8 *BufferPtr, u16 ByteCount); +static int SetupInterruptSystem(XIic *IicInstPtr); +static void StatusHandler(XIic *InstancePtr, int Event); +static void SendHandler(XIic *InstancePtr); +static void ReceiveHandler(XIic *InstancePtr); + +/************************** Variable Definitions *****************************/ + +XIic IicInstance; /* The instance of the IIC device. */ +XIntc InterruptController; /* The instance of the Interrupt Controller */ + + +u8 WriteBuffer[SEND_COUNT]; /* Write buffer for writing a page. */ +u8 ReadBuffer[RECEIVE_COUNT]; /* Read buffer for reading a page. */ + +volatile u8 TransmitComplete; +volatile u8 ReceiveComplete; + +volatile u8 SlaveRead; +volatile u8 SlaveWrite; + +/************************** Function Definitions *****************************/ + +/*****************************************************************************/ +/** +* +* Main function to call the IIC Slave example. +* +* @param None. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int main(void) +{ + int Status; + + /* + * Run the IIC Slave example for 10 bit addressing. + */ + Status = IicTenBitAddrExample(); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function writes and reads the data as a slave. The IIC master on the bus +* initiates the transfers. +* +* @param None. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int IicTenBitAddrExample() +{ + int Status; + u8 Index; + XIic_Config *ConfigPtr; /* Pointer to configuration data */ + + /* + * Initialize the IIC driver so that it is ready to use. + */ + ConfigPtr = XIic_LookupConfig(IIC_DEVICE_ID); + if (ConfigPtr == NULL) { + return XST_FAILURE; + } + + Status = XIic_CfgInitialize(&IicInstance, ConfigPtr, + ConfigPtr->BaseAddress); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Set the options to enable 10-bit addressing. + */ + XIic_SetOptions(&IicInstance, XII_SEND_10_BIT_OPTION); + + /* + * Setup the Interrupt System. + */ + Status = SetupInterruptSystem(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Include the Slave functions. + */ + XIic_SlaveInclude(); + + /* + * Set the Transmit, Receive and Status Handlers. + */ + XIic_SetStatusHandler(&IicInstance, &IicInstance, + (XIic_StatusHandler) StatusHandler); + XIic_SetSendHandler(&IicInstance, &IicInstance, + (XIic_Handler) SendHandler); + XIic_SetRecvHandler(&IicInstance, &IicInstance, + (XIic_Handler) ReceiveHandler); + + /* + * Set the Address as a RESPOND type. + */ + Status = XIic_SetAddress(&IicInstance, XII_ADDR_TO_RESPOND_TYPE, + SLAVE_ADDRESS); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * The IIC Master on this bus should initiate the transfer + * and write data to the slave at this instance. + */ + TenBitAddrReadData(ReadBuffer, RECEIVE_COUNT); + + for (Index = 0; Index < SEND_COUNT; Index++) { + WriteBuffer[Index] = Index; + } + + /* + * The IIC Master on this bus should initiate the transfer + * and read data from the slave. + */ + TenBitAddrWriteData(SEND_COUNT); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* This function reads a buffer of bytes when the IIC Master on the bus writes +* data to the slave device. +* +* @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 +* +******************************************************************************/ +int TenBitAddrReadData(u8 *BufferPtr, u16 ByteCount) +{ + int Status; + + /* + * Set the defaults. + */ + ReceiveComplete = 1; + + /* + * Start the IIC device. + */ + Status = XIic_Start(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Set the Global Interrupt Enable. + */ + XIic_IntrGlobalEnable(IicInstance.BaseAddress); + + /* + * Wait for AAS interrupt and completion of data reception. + */ + while ((ReceiveComplete) || (XIic_IsIicBusy(&IicInstance) == TRUE)) { + if (SlaveRead) { + XIic_SlaveRecv(&IicInstance, ReadBuffer, RECEIVE_COUNT); + SlaveRead = 0; + } + } + + /* + * Disable the Global Interrupt Enable. + */ + XIic_IntrGlobalDisable(IicInstance.BaseAddress); + + /* + * Stop the IIC device. + */ + Status = XIic_Stop(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* This function writes a buffer of bytes to the IIC bus when the IIC master +* initiates a read operation. +* +* @param ByteCount contains the number of bytes in the buffer to be +* written. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int TenBitAddrWriteData(u16 ByteCount) +{ + int Status; + + /* + * Set the defaults. + */ + TransmitComplete = 1; + + /* + * Start the IIC device. + */ + Status = XIic_Start(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Set the Global Interrupt Enable. + */ + XIic_IntrGlobalEnable(IicInstance.BaseAddress); + + /* + * Wait for AAS interrupt and transmission to complete. + */ + while ((TransmitComplete) || (XIic_IsIicBusy(&IicInstance) == TRUE)) { + if (SlaveWrite) { + XIic_SlaveSend(&IicInstance, WriteBuffer, SEND_COUNT); + SlaveWrite = 0; + } + } + + /* + * Disable the Global Interrupt Enable bit. + */ + XIic_IntrGlobalDisable(IicInstance.BaseAddress); + + /* + * Stop the IIC device. + */ + Status = XIic_Stop(&IicInstance); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/****************************************************************************/ +/** +* This Status handler is called asynchronously from an interrupt context and +* indicates the events that have occurred. +* +* @param InstancePtr is not used, but contains a pointer to the IIC +* device driver instance which the handler is being called for. +* @param Event indicates whether it is a request for a write or read. +* +* @return None. +* +* @note None. +* +****************************************************************************/ +static void StatusHandler(XIic *InstancePtr, int Event) +{ + /* + * Check whether the Event is to write or read the data from the slave. + */ + if (Event == XII_MASTER_WRITE_EVENT) { + /* + * Its a Write request from Master. + */ + SlaveRead = 1; + } + else { + /* + * Its a Read request from the master. + */ + SlaveWrite = 1; + } +} + +/****************************************************************************/ +/** +* This Send handler is called asynchronously from an interrupt +* context and indicates that data in the specified buffer has been sent. +* +* @param InstancePtr is a pointer to the IIC driver instance for which +* the handler is being called for. +* +* @return None. +* +* @note None. +* +****************************************************************************/ +static void SendHandler(XIic *InstancePtr) +{ + TransmitComplete = 0; +} + +/****************************************************************************/ +/** +* This Receive handler is called asynchronously from an interrupt +* context and indicates that data in the specified buffer has been Received. +* +* @param InstancePtr is a pointer to the IIC driver instance for which +* the handler is being called for. +* +* @return None. +* +* @note None. +* +****************************************************************************/ +static void ReceiveHandler(XIic *InstancePtr) +{ + ReceiveComplete = 0; +} + +/****************************************************************************/ +/** +* This function setups the interrupt system so interrupts can occur for the +* IIC. The function is application-specific since the actual system may or +* may not have an interrupt controller. The IIC device could be directly +* connected to a processor without an interrupt controller. The user should +* modify this function to fit the application. +* +* @param IicInstPtr contains a pointer to the instance of the IIC which +* is going to be connected to the interrupt controller. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +****************************************************************************/ +static int SetupInterruptSystem(XIic * IicInstPtr) +{ + int Status; + + if (InterruptController.IsStarted == XIL_COMPONENT_IS_STARTED) { + return XST_SUCCESS; + } + + /* + * Initialize the interrupt controller driver so that it's ready to use. + */ + Status = XIntc_Initialize(&InterruptController, INTC_DEVICE_ID); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * 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 = XIntc_Connect(&InterruptController, IIC_INTR_ID, + (XInterruptHandler) XIic_InterruptHandler, + IicInstPtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Start the interrupt controller so interrupts are enabled for all + * devices that cause interrupts. + */ + Status = XIntc_Start(&InterruptController, XIN_REAL_MODE); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Enable the interrupts for the IIC device. + */ + XIntc_Enable(&InterruptController, IIC_INTR_ID); + + /* + * Initialize the exception table. + */ + Xil_ExceptionInit(); + + /* + * Register the interrupt controller handler with the exception table. + */ + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, + (Xil_ExceptionHandler) XIntc_InterruptHandler, + &InterruptController); + + /* + * Enable non-critical exceptions. + */ + Xil_ExceptionEnable(); + + return XST_SUCCESS; +} diff --git a/XilinxProcessorIPLib/drivers/iic/src/Makefile b/XilinxProcessorIPLib/drivers/iic/src/Makefile new file mode 100644 index 00000000..a591d906 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/iic/src/Makefile @@ -0,0 +1,27 @@ +COMPILER= +ARCHIVER= +CP=cp +COMPILER_FLAGS= +EXTRA_COMPILER_FLAGS= +LIB=libxil.a + +RELEASEDIR=../../../lib +INCLUDEDIR=../../../include +INCLUDES=-I./. -I${INCLUDEDIR} + +INCLUDEFILES=xiic.h xiic_l.h +LIBSOURCES=*.c +OUTS = *.o + + +libs: + echo "Compiling iic" + $(COMPILER) $(COMPILER_FLAGS) $(EXTRA_COMPILER_FLAGS) $(INCLUDES) $(LIBSOURCES) + $(ARCHIVER) -r ${RELEASEDIR}/${LIB} ${OUTS} + make clean + +include: + ${CP} ${INCLUDEFILES} ${INCLUDEDIR} + +clean: + rm -rf ${OUTS} diff --git a/XilinxProcessorIPLib/drivers/iic/src/xiic.c b/XilinxProcessorIPLib/drivers/iic/src/xiic.c new file mode 100644 index 00000000..5aafb09c --- /dev/null +++ b/XilinxProcessorIPLib/drivers/iic/src/xiic.c @@ -0,0 +1,767 @@ +/****************************************************************************** +* +* Copyright (C) 2002 - 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 THE +* XILINX CONSORTIUM 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 xiic.c +* +* Contains required functions for the XIic component. See xiic.h for more +* information on the driver. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- --- ------- ----------------------------------------------- +* 1.01a rfp 10/19/01 release +* 1.01c ecm 12/05/02 new rev +* 1.01c rmm 05/14/03 Fixed diab compiler warnings relating to asserts. +* 1.01d jhl 10/08/03 Added general purpose output feature +* 1.02a jvb 12/13/05 Added CfgInitialize(), and made CfgInitialize() take +* a pointer to a config structure instead of a device id. +* Moved Initialize() into xiic_sinit.c, and have +* Initialize() call CfgInitialize() after it retrieved the +* config structure using the device id. Removed include of +* xparameters.h along with any dependencies on xparameters.h +* and the _g.c config table. +* 1.02a mta 03/09/06 Added a new function XIic_IsIicBusy() which returns +* whether IIC Bus is Busy or Free. +* 1.13a wgr 03/22/07 Converted to new coding style. +* 1.15a ktn 02/17/09 Fixed XIic_GetAddress() to return correct device address. +* 1.16a ktn 07/18/09 Updated the notes in XIic_Reset function to clearly +* indicate that only the Interrupt Registers are reset. +* 1.16a ktn 10/16/09 Updated the notes in the XIic_SelfTest() API to mention +* that the complete IIC core is Reset on giving a software +* reset to the IIC core. This issue is fixed in the latest +* version of the IIC core (some previous versions of the +* core only reset the Interrupt Logic/Registers), please +* see the Hw specification for further information. +* 2.00a ktn 10/22/09 Converted all register accesses to 32 bit access. +* Some of the macros have been renamed to remove _m from +* the name see the xiic_i.h and xiic_l.h file for further +* information (Example XIic_mClearIntr is now +* XIic_ClearIntr). +* Some of the macros have been renamed to be consistent, +* see the xiic_l.h file for further information +* (Example XIIC_WRITE_IIER is renamed as XIic_WriteIier). +* The driver has been updated to use the HAL APIs/macros. +* 2.07a adk 18/04/13 Updated the code to avoid unused variable warnings +* when compiling with the -Wextra -Wall flags. +* Changes done if files xiic.c and xiic_i.h. CR:705001. +* +*+* +****************************************************************************/ + +/***************************** Include Files *******************************/ + +#include "xiic.h" +#include "xiic_i.h" + +/************************** Constant Definitions ***************************/ + + +/**************************** Type Definitions *****************************/ + + +/***************** Macros (Inline Functions) Definitions *******************/ + + +/************************** Function Prototypes ****************************/ + +static void XIic_StubStatusHandler(void *CallBackRef, int ErrorCode); + +static void XIic_StubHandler(void *CallBackRef, int ByteCount); + +/************************** Variable Definitions **************************/ + + +/*****************************************************************************/ +/** +* +* Initializes a specific XIic instance. The initialization entails: +* +* - Initialize the driver to allow access to the device registers and +* initialize other subcomponents necessary for the operation of the device. +* - Default options to: +* - 7-bit slave addressing +* - Send messages as a slave device +* - Repeated start off +* - General call recognition disabled +* - Clear messageing and error statistics +* +* The XIic_Start() function must be called after this function before the device +* is ready to send and receive data on the IIC bus. +* +* Before XIic_Start() is called, the interrupt control must connect the ISR +* routine to the interrupt handler. This is done by the user, and not +* XIic_Start() to allow the user to use an interrupt controller of their choice. +* +* @param InstancePtr is a pointer to the XIic instance to be worked on. +* @param Config is a reference to a structure containing information +* about a specific IIC device. This function can initialize +* multiple instance objects with the use of multiple calls giving +* different Config information on each call. +* @param EffectiveAddr is the device base address in the virtual memory +* address space. The caller is responsible for keeping the +* address mapping from EffectiveAddr to the device physical base +* address unchanged once this function is invoked. Unexpected +* errors may occur if the address mapping changes after this +* function is called. If address translation is not used, use +* Config->BaseAddress for this parameters, passing the physical +* address instead. +* +* @return +* - XST_SUCCESS when successful +* - XST_DEVICE_IS_STARTED indicates the device is started +* (i.e. interrupts enabled and messaging is possible). Must stop +* before re-initialization is allowed. +* +* @note None. +* +****************************************************************************/ +int XIic_CfgInitialize(XIic *InstancePtr, XIic_Config * Config, + u32 EffectiveAddr) +{ + /* + * Asserts test the validity of selected input arguments. + */ + Xil_AssertNonvoid(InstancePtr != NULL); + + InstancePtr->IsReady = 0; + + /* + * If the device is started, disallow the initialize and return a Status + * indicating it is started. This allows the user to stop the device + * and reinitialize, but prevents a user from inadvertently + * initializing. + */ + if (InstancePtr->IsStarted == XIL_COMPONENT_IS_STARTED) { + return XST_DEVICE_IS_STARTED; + } + + /* + * Set default values and configuration data, including setting the + * callback handlers to stubs so the system will not crash should the + * application not assign its own callbacks. + */ + InstancePtr->IsStarted = 0; + InstancePtr->BaseAddress = EffectiveAddr; + InstancePtr->RecvHandler = XIic_StubHandler; + InstancePtr->RecvBufferPtr = NULL; + InstancePtr->SendHandler = XIic_StubHandler; + InstancePtr->SendBufferPtr = NULL; + InstancePtr->StatusHandler = XIic_StubStatusHandler; + InstancePtr->Has10BitAddr = Config->Has10BitAddr; + InstancePtr->IsReady = XIL_COMPONENT_IS_READY; + InstancePtr->Options = 0; + InstancePtr->BNBOnly = FALSE; + InstancePtr->GpOutWidth = Config->GpOutWidth; + InstancePtr->IsDynamic = FALSE; + InstancePtr->IsSlaveSetAckOff = FALSE; + + /* + * Reset the device. + */ + XIic_Reset(InstancePtr); + + XIic_ClearStats(InstancePtr); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function starts the IIC device and driver by enabling the proper +* interrupts such that data may be sent and received on the IIC bus. +* This function must be called before the functions to send and receive data. +* +* Before XIic_Start() is called, the interrupt control must connect the ISR +* routine to the interrupt handler. This is done by the user, and not +* XIic_Start() to allow the user to use an interrupt controller of their choice. +* +* Start enables: +* - IIC device +* - Interrupts: +* - Addressed as slave to allow messages from another master +* - Arbitration Lost to detect Tx arbitration errors +* - Global IIC interrupt +* +* @param InstancePtr is a pointer to the XIic instance to be worked on. +* +* @return XST_SUCCESS always. +* +* @note +* +* The device interrupt is connected to the interrupt controller, but no +* "messaging" interrupts are enabled. Addressed as Slave is enabled to +* reception of messages when this devices address is written to the bus. +* The correct messaging interrupts are enabled when sending or receiving +* via the IicSend() and IicRecv() functions. No action is required +* by the user to control any IIC interrupts as the driver completely +* manages all 8 interrupts. Start and Stop control the ability +* to use the device. Stopping the device completely stops all device +* interrupts from the processor. +* +****************************************************************************/ +int XIic_Start(XIic *InstancePtr) +{ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* + * Mask off all interrupts, each is enabled when needed. + */ + XIic_WriteIier(InstancePtr->BaseAddress, 0); + + /* + * Clear all interrupts by reading and rewriting exact value back. + * Only those bits set will get written as 1 (writing 1 clears intr). + */ + XIic_ClearIntr(InstancePtr->BaseAddress, 0xFFFFFFFF); + + /* + * Enable the device. + */ + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, + XIIC_CR_ENABLE_DEVICE_MASK); + /* + * Set Rx FIFO Occupancy depth to throttle at + * first byte(after reset = 0). + */ + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_RFD_REG_OFFSET, 0); + + /* + * Clear and enable the interrupts needed. + */ + XIic_ClearEnableIntr(InstancePtr->BaseAddress, + XIIC_INTR_AAS_MASK | XIIC_INTR_ARB_LOST_MASK); + + InstancePtr->IsStarted = XIL_COMPONENT_IS_STARTED; + InstancePtr->IsDynamic = FALSE; + + /* + * Enable the Global interrupt enable. + */ + XIic_IntrGlobalEnable(InstancePtr->BaseAddress); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function stops the IIC device and driver such that data is no longer +* sent or received on the IIC bus. This function stops the device by +* disabling interrupts. This function only disables interrupts within the +* device such that the caller is responsible for disconnecting the interrupt +* handler of the device from the interrupt source and disabling interrupts +* at other levels. +* +* Due to bus throttling that could hold the bus between messages when using +* repeated start option, stop will not occur when the device is actively +* sending or receiving data from the IIC bus or the bus is being throttled +* by this device, but instead return XST_IIC_BUS_BUSY. +* +* @param InstancePtr is a pointer to the XIic instance to be worked on. +* +* @return +* - XST_SUCCESS indicates all IIC interrupts are disabled. +* No messages can be received or transmitted until XIic_Start() +* is called. +* - XST_IIC_BUS_BUSY indicates this device is currently engaged +* in message traffic and cannot be stopped. +* +* @note None. +* +****************************************************************************/ +int XIic_Stop(XIic *InstancePtr) +{ + u32 Status; + u32 CntlReg; + + Xil_AssertNonvoid(InstancePtr != NULL); + + /* + * Disable all interrupts globally. + */ + XIic_IntrGlobalDisable(InstancePtr->BaseAddress); + + CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET); + Status = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_SR_REG_OFFSET); + + if ((CntlReg & XIIC_CR_MSMS_MASK) || + (Status & XIIC_SR_ADDR_AS_SLAVE_MASK)) { + /* + * When this device is using the bus + * - re-enable interrupts to finish current messaging + * - return bus busy + */ + XIic_IntrGlobalEnable(InstancePtr->BaseAddress); + + return XST_IIC_BUS_BUSY; + } + + InstancePtr->IsStarted = 0; + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* Resets the IIC device. +* +* @param InstancePtr is a pointer to the XIic instance to be worked on. +* +* @return None. +* +* @note The complete IIC core is Reset on giving a software reset to +* the IIC core. Some previous versions of the core only reset +* the Interrupt Logic/Registers, please refer to the HW specification +* for futher details about this. +* +****************************************************************************/ +void XIic_Reset(XIic *InstancePtr) +{ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_RESETR_OFFSET, + XIIC_RESET_MASK); +} + +/*****************************************************************************/ +/** +* +* This function sets the bus addresses. The addresses include the device +* address that the device responds to as a slave, or the slave address +* to communicate with on the bus. The IIC device hardware is built to +* allow either 7 or 10 bit slave addressing only at build time rather +* than at run time. When this device is a master, slave addressing can +* be selected at run time to match addressing modes for other bus devices. +* +* Addresses are represented as hex values with no adjustment for the data +* direction bit as the software manages address bit placement. +* Example: For a 7 address written to the device of 1010 011X where X is +* the transfer direction (send/recv), the address parameter for this function +* needs to be 01010011 or 0x53 where the correct bit alllignment will be +* handled for 7 as well as 10 bit devices. This is especially important as +* the bit placement is not handled the same depending on which options are +* used such as repeated start. +* +* @param InstancePtr is a pointer to the XIic instance to be worked on. +* @param AddressType indicates which address is being modified, the +* address which this device responds to on the IIC bus as a slave, +* or the slave address to communicate with when this device is a +* master. One of the following values must be contained in +* this argument. +*
+* XII_ADDR_TO_SEND_TYPE Slave being addressed by a this master +* XII_ADDR_TO_RESPOND_TYPE Address to respond to as a slave device +*+* +* @param Address contains the address to be set, 7 bit or 10 bit address. +* A ten bit address must be within the range: 0 - 1023 and a 7 bit +* address must be within the range 0 - 127. +* +* @return +* - XST_SUCCESS is returned if the address was successfully set. +* - XST_IIC_NO_10_BIT_ADDRESSING indicates only 7 bit addressing +* supported. +* - XST_INVALID_PARAM indicates an invalid parameter was +* specified. +* +* @note +* +* Upper bits of 10-bit address is written only when current device is built +* as a ten bit device. +* +****************************************************************************/ +int XIic_SetAddress(XIic *InstancePtr, int AddressType, int Address) +{ + u32 SendAddr; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(Address < 1023); + + /* + * Set address to respond to for this device into address registers. + */ + if (AddressType == XII_ADDR_TO_RESPOND_TYPE) { + /* + * Address in upper 7 bits. + */ + SendAddr = ((Address & 0x007F) << 1); + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_ADR_REG_OFFSET, + SendAddr); + + if (InstancePtr->Has10BitAddr == TRUE) { + /* + * Write upper 3 bits of addr to DTR only when 10 bit + * option included in design i.e. register exists. + */ + SendAddr = ((Address & 0x0380) >> 7); + XIic_WriteReg(InstancePtr->BaseAddress, + XIIC_TBA_REG_OFFSET, SendAddr); + } + + return XST_SUCCESS; + } + + /* + * Store address of slave device being read from. + */ + if (AddressType == XII_ADDR_TO_SEND_TYPE) { + InstancePtr->AddrOfSlave = Address; + return XST_SUCCESS; + } + + return XST_INVALID_PARAM; +} + +/*****************************************************************************/ +/** +* +* This function gets the addresses for the IIC device driver. The addresses +* include the device address that the device responds to as a slave, or the +* slave address to communicate with on the bus. The address returned has the +* same format whether 7 or 10 bits. +* +* @param InstancePtr is a pointer to the XIic instance to be worked on. +* @param AddressType indicates which address, the address which this +* responds to on the IIC bus as a slave, or the slave address to +* communicate with when this device is a master. One of the +* following values must be contained in this argument. +*
+* XII_ADDR_TO_SEND_TYPE Slave being addressed as a master +* XII_ADDR_TO_RESPOND_TYPE Slave address to respond to as a slave +*+* If neither of the two valid arguments are used, the function returns +* the address of the slave device +* +* @return The address retrieved. +* +* @note None. +* +****************************************************************************/ +u16 XIic_GetAddress(XIic *InstancePtr, int AddressType) +{ + u8 LowAddr; + u16 HighAddr = 0; + + Xil_AssertNonvoid(InstancePtr != NULL); + + /* + * Return this device's address. + */ + if (AddressType == XII_ADDR_TO_RESPOND_TYPE) { + + LowAddr = (u8) XIic_ReadReg(InstancePtr->BaseAddress, + XIIC_ADR_REG_OFFSET); + + if (InstancePtr->Has10BitAddr == TRUE) { + HighAddr = (u16) XIic_ReadReg(InstancePtr->BaseAddress, + XIIC_TBA_REG_OFFSET); + } + return ((HighAddr << 8) | (u16) LowAddr); + } + + /* + * Otherwise return address of slave device on the IIC bus. + */ + return InstancePtr->AddrOfSlave; +} + +/*****************************************************************************/ +/** +* +* This function sets the contents of the General Purpose Output register +* for the IIC device driver. Note that the number of bits in this register is +* parameterizable in the hardware such that it may not exist. This function +* checks to ensure that it does exist to prevent bus errors, but does not +* ensure that the number of bits in the register are sufficient for the +* value being written (won't cause a bus error). +* +* @param InstancePtr is a pointer to the XIic instance to be worked on. +* @param OutputValue contains the value to be written to the register. +* +* @return +* - XST_SUCCESS if the given data is written to the GPO register. +* - XST_NO_FEATURE if the hardware is configured such that this +* register does not contain any bits to read or write. +* +* @note None. +* +****************************************************************************/ +int XIic_SetGpOutput(XIic *InstancePtr, u8 OutputValue) +{ + Xil_AssertNonvoid(InstancePtr != NULL); + + /* + * If the general purpose output register is implemented by the hardware + * then write the specified value to it, otherwise indicate an error. + */ + if (InstancePtr->GpOutWidth > 0) { + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_GPO_REG_OFFSET, + OutputValue); + return XST_SUCCESS; + } else { + return XST_NO_FEATURE; + } +} + +/*****************************************************************************/ +/** +* +* This function gets the contents of the General Purpose Output register +* for the IIC device driver. Note that the number of bits in this register is +* parameterizable in the hardware such that it may not exist. This function +* checks to ensure that it does exist to prevent bus errors. +* +* @param InstancePtr is a pointer to the XIic instance to be worked on. +* @param OutputValuePtr contains the value which was read from the +* register. +* +* @return +* - XST_SUCCESS if the given data is read from the GPO register. +* - XST_NO_FEATURE if the hardware is configured such that this +* register does not contain any bits to read or write. +* +* The OutputValuePtr is also an output as it contains the value read. +* +* @note None. +* +****************************************************************************/ +int XIic_GetGpOutput(XIic *InstancePtr, u8 *OutputValuePtr) +{ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(OutputValuePtr != NULL); + + /* + * If the general purpose output register is implemented by the hardware + * then read the value from it, otherwise indicate an error. + */ + if (InstancePtr->GpOutWidth > 0) { + *OutputValuePtr = XIic_ReadReg(InstancePtr->BaseAddress, + XIIC_GPO_REG_OFFSET); + return XST_SUCCESS; + } else { + return XST_NO_FEATURE; + } +} + +/*****************************************************************************/ +/** +* +* A function to determine if the device is currently addressed as a slave. +* +* @param InstancePtr is a pointer to the XIic instance to be worked on. +* +* @return +* - TRUE if the device is addressed as slave. +* - FALSE if the device is NOT addressed as slave. +* +* @note None. +* +****************************************************************************/ +u32 XIic_IsSlave(XIic *InstancePtr) +{ + Xil_AssertNonvoid(InstancePtr != NULL); + + if ((XIic_ReadReg(InstancePtr->BaseAddress, XIIC_SR_REG_OFFSET) & + XIIC_SR_ADDR_AS_SLAVE_MASK) == 0) { + return FALSE; + } + return TRUE; +} + +/*****************************************************************************/ +/** +* +* Sets the receive callback function, the receive handler, which the driver +* calls when it finishes receiving data. The number of bytes used to signal +* when the receive is complete is the number of bytes set in the XIic_Recv +* function. +* +* The handler executes in an interrupt context such that it must minimize +* the amount of processing performed such as transferring data to a thread +* context. +* +* The number of bytes received is passed to the handler as an argument. +* +* @param InstancePtr is a pointer to the XIic instance to be worked on. +* @param CallBackRef is the upper layer callback reference passed back +* when the callback function is invoked. +* @param FuncPtr is the pointer to the callback function. +* +* @return None. +* +* @note The handler is called within interrupt context . +* +****************************************************************************/ +void XIic_SetRecvHandler(XIic *InstancePtr, void *CallBackRef, + XIic_Handler FuncPtr) +{ + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(FuncPtr != NULL); + + InstancePtr->RecvHandler = FuncPtr; + InstancePtr->RecvCallBackRef = CallBackRef; +} + +/*****************************************************************************/ +/** +* +* Sets the send callback function, the send handler, which the driver calls when +* it receives confirmation of sent data. The handler executes in an interrupt +* context such that it must minimize the amount of processing performed such +* as transferring data to a thread context. +* +* @param InstancePtr the pointer to the XIic instance to be worked on. +* @param CallBackRef the upper layer callback reference passed back when +* the callback function is invoked. +* @param FuncPtr the pointer to the callback function. +* +* @return None. +* +* @note The handler is called within interrupt context . +* +****************************************************************************/ +void XIic_SetSendHandler(XIic *InstancePtr, void *CallBackRef, + XIic_Handler FuncPtr) +{ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertVoid(FuncPtr != NULL); + + InstancePtr->SendHandler = FuncPtr; + InstancePtr->SendCallBackRef = CallBackRef; +} + +/*****************************************************************************/ +/** +* +* Sets the status callback function, the status handler, which the driver calls +* when it encounters conditions which are not data related. The handler +* executes in an interrupt context such that it must minimize the amount of +* processing performed such as transferring data to a thread context. The +* status events that can be returned are described in xiic.h. +* +* @param InstancePtr points to the XIic instance to be worked on. +* @param CallBackRef is the upper layer callback reference passed back +* when the callback function is invoked. +* @param FuncPtr is the pointer to the callback function. +* +* @return None. +* +* @note The handler is called within interrupt context . +* +****************************************************************************/ +void XIic_SetStatusHandler(XIic *InstancePtr, void *CallBackRef, + XIic_StatusHandler FuncPtr) +{ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertVoid(FuncPtr != NULL); + + InstancePtr->StatusHandler = FuncPtr; + InstancePtr->StatusCallBackRef = CallBackRef; +} + +/***************************************************************************** +* +* This is a stub for the send and recv callbacks. The stub is here in case the +* upper layers forget to set the handlers. +* +* @param CallBackRef is a pointer to the upper layer callback reference +* @param ByteCount is the number of bytes sent or received +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void XIic_StubHandler(void *CallBackRef, int ByteCount) +{ + (void) ByteCount; + (void) CallBackRef; + Xil_AssertVoidAlways(); +} + +/***************************************************************************** +* +* This is a stub for the asynchronous error callback. The stub is here in case +* the upper layers forget to set the handler. +* +* @param CallBackRef is a pointer to the upper layer callback reference. +* @param ErrorCode is the Xilinx error code, indicating the cause of +* the error. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void XIic_StubStatusHandler(void *CallBackRef, int ErrorCode) +{ + (void) ErrorCode; + (void) CallBackRef; + Xil_AssertVoidAlways(); +} + +/***************************************************************************** +* +* This is a function which tells whether Bus is Busy or free. +* +* @param InstancePtr points to the XIic instance to be worked on. +* +* @return +* - TRUE if the Bus is Busy. +* - FALSE if the Bus is NOT Busy. +* +* @note None. +* +******************************************************************************/ +u32 XIic_IsIicBusy(XIic *InstancePtr) +{ + u32 StatusReg; + + StatusReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_SR_REG_OFFSET); + if (StatusReg & XIIC_SR_BUS_BUSY_MASK) { + return TRUE; + } else { + return FALSE; + } +} diff --git a/XilinxProcessorIPLib/drivers/iic/src/xiic.h b/XilinxProcessorIPLib/drivers/iic/src/xiic.h new file mode 100644 index 00000000..6f6e51c4 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/iic/src/xiic.h @@ -0,0 +1,572 @@ +/****************************************************************************** +* +* Copyright (C) 2002 - 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 THE +* XILINX CONSORTIUM 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 xiic.h +* +* XIic is the driver for an IIC master or slave device. +* +* In order to reduce the memory requirements of the driver the driver is +* partitioned such that there are optional parts of the driver. +* Slave, master, and multimaster features are optional such that all these files +* are not required at the same time. +* In order to use the slave and multimaster features of the driver, the user +* must call functions (XIic_SlaveInclude and XIic_MultiMasterInclude) +* to dynamically include the code. These functions may be called at any time. +* +* Two sets of higher level API's are available in the XIic driver that can +* be used for Transmission/Reception in Master mode : +* - XIic_MasterSend()/ XIic_MasterRecv() which is used in normal mode. +* - XIic_DynMasterSend()/ XIic_DynMasterRecv() which is used in Dynamic mode. +* +* Similarly two sets of lower level API's are available in XIic driver that +* can be used for Transmission/Reception in Master mode: +* - XIic_Send()/ XIic_Recv() which is used in normal mode +* - XIic_DynSend()/ XIic_DynRecv() which is used in Dynamic mode. +* +* The user should use a single set of APIs as per his requirement and +* should not intermix them. +* +* All the driver APIs can be used for read, write and combined mode of +* operations on the IIC bus. +* +* In the normal mode IIC support both 7-bit and 10-bit addressing, and in +* the dynamic mode support only 7-bit addressing. +* +* Initialization & Configuration +* +* The XIic_Config structure is used by the driver to configure itself. This +* configuration structure is typically created by the tool-chain based on HW +* build properties. +* +* To support multiple runtime loading and initialization strategies employed +* by various operating systems, the driver instance can be initialized in one +* of the following ways: +* +* - XIic_Initialize() - The driver looks up its own +* configuration structure created by the tool-chain based on an ID provided +* by the tool-chain. +* +* - XIic_CfgInitialize() - The driver uses a configuration structure provided +* by the caller. If running in a system with address translation, the +* provided virtual memory base address replaces the physical address present +* in the configuration structure. +* +* General Purpose Output +* The IIC hardware provides a General Purpose Output Register that allows the +* user to connect general purpose outputs to devices, such as a write protect, +* for an EEPROM. This register is parameterizable in the hardware such that +* there could be zero bits in this register and in this case it will cause +* a bus error if read or written. +* +* Bus Throttling +* +* The IIC hardware provides bus throttling which allows either the device, as +* either a master or a slave, to stop the clock on the IIC bus. This feature +* allows the software to perform the appropriate processing for each interrupt +* without an unreasonable response restriction. With this design, it is +* important for the user to understand the implications of bus throttling. +* +* Repeated Start +* +* An application can send multiple messages, as a master, to a slave device +* and re-acquire the IIC bus each time a message is sent. The repeated start +* option allows the application to send multiple messages without re-acquiring +* the IIC bus for each message. The transactions involving repeated start +* are also called combined transfers if there is Read and Write in the +* same transaction. +* +* The repeated start feature works with all the API's in XIic driver. +* +* The Repeated Start feature also could cause the application to lock up, or +* monopolize the IIC bus, should repeated start option be enabled and sequences +* of messages never end(periodic data collection). +* Also when repeated start is not disable before the last master message is +* sent or received, will leave the bus captive to the master, but unused. +* +* Addressing +* +* The IIC hardware is parameterized such that it can be built for 7 or 10 +* bit addresses. The driver provides the ability to control which address +* size is sent in messages as a master to a slave device. The address size +* which the hardware responds to as a slave is parameterized as 7 or 10 bits +* but fixed by the hardware build. +* +* Addresses are represented as hex values with no adjustment for the data +* direction bit as the software manages address bit placement. This is +* especially important as the bit placement is not handled the same depending +* on which options are used such as repeated start and 7 vs 10 bit addessing. +* +* Data Rates +* +* The IIC hardware is parameterized such that it can be built to support +* data rates from DC to 400KBit. The frequency of the interrupts which +* occur is proportional to the data rate. +* +* Polled Mode Operation +* +* This driver does not provide a polled mode of operation primarily because +* polled mode which is non-blocking is difficult with the amount of +* interaction with the hardware that is necessary. +* +* Interrupts +* +* The device has many interrupts which allow IIC data transactions as well +* as bus status processing to occur. +* +* The interrupts are divided into two types, data and status. Data interrupts +* indicate data has been received or transmitted while the status interrupts +* indicate the status of the IIC bus. Some of the interrupts, such as Not +* Addressed As Slave and Bus Not Busy, are only used when these specific +* events must be recognized as opposed to being enabled at all times. +* +* Many of the interrupts are not a single event in that they are continuously +* present such that they must be disabled after recognition or when undesired. +* Some of these interrupts, which are data related, may be acknowledged by the +* software by reading or writing data to the appropriate register, or must +* be disabled. The following interrupts can be continuous rather than single +* events. +* - Data Transmit Register Empty/Transmit FIFO Empty +* - Data Receive Register Full/Receive FIFO +* - Transmit FIFO Half Empty +* - Bus Not Busy +* - Addressed As Slave +* - Not Addressed As Slave +* +* The following interrupts are not passed directly to the application thru the +* status callback. These are only used internally for the driver processing +* and may result in the receive and send handlers being called to indicate +* completion of an operation. The following interrupts are data related +* rather than status. +* - Data Transmit Register Empty/Transmit FIFO Empty +* - Data Receive Register Full/Receive FIFO +* - Transmit FIFO Half Empty +* - Slave Transmit Complete +* +* Interrupt To Event Mapping +* +* The following table provides a mapping of the interrupts to the events which +* are passed to the status handler and the intended role (master or slave) for +* the event. Some interrupts can cause multiple events which are combined +* together into a single status event such as XII_MASTER_WRITE_EVENT and +* XII_GENERAL_CALL_EVENT +*
+* Interrupt Event(s) Role +* +* Arbitration Lost Interrupt XII_ARB_LOST_EVENT Master +* Transmit Error XII_SLAVE_NO_ACK_EVENT Master +* IIC Bus Not Busy XII_BUS_NOT_BUSY_EVENT Master +* Addressed As Slave XII_MASTER_READ_EVENT, Slave +* XII_MASTER_WRITE_EVENT, Slave +* XII_GENERAL_CALL_EVENT Slave +*+* Not Addressed As Slave Interrupt +* +* The Not Addressed As Slave interrupt is not passed directly to the +* application thru the status callback. It is used to determine the end of +* a message being received by a slave when there was no stop condition +* (repeated start). It will cause the receive handler to be called to +* indicate completion of the operation. +* +* RTOS Independence +* +* This driver is intended to be RTOS and processor independent. It works +* with physical addresses only. Any needs for dynamic memory management, +* threads or thread mutual exclusion, virtual memory, or cache control must +* be satisfied by the layer above this driver. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.01a rfp 10/19/01 release +* 1.01c ecm 12/05/02 new rev +* 1.01d jhl 10/08/03 Added general purpose output feature +* 1.01d sv 05/09/05 Changed the data being written to the Address/Control +* Register and removed the code for testing the +* Receive Data Register in XIic_SelfTest function of +* xiic_selftest.c source file +* 1.02a jvb 12/14/05 I separated dependency on the static config table and +* xparameters.h from the driver initialization by moving +* _Initialize and _LookupConfig to _sinit.c. I also added +* the new _CfgInitialize routine. +* 1.02a mta 03/09/06 Added a new function XIic_IsIicBusy() which returns +* whether IIC Bus is Busy or Free. +* 1.02a mta 03/09/06 Implemented Repeated Start in the Low Level Driver. +* 1.03a mta 07/17/06 Added files to support Dynamic IIC controller in High +* level driver. Added xiic_dyn_master.c. Added support +* for IIC Dynamic controller in Low level driver in xiic_l.c +* 1.13a wgr 03/22/07 Converted to new coding style. +* 1.13b ecm 11/29/07 added BB polling loops to the DynSend and DynRecv +* routines to handle the race condition with BNB in IISR. +* 1.14a sdm 08/22/08 Removed support for static interrupt handlers from the MDD +* file +* 1.14a ecm 11/13/08 changed BB polling loops in DynRecv to handle race +* condition, CR491889. DynSend was correct from v1.13.b +* 1.15a ktn 02/17/09 Fixed XIic_GetAddress() to return correct device address. +* 1.16a ktn 07/17/09 Updated the XIic_SelfTest() to test only Interrupt +* Registers. +* 2.00a ktn 10/22/09 Converted all register accesses to 32 bit access., +* Removed the macro XIIC_RESET, XIic_Reset API should be +* used in its place. +* Removed the XIIC_CLEAR_STATS macro, XIic_ClearStats API +* should be used in its place. +* Removed the macro XIic_mEnterCriticalRegion, +* XIic_IntrGlobalDisable should be used in its place. +* Removed the macro XIic_mExitCriticalRegion, +* XIic_IntrGlobalEnable should be used in its place. +* Some of the macros have been renamed to remove _m from +* the name see the xiic_i.h and xiic_l.h file for further +* information (Example XIic_mClearIntr is now +* XIic_ClearIntr). +* Some of the macros have been renamed to be consistent, +* see the xiic_l.h file for further information +* (Example XIIC_WRITE_IIER is renamed as XIic_WriteIier). +* The driver has been updated to use the HAL APIs/macros +* (Example XASSERT_NONVOID is now Xil_AssertNonvoid) +* 2.01a ktn 04/09/10 Updated TxErrorhandler in xiic_intr.c to be called for +* Master Transmitter case based on Addressed As Slave (AAS) +* bit rather than MSMS bit(CR 540199). +* 2.02a sdm 10/08/10 Updated to disable the device at the end of the transfer, +* using Addressed As Slave (AAS) bit when addressed as +* slave in XIic_Send for CR565373. +* 2.03a rkv 01/25/11 Updated in NAAS interrupt handler to support data +* recieved less than FIFO size prior to NAAS interrupt. +* Fixed for CR590212. +* 2.04a sdm 07/22/11 Added IsSlaveSetAckOff flag to the instance structure. +* This flag is set when the Slave has set the Ack Off in the +* RecvSlaveData function (xiic_slave.c) and +* is cleared in the NotAddrAsSlaveHandler (xiic_slave.c) +* when the master has released the bus. This flag is +* to be used by slave applications for recovering when it +* has gone out of sync with the master for CR 615004. +* Removed a compiler warning in XIic_Send (xiic_l.c) +* 2.05a bss 02/05/12 Assigned RecvBufferPtr in XIic_MasterSend API and +* SendBufferPtr in XIic_MasterRecv to NULL in xiic_master.c +* 2.06a bss 02/14/13 Modified TxErrorHandler in xiic_intr.c to fix CR #686483 +* Modified xiic_eeprom_example.c to fix CR# 683509. +* Modified bitwise OR to logical OR in +* XIic_InterruptHandler API in xiic_intr.c. +* 2.07a adk 18/04/13 Updated the code to avoid unused variable warnings +* when compiling with the -Wextra -Wall flags. +* Changes done in files xiic.c and xiic_i.h. CR:705001 +* 2.08a adk 29/07/13 In Low level driver In repeated start condition the +* Direction of Tx bit must be disabled in recv condition +* It Fixes the CR:685759 Changes are done in the file +* xiic_l.c in the function XIic_Recv. +* 3.0 adk 19/12/13 Updated as per the New Tcl API's +*+* +******************************************************************************/ +#ifndef XIIC_H /* prevent circular inclusions */ +#define XIIC_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include "xil_types.h" +#include "xil_assert.h" +#include "xstatus.h" +#include "xiic_l.h" + +/************************** Constant Definitions *****************************/ + +/** @name Configuration options + * + * The following options may be specified or retrieved for the device and + * enable/disable additional features of the IIC bus. Each of the options + * are bit fields such that more than one may be specified. + * @{ + */ +/** + *
+ * XII_GENERAL_CALL_OPTION The general call option allows an IIC slave to + * recognized the general call address. The status + * handler is called as usual indicating the device + * has been addressed as a slave with a general + * call. It is the application's responsibility to + * perform any special processing for the general + * call. + * + * XII_REPEATED_START_OPTION The repeated start option allows multiple + * messages to be sent/received on the IIC bus + * without rearbitrating for the bus. The messages + * are sent as a series of messages such that the + * option must be enabled before the 1st message of + * the series, to prevent an stop condition from + * being generated on the bus, and disabled before + * the last message of the series, to allow the + * stop condition to be generated. + * + * XII_SEND_10_BIT_OPTION The send 10 bit option allows 10 bit addresses + * to be sent on the bus when the device is a + * master. The device can be configured to respond + * as to 7 bit addresses even though it may be + * communicating with other devices that support 10 + * bit addresses. When this option is not enabled, + * only 7 bit addresses are sent on the bus. + * + *+ */ +#define XII_GENERAL_CALL_OPTION 0x00000001 +#define XII_REPEATED_START_OPTION 0x00000002 +#define XII_SEND_10_BIT_OPTION 0x00000004 + +/*@}*/ + +/** @name Status events + * + * The following status events occur during IIC bus processing and are passed + * to the status callback. Each event is only valid during the appropriate + * processing of the IIC bus. Each of these events are bit fields such that + * more than one may be specified. + * @{ + */ +#define XII_BUS_NOT_BUSY_EVENT 0x00000001 /**< Bus transitioned to not busy */ +#define XII_ARB_LOST_EVENT 0x00000002 /**< Arbitration was lost */ +#define XII_SLAVE_NO_ACK_EVENT 0x00000004 /**< Slave did not ACK (had error) */ +#define XII_MASTER_READ_EVENT 0x00000008 /**< Master reading from slave */ +#define XII_MASTER_WRITE_EVENT 0x00000010 /**< Master writing to slave */ +#define XII_GENERAL_CALL_EVENT 0x00000020 /**< General call to all slaves */ +/*@}*/ + + +/* + * The following address types are used when setting and getting the addresses + * of the driver. These are mutually exclusive such that only one or the other + * may be specified. + */ +#define XII_ADDR_TO_SEND_TYPE 1 /**< Bus address of slave device */ +#define XII_ADDR_TO_RESPOND_TYPE 2 /**< This device's bus address as slave */ + +/**************************** Type Definitions *******************************/ + +/** + * This typedef contains configuration information for the device. + */ +typedef struct { + u16 DeviceId; /**< Unique ID of device */ + u32 BaseAddress; /**< Device base address */ + int Has10BitAddr; /**< Does device have 10 bit address decoding */ + u8 GpOutWidth; /**< Number of bits in general purpose output */ +} XIic_Config; + +/****************************************************************************/ +/** +* This callback function data type is defined to handle the asynchronous +* processing of sent and received data of the IIC driver. The application +* using this driver is expected to define a handler of this type to support +* interrupt driven mode. The handlers are called in an interrupt context such +* that minimal processing should be performed. The handler data type is +* utilized for both send and receive handlers. +* +* @param CallBackRef is a callback reference passed in by the upper +* layer when setting the callback functions, and passed back +* to the upper layer when the callback is invoked. Its type is +* unimportant to the driver component, so it is a void pointer. +* @param ByteCount indicates the number of bytes remaining to be sent or +* received. A value of zero indicates that the requested number +* of bytes were sent or received. +* +******************************************************************************/ +typedef void (*XIic_Handler) (void *CallBackRef, int ByteCount); + +/******************************************************************************/ +/** +* This callback function data type is defined to handle the asynchronous +* processing of status events of the IIC driver. The application using +* this driver is expected to define a handler of this type to support +* interrupt driven mode. The handler is called in an interrupt context such +* that minimal processing should be performed. +* +* @param CallBackRef is a callback reference passed in by the upper +* layer when setting the callback functions, and passed back +* to the upper layer when the callback is invoked. Its type is +* unimportant to the driver component, so it is a void pointer. +* @param StatusEvent indicates one or more status events that occurred. +* See the definition of the status events above. +* +********************************************************************************/ +typedef void (*XIic_StatusHandler) (void *CallBackRef, int StatusEvent); + +/** + * XIic statistics + */ +typedef struct { + u8 ArbitrationLost;/**< Number of times arbitration was lost */ + u8 RepeatedStarts; /**< Number of repeated starts */ + u8 BusBusy; /**< Number of times bus busy status returned */ + u8 RecvBytes; /**< Number of bytes received */ + u8 RecvInterrupts; /**< Number of receive interrupts */ + u8 SendBytes; /**< Number of transmit bytes received */ + u8 SendInterrupts; /**< Number of transmit interrupts */ + u8 TxErrors; /**< Number of transmit errors (no ack) */ + u8 IicInterrupts; /**< Number of IIC (device) interrupts */ +} XIicStats; + +/** + * The XIic driver instance data. The user is required to allocate a + * variable of this type for every IIC device in the system. A pointer + * to a variable of this type is then passed to the driver API functions. + */ +typedef struct { + XIicStats Stats; /**< Statistics */ + u32 BaseAddress; /**< Device base address */ + int Has10BitAddr; /**< TRUE when 10 bit addressing in design */ + int IsReady; /**< Device is initialized and ready */ + int IsStarted; /**< Device has been started */ + int AddrOfSlave; /**< Slave Address writing to */ + + u32 Options; /**< Current operating options */ + u8 *SendBufferPtr; /**< Buffer to send (state) */ + u8 *RecvBufferPtr; /**< Buffer to receive (state) */ + u8 TxAddrMode; /**< State of Tx Address transmission */ + int SendByteCount; /**< Number of data bytes in buffer (state) */ + int RecvByteCount; /**< Number of empty bytes in buffer (state) */ + + u32 BNBOnly; /**< TRUE when BNB interrupt needs to */ + /**< call callback */ + u8 GpOutWidth; /**< General purpose output width */ + + XIic_StatusHandler StatusHandler; /**< Status Handler */ + void *StatusCallBackRef; /**< Callback reference for status handler */ + XIic_Handler RecvHandler; /**< Receive Handler */ + void *RecvCallBackRef; /**< Callback reference for Recv handler */ + XIic_Handler SendHandler; /**< Send Handler */ + void *SendCallBackRef; /**< Callback reference for send handler */ + int IsDynamic; /**< TRUE when Dynamic control is used */ + int IsSlaveSetAckOff; /**< TRUE when Slave has set the ACK Off */ + +} XIic; + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +/* + * Initialization functions in xiic_sinit.c + */ +int XIic_Initialize(XIic *InstancePtr, u16 DeviceId); +XIic_Config *XIic_LookupConfig(u16 DeviceId); + +/* + * Functions in xiic.c + */ +int XIic_CfgInitialize(XIic *InstancePtr, XIic_Config *Config, + u32 EffectiveAddr); + +int XIic_Start(XIic *InstancePtr); +int XIic_Stop(XIic *InstancePtr); + +void XIic_Reset(XIic *InstancePtr); + +int XIic_SetAddress(XIic *InstancePtr, int AddressType, int Address); +u16 XIic_GetAddress(XIic *InstancePtr, int AddressType); + +int XIic_SetGpOutput(XIic *InstancePtr, u8 OutputValue); +int XIic_GetGpOutput(XIic *InstancePtr, u8 *OutputValuePtr); + +u32 XIic_IsSlave(XIic *InstancePtr); + +void XIic_SetRecvHandler(XIic *InstancePtr, void *CallBackRef, + XIic_Handler FuncPtr); +void XIic_SetSendHandler(XIic *InstancePtr, void *CallBackRef, + XIic_Handler FuncPtr); +void XIic_SetStatusHandler(XIic *InstancePtr, void *CallBackRef, + XIic_StatusHandler FuncPtr); + +/* + * Interrupt functions in xiic_intr.c + */ +void XIic_InterruptHandler(void *InstancePtr); + +/* + * Master send and receive functions in normal mode in xiic_master.c + */ +int XIic_MasterRecv(XIic *InstancePtr, u8 *RxMsgPtr, int ByteCount); +int XIic_MasterSend(XIic *InstancePtr, u8 *TxMsgPtr, int ByteCount); + +/* + * Master send and receive functions in dynamic mode in xiic_master.c + */ +int XIic_DynMasterRecv(XIic *InstancePtr, u8 *RxMsgPtr, u8 ByteCount); +int XIic_DynMasterSend(XIic *InstancePtr, u8 *TxMsgPtr, u8 ByteCount); + +/* + * Dynamic IIC Core Initialization. + */ +int XIic_DynamicInitialize(XIic *InstancePtr); + +/* + * Slave send and receive functions in xiic_slave.c + */ +void XIic_SlaveInclude(void); +int XIic_SlaveRecv(XIic *InstancePtr, u8 *RxMsgPtr, int ByteCount); +int XIic_SlaveSend(XIic *InstancePtr, u8 *TxMsgPtr, int ByteCount); + +/* + * Statistics functions in xiic_stats.c + */ +void XIic_GetStats(XIic *InstancePtr, XIicStats *StatsPtr); +void XIic_ClearStats(XIic *InstancePtr); + +/* + * Self test functions in xiic_selftest.c + */ +int XIic_SelfTest(XIic *InstancePtr); + +/* + * Bus busy Function in xiic.c + */ +u32 XIic_IsIicBusy(XIic *InstancePtr); + +/* + * Options functions in xiic_options.c + */ +void XIic_SetOptions(XIic *InstancePtr, u32 Options); +u32 XIic_GetOptions(XIic *InstancePtr); + +/* + * Multi-master functions in xiic_multi_master.c + */ +void XIic_MultiMasterInclude(void); + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ diff --git a/XilinxProcessorIPLib/drivers/iic/src/xiic_dyn_master.c b/XilinxProcessorIPLib/drivers/iic/src/xiic_dyn_master.c new file mode 100644 index 00000000..3e69400d --- /dev/null +++ b/XilinxProcessorIPLib/drivers/iic/src/xiic_dyn_master.c @@ -0,0 +1,626 @@ +/****************************************************************************** +* +* Copyright (C) 2006 - 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 THE +* XILINX CONSORTIUM 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 xiic_dyn_master.c +* +* Contains master functions for the XIic component in Dynamic controller mode. +* This file is necessary to send or receive as a master on the IIC bus. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- --- ------- ----------------------------------------------------------- +* 1.03a mta 04/10/06 Created. +* 1.13a wgr 03/22/07 Converted to new coding style. +* 2.00a ktn 10/22/09 Converted all register accesses to 32 bit access. +* Updated to use the HAL APIs/macros. The macros +* XIic_mDynSend7BitAddress and XIic_mDynSendStop have +* been removed from this file as they were already +* defined in a header file. +* Some of the macros have been renamed to remove _m from +* the name and Some of the macros have been renamed to be +* consistent, see the xiic_l.h file for further information. +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xiic.h" +#include "xiic_i.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/****************************************************************************** +* +* This macro includes dynamic master code such that dynamic master operations, +* sending and receiving data, may be used. This function hooks the dynamic +* master processing to the driver such that events are handled properly and +* allows dynamic master processing to be optional. It must be called before any +* functions which are contained in this file are called, such as after the +* driver is initialized. +* +* @param None. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +#define XIIC_DYN_MASTER_INCLUDE \ +{ \ + XIic_RecvMasterFuncPtr = DynRecvMasterData; \ + XIic_SendMasterFuncPtr = DynSendMasterData; \ +} + +/************************** Function Prototypes ******************************/ + +static void DynRecvMasterData(XIic *InstancePtr); +static void DynSendMasterData(XIic *InstancePtr); +static int IsBusBusy(XIic *InstancePtr); + +/************************** Variable Definitions *****************************/ + +/*****************************************************************************/ +/** +* This function sends data as a Dynamic master on the IIC bus. If the bus is +* busy, it will indicate so and then enable an interrupt such that the status +* handler will be called when the bus is no longer busy. The slave address is +* sent by using XIic_DynSend7BitAddress(). +* +* @param InstancePtr points to the Iic instance to be worked on. +* @param TxMsgPtr points to the data to be transmitted. +* @param ByteCount is the number of message bytes to be sent. +* +* @return XST_SUCCESS if successful else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int XIic_DynMasterSend(XIic *InstancePtr, u8 *TxMsgPtr, u8 ByteCount) +{ + u32 CntlReg; + + XIic_IntrGlobalDisable(InstancePtr->BaseAddress); + + /* + * Ensure that the Dynamic master processing has been included such that + * events will be properly handled. + */ + XIIC_DYN_MASTER_INCLUDE; + InstancePtr->IsDynamic = TRUE; + + /* + * If the busy is busy, then exit the critical region and wait for the + * bus not to be busy. The function enables the BusNotBusy interrupt. + */ + if (IsBusBusy(InstancePtr)) { + XIic_IntrGlobalEnable(InstancePtr->BaseAddress); + + return XST_FAILURE; + } + + /* + * If it is already a master on the bus (repeated start), the direction + * was set to Tx which is throttling bus. The control register needs to + * be set before putting data into the FIFO. + */ + CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET); + if (CntlReg & XIIC_CR_MSMS_MASK) { + CntlReg &= ~XIIC_CR_NO_ACK_MASK; + CntlReg |= XIIC_CR_DIR_IS_TX_MASK; + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, + CntlReg); + InstancePtr->Stats.RepeatedStarts++; + } + + /* + * Save message state. + */ + InstancePtr->SendByteCount = ByteCount; + InstancePtr->SendBufferPtr = TxMsgPtr; + + /* + * Send the Seven Bit address. Only 7 bit addressing is supported in + * Dynamic mode. + */ + XIic_DynSend7BitAddress(InstancePtr->BaseAddress, + InstancePtr->AddrOfSlave, + XIIC_WRITE_OPERATION); + + /* + * Set the transmit address state to indicate the address has been sent + * for communication with event driven processing. + */ + InstancePtr->TxAddrMode = XIIC_TX_ADDR_SENT; + + /* + * Fill the Tx FIFO. + */ + if (InstancePtr->SendByteCount > 1) { + XIic_TransmitFifoFill(InstancePtr, XIIC_MASTER_ROLE); + } + + /* + * After filling fifo, if data yet to send > 1, enable Tx � empty + * interrupt. + */ + if (InstancePtr->SendByteCount > 1) { + XIic_ClearEnableIntr(InstancePtr->BaseAddress, + XIIC_INTR_TX_HALF_MASK); + } + + /* + * Clear any pending Tx empty, Tx Error and then enable them. + */ + XIic_ClearEnableIntr(InstancePtr->BaseAddress, + XIIC_INTR_TX_ERROR_MASK | + XIIC_INTR_TX_EMPTY_MASK); + + /* + * Enable the Interrupts. + */ + XIic_IntrGlobalEnable(InstancePtr->BaseAddress); + + return XST_SUCCESS; +} + +/****************************************************************************** +* +* When the IIC Tx FIFO/register goes empty, this routine is called by the +* interrupt service routine to fill the transmit FIFO with data to be sent. +* +* This function also is called by the Tx � empty interrupt as the data handling +* is identical when you don't assume the FIFO is empty but use the Tx_FIFO_OCY +* register to indicate the available free FIFO bytes. +* +* @param InstancePtr is a pointer to the XIic instance to be worked on. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void DynSendMasterData(XIic *InstancePtr) +{ + u32 CntlReg; + + /* + * In between 1st and last byte of message, fill the FIFO with more data + * to send, disable the 1/2 empty interrupt based upon data left to + * send. + */ + if (InstancePtr->SendByteCount > 1) { + XIic_TransmitFifoFill(InstancePtr, XIIC_MASTER_ROLE); + + if (InstancePtr->SendByteCount < 2) { + XIic_DisableIntr(InstancePtr->BaseAddress, + XIIC_INTR_TX_HALF_MASK); + } + } + + /* + * If there is only one byte left to send, processing differs between + * repeated start and normal messages. + */ + else if (InstancePtr->SendByteCount == 1) { + /* + * When using repeated start, another interrupt is expected + * after the last byte has been sent, so the message is not + * done yet. + */ + if (InstancePtr->Options & XII_REPEATED_START_OPTION) { + XIic_WriteSendByte(InstancePtr); + } else { + XIic_DynSendStop(InstancePtr->BaseAddress, + *InstancePtr->SendBufferPtr); + + /* + * Wait for bus to not be busy before declaring message + * has been sent for the no repeated start operation. + * The callback will be called from the BusNotBusy part + * of the Interrupt handler to ensure that the message + * is completely sent. Disable the Tx interrupts and + * enable the BNB interrupt. + */ + InstancePtr->BNBOnly = FALSE; + XIic_DisableIntr(InstancePtr->BaseAddress, + XIIC_TX_INTERRUPTS); + XIic_EnableIntr(InstancePtr->BaseAddress, + XIIC_INTR_BNB_MASK); + } + } else { + if (InstancePtr->Options & XII_REPEATED_START_OPTION) { + /* + * The message being sent has completed. When using + * repeated start with no more bytes to send repeated + * start needs to be set in the control register so + * that the bus will still be held by this master. + */ + CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, + XIIC_CR_REG_OFFSET); + CntlReg |= XIIC_CR_REPEATED_START_MASK; + XIic_WriteReg(InstancePtr->BaseAddress, + XIIC_CR_REG_OFFSET, CntlReg); + + /* + * If the message that was being sent has finished, + * disable all transmit interrupts and call the callback + * that was setup to indicate the message was sent, + * with 0 bytes remaining. + */ + XIic_DisableIntr(InstancePtr->BaseAddress, + XIIC_TX_INTERRUPTS); + InstancePtr->SendHandler(InstancePtr->SendCallBackRef, + 0); + } + } + + return; +} + +/*****************************************************************************/ +/** +* This function receives data as a master from a slave device on the IIC bus. +* If the bus is busy, it will indicate so and then enable an interrupt such +* that the status handler will be called when the bus is no longer busy. The +* slave address which has been set with the XIic_SetAddress() function is the +* address from which data is received. Receiving data on the bus performs a +* read operation. +* +* @param InstancePtr is a pointer to the Iic instance to be worked on. +* @param RxMsgPtr is a pointer to the data to be transmitted. +* @param ByteCount is the number of message bytes to be sent. +* +* @return - XST_SUCCESS indicates the message reception processes has been +* initiated. +* - XST_IIC_BUS_BUSY indicates the bus was in use and that the +* BusNotBusy interrupt is enabled which will update the +* EventStatus when the bus is no longer busy. +* - XST_IIC_GENERAL_CALL_ADDRESS indicates the slave address is +* set to the general call address. This is not allowed for Master +* receive mode. +* +* @note The receive FIFO threshold is a zero based count such that 1 +* must be subtracted from the desired count to get the correct +* value. When receiving data it is also necessary to not receive +* the last byte with the prior bytes because the acknowledge must +* be setup before the last byte is received. +* +******************************************************************************/ +int XIic_DynMasterRecv(XIic *InstancePtr, u8 *RxMsgPtr, u8 ByteCount) +{ + u32 CntlReg; + u32 RxFifoOccy; + + /* + * If the slave address is zero (general call) the master can't perform + * receive operations, indicate an error. + */ + if (InstancePtr->AddrOfSlave == 0) { + return XST_IIC_GENERAL_CALL_ADDRESS; + } + + /* + * Disable the Interrupts. + */ + XIic_IntrGlobalDisable(InstancePtr->BaseAddress); + + /* + * Ensure that the master processing has been included such that events + * will be properly handled. + */ + XIIC_DYN_MASTER_INCLUDE; + InstancePtr->IsDynamic = TRUE; + + /* + * If the busy is busy, then exit the critical region and wait for the + * bus to not be busy, the function enables the bus not busy interrupt. + */ + if (IsBusBusy(InstancePtr)) { + XIic_IntrGlobalEnable(InstancePtr->BaseAddress); + + return XST_IIC_BUS_BUSY; + } + + /* + * Save message state for event driven processing. + */ + InstancePtr->RecvByteCount = ByteCount; + InstancePtr->RecvBufferPtr = RxMsgPtr; + + /* + * Clear and enable Rx full interrupt. + */ + XIic_ClearEnableIntr(InstancePtr->BaseAddress, XIIC_INTR_RX_FULL_MASK); + + /* + * If already a master on the bus, the direction was set by Rx Interrupt + * routine to Tx which is throttling bus because during Rxing, Tx reg is + * empty = throttle. CR needs setting before putting data or the address + * written will go out as Tx instead of receive. Start Master Rx by + * setting CR Bits MSMS to Master and msg direction. + */ + CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET); + if (CntlReg & XIIC_CR_MSMS_MASK) { + /* + * Set the Repeated Start bit in CR. + */ + CntlReg |= XIIC_CR_REPEATED_START_MASK; + XIic_SetControlRegister(InstancePtr, CntlReg, ByteCount); + + /* + * Increment stats counts. + */ + InstancePtr->Stats.RepeatedStarts++; + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, + CntlReg); + } + + /* + * Set receive FIFO occupancy depth which must be done prior to writing + * the address in the FIFO because the transmitter will immediately + * start when in repeated start mode followed by the receiver such + * that the number of bytes to receive should be set 1st. + */ + if (ByteCount == 1) { + RxFifoOccy = 0; + } + else { + if (ByteCount <= IIC_RX_FIFO_DEPTH) { + RxFifoOccy = ByteCount - 2; + } else { + RxFifoOccy = IIC_RX_FIFO_DEPTH - 1; + } + } + + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_RFD_REG_OFFSET, + RxFifoOccy); + + /* + * Send the Seven Bit address. Only 7 bit addressing is supported in + * Dynamic mode and mark that the address has been sent. + */ + XIic_DynSend7BitAddress(InstancePtr->BaseAddress, + InstancePtr->AddrOfSlave, XIIC_READ_OPERATION); + InstancePtr->TxAddrMode = XIIC_TX_ADDR_SENT; + + /* + * Send the bytecount to be received and set the stop bit. + */ + XIic_DynSendStop(InstancePtr->BaseAddress, ByteCount); + + /* + * Tx error is enabled incase the address has no device to answer + * with Ack. When only one byte of data, must set NO ACK before address + * goes out therefore Tx error must not be enabled as it will go off + * immediately and the Rx full interrupt will be checked. If full, then + * the one byte was received and the Tx error will be disabled without + * sending an error callback msg. + */ + XIic_ClearEnableIntr(InstancePtr->BaseAddress, + XIIC_INTR_TX_ERROR_MASK); + + /* + * Enable the Interrupts. + */ + XIic_IntrGlobalEnable(InstancePtr->BaseAddress); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function is called when the receive register is full. The number +* of bytes received to cause the interrupt is adjustable using the Receive FIFO +* Depth register. The number of bytes in the register is read in the Receive +* FIFO occupancy register. Both these registers are zero based values (0-15) +* such that a value of zero indicates 1 byte. +* +* For a Master Receiver to properly signal the end of a message, the data must +* be read in up to the message length - 1, where control register bits will be +* set for bus controls to occur on reading of the last byte. +* +* @param InstancePtr is a pointer to the XIic instance to be worked on. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void DynRecvMasterData(XIic *InstancePtr) +{ + u8 LoopCnt; + u8 BytesInFifo; + u8 BytesToRead; + u32 CntlReg; + + /* + * Device is a master receiving, get the contents of the control + * register and determine the number of bytes in fifo to be read out. + */ + CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET); + BytesInFifo = (u8) XIic_ReadReg(InstancePtr->BaseAddress, + XIIC_RFO_REG_OFFSET) + 1; + + /* + * If data in FIFO holds all data to be retrieved - 1, set NOACK and + * disable the Tx error. + */ + if ((InstancePtr->RecvByteCount - BytesInFifo) == 1) { + /* + * Disable Tx error interrupt to prevent interrupt as this + * device will cause it when it set NO ACK next. + */ + XIic_DisableIntr(InstancePtr->BaseAddress, + XIIC_INTR_TX_ERROR_MASK); + XIic_ClearIntr(InstancePtr->BaseAddress, + XIIC_INTR_TX_ERROR_MASK); + + /* + * Read one byte to clear a place for the last byte to be read + * which will set the NO ACK. + */ + XIic_ReadRecvByte(InstancePtr); + } + + /* + * If data in FIFO is all the data to be received then get the data and + * also leave the device in a good state for the next transaction. + */ + else if ((InstancePtr->RecvByteCount - BytesInFifo) == 0) { + if (InstancePtr->Options & XII_REPEATED_START_OPTION) { + CntlReg |= XIIC_CR_REPEATED_START_MASK; + XIic_WriteReg(InstancePtr->BaseAddress, + XIIC_CR_REG_OFFSET, + CntlReg); + } + + /* + * Read data from the FIFO then set zero based FIFO read depth + * for a byte. + */ + for (LoopCnt = 0; LoopCnt < BytesInFifo; LoopCnt++) { + XIic_ReadRecvByte(InstancePtr); + } + + XIic_WriteReg(InstancePtr->BaseAddress, + XIIC_RFD_REG_OFFSET, 0); + + /* + * Disable Rx full interrupt and write the control reg with ACK + * allowing next byte sent to be acknowledged automatically. + */ + XIic_DisableIntr(InstancePtr->BaseAddress, + XIIC_INTR_RX_FULL_MASK); + + /* + * Send notification of msg Rx complete in RecvHandler callback. + */ + InstancePtr->RecvHandler(InstancePtr->RecvCallBackRef, 0); + } + else { + /* + * Fifo data not at n-1, read all but the last byte of data + * from the slave, if more than a FIFO full yet to receive + * read a FIFO full. + */ + BytesToRead = InstancePtr->RecvByteCount - BytesInFifo - 1; + if (BytesToRead > IIC_RX_FIFO_DEPTH) { + BytesToRead = IIC_RX_FIFO_DEPTH; + } + + /* + * Read in data from the FIFO. + */ + for (LoopCnt = 0; LoopCnt < BytesToRead; LoopCnt++) { + XIic_ReadRecvByte(InstancePtr); + } + } +} + +/****************************************************************************** +* +* This function checks to see if the IIC bus is busy. If so, it will enable +* the bus not busy interrupt such that the driver is notified when the bus +* is no longer busy. +* +* @param InstancePtr points to the Iic instance to be worked on. +* +* @return FALSE if the IIC bus is not busy else TRUE. +* +* @note The BusNotBusy interrupt is enabled which will update the +* EventStatus when the bus is no longer busy. +* +******************************************************************************/ +static int IsBusBusy(XIic *InstancePtr) +{ + u32 CntlReg; + u32 StatusReg; + + CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET); + StatusReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_SR_REG_OFFSET); + + /* + * If this device is already master of the bus as when using the + * repeated start and the bus is busy setup to wait for it to not + * be busy. + */ + if (((CntlReg & XIIC_CR_MSMS_MASK) == 0) && /* Not master */ + (StatusReg & XIIC_SR_BUS_BUSY_MASK)) { /* Is busy */ + /* + * The bus is busy, clear pending BNB interrupt incase + * previously set and then enable BusNotBusy interrupt. + */ + InstancePtr->BNBOnly = TRUE; + XIic_ClearEnableIntr(InstancePtr->BaseAddress, + XIIC_INTR_BNB_MASK); + InstancePtr->Stats.BusBusy++; + + return TRUE; + } + + return FALSE; +} + +/****************************************************************************** +* +* Initialize the IIC core for Dynamic Functionality. +* +* @param InstancePtr points to the Iic instance to be worked on. +* +* @return XST_SUCCESS if Successful else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int XIic_DynamicInitialize(XIic *InstancePtr) +{ + int Status; + + Xil_AssertNonvoid(InstancePtr != NULL); + + Status = XIic_DynInit(InstancePtr->BaseAddress); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} diff --git a/XilinxProcessorIPLib/drivers/iic/src/xiic_g.c b/XilinxProcessorIPLib/drivers/iic/src/xiic_g.c new file mode 100644 index 00000000..78586aac --- /dev/null +++ b/XilinxProcessorIPLib/drivers/iic/src/xiic_g.c @@ -0,0 +1,89 @@ +/****************************************************************************** +* +* Copyright (C) 2002 - 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 THE +* XILINX CONSORTIUM 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 xiic_g.c +* +* This file contains a configuration table that specifies the configuration of +* IIC devices in the system. Each IIC device should have an entry in this table. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- --- ------- ----------------------------------------------- +* 1.01a rfp 10/19/01 release +* 1.01c ecm 12/05/02 new rev +* 1.01d jhl 10/08/03 Added general purpose output feature +* 1.13a wgr 03/22/07 Converted to new coding style. +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xiic.h" +#include "xparameters.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + + +/************************** Variable Definitions *****************************/ + +/** + * The IIC configuration table, sized by the number of instances + * defined in xparameters.h. + */ +XIic_Config XIic_ConfigTable[XPAR_XIIC_NUM_INSTANCES] = { + { + XPAR_IIC_0_DEVICE_ID, /* Device ID for instance */ + XPAR_IIC_0_BASEADDR, /* Base address */ + XPAR_IIC_0_TEN_BIT_ADR,/* Uses 10 bit addressing */ + XPAR_IIC_0_GPO_WIDTH, /* Number of bits in GPO register */ + } + , + { + XPAR_IIC_1_DEVICE_ID, /* Device ID for instance */ + XPAR_IIC_1_BASEADDR, /* Base address */ + XPAR_IIC_1_TEN_BIT_ADR /* Uses 10 bit addressing */ + XPAR_IIC_1_GPO_WIDTH, /* Number of bits in GPO register */ + } +}; diff --git a/XilinxProcessorIPLib/drivers/iic/src/xiic_i.h b/XilinxProcessorIPLib/drivers/iic/src/xiic_i.h new file mode 100644 index 00000000..c00eb8ef --- /dev/null +++ b/XilinxProcessorIPLib/drivers/iic/src/xiic_i.h @@ -0,0 +1,392 @@ +/****************************************************************************** +* +* Copyright (C) 2002 - 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 THE +* XILINX CONSORTIUM 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 xiic_i.h +* +* This header file contains internal identifiers, which are those shared +* between XIic components. The identifiers in this file are not intended for +* use external to the driver. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.01a rfp 10/19/01 release +* 1.01c ecm 12/05/02 new rev +* 1.13a wgr 03/22/07 Converted to new coding style. +* 2.00a sdm 10/22/09 Converted all register accesses to 32 bit access. +* Removed the macro XIIC_CLEAR_STATS, user has to +* use the the XIic_ClearStats API in its place. +* Removed the macro XIic_mEnterCriticalRegion, +* XIic_IntrGlobalDisable should be used in its place. +* Removed the macro XIic_mExitCriticalRegion, +* XIic_IntrGlobalEnable should be used in its place. +* Removed the _m prefix from all the macros +* XIic_mSend10BitAddrByte1 is now XIic_Send10BitAddrByte1 +* XIic_mSend10BitAddrByte2 is now XIic_Send10BitAddrByte2 +* XIic_mSend7BitAddr is now XIic_Send7BitAddr +* XIic_mDisableIntr is now XIic_DisableIntr +* XIic_mEnableIntr is now XIic_EnableIntr +* XIic_mClearIntr is now XIic_ClearIntr +* XIic_mClearEnableIntr is now XIic_ClearEnableIntr +* XIic_mFlushRxFifo is now XIic_FlushRxFifo +* XIic_mFlushTxFifo is now XIic_FlushTxFifo +* XIic_mReadRecvByte is now XIic_ReadRecvByte +* XIic_mWriteSendByte is now XIic_WriteSendByte +* XIic_mSetControlRegister is now XIic_SetControlRegister +* 2.07a adk 18/04/13 Updated the code to avoid unused variable warnings when +* compiling with the -Wextra -Wall flags. +* Changes done in files xiic.c and xiic_i.h. CR:705001 +* +*+* +******************************************************************************/ + +#ifndef XIIC_I_H /* prevent circular inclusions */ +#define XIIC_I_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include "xil_types.h" +#include "xil_assert.h" +#include "xstatus.h" +#include "xiic.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/****************************************************************************** +* +* This macro sends the first byte of the address for a 10 bit address during +* both read and write operations. It takes care of the details to format the +* address correctly. +* +* address = 1111_0xxD xx = address MSBits +* D = Tx direction = 0 = write +* +* @param SlaveAddress contains the address of the slave to send to. +* @param Operation indicates XIIC_READ_OPERATION or XIIC_WRITE_OPERATION +* +* @return None. +* +* @note Signature: +* void XIic_Send10BitAddrByte1(u16 SlaveAddress, u8 Operation); +* +******************************************************************************/ +#define XIic_Send10BitAddrByte1(SlaveAddress, Operation) \ +{ \ + u8 LocalAddr = (u8)((SlaveAddress) >> 7); \ + LocalAddr = (LocalAddr & 0xF6) | 0xF0 | (Operation); \ + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_DTR_REG_OFFSET, \ + (u32) LocalAddr); \ +} + +/****************************************************************************** +* +* This macro sends the second byte of the address for a 10 bit address during +* both read and write operations. It takes care of the details to format the +* address correctly. +* +* @param SlaveAddress contains the address of the slave to send to. +* +* @return None. +* +* @note Signature: void XIic_Send10BitAddrByte2(u16 SlaveAddress, +* u8 Operation); +* +******************************************************************************/ +#define XIic_Send10BitAddrByte2(SlaveAddress) \ + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_DTR_REG_OFFSET, \ + (u32)(SlaveAddress)); \ + +/****************************************************************************** +* +* This macro sends the address for a 7 bit address during both read and write +* operations. It takes care of the details to format the address correctly. +* +* @param SlaveAddress contains the address of the slave to send to. +* @param Operation indicates XIIC_READ_OPERATION or XIIC_WRITE_OPERATION +* +* @return None. +* +* @note Signature: +* void XIic_Send7BitAddr(u16 SlaveAddress, u8 Operation); +* +******************************************************************************/ +#define XIic_Send7BitAddr(SlaveAddress, Operation) \ +{ \ + u8 LocalAddr = (u8)(SlaveAddress << 1); \ + LocalAddr = (LocalAddr & 0xFE) | (Operation); \ + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_DTR_REG_OFFSET, \ + (u32) LocalAddr); \ +} + +/****************************************************************************** +* +* This macro disables the specified interrupts in the Interrupt enable +* register. It is non-destructive in that the register is read and only the +* interrupts specified is changed. +* +* @param BaseAddress is the base address of the IIC device. +* @param InterruptMask contains the interrupts to be disabled +* +* @return None. +* +* @note Signature: +* void XIic_DisableIntr(u32 BaseAddress, u32 InterruptMask); +* +******************************************************************************/ +#define XIic_DisableIntr(BaseAddress, InterruptMask) \ + XIic_WriteIier((BaseAddress), \ + XIic_ReadIier(BaseAddress) & ~(InterruptMask)) + +/****************************************************************************** +* +* This macro enables the specified interrupts in the Interrupt enable +* register. It is non-destructive in that the register is read and only the +* interrupts specified is changed. +* +* @param BaseAddress is the base address of the IIC device. +* @param InterruptMask contains the interrupts to be disabled +* +* @return None. +* +* @note Signature: +* void XIic_EnableIntr(u32 BaseAddress, u32 InterruptMask); +* +******************************************************************************/ +#define XIic_EnableIntr(BaseAddress, InterruptMask) \ + XIic_WriteIier((BaseAddress), \ + XIic_ReadIier(BaseAddress) | (InterruptMask)) + +/****************************************************************************** +* +* This macro clears the specified interrupt in the Interrupt status +* register. It is non-destructive in that the register is read and only the +* interrupt specified is cleared. Clearing an interrupt acknowledges it. +* +* @param BaseAddress is the base address of the IIC device. +* @param InterruptMask contains the interrupts to be disabled +* +* @return None. +* +* @note Signature: +* void XIic_ClearIntr(u32 BaseAddress, u32 InterruptMask); +* +******************************************************************************/ +#define XIic_ClearIntr(BaseAddress, InterruptMask) \ + XIic_WriteIisr((BaseAddress), \ + XIic_ReadIisr(BaseAddress) & (InterruptMask)) + +/****************************************************************************** +* +* This macro clears and enables the specified interrupt in the Interrupt +* status and enable registers. It is non-destructive in that the registers are +* read and only the interrupt specified is modified. +* Clearing an interrupt acknowledges it. +* +* @param BaseAddress is the base address of the IIC device. +* @param InterruptMask contains the interrupts to be cleared and enabled +* +* @return None. +* +* @note Signature: +* void XIic_ClearEnableIntr(u32 BaseAddress, u32 InterruptMask); +* +******************************************************************************/ +#define XIic_ClearEnableIntr(BaseAddress, InterruptMask) \ +{ \ + XIic_WriteIisr(BaseAddress, \ + (XIic_ReadIisr(BaseAddress) & (InterruptMask))); \ + \ + XIic_WriteIier(BaseAddress, \ + (XIic_ReadIier(BaseAddress) | (InterruptMask))); \ +} + +/****************************************************************************** +* +* This macro flushes the receive FIFO such that all bytes contained within it +* are discarded. +* +* @param InstancePtr is a pointer to the IIC instance containing the FIFO +* to be flushed. +* +* @return None. +* +* @note Signature: +* void XIic_FlushRxFifo(XIic *InstancePtr); +* +******************************************************************************/ +#define XIic_FlushRxFifo(InstancePtr) \ +{ \ + int LoopCnt; \ + u8 BytesToRead = XIic_ReadReg(InstancePtr->BaseAddress, \ + XIIC_RFO_REG_OFFSET) + 1; \ + for(LoopCnt = 0; LoopCnt < BytesToRead; LoopCnt++) \ + { \ + XIic_ReadReg(InstancePtr->BaseAddress, \ + XIIC_DRR_REG_OFFSET); \ + } \ +} + +/****************************************************************************** +* +* This macro flushes the transmit FIFO such that all bytes contained within it +* are discarded. +* +* @param InstancePtr is a pointer to the IIC instance containing the FIFO +* to be flushed. +* +* @return None. +* +* @note Signature: +* void XIic_FlushTxFifo(XIic *InstancePtr); +* +******************************************************************************/ +#define XIic_FlushTxFifo(InstancePtr); \ +{ \ + u32 CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, \ + XIIC_CR_REG_OFFSET); \ + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, \ + CntlReg | XIIC_CR_TX_FIFO_RESET_MASK); \ + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, \ + CntlReg); \ +} + +/****************************************************************************** +* +* This macro reads the next available received byte from the receive FIFO +* and updates all the data structures to reflect it. +* +* @param InstancePtr is a pointer to the IIC instance to be operated on. +* +* @return None. +* +* @note Signature: +* void XIic_ReadRecvByte(XIic *InstancePtr); +* +******************************************************************************/ +#define XIic_ReadRecvByte(InstancePtr) \ +{ \ + *InstancePtr->RecvBufferPtr++ = \ + XIic_ReadReg(InstancePtr->BaseAddress, XIIC_DRR_REG_OFFSET); \ + InstancePtr->RecvByteCount--; \ + InstancePtr->Stats.RecvBytes++; \ +} + +/****************************************************************************** +* +* This macro writes the next byte to be sent to the transmit FIFO +* and updates all the data structures to reflect it. +* +* @param InstancePtr is a pointer to the IIC instance to be operated on. +* +* @return None. +* +* @note Signature: +* void XIic_WriteSendByte(XIic *InstancePtr); +* +******************************************************************************/ +#define XIic_WriteSendByte(InstancePtr) \ +{ \ + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_DTR_REG_OFFSET, \ + *InstancePtr->SendBufferPtr++); \ + InstancePtr->SendByteCount--; \ + InstancePtr->Stats.SendBytes++; \ +} + +/****************************************************************************** +* +* This macro sets up the control register for a master receive operation. +* A write is necessary if a 10 bit operation is being performed. +* +* @param InstancePtr is a pointer to the IIC instance to be operated on. +* @param ControlRegister contains the contents of the IIC device control +* register +* @param ByteCount contains the number of bytes to be received for the +* master receive operation +* +* @return None. +* +* @note Signature: +* void XIic_SetControlRegister(XIic *InstancePtr, +* u8 ControlRegister, +* int ByteCount); +* +******************************************************************************/ +#define XIic_SetControlRegister(InstancePtr, ControlRegister, ByteCount) \ +{ \ + (ControlRegister) &= ~(XIIC_CR_NO_ACK_MASK | XIIC_CR_DIR_IS_TX_MASK); \ + if (InstancePtr->Options & XII_SEND_10_BIT_OPTION) { \ + (ControlRegister) |= XIIC_CR_DIR_IS_TX_MASK; \ + } else { \ + if ((ByteCount) == 1) \ + { \ + (ControlRegister) |= XIIC_CR_NO_ACK_MASK; \ + } \ + } \ +} + +/************************** Function Prototypes ******************************/ + +extern XIic_Config XIic_ConfigTable[]; + +/* The following variables are shared across files of the driver and + * are function pointers that are necessary to break dependencies allowing + * optional parts of the driver to be used without condition compilation + */ +extern void (*XIic_AddrAsSlaveFuncPtr) (XIic *InstancePtr); +extern void (*XIic_NotAddrAsSlaveFuncPtr) (XIic *InstancePtr); +extern void (*XIic_RecvSlaveFuncPtr) (XIic *InstancePtr); +extern void (*XIic_SendSlaveFuncPtr) (XIic *InstancePtr); +extern void (*XIic_RecvMasterFuncPtr) (XIic *InstancePtr); +extern void (*XIic_SendMasterFuncPtr) (XIic *InstancePtr); +extern void (*XIic_ArbLostFuncPtr) (XIic *InstancePtr); +extern void (*XIic_BusNotBusyFuncPtr) (XIic *InstancePtr); + +void XIic_TransmitFifoFill(XIic *InstancePtr, int Role); + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ diff --git a/XilinxProcessorIPLib/drivers/iic/src/xiic_intr.c b/XilinxProcessorIPLib/drivers/iic/src/xiic_intr.c new file mode 100644 index 00000000..93bf4073 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/iic/src/xiic_intr.c @@ -0,0 +1,443 @@ +/****************************************************************************** +* +* Copyright (C) 2006 - 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 THE +* XILINX CONSORTIUM 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 xiic_intr.c +* +* Contains interrupt functions of the XIic driver. This file is required +* for the driver. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.01a rfp 10/19/01 release +* 1.01c ecm 12/05/02 new rev +* 1.01c rmm 05/14/03 Fixed diab compiler warnings relating to asserts. +* 1.03a ecm 06/22/06 Added a call to the status handler in the TxErrorHandler +* even if the Rx buffer pointer is not set. This fix is as +* a result of a Sony use model which did not set the Rx +* pointer while in Master mode so it checks if MSMS == 1. +* 1.13a wgr 03/22/07 Converted to new coding style. +* 2.00a sdm 10/22/09 Converted all register accesses to 32 bit access. +* Updated to use the HAL APIs/macros. +* Some of the macros have been renamed to remove _m from +* the name and Some of the macros have been renamed to be +* consistent, see the xiic_l.h file for further information. +* 2.01a ktn 04/09/10 Updated TxErrorhandler to be called for Master Transmitter +* case based on Addressed As Slave (AAS) bit rather than +* MSMS bit(CR 540199). +* 2.06a bss 02/14/13 Modified TxErrorHandler in xiic_intr.c to fix CR #686483 +* Modified bitwise OR to logical OR in +* XIic_InterruptHandler API. +* 2.07a adk 18/04/13 Updated the code to avoid unused variable warnings +* when compiling with the -Wextra -Wall flags. +* In the file xiic.c and xiic_i.h. CR:705001 +*+* +******************************************************************************/ + + +/***************************** Include Files *********************************/ + +#include "xiic.h" +#include "xiic_i.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions ******************/ + +/************************** Function Prototypes ****************************/ + +static void StubFunction(XIic *InstancePtr); +static void TxErrorHandler(XIic *InstancePtr); + +/************************** Variable Definitions *****************************/ + +/* The following function pointers are used to help allow finer partitioning + * of the driver such that some parts of it are optional. These pointers are + * setup by functions in the optional parts of the driver. + */ +void (*XIic_AddrAsSlaveFuncPtr) (XIic *InstancePtr) = StubFunction; +void (*XIic_NotAddrAsSlaveFuncPtr) (XIic *InstancePtr) = StubFunction; +void (*XIic_RecvSlaveFuncPtr) (XIic *InstancePtr) = StubFunction; +void (*XIic_SendSlaveFuncPtr) (XIic *InstancePtr) = StubFunction; +void (*XIic_RecvMasterFuncPtr) (XIic *InstancePtr) = StubFunction; +void (*XIic_SendMasterFuncPtr) (XIic *InstancePtr) = StubFunction; +void (*XIic_ArbLostFuncPtr) (XIic *InstancePtr) = StubFunction; +void (*XIic_BusNotBusyFuncPtr) (XIic *InstancePtr) = StubFunction; + +/*****************************************************************************/ +/** +* +* This function is the interrupt handler for the XIic driver. This function +* should be connected to the interrupt system. +* +* Only one interrupt source is handled for each interrupt allowing +* higher priority system interrupts quicker response time. +* +* @param InstancePtr is a pointer to the XIic instance to be worked on. +* +* @return None. +* +* @internal +* +* The XIIC_INTR_ARB_LOST_MASK and XIIC_INTR_TX_ERROR_MASK interrupts must have +* higher priority than the other device interrupts so that the IIC device does +* not get into a potentially confused state. The remaining interrupts may be +* rearranged with no harm. +* +******************************************************************************/ +void XIic_InterruptHandler(void *InstancePtr) +{ + u32 Status; + u32 IntrStatus; + u32 IntrPending; + u32 IntrEnable; + XIic *IicPtr = NULL; + u32 Clear = 0; + + /* + * Verify that each of the inputs are valid. + */ + Xil_AssertVoid(InstancePtr != NULL); + + /* + * Convert the non-typed pointer to an IIC instance pointer + */ + IicPtr = (XIic *) InstancePtr; + + /* + * Get the interrupt Status. + */ + IntrPending = XIic_ReadIisr(IicPtr->BaseAddress); + IntrEnable = XIic_ReadIier(IicPtr->BaseAddress); + IntrStatus = IntrPending & IntrEnable; + + /* + * Do not processes a devices interrupts if the device has no + * interrupts pending or the global interrupts have been disabled. + */ + if ((IntrStatus == 0) || + (XIic_IsIntrGlobalEnabled(IicPtr->BaseAddress) == FALSE)) { + return; + } + + /* + * Update interrupt stats and get the contents of the status register. + */ + IicPtr->Stats.IicInterrupts++; + Status = XIic_ReadReg(IicPtr->BaseAddress, XIIC_SR_REG_OFFSET); + + /* + * Service requesting interrupt. + */ + if (IntrStatus & XIIC_INTR_ARB_LOST_MASK) { + /* Bus Arbritration Lost */ + + IicPtr->Stats.ArbitrationLost++; + XIic_ArbLostFuncPtr(IicPtr); + + Clear = XIIC_INTR_ARB_LOST_MASK; + } else if (IntrStatus & XIIC_INTR_TX_ERROR_MASK) { + /* Transmit errors (no acknowledge) received */ + IicPtr->Stats.TxErrors++; + TxErrorHandler(IicPtr); + + Clear = XIIC_INTR_TX_ERROR_MASK; + } else if (IntrStatus & XIIC_INTR_NAAS_MASK) { + /* Not Addressed As Slave */ + + XIic_NotAddrAsSlaveFuncPtr(IicPtr); + Clear = XIIC_INTR_NAAS_MASK; + } else if (IntrStatus & XIIC_INTR_RX_FULL_MASK) { + /* Receive register/FIFO is full */ + + IicPtr->Stats.RecvInterrupts++; + + if (Status & XIIC_SR_ADDR_AS_SLAVE_MASK) { + XIic_RecvSlaveFuncPtr(IicPtr); + } else { + XIic_RecvMasterFuncPtr(IicPtr); + } + + Clear = XIIC_INTR_RX_FULL_MASK; + } else if (IntrStatus & XIIC_INTR_AAS_MASK) { + /* Addressed As Slave */ + + XIic_AddrAsSlaveFuncPtr(IicPtr); + Clear = XIIC_INTR_AAS_MASK; + } else if (IntrStatus & XIIC_INTR_BNB_MASK) { + /* IIC bus has transitioned to not busy */ + + /* Check if send callback needs to run */ + if (IicPtr->BNBOnly == TRUE) { + XIic_BusNotBusyFuncPtr(IicPtr); + IicPtr->BNBOnly = FALSE; + } else { + IicPtr->SendHandler(IicPtr->SendCallBackRef, 0); + } + + Clear = XIIC_INTR_BNB_MASK; + + /* The bus is not busy, disable BusNotBusy interrupt */ + XIic_DisableIntr(IicPtr->BaseAddress, XIIC_INTR_BNB_MASK); + + } else if ((IntrStatus & XIIC_INTR_TX_EMPTY_MASK) || + (IntrStatus & XIIC_INTR_TX_HALF_MASK)) { + /* Transmit register/FIFO is empty or � empty */ + IicPtr->Stats.SendInterrupts++; + + if (Status & XIIC_SR_ADDR_AS_SLAVE_MASK) { + XIic_SendSlaveFuncPtr(IicPtr); + } else { + XIic_SendMasterFuncPtr(IicPtr); + } + + IntrStatus = XIic_ReadIisr(IicPtr->BaseAddress); + Clear = IntrStatus & (XIIC_INTR_TX_EMPTY_MASK | + XIIC_INTR_TX_HALF_MASK); + } + + /* + * Clear Interrupts. + */ + XIic_WriteIisr(IicPtr->BaseAddress, Clear); +} + +/****************************************************************************** +* +* This function fills the FIFO using the occupancy register to determine the +* available space to be filled. When the repeated start option is on, the last +* byte is withheld to allow the control register to be properly set on the last +* byte. +* +* @param InstancePtr is a pointer to the XIic instance to be worked on. +* +* @param Role indicates the role of this IIC device, a slave or a master, +* on the IIC bus (XIIC_SLAVE_ROLE or XIIC_MASTER_ROLE). +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XIic_TransmitFifoFill(XIic *InstancePtr, int Role) +{ + u8 AvailBytes; + int LoopCnt; + int NumBytesToSend; + + /* + * Determine number of bytes to write to FIFO. Number of bytes that + * can be put into the FIFO is (FIFO depth) - (current occupancy + 1) + * When more room in FIFO than msg bytes put all of message in the FIFO. + */ + AvailBytes = IIC_TX_FIFO_DEPTH - + (u8) (XIic_ReadReg(InstancePtr->BaseAddress, + XIIC_TFO_REG_OFFSET) + 1); + + if (InstancePtr->SendByteCount > AvailBytes) { + NumBytesToSend = AvailBytes; + } else { + /* + * More space in FIFO than bytes in message. + */ + if ((InstancePtr->Options & XII_REPEATED_START_OPTION) || + (Role == XIIC_SLAVE_ROLE)) { + NumBytesToSend = InstancePtr->SendByteCount; + } else { + NumBytesToSend = InstancePtr->SendByteCount - 1; + } + } + + /* + * Fill FIFO with amount determined above. + */ + for (LoopCnt = 0; LoopCnt < NumBytesToSend; LoopCnt++) { + XIic_WriteSendByte(InstancePtr); + } +} + +/*****************************************************************************/ +/** +* +* This interrupt occurs four different ways: Two as master and two as slave. +* Master: +*
+* (1) Transmitter (IMPLIES AN ERROR) +* The slave receiver did not acknowledge properly. +* (2) Receiver (Implies Tx complete) +* Interrupt caused by setting TxAck high in the IIC to indicate to the +* the last byte has been transmitted. +*+* +* Slave: +*
+* (3) Transmitter (Implies Tx complete) +* Interrupt caused by master device indicating last byte of the message +* has been transmitted. +* (4) Receiver (IMPLIES AN ERROR) +* Interrupt caused by setting TxAck high in the IIC to indicate Rx +* IIC had a problem - set by this device and condition already known +* and interrupt is not enabled. +*+* +* This interrupt is enabled during Master send and receive and disabled +* when this device knows it is going to send a negative acknowledge (Ack = No). +* +* Signals user of Tx error via status callback sending: XII_TX_ERROR_EVENT +* +* When MasterRecv has no message to send and only receives one byte of data +* from the salve device, the TxError must be enabled to catch addressing +* errors, yet there is not opportunity to disable TxError when there is no +* data to send allowing disabling on last byte. When the slave sends the +* only byte the NOAck causes a Tx Error. To disregard this as no real error, +* when there is data in the Receive FIFO/register then the error was not +* a device address write error, but a NOACK read error - to be ignored. +* To work with or without FIFO's, the Rx Data interrupt is used to indicate +* data is in the Rx register. +* +* @param InstancePtr is a pointer to the XIic instance to be worked on. +* +* @return None. +* +******************************************************************************/ +static void TxErrorHandler(XIic *InstancePtr) +{ + u32 IntrStatus; + u32 CntlReg; + + /* + * When Sending as a slave, Tx error signals end of msg. Not Addressed + * As Slave will handle the callbacks. this is used to only flush + * the Tx fifo. The addressed as slave bit is gone as soon as the bus + * has been released such that the buffer pointers are used to determine + * the direction of transfer (send or receive). + */ + if (InstancePtr->RecvBufferPtr == NULL) { + /* + * Master Receiver finished reading message. Flush Tx fifo to + * remove an 0xFF that was written to prevent bus throttling, + * and disable all transmit and receive interrupts. + */ + XIic_FlushTxFifo(InstancePtr); + XIic_DisableIntr(InstancePtr->BaseAddress, + XIIC_TX_RX_INTERRUPTS); + + /* + * If operating in Master mode, call status handler to indicate + * NOACK occured. + */ + IntrStatus = XIic_ReadIisr(InstancePtr->BaseAddress); + if ((IntrStatus & XIIC_INTR_AAS_MASK) == 0) { + InstancePtr->StatusHandler(InstancePtr-> + StatusCallBackRef, + XII_SLAVE_NO_ACK_EVENT); + } else { + /* Decrement the Tx Error since Tx Error interrupt + * implies transmit complete while sending as Slave + */ + InstancePtr->Stats.TxErrors--; + } + + return; + } + + /* + * Data in the receive register from either master or slave receive + * When:slave, indicates master sent last byte, message completed. + * When:master, indicates a master Receive with one byte received. When + * a byte is in Rx reg then the Tx error indicates the Rx data was + * recovered normally Tx errors are not enabled such that this should + * not occur. + */ + IntrStatus = XIic_ReadIisr(InstancePtr->BaseAddress); + if (IntrStatus & XIIC_INTR_RX_FULL_MASK) { + /* Rx Reg/FIFO has data, Disable Tx error interrupts */ + + XIic_DisableIntr(InstancePtr->BaseAddress, + XIIC_INTR_TX_ERROR_MASK); + return; + } + + XIic_FlushTxFifo(InstancePtr); + + /* + * Disable and clear Tx empty, � empty, Rx Full or Tx error interrupts. + */ + XIic_DisableIntr(InstancePtr->BaseAddress, XIIC_TX_RX_INTERRUPTS); + XIic_ClearIntr(InstancePtr->BaseAddress, XIIC_TX_RX_INTERRUPTS); + + /* Clear MSMS as on Tx error when Rxing, the bus will be + * stopped but MSMS bit is still set. Reset to proper state + */ + CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET); + CntlReg &= ~XIIC_CR_MSMS_MASK; + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, CntlReg); + + + /* + * Set FIFO occupancy depth = 1 so that the first byte will throttle + * next recieve msg. + */ + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_RFD_REG_OFFSET, 0); + + /* + * Call the event callback. + */ + InstancePtr->StatusHandler(InstancePtr->StatusCallBackRef, + XII_SLAVE_NO_ACK_EVENT); +} + +/*****************************************************************************/ +/** +* +* This function is a stub function that is used for the default function for +* events that are handled optionally only when the appropriate modules are +* linked in. Function pointers are used to handle some events to allow +* some events to be optionally handled. +* +* @param InstancePtr is a pointer to the XIic instance to be worked on. +* +******************************************************************************/ +static void StubFunction(XIic *InstancePtr) +{ + (void )InstancePtr; + Xil_AssertVoidAlways(); +} diff --git a/XilinxProcessorIPLib/drivers/iic/src/xiic_l.c b/XilinxProcessorIPLib/drivers/iic/src/xiic_l.c new file mode 100644 index 00000000..3a4178c9 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/iic/src/xiic_l.c @@ -0,0 +1,1010 @@ +/****************************************************************************** +* +* Copyright (C) 2002 - 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 THE +* XILINX CONSORTIUM 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 xiic_l.c +* +* This file contains low-level driver functions that can be used to access the +* device in normal and dynamic controller mode. The user should refer to the +* hardware device specification for more details of the device operation. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- --- ------- ----------------------------------------------- +* 1.01b jhl 05/13/02 First release +* 1.01b jhl 10/14/02 Corrected bug in the receive function, the setup of the +* interrupt status mask was not being done in the loop such +* that a read would sometimes fail on the last byte because +* the transmit error which should have been ignored was +* being used. This would leave an extra byte in the FIFO +* and the bus throttled such that the next operation would +* also fail. Also updated the receive function to not +* disable the device after the last byte until after the +* bus transitions to not busy which is more consistent +* with the expected behavior. +* 1.01c ecm 12/05/02 new rev +* 1.02a mta 03/09/06 Implemented Repeated Start in the Low Level Driver. +* 1.03a mta 04/04/06 Implemented Dynamic IIC core routines. +* 1.03a ecm 06/15/06 Fixed the hang in low_level_eeprom_test with -O0 +* Added polling loops for BNB to allow the slave to +* respond correctly. Also added polling loop prior +* to reset in _Recv. +* 1.13a wgr 03/22/07 Converted to new coding style. +* 1.13b ecm 11/29/07 added BB polling loops to the DynSend and DynRecv +* routines to handle the race condition with BNB in IISR. +* 2.00a sdm 10/22/09 Converted all register accesses to 32 bit access. +* Updated to use the HAL APIs/macros. +* Some of the macros have been renamed to remove _m from +* the name and Some of the macros have been renamed to be +* consistent, see the xiic_i.h and xiic_l.h files for +* further information. +* 2.02a sdm 10/08/10 Updated to disable the device at the end of the transfer, +* only when addressed as slave in XIic_Send for CR565373. +* 2.04a sdm 07/22/11 Removed a compiler warning by adding parenthesis around & +* at line 479. +* 2.08a adk 29/07/13 In Low level driver In repeated start condition the +* Direction of Tx bit must be disabled in Receive +* condition It Fixes the CR:685759 Changes are done +* in the function XIic_Recv. +*+* +****************************************************************************/ + +/***************************** Include Files *******************************/ + +#include "xil_types.h" +#include "xil_assert.h" +#include "xiic_l.h" + +/************************** Constant Definitions ***************************/ + +/**************************** Type Definitions *****************************/ + +/***************** Macros (Inline Functions) Definitions *******************/ + +/************************** Function Prototypes ****************************/ + +static unsigned RecvData(u32 BaseAddress, u8 *BufferPtr, + unsigned ByteCount, u8 Option); +static unsigned SendData(u32 BaseAddress, u8 *BufferPtr, + unsigned ByteCount, u8 Option); + +static unsigned DynRecvData(u32 BaseAddress, u8 *BufferPtr, u8 ByteCount); +static unsigned DynSendData(u32 BaseAddress, u8 *BufferPtr, + u8 ByteCount, u8 Option); + +/************************** Variable Definitions **************************/ + +/****************************************************************************/ +/** +* Receive data as a master on the IIC bus. This function receives the data +* using polled I/O and blocks until the data has been received. It only +* supports 7 bit addressing mode of operation. The user is responsible for +* ensuring the bus is not busy if multiple masters are present on the bus. +* +* @param BaseAddress contains the base address of the IIC device. +* @param Address contains the 7 bit IIC address of the device to send the +* specified data to. +* @param BufferPtr points to the data to be sent. +* @param ByteCount is the number of bytes to be sent. +* @param Option indicates whether to hold or free the bus after reception +* of data, XIIC_STOP = end with STOP condition, +* XIIC_REPEATED_START = don't end with STOP condition. +* +* @return The number of bytes received. +* +* @note None. +* +******************************************************************************/ +unsigned XIic_Recv(u32 BaseAddress, u8 Address, + u8 *BufferPtr, unsigned ByteCount, u8 Option) +{ + u32 CntlReg; + unsigned RemainingByteCount; + volatile u32 StatusReg; + + /* Tx error is enabled incase the address (7 or 10) has no device to + * answer with Ack. When only one byte of data, must set NO ACK before + * address goes out therefore Tx error must not be enabled as it will go + * off immediately and the Rx full interrupt will be checked. If full, + * then the one byte was received and the Tx error will be disabled + * without sending an error callback msg + */ + XIic_ClearIisr(BaseAddress, + XIIC_INTR_RX_FULL_MASK | XIIC_INTR_TX_ERROR_MASK | + XIIC_INTR_ARB_LOST_MASK); + + /* Set receive FIFO occupancy depth for 1 byte (zero based) */ + XIic_WriteReg(BaseAddress, XIIC_RFD_REG_OFFSET, 0); + + + /* Check to see if already Master on the Bus. + * If Repeated Start bit is not set send Start bit by setting MSMS bit + * else Send the address + */ + CntlReg = XIic_ReadReg(BaseAddress, XIIC_CR_REG_OFFSET); + if ((CntlReg & XIIC_CR_REPEATED_START_MASK) == 0) { + /* 7 bit slave address, send the address for a read operation + * and set the state to indicate the address has been sent + */ + XIic_Send7BitAddress(BaseAddress, Address, + XIIC_READ_OPERATION); + + + /* MSMS gets set after putting data in FIFO. Start the master + * receive operation by setting CR Bits MSMS to Master, if the + * buffer is only one byte, then it should not be acknowledged + * to indicate the end of data + */ + CntlReg = XIIC_CR_MSMS_MASK | XIIC_CR_ENABLE_DEVICE_MASK; + if (ByteCount == 1) { + CntlReg |= XIIC_CR_NO_ACK_MASK; + } + + /* Write out the control register to start receiving data and + * call the function to receive each byte into the buffer + */ + XIic_WriteReg(BaseAddress, XIIC_CR_REG_OFFSET, CntlReg); + + /* Clear the latched interrupt status for the bus not busy bit + * which must be done while the bus is busy + */ + StatusReg = XIic_ReadReg(BaseAddress, XIIC_SR_REG_OFFSET); + + while ((StatusReg & XIIC_SR_BUS_BUSY_MASK) == 0) { + StatusReg = XIic_ReadReg(BaseAddress, + XIIC_SR_REG_OFFSET); + } + + XIic_ClearIisr(BaseAddress, XIIC_INTR_BNB_MASK); + } else { + /* Before writing 7bit slave address the Direction of Tx bit + * must be disabled + */ + CntlReg &= ~XIIC_CR_DIR_IS_TX_MASK; + XIic_WriteReg(BaseAddress, XIIC_CR_REG_OFFSET, CntlReg); + /* Already owns the Bus indicating that its a Repeated Start + * call. 7 bit slave address, send the address for a read + * operation and set the state to indicate the address has been + * sent + */ + XIic_Send7BitAddress(BaseAddress, Address, + XIIC_READ_OPERATION); + } + /* Try to receive the data from the IIC bus */ + + RemainingByteCount = RecvData(BaseAddress, BufferPtr, + ByteCount, Option); + + CntlReg = XIic_ReadReg(BaseAddress, XIIC_CR_REG_OFFSET); + if ((CntlReg & XIIC_CR_REPEATED_START_MASK) == 0) { + /* The receive is complete, disable the IIC device if the Option + * is to release the Bus after Reception of data and return the + * number of bytes that was received + */ + XIic_WriteReg(BaseAddress, XIIC_CR_REG_OFFSET, 0); + } + + /* Return the number of bytes that was received */ + return ByteCount - RemainingByteCount; +} + +/****************************************************************************** +* +* Receive the specified data from the device that has been previously addressed +* on the IIC bus. This function assumes that the 7 bit address has been sent +* and it should wait for the transmit of the address to complete. +* +* @param BaseAddress contains the base address of the IIC device. +* @param BufferPtr points to the buffer to hold the data that is +* received. +* @param ByteCount is the number of bytes to be received. +* @param Option indicates whether to hold or free the bus after reception +* of data, XIIC_STOP = end with STOP condition, +* XIIC_REPEATED_START = don't end with STOP condition. +* +* @return The number of bytes remaining to be received. +* +* @note +* +* This function does not take advantage of the receive FIFO because it is +* designed for minimal code space and complexity. It contains loops that +* that could cause the function not to return if the hardware is not working. +* +* This function assumes that the calling function will disable the IIC device +* after this function returns. +* +******************************************************************************/ +static unsigned RecvData(u32 BaseAddress, u8 *BufferPtr, + unsigned ByteCount, u8 Option) +{ + u32 CntlReg; + u32 IntrStatusMask; + u32 IntrStatus; + + /* Attempt to receive the specified number of bytes on the IIC bus */ + + while (ByteCount > 0) { + /* Setup the mask to use for checking errors because when + * receiving one byte OR the last byte of a multibyte message an + * error naturally occurs when the no ack is done to tell the + * slave the last byte + */ + if (ByteCount == 1) { + IntrStatusMask = + XIIC_INTR_ARB_LOST_MASK | XIIC_INTR_BNB_MASK; + } else { + IntrStatusMask = + XIIC_INTR_ARB_LOST_MASK | + XIIC_INTR_TX_ERROR_MASK | XIIC_INTR_BNB_MASK; + } + + /* Wait for the previous transmit and the 1st receive to + * complete by checking the interrupt status register of the + * IPIF + */ + while (1) { + IntrStatus = XIic_ReadIisr(BaseAddress); + if (IntrStatus & XIIC_INTR_RX_FULL_MASK) { + break; + } + /* Check the transmit error after the receive full + * because when sending only one byte transmit error + * will occur because of the no ack to indicate the end + * of the data + */ + if (IntrStatus & IntrStatusMask) { + return ByteCount; + } + } + + CntlReg = XIic_ReadReg(BaseAddress, XIIC_CR_REG_OFFSET); + + /* Special conditions exist for the last two bytes so check for + * them. Note that the control register must be setup for these + * conditions before the data byte which was already received is + * read from the receive FIFO (while the bus is throttled + */ + if (ByteCount == 1) { + if (Option == XIIC_STOP) { + + /* If the Option is to release the bus after the + * last data byte, it has already been read and + * no ack has been done, so clear MSMS while + * leaving the device enabled so it can get off + * the IIC bus appropriately with a stop + */ + XIic_WriteReg(BaseAddress, XIIC_CR_REG_OFFSET, + XIIC_CR_ENABLE_DEVICE_MASK); + } + } + + /* Before the last byte is received, set NOACK to tell the slave + * IIC device that it is the end, this must be done before + * reading the byte from the FIFO + */ + if (ByteCount == 2) { + /* Write control reg with NO ACK allowing last byte to + * have the No ack set to indicate to slave last byte + * read + */ + XIic_WriteReg(BaseAddress, XIIC_CR_REG_OFFSET, + CntlReg | XIIC_CR_NO_ACK_MASK); + } + + /* Read in data from the FIFO and unthrottle the bus such that + * the next byte is read from the IIC bus + */ + *BufferPtr++ = (u8) XIic_ReadReg(BaseAddress, + XIIC_DRR_REG_OFFSET); + + if ((ByteCount == 1) && (Option == XIIC_REPEATED_START)) { + + /* RSTA bit should be set only when the FIFO is + * completely Empty. + */ + XIic_WriteReg(BaseAddress, XIIC_CR_REG_OFFSET, + XIIC_CR_ENABLE_DEVICE_MASK | XIIC_CR_MSMS_MASK + | XIIC_CR_REPEATED_START_MASK); + + } + + /* Clear the latched interrupt status so that it will be updated + * with the new state when it changes, this must be done after + * the receive register is read + */ + XIic_ClearIisr(BaseAddress, XIIC_INTR_RX_FULL_MASK | + XIIC_INTR_TX_ERROR_MASK | + XIIC_INTR_ARB_LOST_MASK); + ByteCount--; + } + + if (Option == XIIC_STOP) { + + /* If the Option is to release the bus after Reception of data, + * wait for the bus to transition to not busy before returning, + * the IIC device cannot be disabled until this occurs. It + * should transition as the MSMS bit of the control register was + * cleared before the last byte was read from the FIFO + */ + while (1) { + if (XIic_ReadIisr(BaseAddress) & XIIC_INTR_BNB_MASK) { + break; + } + } + } + + return ByteCount; +} + +/****************************************************************************/ +/** +* Send data as a master on the IIC bus. This function sends the data +* using polled I/O and blocks until the data has been sent. It only supports +* 7 bit addressing mode of operation. The user is responsible for ensuring +* the bus is not busy if multiple masters are present on the bus. +* +* @param BaseAddress contains the base address of the IIC device. +* @param Address contains the 7 bit IIC address of the device to send the +* specified data to. +* @param BufferPtr points to the data to be sent. +* @param ByteCount is the number of bytes to be sent. +* @param Option indicates whether to hold or free the bus after +* transmitting the data. +* +* @return The number of bytes sent. +* +* @note None. +* +******************************************************************************/ +unsigned XIic_Send(u32 BaseAddress, u8 Address, + u8 *BufferPtr, unsigned ByteCount, u8 Option) +{ + unsigned RemainingByteCount; + u32 ControlReg; + volatile u32 StatusReg; + + /* Check to see if already Master on the Bus. + * If Repeated Start bit is not set send Start bit by setting + * MSMS bit else Send the address. + */ + ControlReg = XIic_ReadReg(BaseAddress, XIIC_CR_REG_OFFSET); + if ((ControlReg & XIIC_CR_REPEATED_START_MASK) == 0) { + /* + * Put the address into the FIFO to be sent and indicate + * that the operation to be performed on the bus is a + * write operation + */ + XIic_Send7BitAddress(BaseAddress, Address, + XIIC_WRITE_OPERATION); + /* Clear the latched interrupt status so that it will + * be updated with the new state when it changes, this + * must be done after the address is put in the FIFO + */ + XIic_ClearIisr(BaseAddress, XIIC_INTR_TX_EMPTY_MASK | + XIIC_INTR_TX_ERROR_MASK | + XIIC_INTR_ARB_LOST_MASK); + + /* + * MSMS must be set after putting data into transmit FIFO, + * indicate the direction is transmit, this device is master + * and enable the IIC device + */ + XIic_WriteReg(BaseAddress, XIIC_CR_REG_OFFSET, + XIIC_CR_MSMS_MASK | XIIC_CR_DIR_IS_TX_MASK | + XIIC_CR_ENABLE_DEVICE_MASK); + + /* + * Clear the latched interrupt + * status for the bus not busy bit which must be done while + * the bus is busy + */ + StatusReg = XIic_ReadReg(BaseAddress, XIIC_SR_REG_OFFSET); + while ((StatusReg & XIIC_SR_BUS_BUSY_MASK) == 0) { + StatusReg = XIic_ReadReg(BaseAddress, + XIIC_SR_REG_OFFSET); + } + + XIic_ClearIisr(BaseAddress, XIIC_INTR_BNB_MASK); + } + else { + /* + * Already owns the Bus indicating that its a Repeated Start + * call. 7 bit slave address, send the address for a write + * operation and set the state to indicate the address has + * been sent. + */ + XIic_Send7BitAddress(BaseAddress, Address, + XIIC_WRITE_OPERATION); + } + + /* Send the specified data to the device on the IIC bus specified by the + * the address + */ + RemainingByteCount = SendData(BaseAddress, BufferPtr, + ByteCount, Option); + + ControlReg = XIic_ReadReg(BaseAddress, XIIC_CR_REG_OFFSET); + if ((ControlReg & XIIC_CR_REPEATED_START_MASK) == 0) { + /* + * The Transmission is completed, disable the IIC device if + * the Option is to release the Bus after transmission of data + * and return the number of bytes that was received. Only wait + * if master, if addressed as slave just reset to release + * the bus. + */ + if ((ControlReg & XIIC_CR_MSMS_MASK) != 0) { + XIic_WriteReg(BaseAddress, XIIC_CR_REG_OFFSET, + (ControlReg & ~XIIC_CR_MSMS_MASK)); + StatusReg = XIic_ReadReg(BaseAddress, + XIIC_SR_REG_OFFSET); + while ((StatusReg & XIIC_SR_BUS_BUSY_MASK) != 0) { + StatusReg = XIic_ReadReg(BaseAddress, + XIIC_SR_REG_OFFSET); + } + } + + if ((XIic_ReadReg(BaseAddress, XIIC_SR_REG_OFFSET) & + XIIC_SR_ADDR_AS_SLAVE_MASK) != 0) { + XIic_WriteReg(BaseAddress, XIIC_CR_REG_OFFSET, 0); + } + } + + return ByteCount - RemainingByteCount; +} + +/****************************************************************************** +* +* Send the specified buffer to the device that has been previously addressed +* on the IIC bus. This function assumes that the 7 bit address has been sent +* and it should wait for the transmit of the address to complete. +* +* @param BaseAddress contains the base address of the IIC device. +* @param BufferPtr points to the data to be sent. +* @param ByteCount is the number of bytes to be sent. +* @param Option indicates whether to hold or free the bus after +* transmitting the data. +* +* @return The number of bytes remaining to be sent. +* +* @note +* +* This function does not take advantage of the transmit FIFO because it is +* designed for minimal code space and complexity. It contains loops that +* that could cause the function not to return if the hardware is not working. +* +******************************************************************************/ +static unsigned SendData(u32 BaseAddress, u8 *BufferPtr, + unsigned ByteCount, u8 Option) +{ + u32 IntrStatus; + + /* + * Send the specified number of bytes in the specified buffer by polling + * the device registers and blocking until complete + */ + while (ByteCount > 0) { + /* + * Wait for the transmit to be empty before sending any more + * data by polling the interrupt status register + */ + while (1) { + IntrStatus = XIic_ReadIisr(BaseAddress); + + if (IntrStatus & (XIIC_INTR_TX_ERROR_MASK | + XIIC_INTR_ARB_LOST_MASK | + XIIC_INTR_BNB_MASK)) { + return ByteCount; + } + + if (IntrStatus & XIIC_INTR_TX_EMPTY_MASK) { + break; + } + } + /* If there is more than one byte to send then put the + * next byte to send into the transmit FIFO + */ + if (ByteCount > 1) { + XIic_WriteReg(BaseAddress, XIIC_DTR_REG_OFFSET, + *BufferPtr++); + } + else { + if (Option == XIIC_STOP) { + /* + * If the Option is to release the bus after + * the last data byte, Set the stop Option + * before sending the last byte of data so + * that the stop Option will be generated + * immediately following the data. This is + * done by clearing the MSMS bit in the + * control register. + */ + XIic_WriteReg(BaseAddress, XIIC_CR_REG_OFFSET, + XIIC_CR_ENABLE_DEVICE_MASK | + XIIC_CR_DIR_IS_TX_MASK); + } + + /* + * Put the last byte to send in the transmit FIFO + */ + XIic_WriteReg(BaseAddress, XIIC_DTR_REG_OFFSET, + *BufferPtr++); + + if (Option == XIIC_REPEATED_START) { + XIic_ClearIisr(BaseAddress, + XIIC_INTR_TX_EMPTY_MASK); + /* + * Wait for the transmit to be empty before + * setting RSTA bit. + */ + while (1) { + IntrStatus = + XIic_ReadIisr(BaseAddress); + if (IntrStatus & + XIIC_INTR_TX_EMPTY_MASK) { + /* + * RSTA bit should be set only + * when the FIFO is completely + * Empty. + */ + XIic_WriteReg(BaseAddress, + XIIC_CR_REG_OFFSET, + XIIC_CR_REPEATED_START_MASK | + XIIC_CR_ENABLE_DEVICE_MASK | + XIIC_CR_DIR_IS_TX_MASK | + XIIC_CR_MSMS_MASK); + break; + } + } + } + } + + /* + * Clear the latched interrupt status register and this must be + * done after the transmit FIFO has been written to or it won't + * clear + */ + XIic_ClearIisr(BaseAddress, XIIC_INTR_TX_EMPTY_MASK); + + /* + * Update the byte count to reflect the byte sent and clear + * the latched interrupt status so it will be updated for the + * new state + */ + ByteCount--; + } + + if (Option == XIIC_STOP) { + /* + * If the Option is to release the bus after transmission of + * data, Wait for the bus to transition to not busy before + * returning, the IIC device cannot be disabled until this + * occurs. Note that this is different from a receive operation + * because the stop Option causes the bus to go not busy. + */ + while (1) { + if (XIic_ReadIisr(BaseAddress) & + XIIC_INTR_BNB_MASK) { + break; + } + } + } + + return ByteCount; +} + +/*****************************************************************************/ +/** +* Receive data as a master on the IIC bus. This function receives the data +* using polled I/O and blocks until the data has been received. It only +* supports 7 bit addressing. The user is responsible for ensuring the bus is +* not busy if multiple masters are present on the bus. +* +* @param BaseAddress contains the base address of the IIC Device. +* @param Address contains the 7 bit IIC Device address of the device to +* send the specified data to. +* @param BufferPtr points to the data to be sent. +* @param ByteCount is the number of bytes to be sent. This value can't be +* greater than 255 and needs to be greater than 0. +* +* @return The number of bytes received. +* +* @note Upon entry to this function, the IIC interface needs to be +* already enabled in the CR register. +* +******************************************************************************/ +unsigned XIic_DynRecv(u32 BaseAddress, u8 Address, u8 *BufferPtr, u8 ByteCount) +{ + unsigned RemainingByteCount; + u32 StatusRegister; + + /* + * Clear the latched interrupt status so that it will be updated with + * the new state when it changes. + */ + XIic_ClearIisr(BaseAddress, XIIC_INTR_TX_EMPTY_MASK | + XIIC_INTR_TX_ERROR_MASK | XIIC_INTR_ARB_LOST_MASK); + + /* + * Send the 7 bit slave address for a read operation and set the state + * to indicate the address has been sent. Upon writing the address, a + * start condition is initiated. MSMS is automatically set to master + * when the address is written to the Fifo. If MSMS was already set, + * then a re-start is sent prior to the address. + */ + XIic_DynSend7BitAddress(BaseAddress, Address, XIIC_READ_OPERATION); + + /* + * Wait for the bus to go busy. + */ + StatusRegister = XIic_ReadReg(BaseAddress, XIIC_SR_REG_OFFSET); + + while (( StatusRegister & XIIC_SR_BUS_BUSY_MASK) + != XIIC_SR_BUS_BUSY_MASK) { + StatusRegister = XIic_ReadReg(BaseAddress, + XIIC_SR_REG_OFFSET); + } + + /* + * Clear the latched interrupt status for the bus not busy bit which + * must be done while the bus is busy. + */ + XIic_ClearIisr(BaseAddress, XIIC_INTR_BNB_MASK); + + /* + * Write to the Tx Fifo the dynamic stop control bit with the number of + * bytes that are to be read over the IIC interface from the presently + * addressed device. + */ + XIic_DynSendStop(BaseAddress, ByteCount); + + /* + * Receive the data from the IIC bus. + */ + RemainingByteCount = DynRecvData(BaseAddress, BufferPtr, ByteCount); + + /* + * The receive is complete. Return the number of bytes that were + * received. + */ + return ByteCount - RemainingByteCount; +} + +/*****************************************************************************/ +/** +* Receive the specified data from the device that has been previously addressed +* on the IIC bus. This function assumes the following: +* - The Rx Fifo occupancy depth has been set to its max. +* - Upon entry, the Rx Fifo is empty. +* - The 7 bit address has been sent. +* - The dynamic stop and number of bytes to receive has been written to Tx +* Fifo. +* +* @param BaseAddress contains the base address of the IIC Device. +* @param BufferPtr points to the buffer to hold the data that is +* received. +* @param ByteCount is the number of bytes to be received. The range of +* this value is greater than 0 and not higher than 255. +* +* @return The number of bytes remaining to be received. +* +* @note This function contains loops that could cause the function not +* to return if the hardware is not working. +* +******************************************************************************/ +static unsigned DynRecvData(u32 BaseAddress, u8 *BufferPtr, u8 ByteCount) +{ + u32 StatusReg; + u32 IntrStatus; + u32 IntrStatusMask; + + while (ByteCount > 0) { + + /* + * Setup the mask to use for checking errors because when + * receiving one byte OR the last byte of a multibyte message + * an error naturally occurs when the no ack is done to tell + * the slave the last byte. + */ + if (ByteCount == 1) { + IntrStatusMask = + XIIC_INTR_ARB_LOST_MASK | XIIC_INTR_BNB_MASK; + } else { + IntrStatusMask = + XIIC_INTR_ARB_LOST_MASK | + XIIC_INTR_TX_ERROR_MASK | XIIC_INTR_BNB_MASK; + } + + /* + * Wait for a byte to show up in the Rx Fifo. + */ + while (1) { + IntrStatus = XIic_ReadIisr(BaseAddress); + StatusReg = XIic_ReadReg(BaseAddress, + XIIC_SR_REG_OFFSET); + + if ((StatusReg & XIIC_SR_RX_FIFO_EMPTY_MASK) != + XIIC_SR_RX_FIFO_EMPTY_MASK) { + break; + } + /* + * Check the transmit error after the receive full + * because when sending only one byte transmit error + * will occur because of the no ack to indicate the end + * of the data. + */ + if (IntrStatus & IntrStatusMask) { + return ByteCount; + } + } + + /* + * Read in byte from the Rx Fifo. If the Fifo reached the + * programmed occupancy depth as programmed in the Rx occupancy + * reg, this read access will un throttle the bus such that + * the next byte is read from the IIC bus. + */ + *BufferPtr++ = XIic_ReadReg(BaseAddress, XIIC_DRR_REG_OFFSET); + ByteCount--; + } + + return ByteCount; +} + +/*****************************************************************************/ +/** +* Send data as a master on the IIC bus. This function sends the data using +* polled I/O and blocks until the data has been sent. It only supports 7 bit +* addressing. The user is responsible for ensuring the bus is not busy if +* multiple masters are present on the bus. +* +* @param BaseAddress contains the base address of the IIC Device. +* @param Address contains the 7 bit IIC address of the device to send the +* specified data to. +* @param BufferPtr points to the data to be sent. +* @param ByteCount is the number of bytes to be sent. +* @param Option: XIIC_STOP = end with STOP condition, +* XIIC_REPEATED_START = don't end with STOP condition. +* +* @return The number of bytes sent. +* +* @note None. +* +******************************************************************************/ +unsigned XIic_DynSend(u32 BaseAddress, u16 Address, u8 *BufferPtr, + u8 ByteCount, u8 Option) +{ + unsigned RemainingByteCount; + u32 StatusRegister; + + /* + * Clear the latched interrupt status so that it will be updated with + * the new state when it changes, this must be done after the address + * is put in the FIFO + */ + XIic_ClearIisr(BaseAddress, XIIC_INTR_TX_EMPTY_MASK | + XIIC_INTR_TX_ERROR_MASK | XIIC_INTR_ARB_LOST_MASK); + + /* + * Put the address into the Fifo to be sent and indicate that the + * operation to be performed on the bus is a write operation. Upon + * writing the address, a start condition is initiated. MSMS is + * automatically set to master when the address is written to the Fifo. + * If MSMS was already set, then a re-start is sent prior to the + * address. + */ + if(!(Address & XIIC_TX_DYN_STOP_MASK)) { + + XIic_DynSend7BitAddress(BaseAddress, Address, + XIIC_WRITE_OPERATION); + } else { + XIic_DynSendStartStopAddress(BaseAddress, Address, + XIIC_WRITE_OPERATION); + } + + /* + * Wait for the bus to go busy. + */ + StatusRegister = XIic_ReadReg(BaseAddress, XIIC_SR_REG_OFFSET); + + while (( StatusRegister & XIIC_SR_BUS_BUSY_MASK) != + XIIC_SR_BUS_BUSY_MASK) { + StatusRegister = XIic_ReadReg(BaseAddress, + XIIC_SR_REG_OFFSET); + } + + /* + * Clear the latched interrupt status for the bus not busy bit which + * must be done while the bus is busy. + */ + XIic_ClearIisr(BaseAddress, XIIC_INTR_BNB_MASK); + + /* + * Send the specified data to the device on the IIC bus specified by the + * the address. + */ + RemainingByteCount = DynSendData(BaseAddress, BufferPtr, ByteCount, + Option); + + /* + * The send is complete return the number of bytes that was sent. + */ + return ByteCount - RemainingByteCount; +} + +/****************************************************************************** +* +* Send the specified buffer to the device that has been previously addressed +* on the IIC bus. This function assumes that the 7 bit address has been sent. +* +* @param BaseAddress contains the base address of the IIC Device. +* @param BufferPtr points to the data to be sent. +* @param ByteCount is the number of bytes to be sent. +* @param Option: XIIC_STOP = end with STOP condition, XIIC_REPEATED_START +* = don't end with STOP condition. +* +* @return The number of bytes remaining to be sent. +* +* @note This function does not take advantage of the transmit Fifo +* because it is designed for minimal code space and complexity. +* +******************************************************************************/ +static unsigned DynSendData(u32 BaseAddress, u8 *BufferPtr, + u8 ByteCount, u8 Option) +{ + u32 IntrStatus; + + while (ByteCount > 0) { + /* + * Wait for the transmit to be empty before sending any more + * data by polling the interrupt status register. + */ + while (1) { + IntrStatus = XIic_ReadIisr(BaseAddress); + if (IntrStatus & (XIIC_INTR_TX_ERROR_MASK | + XIIC_INTR_ARB_LOST_MASK | + XIIC_INTR_BNB_MASK)) { + /* + * Error condition (NACK or ARB Lost or BNB + * Error Has occurred. Clear the Control + * register to send a STOP condition on the Bus + * and return the number of bytes still to + * transmit. + */ + XIic_WriteReg(BaseAddress, XIIC_CR_REG_OFFSET, + 0x03); + XIic_WriteReg(BaseAddress, XIIC_CR_REG_OFFSET, + 0x01); + + return ByteCount; + } + + /* + * Check for the transmit Fifo to become Empty. + */ + if (IntrStatus & XIIC_INTR_TX_EMPTY_MASK) { + break; + } + } + + /* + * Send data to Tx Fifo. If a stop condition is specified and + * the last byte is being sent, then set the dynamic stop bit. + */ + if ((ByteCount == 1) && (Option == XIIC_STOP)) { + /* + * The MSMS will be cleared automatically upon setting + * dynamic stop. + */ + XIic_WriteReg(BaseAddress, XIIC_DTR_REG_OFFSET, + XIIC_TX_DYN_STOP_MASK | *BufferPtr++); + } else { + XIic_WriteReg(BaseAddress, XIIC_DTR_REG_OFFSET, + *BufferPtr++); + } + + /* + * Update the byte count to reflect the byte sent. + */ + ByteCount--; + } + + if (Option == XIIC_STOP) { + /* + * If the Option is to release the bus after transmission of + * data, Wait for the bus to transition to not busy before + * returning, the IIC device cannot be disabled until this + * occurs. + */ + while (1) { + if (XIic_ReadIisr(BaseAddress) & XIIC_INTR_BNB_MASK) { + break; + } + } + } + + return ByteCount; +} + +/****************************************************************************** +* +* Initialize the IIC core for Dynamic Functionality. +* +* @param BaseAddress contains the base address of the IIC Device. +* +* @return XST_SUCCESS if Successful else XST_FAILURE. +* +* @note None. +* +******************************************************************************/ +int XIic_DynInit(u32 BaseAddress) +{ + u32 Status; + + /* + * Reset IIC Core. + */ + XIic_WriteReg(BaseAddress, XIIC_RESETR_OFFSET, XIIC_RESET_MASK); + + /* + * Set receive Fifo depth to maximum (zero based). + */ + XIic_WriteReg(BaseAddress, XIIC_RFD_REG_OFFSET, + IIC_RX_FIFO_DEPTH - 1); + + /* + * Reset Tx Fifo. + */ + XIic_WriteReg(BaseAddress, XIIC_CR_REG_OFFSET, + XIIC_CR_TX_FIFO_RESET_MASK); + + /* + * Enable IIC Device, remove Tx Fifo reset & disable general call. + */ + XIic_WriteReg(BaseAddress, XIIC_CR_REG_OFFSET, + XIIC_CR_ENABLE_DEVICE_MASK); + + /* + * Read status register and verify IIC Device is in initial state. Only + * the Tx Fifo and Rx Fifo empty bits should be set. + */ + Status = XIic_ReadReg(BaseAddress, XIIC_SR_REG_OFFSET); + if(Status == (XIIC_SR_RX_FIFO_EMPTY_MASK | + XIIC_SR_TX_FIFO_EMPTY_MASK)) { + return XST_SUCCESS; + } + + return XST_FAILURE; +} diff --git a/XilinxProcessorIPLib/drivers/iic/src/xiic_l.h b/XilinxProcessorIPLib/drivers/iic/src/xiic_l.h new file mode 100644 index 00000000..9bafde0e --- /dev/null +++ b/XilinxProcessorIPLib/drivers/iic/src/xiic_l.h @@ -0,0 +1,588 @@ +/****************************************************************************** +* +* Copyright (C) 2002 - 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 THE +* XILINX CONSORTIUM 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 xiic_l.h +* +* This header file contains identifiers and driver functions (or +* macros) that can be used to access the device in normal and dynamic +* controller mode. High-level driver functions are defined in xiic.h. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00b jhl 05/07/02 First release +* 1.01c ecm 12/05/02 new rev +* 1.01d jhl 10/08/03 Added general purpose output feature +* 1.02a mta 03/09/06 Implemented Repeated Start in the Low Level Driver. +* 1.03a mta 04/04/06 Implemented Dynamic IIC core routines. +* 1.03a rpm 09/08/06 Added include of xstatus.h for completeness +* 1.13a wgr 03/22/07 Converted to new coding style. +* 1.16a ktn 07/18/09 Updated the notes in XIIC_RESET macro to clearly indicate +* that only the Interrupt Registers are reset. +* 1.16a ktn 10/16/09 Updated the notes in the XIIC_RESET macro to mention +* that the complete IIC core is Reset on giving a software +* reset to the IIC core. Some previous versions of the +* core only reset the Interrupt Logic/Registers, please +* refer to the HW specification for futher details. +* 2.00a sdm 10/22/09 Converted all register accesses to 32 bit access, +* the register offsets are defined to be on 32 bit boundry. +* Removed the macro XIIC_RESET, XIic_Reset API should be +* used in its place. +* Some of the macros have been renamed to be consistent - +* XIIC_GINTR_DISABLE is renamed as XIic_IntrGlobalDisable, +* XIIC_GINTR_ENABLE is renamed as XIic_IntrGlobalEnable, +* XIIC_IS_GINTR_ENABLED is renamed as +* XIic_IsIntrGlobalEnabled, +* XIIC_WRITE_IISR is renamed as XIic_WriteIisr, +* XIIC_READ_IISR is renamed as XIic_ReadIisr, +* XIIC_WRITE_IIER is renamed as XIic_WriteIier +* The _m prefix in the name of the macros has been removed - +* XIic_mClearIisr is now XIic_ClearIisr, +* XIic_mSend7BitAddress is now XIic_Send7BitAddress, +* XIic_mDynSend7BitAddress is now XIic_DynSend7BitAddress, +* XIic_mDynSendStartStopAddress is now +* XIic_DynSendStartStopAddress, +* XIic_mDynSendStop is now XIic_DynSendStop. +* +* +*+* +*****************************************************************************/ +#ifndef XIIC_L_H /* prevent circular inclusions */ +#define XIIC_L_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files ********************************/ + +#include "xil_types.h" +#include "xil_assert.h" +#include "xstatus.h" +#include "xil_io.h" + +/************************** Constant Definitions ****************************/ + +/** @name Register Map + * + * Register offsets for the XIic device. + * @{ + */ +#define XIIC_DGIER_OFFSET 0x1C /**< Global Interrupt Enable Register */ +#define XIIC_IISR_OFFSET 0x20 /**< Interrupt Status Register */ +#define XIIC_IIER_OFFSET 0x28 /**< Interrupt Enable Register */ +#define XIIC_RESETR_OFFSET 0x40 /**< Reset Register */ +#define XIIC_CR_REG_OFFSET 0x100 /**< Control Register */ +#define XIIC_SR_REG_OFFSET 0x104 /**< Status Register */ +#define XIIC_DTR_REG_OFFSET 0x108 /**< Data Tx Register */ +#define XIIC_DRR_REG_OFFSET 0x10C /**< Data Rx Register */ +#define XIIC_ADR_REG_OFFSET 0x110 /**< Address Register */ +#define XIIC_TFO_REG_OFFSET 0x114 /**< Tx FIFO Occupancy */ +#define XIIC_RFO_REG_OFFSET 0x118 /**< Rx FIFO Occupancy */ +#define XIIC_TBA_REG_OFFSET 0x11C /**< 10 Bit Address reg */ +#define XIIC_RFD_REG_OFFSET 0x120 /**< Rx FIFO Depth reg */ +#define XIIC_GPO_REG_OFFSET 0x124 /**< Output Register */ +/* @} */ + + +/** + * @name Device Global Interrupt Enable Register masks (CR) mask(s) + * @{ + */ +#define XIIC_GINTR_ENABLE_MASK 0x80000000 /**< Global Interrupt Enable Mask */ +/* @} */ + +/** @name IIC Device Interrupt Status/Enable (INTR) Register Masks + * + * Interrupt Status Register (IISR) + * + * This register holds the interrupt status flags for the Spi device. + * + * Interrupt Enable Register (IIER) + * + * This register is used to enable interrupt sources for the IIC device. + * Writing a '1' to a bit in this register enables the corresponding Interrupt. + * Writing a '0' to a bit in this register disables the corresponding Interrupt. + * + * IISR/IIER registers have the same bit definitions and are only defined once. + * @{ + */ +#define XIIC_INTR_ARB_LOST_MASK 0x00000001 /**< 1 = Arbitration lost */ +#define XIIC_INTR_TX_ERROR_MASK 0x00000002 /**< 1 = Tx error/msg complete */ +#define XIIC_INTR_TX_EMPTY_MASK 0x00000004 /**< 1 = Tx FIFO/reg empty */ +#define XIIC_INTR_RX_FULL_MASK 0x00000008 /**< 1 = Rx FIFO/reg=OCY level */ +#define XIIC_INTR_BNB_MASK 0x00000010 /**< 1 = Bus not busy */ +#define XIIC_INTR_AAS_MASK 0x00000020 /**< 1 = When addr as slave */ +#define XIIC_INTR_NAAS_MASK 0x00000040 /**< 1 = Not addr as slave */ +#define XIIC_INTR_TX_HALF_MASK 0x00000080 /**< 1 = Tx FIFO half empty */ + +/** + * All Tx interrupts commonly used. + */ +#define XIIC_TX_INTERRUPTS (XIIC_INTR_TX_ERROR_MASK | \ + XIIC_INTR_TX_EMPTY_MASK | \ + XIIC_INTR_TX_HALF_MASK) + +/** + * All interrupts commonly used + */ +#define XIIC_TX_RX_INTERRUPTS (XIIC_INTR_RX_FULL_MASK | XIIC_TX_INTERRUPTS) + +/* @} */ + +/** + * @name Reset Register mask + * @{ + */ +#define XIIC_RESET_MASK 0x0000000A /**< RESET Mask */ +/* @} */ + + +/** + * @name Control Register masks (CR) mask(s) + * @{ + */ +#define XIIC_CR_ENABLE_DEVICE_MASK 0x00000001 /**< Device enable = 1 */ +#define XIIC_CR_TX_FIFO_RESET_MASK 0x00000002 /**< Transmit FIFO reset=1 */ +#define XIIC_CR_MSMS_MASK 0x00000004 /**< Master starts Txing=1 */ +#define XIIC_CR_DIR_IS_TX_MASK 0x00000008 /**< Dir of Tx. Txing=1 */ +#define XIIC_CR_NO_ACK_MASK 0x00000010 /**< Tx Ack. NO ack = 1 */ +#define XIIC_CR_REPEATED_START_MASK 0x00000020 /**< Repeated start = 1 */ +#define XIIC_CR_GENERAL_CALL_MASK 0x00000040 /**< Gen Call enabled = 1 */ +/* @} */ + +/** + * @name Status Register masks (SR) mask(s) + * @{ + */ +#define XIIC_SR_GEN_CALL_MASK 0x00000001 /**< 1 = A Master issued + * a GC */ +#define XIIC_SR_ADDR_AS_SLAVE_MASK 0x00000002 /**< 1 = When addressed as + * slave */ +#define XIIC_SR_BUS_BUSY_MASK 0x00000004 /**< 1 = Bus is busy */ +#define XIIC_SR_MSTR_RDING_SLAVE_MASK 0x00000008 /**< 1 = Dir: Master <-- + * slave */ +#define XIIC_SR_TX_FIFO_FULL_MASK 0x00000010 /**< 1 = Tx FIFO full */ +#define XIIC_SR_RX_FIFO_FULL_MASK 0x00000020 /**< 1 = Rx FIFO full */ +#define XIIC_SR_RX_FIFO_EMPTY_MASK 0x00000040 /**< 1 = Rx FIFO empty */ +#define XIIC_SR_TX_FIFO_EMPTY_MASK 0x00000080 /**< 1 = Tx FIFO empty */ +/* @} */ + +/** + * @name Data Tx Register (DTR) mask(s) + * @{ + */ +#define XIIC_TX_DYN_START_MASK 0x00000100 /**< 1 = Set dynamic start */ +#define XIIC_TX_DYN_STOP_MASK 0x00000200 /**< 1 = Set dynamic stop */ +#define IIC_TX_FIFO_DEPTH 16 /**< Tx fifo capacity */ +/* @} */ + +/** + * @name Data Rx Register (DRR) mask(s) + * @{ + */ +#define IIC_RX_FIFO_DEPTH 16 /**< Rx fifo capacity */ +/* @} */ + + +#define XIIC_TX_ADDR_SENT 0x00 +#define XIIC_TX_ADDR_MSTR_RECV_MASK 0x02 + + +/** + * The following constants are used to specify whether to do + * Read or a Write operation on IIC bus. + */ +#define XIIC_READ_OPERATION 1 /**< Read operation on the IIC bus */ +#define XIIC_WRITE_OPERATION 0 /**< Write operation on the IIC bus */ + +/** + * The following constants are used with the transmit FIFO fill function to + * specify the role which the IIC device is acting as, a master or a slave. + */ +#define XIIC_MASTER_ROLE 1 /**< Master on the IIC bus */ +#define XIIC_SLAVE_ROLE 0 /**< Slave on the IIC bus */ + +/** + * The following constants are used with Transmit Function (XIic_Send) to + * specify whether to STOP after the current transfer of data or own the bus + * with a Repeated start. + */ +#define XIIC_STOP 0x00 /**< Send a stop on the IIC bus after + * the current data transfer */ +#define XIIC_REPEATED_START 0x01 /**< Donot Send a stop on the IIC bus after + * the current data transfer */ + +/***************** Macros (Inline Functions) Definitions *********************/ + +#define XIic_In32 Xil_In32 +#define XIic_Out32 Xil_Out32 + +/****************************************************************************/ +/** +* +* Read from the specified IIC device register. +* +* @param BaseAddress is the base address of the device. +* @param RegOffset is the offset from the 1st register of the device to +* select the specific register. +* +* @return The value read from the register. +* +* @note C-Style signature: +* u32 XIic_ReadReg(u32 BaseAddress, u32 RegOffset); +* +* This macro does not do any checking to ensure that the +* register exists if the register may be excluded due to +* parameterization, such as the GPO Register. +* +******************************************************************************/ +#define XIic_ReadReg(BaseAddress, RegOffset) \ + XIic_In32((BaseAddress) + (RegOffset)) + +/***************************************************************************/ +/** +* +* Write to the specified IIC device register. +* +* @param BaseAddress is the base address of the device. +* @param RegOffset is the offset from the 1st register of the +* device to select the specific register. +* @param RegisterValue is the value to be written to the register. +* +* @return None. +* +* @note C-Style signature: +* void XIic_WriteReg(u32 BaseAddress, u32 RegOffset, +* u32 RegisterValue); +* This macro does not do any checking to ensure that the +* register exists if the register may be excluded due to +* parameterization, such as the GPO Register. +* +******************************************************************************/ +#define XIic_WriteReg(BaseAddress, RegOffset, RegisterValue) \ + XIic_Out32((BaseAddress) + (RegOffset), (RegisterValue)) + +/******************************************************************************/ +/** +* +* This macro disables all interrupts for the device by writing to the Global +* interrupt enable register. +* +* @param BaseAddress is the base address of the IIC device. +* +* @return None. +* +* @note C-Style signature: +* void XIic_IntrGlobalDisable(u32 BaseAddress); +* +******************************************************************************/ +#define XIic_IntrGlobalDisable(BaseAddress) \ + XIic_WriteReg((BaseAddress), XIIC_DGIER_OFFSET, 0) + +/******************************************************************************/ +/** +* +* This macro writes to the global interrupt enable register to enable +* interrupts from the device. This function does not enable individual +* interrupts as the Interrupt Enable Register must be set appropriately. +* +* @param BaseAddress is the base address of the IIC device. +* +* @return None. +* +* @note C-Style signature: +* void XIic_IntrGlobalEnable(u32 BaseAddress); +* +******************************************************************************/ +#define XIic_IntrGlobalEnable(BaseAddress) \ + XIic_WriteReg((BaseAddress), XIIC_DGIER_OFFSET, \ + XIIC_GINTR_ENABLE_MASK) + +/******************************************************************************/ +/** +* +* This function determines if interrupts are enabled at the global level by +* reading the global interrupt register. +* +* @param BaseAddress is the base address of the IIC device. +* +* @return +* - TRUE if the global interrupt is enabled. +* - FALSE if global interrupt is disabled. +* +* @note C-Style signature: +* int XIic_IsIntrGlobalEnabled(u32 BaseAddress); +* +******************************************************************************/ +#define XIic_IsIntrGlobalEnabled(BaseAddress) \ + (XIic_ReadReg((BaseAddress), XIIC_DGIER_OFFSET) == \ + XIIC_GINTR_ENABLE_MASK) + +/******************************************************************************/ +/** +* +* This function sets the Interrupt status register to the specified value. +* +* This register implements a toggle on write functionality. The interrupt is +* cleared by writing to this register with the bits to be cleared set to a one +* and all others to zero. Setting a bit which is zero within this register +* causes an interrupt to be generated. +* +* This function writes only the specified value to the register such that +* some status bits may be set and others cleared. It is the caller's +* responsibility to get the value of the register prior to setting the value +* to prevent an destructive behavior. +* +* @param BaseAddress is the base address of the IIC device. +* @param Status is the value to be written to the Interrupt +* status register. +* +* @return None. +* +* @note C-Style signature: +* void XIic_WriteIisr(u32 BaseAddress, u32 Status); +* +******************************************************************************/ +#define XIic_WriteIisr(BaseAddress, Status) \ + XIic_WriteReg((BaseAddress), XIIC_IISR_OFFSET, (Status)) + +/******************************************************************************/ +/** +* +* This function gets the contents of the Interrupt Status Register. +* This register indicates the status of interrupt sources for the device. +* The status is independent of whether interrupts are enabled such +* that the status register may also be polled when interrupts are not enabled. +* +* @param BaseAddress is the base address of the IIC device. +* +* @return The value read from the Interrupt Status Register. +* +* @note C-Style signature: +* u32 XIic_ReadIisr(u32 BaseAddress); +* +******************************************************************************/ +#define XIic_ReadIisr(BaseAddress) \ + XIic_ReadReg((BaseAddress), XIIC_IISR_OFFSET) + +/******************************************************************************/ +/** +* +* This function sets the contents of the Interrupt Enable Register. +* +* This function writes only the specified value to the register such that +* some interrupt sources may be enabled and others disabled. It is the +* caller's responsibility to get the value of the interrupt enable register +* prior to setting the value to prevent a destructive behavior. +* +* @param BaseAddress is the base address of the IIC device. +* @param Enable is the value to be written to the Interrupt Enable +* Register. Bit positions of 1 will be enabled. Bit positions of 0 +* will be disabled. +* +* @return None +* +* @note C-Style signature: +* void XIic_WriteIier(u32 BaseAddress, u32 Enable); +* +******************************************************************************/ +#define XIic_WriteIier(BaseAddress, Enable) \ + XIic_WriteReg((BaseAddress), XIIC_IIER_OFFSET, (Enable)) + +/******************************************************************************/ +/** +* +* +* This function gets the Interrupt Enable Register contents. +* +* @param BaseAddress is the base address of the IIC device. +* +* @return The contents read from the Interrupt Enable Register. +* Bit positions of 1 indicate that the corresponding interrupt +* is enabled. Bit positions of 0 indicate that the corresponding +* interrupt is disabled. +* +* @note C-Style signature: +* u32 XIic_ReadIier(u32 BaseAddress) +* +******************************************************************************/ +#define XIic_ReadIier(BaseAddress) \ + XIic_ReadReg((BaseAddress), XIIC_IIER_OFFSET) + +/******************************************************************************/ +/** +* +* This macro clears the specified interrupt in the Interrupt status +* register. It is non-destructive in that the register is read and only the +* interrupt specified is cleared. Clearing an interrupt acknowledges it. +* +* @param BaseAddress is the base address of the IIC device. +* @param InterruptMask is the bit mask of the interrupts to be cleared. +* +* @return None. +* +* @note C-Style signature: +* void XIic_ClearIisr(u32 BaseAddress, u32 InterruptMask); +* +******************************************************************************/ +#define XIic_ClearIisr(BaseAddress, InterruptMask) \ + XIic_WriteIisr((BaseAddress), \ + XIic_ReadIisr(BaseAddress) & (InterruptMask)) + +/******************************************************************************/ +/** +* +* This macro sends the address for a 7 bit address during both read and write +* operations. It takes care of the details to format the address correctly. +* This macro is designed to be called internally to the drivers. +* +* @param BaseAddress is the base address of the IIC Device. +* @param SlaveAddress is the address of the slave to send to. +* @param Operation indicates XIIC_READ_OPERATION or XIIC_WRITE_OPERATION +* +* @return None. +* +* @note C-Style signature: +* void XIic_Send7BitAddress(u32 BaseAddress, u8 SlaveAddress, +* u8 Operation); +* +******************************************************************************/ +#define XIic_Send7BitAddress(BaseAddress, SlaveAddress, Operation) \ +{ \ + u8 LocalAddr = (u8)(SlaveAddress << 1); \ + LocalAddr = (LocalAddr & 0xFE) | (Operation); \ + XIic_WriteReg(BaseAddress, XIIC_DTR_REG_OFFSET, LocalAddr); \ +} + +/******************************************************************************/ +/** +* +* This macro sends the address for a 7 bit address during both read and write +* operations. It takes care of the details to format the address correctly. +* This macro is designed to be called internally to the drivers for Dynamic +* controller functionality. +* +* @param BaseAddress is the base address of the IIC Device. +* @param SlaveAddress is the address of the slave to send to. +* @param Operation indicates XIIC_READ_OPERATION or XIIC_WRITE_OPERATION. +* +* @return None. +* +* @note C-Style signature: +* void XIic_DynSend7BitAddress(u32 BaseAddress, +* u8 SlaveAddress, u8 Operation); +* +******************************************************************************/ +#define XIic_DynSend7BitAddress(BaseAddress, SlaveAddress, Operation) \ +{ \ + u8 LocalAddr = (u8)(SlaveAddress << 1); \ + LocalAddr = (LocalAddr & 0xFE) | (Operation); \ + XIic_WriteReg(BaseAddress, XIIC_DTR_REG_OFFSET, \ + XIIC_TX_DYN_START_MASK | LocalAddr); \ +} + +/******************************************************************************/ +/** +* +* This macro sends the address, start and stop for a 7 bit address during both +* write operations. It takes care of the details to format the address +* correctly. This macro is designed to be called internally to the drivers. +* +* @param BaseAddress is the base address of the IIC Device. +* @param SlaveAddress is the address of the slave to send to. +* @param Operation indicates XIIC_WRITE_OPERATION. +* +* @return None. +* +* @note C-Style signature: +* void XIic_DynSendStartStopAddress(u32 BaseAddress, +* u8 SlaveAddress, +* u8 Operation); +* +******************************************************************************/ +#define XIic_DynSendStartStopAddress(BaseAddress, SlaveAddress, Operation) \ +{ \ + u8 LocalAddr = (u8)(SlaveAddress << 1); \ + LocalAddr = (LocalAddr & 0xFE) | (Operation); \ + XIic_WriteReg(BaseAddress, XIIC_DTR_REG_OFFSET, \ + XIIC_TX_DYN_START_MASK | XIIC_TX_DYN_STOP_MASK | \ + LocalAddr); \ +} + +/******************************************************************************/ +/** +* +* This macro sends a stop condition on IIC bus for Dynamic logic. +* +* @param BaseAddress is the base address of the IIC Device. +* @param ByteCount is the number of Rx bytes received before the master. +* doesn't respond with ACK. +* +* @return None. +* +* @note C-Style signature: +* void XIic_DynSendStop(u32 BaseAddress, u32 ByteCount); +* +******************************************************************************/ +#define XIic_DynSendStop(BaseAddress, ByteCount) \ +{ \ + XIic_WriteReg(BaseAddress, XIIC_DTR_REG_OFFSET, \ + XIIC_TX_DYN_STOP_MASK | ByteCount); \ +} + +/************************** Function Prototypes *****************************/ + +unsigned XIic_Recv(u32 BaseAddress, u8 Address, + u8 *BufferPtr, unsigned ByteCount, u8 Option); + +unsigned XIic_Send(u32 BaseAddress, u8 Address, + u8 *BufferPtr, unsigned ByteCount, u8 Option); + +unsigned XIic_DynRecv(u32 BaseAddress, u8 Address, u8 *BufferPtr, u8 ByteCount); + +unsigned XIic_DynSend(u32 BaseAddress, u16 Address, u8 *BufferPtr, + u8 ByteCount, u8 Option); + +int XIic_DynInit(u32 BaseAddress); + + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ diff --git a/XilinxProcessorIPLib/drivers/iic/src/xiic_master.c b/XilinxProcessorIPLib/drivers/iic/src/xiic_master.c new file mode 100644 index 00000000..76ea3ed5 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/iic/src/xiic_master.c @@ -0,0 +1,762 @@ +/****************************************************************************** +* +* Copyright (C) 2002 - 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 THE +* XILINX CONSORTIUM 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 xiic_master.c +* +* Contains master functions for the XIic component. This file is necessary to +* send or receive as a master on the IIC bus. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- --- ------- ----------------------------------------------- +* 1.01b jhl 03/27/02 Reparitioned the driver +* 1.01c ecm 12/05/02 new rev +* 1.13a wgr 03/22/07 Converted to new coding style. +* 2.00a ktn 10/22/09 Converted all register accesses to 32 bit access. +* Updated to use the HAL APIs/macros. +* Removed the macro XIic_mEnterCriticalRegion, +* XIic_IntrGlobalDisable should be used in its place. +* Removed the macro XIic_mExitCriticalRegion, +* XIic_IntrGlobalEnable should be used in its place. +* Some of the macros have been renamed to remove _m from +* the name and some of the macros have been renamed to be +* consistent, see the xiic_i.h and xiic_l.h files for +* further information +* 2.05a bss 02/05/12 Assigned RecvBufferPtr in XIic_MasterSend API and +* SendBufferPtr in XIic_MasterRecv NULL +*+* +****************************************************************************/ + +/***************************** Include Files *******************************/ + +#include "xiic.h" +#include "xiic_i.h" + +/************************** Constant Definitions ***************************/ + + +/**************************** Type Definitions *****************************/ + + +/***************** Macros (Inline Functions) Definitions *******************/ + +/***************************************************************************** +* +* This macro includes master code such that master operations, sending +* and receiving data, may be used. This function hooks the master processing +* to the driver such that events are handled properly and allows master +* processing to be optional. It must be called before any functions which +* are contained in this file are called, such as after the driver is +* initialized. +* +* @param None. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +#define XIIC_MASTER_INCLUDE \ +{ \ + XIic_RecvMasterFuncPtr = RecvMasterData; \ + XIic_SendMasterFuncPtr = SendMasterData; \ +} + +/************************** Function Prototypes ****************************/ + +static void SendSlaveAddr(XIic *InstancePtr); +static void RecvMasterData(XIic *InstancePtr); +static void SendMasterData(XIic *InstancePtr); +static int IsBusBusy(XIic *InstancePtr); + +/************************** Variable Definitions **************************/ + +/****************************************************************************/ +/** +* This function sends data as a master on the IIC bus. If the bus is busy, it +* will indicate so and then enable an interrupt such that the status handler +* will be called when the bus is no longer busy. The slave address which has +* been set with the XIic_SetAddress() function is the address to which the +* specific data is sent. Sending data on the bus performs a write operation. +* +* @param InstancePtr points to the Iic instance to be worked on. +* @param TxMsgPtr points to the data to be transmitted. +* @param ByteCount is the number of message bytes to be sent. +* +* @return +* - XST_SUCCESS indicates the message transmission has been +* initiated. +* - XST_IIC_BUS_BUSY indicates the bus was in use and that +* the BusNotBusy interrupt is enabled which will update the +* EventStatus when the bus is no longer busy. +* +* @note None. +* +******************************************************************************/ +int XIic_MasterSend(XIic *InstancePtr, u8 *TxMsgPtr, int ByteCount) +{ + u32 CntlReg; + + XIic_IntrGlobalDisable(InstancePtr->BaseAddress); + + /* + * Ensure that the master processing has been included such that events + * will be properly handled. + */ + XIIC_MASTER_INCLUDE; + InstancePtr->IsDynamic = FALSE; + + /* + * If the busy is busy, then exit the critical region and wait for the + * bus to not be busy, the function enables the bus not busy interrupt. + */ + if (IsBusBusy(InstancePtr)) { + XIic_IntrGlobalEnable(InstancePtr->BaseAddress); + + return XST_IIC_BUS_BUSY; + } + + /* + * If it is already a master on the bus (repeated start), the direction + * was set to Tx which is throttling bus. The control register needs to + * be set before putting data into the FIFO. + */ + CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET); + if (CntlReg & XIIC_CR_MSMS_MASK) { + CntlReg &= ~XIIC_CR_NO_ACK_MASK; + CntlReg |= (XIIC_CR_DIR_IS_TX_MASK | + XIIC_CR_REPEATED_START_MASK); + + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, + CntlReg); + InstancePtr->Stats.RepeatedStarts++; + } + + /* + * Save message state. + */ + InstancePtr->SendByteCount = ByteCount; + InstancePtr->SendBufferPtr = TxMsgPtr; + InstancePtr->RecvBufferPtr = NULL; + + /* + * Put the address into the FIFO to be sent and indicate that the + * operation to be performed on the bus is a write operation, + * a general call address is handled the same as a 7 bit address even + * if 10 bit address is selected. + * Set the transmit address state to indicate the address has been sent. + */ + if ((InstancePtr->Options & XII_SEND_10_BIT_OPTION) && + (InstancePtr->AddrOfSlave != 0)) { + XIic_Send10BitAddrByte1(InstancePtr->AddrOfSlave, + XIIC_WRITE_OPERATION); + XIic_Send10BitAddrByte2(InstancePtr->AddrOfSlave); + } else { + XIic_Send7BitAddr(InstancePtr->AddrOfSlave, + XIIC_WRITE_OPERATION); + } + /* + * Set the transmit address state to indicate the address has been sent + * for communication with event driven processing. + */ + InstancePtr->TxAddrMode = XIIC_TX_ADDR_SENT; + + /* + * Fill remaining available FIFO with message data. + */ + if (InstancePtr->SendByteCount > 1) { + XIic_TransmitFifoFill(InstancePtr, XIIC_MASTER_ROLE); + } + + /* + * After filling fifo, if data yet to send > 1, enable Tx � empty + * interrupt. + */ + if (InstancePtr->SendByteCount > 1) { + XIic_ClearEnableIntr(InstancePtr->BaseAddress, + XIIC_INTR_TX_HALF_MASK); + } + + /* + * Clear any pending Tx empty, Tx Error and then enable them. + */ + XIic_ClearEnableIntr(InstancePtr->BaseAddress, + XIIC_INTR_TX_ERROR_MASK | + XIIC_INTR_TX_EMPTY_MASK); + + /* + * When repeated start not used, MSMS must be set after putting data + * into transmit FIFO, start the transmitter. + */ + CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET); + if ((CntlReg & XIIC_CR_MSMS_MASK) == 0) { + CntlReg &= ~XIIC_CR_NO_ACK_MASK; + CntlReg |= XIIC_CR_MSMS_MASK | XIIC_CR_DIR_IS_TX_MASK; + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, + CntlReg); + } + + XIic_IntrGlobalEnable(InstancePtr->BaseAddress); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* This function receives data as a master from a slave device on the IIC bus. +* If the bus is busy, it will indicate so and then enable an interrupt such +* that the status handler will be called when the bus is no longer busy. The +* slave address which has been set with the XIic_SetAddress() function is the +* address from which data is received. Receiving data on the bus performs a +* read operation. +* +* @param InstancePtr is a pointer to the Iic instance to be worked on. +* @param RxMsgPtr is a pointer to the data to be transmitted +* @param ByteCount is the number of message bytes to be sent +* +* @return +* - XST_SUCCESS indicates the message reception processes has +* been initiated. +* - XST_IIC_BUS_BUSY indicates the bus was in use and that the +* BusNotBusy interrupt is enabled which will update the +* EventStatus when the bus is no longer busy. +* - XST_IIC_GENERAL_CALL_ADDRESS indicates the slave address +* is set to the the general call address. This is not allowed +* for Master receive mode. +* +* @internal +* +* The receive FIFO threshold is a zero based count such that 1 must be +* subtracted from the desired count to get the correct value. When receiving +* data it is also necessary to not receive the last byte with the prior bytes +* because the acknowledge must be setup before the last byte is received. +* +******************************************************************************/ +int XIic_MasterRecv(XIic *InstancePtr, u8 *RxMsgPtr, int ByteCount) +{ + u32 CntlReg; + u8 Temp; + + /* + * If the slave address is zero (general call) the master can't perform + * receive operations, indicate an error. + */ + if (InstancePtr->AddrOfSlave == 0) { + return XST_IIC_GENERAL_CALL_ADDRESS; + } + + XIic_IntrGlobalDisable(InstancePtr->BaseAddress); + + /* + * Ensure that the master processing has been included such that events + * will be properly handled. + */ + XIIC_MASTER_INCLUDE; + InstancePtr->IsDynamic = FALSE; + + /* + * If the busy is busy, then exit the critical region and wait for the + * bus to not be busy, the function enables the bus not busy interrupt. + */ + if (IsBusBusy(InstancePtr)) { + XIic_IntrGlobalEnable(InstancePtr->BaseAddress); + + return XST_IIC_BUS_BUSY; + } + + /* + * Save message state for event driven processing. + */ + InstancePtr->RecvByteCount = ByteCount; + InstancePtr->RecvBufferPtr = RxMsgPtr; + InstancePtr->SendBufferPtr = NULL; + + /* + * Clear and enable Rx full interrupt if using 7 bit, If 10 bit, wait + * until last address byte sent incase arbitration gets lost while + * sending out address. + */ + if ((InstancePtr->Options & XII_SEND_10_BIT_OPTION) == 0) { + XIic_ClearEnableIntr(InstancePtr->BaseAddress, + XIIC_INTR_RX_FULL_MASK); + } + + /* + * If already a master on the bus, the direction was set by Rx Interrupt + * routine to Tx which is throttling bus because during Rxing, Tx reg is + * empty = throttle. CR needs setting before putting data or the address + * written will go out as Tx instead of receive. Start Master Rx by + * setting CR Bits MSMS to Master and msg direction. + */ + CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET); + + if (CntlReg & XIIC_CR_MSMS_MASK) { + CntlReg |= XIIC_CR_REPEATED_START_MASK; + XIic_SetControlRegister(InstancePtr, CntlReg, ByteCount); + + InstancePtr->Stats.RepeatedStarts++; + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, + CntlReg); + + } + + /* + * Set receive FIFO occupancy depth which must be done prior to writing + * the address in the FIFO because the transmitter will immediatedly + * start when in repeated start mode followed by the receiver such that + * the number of bytes to receive should be set 1st. + */ + if (ByteCount == 1) { + Temp = 0; + } else { + if (ByteCount <= IIC_RX_FIFO_DEPTH) { + Temp = ByteCount - 2; + } else { + Temp = IIC_RX_FIFO_DEPTH - 1; + } + } + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_RFD_REG_OFFSET, + (u32) Temp); + + if (InstancePtr->Options & XII_SEND_10_BIT_OPTION) { + /* + * Send the 1st and 2nd byte of the 10 bit address of a write + * operation, write because it's a 10 bit address. + */ + XIic_Send10BitAddrByte1(InstancePtr->AddrOfSlave, + XIIC_WRITE_OPERATION); + XIic_Send10BitAddrByte2(InstancePtr->AddrOfSlave); + + /* + * Set flag to indicate the next byte of the address needs to be + * send, clear and enable Tx empty interrupt. + */ + InstancePtr->TxAddrMode = XIIC_TX_ADDR_MSTR_RECV_MASK; + XIic_ClearEnableIntr(InstancePtr->BaseAddress, + XIIC_INTR_TX_EMPTY_MASK); + } else { + /* + * 7 bit slave address, send the address for a read operation + * and set the state to indicate the address has been sent. + */ + XIic_Send7BitAddr(InstancePtr->AddrOfSlave, + XIIC_READ_OPERATION); + InstancePtr->TxAddrMode = XIIC_TX_ADDR_SENT; + } + + /* + * Tx error is enabled incase the address (7 or 10) has no device to + * answer with Ack. When only one byte of data, must set NO ACK before + * address goes out therefore Tx error must not be enabled as it will + * go off immediately and the Rx full interrupt will be checked. + * If full, then the one byte was received and the Tx error will be + * disabled without sending an error callback msg. + */ + XIic_ClearEnableIntr(InstancePtr->BaseAddress, + XIIC_INTR_TX_ERROR_MASK); + + /* + * When repeated start not used, MSMS gets set after putting data + * in Tx reg. Start Master Rx by setting CR Bits MSMS to Master and + * msg direction. + */ + CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET); + if ((CntlReg & XIIC_CR_MSMS_MASK) == 0) { + CntlReg |= XIIC_CR_MSMS_MASK; + XIic_SetControlRegister(InstancePtr, CntlReg, ByteCount); + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, + CntlReg); + } + + XIic_IntrGlobalEnable(InstancePtr->BaseAddress); + + return XST_SUCCESS; +} + +/***************************************************************************** +* +* This function checks to see if the IIC bus is busy. If so, it will enable +* the bus not busy interrupt such that the driver is notified when the bus +* is no longer busy. +* +* @param InstancePtr points to the Iic instance to be worked on. +* +* @return +* - FALSE indicates the IIC bus is not busy. +* - TRUE indicates the bus was in use and that the BusNotBusy +* interrupt is enabled which will update the EventStatus when +* the bus is no longer busy. +* +* @note None. +* +******************************************************************************/ +static int IsBusBusy(XIic *InstancePtr) +{ + u32 CntlReg; + u32 StatusReg; + + CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET); + StatusReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_SR_REG_OFFSET); + + /* + * If this device is already master of the bus as when using the + * repeated start and the bus is busy setup to wait for it to not be + * busy. + */ + if (((CntlReg & XIIC_CR_MSMS_MASK) == 0) && /* Not master */ + (StatusReg & XIIC_SR_BUS_BUSY_MASK)) { /* Is busy */ + /* + * The bus is busy, clear pending BNB interrupt incase + * previously set and then enable BusNotBusy interrupt. + */ + InstancePtr->BNBOnly = TRUE; + XIic_ClearEnableIntr(InstancePtr->BaseAddress, + XIIC_INTR_BNB_MASK); + InstancePtr->Stats.BusBusy++; + + return TRUE; + } + + return FALSE; +} + +/****************************************************************************** +* +* This function sends the proper byte of the address as well as generate the +* proper address bit fields depending on the address byte required and the +* direction of the data (write or read). +* +* A master receiving has the restriction that the direction must be switched +* from write to read when the third address byte is transmitted. +* For the last byte of the 10 bit address, repeated start must be set prior +* to writing the address. If repeated start options is enabled, the +* control register is written before the address is written to the Tx reg. +* +* @param InstancePtr is a pointer to the XIic instance to be worked on. +* +* @return None. +* +* @note +* +* This function does read/modify/write to the device control register. Calling +* functions must ensure critical sections are used. +* +******************************************************************************/ +static void SendSlaveAddr(XIic *InstancePtr) +{ + u32 CRreg; + + /* + * Set the control register for Master Receive, repeated start must be + * set before writing the address, MSMS should be already set, don't + * set here so if arbitration is lost or some other reason we don't + * want MSMS set incase of error. + */ + CRreg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET); + + CRreg |= XIIC_CR_REPEATED_START_MASK; + CRreg &= ~XIIC_CR_DIR_IS_TX_MASK; + + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, CRreg); + + /* + * Send the 1st byte of the 10 bit address as a read operation, enable + * the receive interrupt to know when data is received, assuming that + * the receive FIFO threshold has been previously set. + */ + XIic_Send10BitAddrByte1(InstancePtr->AddrOfSlave, XIIC_READ_OPERATION); + + XIic_ClearEnableIntr(InstancePtr->BaseAddress, XIIC_INTR_RX_FULL_MASK); +} + +/****************************************************************************** +* +* When the IIC Tx FIFO/register goes empty, this routine is called by the +* interrupt service routine to fill the transmit FIFO with data to be sent. +* +* This function also is called by the Tx � empty interrupt as the data handling +* is identical when you don't assume the FIFO is empty but use the Tx_FIFO_OCY +* register to indicate the available free FIFO bytes. +* +* @param InstancePtr is a pointer to the XIic instance to be worked on. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void SendMasterData(XIic *InstancePtr) +{ + u32 CntlReg; + + /* + * The device is a master on the bus. If there is still more address + * bytes to send when in master receive operation and the slave device + * is 10 bit addressed. + * This requires the lower 7 bits of address to be resent when the mode + * switches to Read instead of write (while sending addresses). + */ + if (InstancePtr->TxAddrMode & XIIC_TX_ADDR_MSTR_RECV_MASK) { + /* + * Send the 1st byte of the slave address in the read operation + * and change the state to indicate this has been done + */ + SendSlaveAddr(InstancePtr); + InstancePtr->TxAddrMode = XIIC_TX_ADDR_SENT; + } + + /* + * In between 1st and last byte of message, fill the FIFO with more data + * to send, disable the 1/2 empty interrupt based upon data left to + * send. + */ + else if (InstancePtr->SendByteCount > 1) { + XIic_TransmitFifoFill(InstancePtr, XIIC_MASTER_ROLE); + + if (InstancePtr->SendByteCount < 2) { + XIic_DisableIntr(InstancePtr->BaseAddress, + XIIC_INTR_TX_HALF_MASK); + } + } + /* + * If there is only one byte left to send, processing differs between + * repeated start and normal messages. + */ + else if (InstancePtr->SendByteCount == 1) { + /* + * When using repeated start, another interrupt is expected + * after the last byte has been sent, so the message is not + * done yet. + */ + if (InstancePtr->Options & XII_REPEATED_START_OPTION) { + XIic_WriteSendByte(InstancePtr); + } + + /* + * When not using repeated start, the stop condition must be + * generated after the last byte is written. The bus is + * throttled waiting for the last byte. + */ + else { + /* + * Set the stop condition before sending the last byte + * of data so that the stop condition will be generated + * immediately following the data another transmit + * interrupt is not expected so the message is done. + */ + CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, + XIIC_CR_REG_OFFSET); + CntlReg &= ~XIIC_CR_MSMS_MASK; + XIic_WriteReg(InstancePtr->BaseAddress, + XIIC_CR_REG_OFFSET, + CntlReg); + + XIic_WriteSendByte(InstancePtr); + + /* + * Wait for bus to not be busy before declaring message + * has been sent for the no repeated start operation. + * The callback will be called from the BusNotBusy part + * of the Interrupt handler to ensure that the message + * is completely sent. + * Disable the Tx interrupts and enable the BNB + * interrupt. + */ + + InstancePtr->BNBOnly = FALSE; + XIic_DisableIntr(InstancePtr->BaseAddress, + XIIC_TX_INTERRUPTS); + XIic_EnableIntr(InstancePtr->BaseAddress, + XIIC_INTR_BNB_MASK); + + } + } else { + if (InstancePtr->Options & XII_REPEATED_START_OPTION) { + + /* + * The message being sent has completed. When using + * repeated start with no more bytes to send repeated + * start needs to be set in the control register so + * that the bus will still be held by this master. + */ + CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, + XIIC_CR_REG_OFFSET); + CntlReg |= XIIC_CR_REPEATED_START_MASK; + XIic_WriteReg(InstancePtr->BaseAddress, + XIIC_CR_REG_OFFSET, CntlReg); + + /* + * If the message that was being sent has finished, + * disable all transmit interrupts and call the callback + * that was setup to indicate the message was sent, + * with 0 bytes remaining. + */ + + XIic_DisableIntr(InstancePtr->BaseAddress, + XIIC_TX_INTERRUPTS); + InstancePtr->SendHandler(InstancePtr->SendCallBackRef, + 0); + } + } + + return; +} + +/*****************************************************************************/ +/** +* +* This function is called when the receive register is full. The number +* of bytes received to cause the interrupt is adjustable using the Receive FIFO +* Depth register. The number of bytes in the register is read in the Receive +* FIFO occupancy register. Both these registers are zero based values (0-15) +* such that a value of zero indicates 1 byte. +* +* For a Master Receiver to properly signal the end of a message, the data must +* be read in up to the message length - 1, where control register bits will be +* set for bus controls to occur on reading of the last byte. +* +* @param InstancePtr is a pointer to the XIic instance to be worked on. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void RecvMasterData(XIic *InstancePtr) +{ + u8 LoopCnt; + int BytesInFifo; + int BytesToRead; + u32 CntlReg; + + /* + * Device is a master receiving, get the contents of the control + * register and determine the number of bytes in fifo to be read out. + */ + CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET); + BytesInFifo = XIic_ReadReg(InstancePtr->BaseAddress, + XIIC_RFO_REG_OFFSET) + 1; + + /* + * If data in FIFO holds all data to be retrieved - 1, set NOACK and + * disable the Tx error. + */ + if ((InstancePtr->RecvByteCount - BytesInFifo) == 1) { + /* + * Disable Tx error interrupt to prevent interrupt + * as this device will cause it when it set NO ACK next. + */ + XIic_DisableIntr(InstancePtr->BaseAddress, + XIIC_INTR_TX_ERROR_MASK); + XIic_ClearIntr(InstancePtr->BaseAddress, + XIIC_INTR_TX_ERROR_MASK); + + /* + * Write control reg with NO ACK allowing last byte to + * have the No ack set to indicate to slave last byte read. + */ + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, + (CntlReg | XIIC_CR_NO_ACK_MASK)); + + /* + * Read one byte to clear a place for the last byte to be read + * which will set the NO ACK. + */ + XIic_ReadRecvByte(InstancePtr); + } + + /* + * If data in FIFO is all the data to be received then get the data + * and also leave the device in a good state for the next transaction. + */ + else if ((InstancePtr->RecvByteCount - BytesInFifo) == 0) { + /* + * If repeated start option is off then the master should stop + * using the bus, otherwise hold the bus, setting repeated start + * stops the slave from transmitting data when the FIFO is read. + */ + if ((InstancePtr->Options & XII_REPEATED_START_OPTION) == 0) { + CntlReg &= ~XIIC_CR_MSMS_MASK; + } else { + CntlReg |= XIIC_CR_REPEATED_START_MASK; + } + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, + CntlReg); + + /* + * Read data from the FIFO then set zero based FIFO read depth + * for a byte. + */ + for (LoopCnt = 0; LoopCnt < BytesInFifo; LoopCnt++) { + XIic_ReadRecvByte(InstancePtr); + } + XIic_WriteReg(InstancePtr->BaseAddress, + XIIC_RFD_REG_OFFSET, 0); + + /* + * Disable Rx full interrupt and write the control reg with ACK + * allowing next byte sent to be acknowledged automatically. + */ + XIic_DisableIntr(InstancePtr->BaseAddress, + XIIC_INTR_RX_FULL_MASK); + + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, + (CntlReg & ~XIIC_CR_NO_ACK_MASK)); + + /* + * Send notification of msg Rx complete in RecvHandler callback. + */ + InstancePtr->RecvHandler(InstancePtr->RecvCallBackRef, 0); + } else { + /* + * Fifo data not at n-1, read all but the last byte of data + * from the slave, if more than a FIFO full yet to receive + * read a FIFO full. + */ + BytesToRead = InstancePtr->RecvByteCount - BytesInFifo - 1; + if (BytesToRead > IIC_RX_FIFO_DEPTH) { + BytesToRead = IIC_RX_FIFO_DEPTH; + } + + /* + * Read in data from the FIFO. + */ + for (LoopCnt = 0; LoopCnt < BytesToRead; LoopCnt++) { + XIic_ReadRecvByte(InstancePtr); + } + } +} diff --git a/XilinxProcessorIPLib/drivers/iic/src/xiic_multi_master.c b/XilinxProcessorIPLib/drivers/iic/src/xiic_multi_master.c new file mode 100644 index 00000000..f8a6632e --- /dev/null +++ b/XilinxProcessorIPLib/drivers/iic/src/xiic_multi_master.c @@ -0,0 +1,235 @@ +/****************************************************************************** +* +* Copyright (C) 2002 - 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 THE +* XILINX CONSORTIUM 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 xiic_multi_master.c +* +* Contains multi-master functions for the XIic component. This file is +* necessary if multiple masters are on the IIC bus such that arbitration can +* be lost or the bus can be busy. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- --- ------- ----------------------------------------------- +* 1.01b jhl 3/27/02 Reparitioned the driver +* 1.01c ecm 12/05/02 new rev +* 1.13a wgr 03/22/07 Converted to new coding style. +* 2.00a ktn 10/22/09 Converted all register accesses to 32 bit access. +* Updated to use the HAL APIs/macros. +* Some of the macros have been renamed to remove _m from +* the name and some of the macros have been renamed to be +* consistent, see the xiic_i.h and xiic_l.h files for further +* information +*+* +****************************************************************************/ + +/***************************** Include Files *******************************/ + +#include "xiic.h" +#include "xiic_i.h" + +/************************** Constant Definitions ***************************/ + + +/**************************** Type Definitions *****************************/ + + +/***************** Macros (Inline Functions) Definitions *******************/ + + +/************************** Function Prototypes ****************************/ + +static void BusNotBusyHandler(XIic *InstancePtr); +static void ArbitrationLostHandler(XIic *InstancePtr); + +/************************** Variable Definitions **************************/ + + +/****************************************************************************/ +/** +* This function includes multi-master code such that multi-master events are +* handled properly. Multi-master events include a loss of arbitration and +* the bus transitioning from busy to not busy. This function allows the +* multi-master processing to be optional. This function must be called prior +* to allowing any multi-master events to occur, such as after the driver is +* initialized. +* +* @param None. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XIic_MultiMasterInclude() +{ + XIic_ArbLostFuncPtr = ArbitrationLostHandler; + XIic_BusNotBusyFuncPtr = BusNotBusyHandler; +} + +/*****************************************************************************/ +/** +* +* The IIC bus busy signals when a master has control of the bus. Until the bus +* is released, i.e. not busy, other devices must wait to use it. +* +* When this interrupt occurs, it signals that the previous master has released +* the bus for another user. +* +* This interrupt is only enabled when the master Tx is waiting for the bus. +* +* This interrupt causes the following tasks: +* - Disable Bus not busy interrupt +* - Enable bus Ack +* Should the slave receive have disabled acknowledgement, enable to allow +* acknowledgment of the sending of our address to again be addresed as +* slave +* - Flush Rx FIFO +* Should the slave receive have disabled acknowledgement, a few bytes may +* be in FIFO if Rx full did not occur because of not enough byte in FIFO +* to have caused an interrupt. +* - Send status to user via status callback with the value: +* XII_BUS_NOT_BUSY_EVENT +* +* @param InstancePtr is a pointer to the XIic instance to be worked on. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void BusNotBusyHandler(XIic *InstancePtr) +{ + u32 Status; + u32 CntlReg; + + /* + * Should the slave receive have disabled acknowledgement, + * enable to allow acknowledgment of the sending of our address to + * again be addresed as slave. + */ + CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET); + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, + (CntlReg & ~XIIC_CR_NO_ACK_MASK)); + + /* + * Flush Tx FIFO by toggling TxFIFOResetBit. FIFO runs normally at 0 + * Do this incase needed to Tx FIFO with more than expected if what + * was set to Tx was less than what the Master expected - read more + * from this slave so FIFO had junk in it. + */ + XIic_FlushTxFifo(InstancePtr); + + /* + * Flush Rx FIFO should slave Rx had a problem, sent No ack but + * still received a few bytes. Should the slave receive have disabled + * acknowledgement, clear Rx FIFO. + */ + XIic_FlushRxFifo(InstancePtr); + + /* + * Send Application messaging status via callbacks. Disable either Tx or + * Receive interrupt. Which callback depends on messaging direction. + */ + Status = XIic_ReadIier(InstancePtr->BaseAddress); + if (InstancePtr->RecvBufferPtr == NULL) { + /* + * Slave was sending data (master was reading), disable + * all the transmit interrupts. + */ + XIic_WriteIier(InstancePtr->BaseAddress, + (Status & ~XIIC_TX_INTERRUPTS)); + } + else { + /* + * Slave was receiving data (master was writing) disable receive + * interrupts. + */ + XIic_WriteIier(InstancePtr->BaseAddress, + (Status & ~XIIC_INTR_RX_FULL_MASK)); + } + + /* + * Send Status in StatusHandler callback. + */ + InstancePtr->StatusHandler(InstancePtr->StatusCallBackRef, + XII_BUS_NOT_BUSY_EVENT); +} + +/*****************************************************************************/ +/** +* +* When multiple IIC devices attempt to use the bus simultaneously, only +* a single device will be able to keep control as a master. Those devices +* that didn't retain control over the bus are said to have lost arbitration. +* When arbitration is lost, this interrupt occurs sigaling the user that +* the message did not get sent as expected. +* +* This function, at arbitration lost: +* - Disables Tx empty, � empty and Tx error interrupts +* - Clears any Tx empty, � empty Rx Full or Tx error interrupts +* - Clears Arbitration lost interrupt, +* - Flush Tx FIFO +* - Call StatusHandler callback with the value: XII_ARB_LOST_EVENT +* +* @param InstancePtr is a pointer to the XIic instance to be worked on. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void ArbitrationLostHandler(XIic *InstancePtr) +{ + /* + * Disable Tx empty and � empty and Tx error interrupts before clearing + * them so they won't occur again. + */ + XIic_DisableIntr(InstancePtr->BaseAddress, XIIC_TX_INTERRUPTS); + + /* + * Clear any Tx empty, � empty Rx Full or Tx error interrupts. + */ + XIic_ClearIntr(InstancePtr->BaseAddress, XIIC_TX_INTERRUPTS); + + XIic_FlushTxFifo(InstancePtr); + + /* + * Update Status via StatusHandler callback. + */ + InstancePtr->StatusHandler(InstancePtr->StatusCallBackRef, + XII_ARB_LOST_EVENT); +} diff --git a/XilinxProcessorIPLib/drivers/iic/src/xiic_options.c b/XilinxProcessorIPLib/drivers/iic/src/xiic_options.c new file mode 100644 index 00000000..b8ab471c --- /dev/null +++ b/XilinxProcessorIPLib/drivers/iic/src/xiic_options.c @@ -0,0 +1,173 @@ +/****************************************************************************** +* +* Copyright (C) 2002 - 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 THE +* XILINX CONSORTIUM 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 xiic_options.c +* +* Contains options functions for the XIic component. This file is not required +* unless the functions in this file are called. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- --- ------- ----------------------------------------------- +* 1.01b jhl 3/26/02 repartioned the driver +* 1.01c ecm 12/05/02 new rev +* 1.13a wgr 03/22/07 Converted to new coding style. +* 2.00a ktn 10/22/09 Converted all register accesses to 32 bit access. +* Updated to use the HAL APIs/macros. +*+* +****************************************************************************/ + +/***************************** Include Files *******************************/ + +#include "xiic.h" +#include "xiic_i.h" + +/************************** Constant Definitions ***************************/ + + +/**************************** Type Definitions *****************************/ + + +/***************** Macros (Inline Functions) Definitions *******************/ + + +/************************** Function Prototypes ****************************/ + + +/************************** Variable Definitions **************************/ + + +/*****************************************************************************/ +/** +* +* This function sets the options for the IIC device driver. The options control +* how the device behaves relative to the IIC bus. If an option applies to +* how messages are sent or received on the IIC bus, it must be set prior to +* calling functions which send or receive data. +* +* To set multiple options, the values must be ORed together. To not change +* existing options, read/modify/write with the current options using +* XIic_GetOptions(). +* +* USAGE EXAMPLE: +* +* Read/modify/write to enable repeated start: +*
+* u8 Options; +* Options = XIic_GetOptions(&Iic); +* XIic_SetOptions(&Iic, Options | XII_REPEATED_START_OPTION); +*+* +* Disabling General Call: +*
+* Options = XIic_GetOptions(&Iic); +* XIic_SetOptions(&Iic, Options &= ~XII_GENERAL_CALL_OPTION); +*+* +* @param InstancePtr is a pointer to the XIic instance to be worked on. +* @param NewOptions are the options to be set. See xiic.h for a list of +* the available options. +* +* @return None. +* +* @note +* +* Sending or receiving messages with repeated start enabled, and then +* disabling repeated start, will not take effect until another master +* transaction is completed. i.e. After using repeated start, the bus will +* continue to be throttled after repeated start is disabled until a master +* transaction occurs allowing the IIC to release the bus. +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- --- ------- ----------------------------------------------- +* 1.01b jhl 03/26/02 repartioned the driver +* 1.01c ecm 12/05/02 new rev +* 1.01c sv 05/09/05 Changed the data being written to the Address/Control +* Register and removed the code for testing the +* Receive Data Register. +* 1.13a wgr 03/22/07 Converted to new coding style. +* 1.16a ktn 07/17/09 Updated the test to test only Interrupt Registers +* as the software reset only resets the interrupt logic +* and the Interrupt Registers are set to default values. +* 1.16a ktn 10/16/09 Updated the notes in the XIic_SelfTest() API and +* XIIC_RESET macro to mention that the complete IIC core +* is Reset on giving a software reset to the IIC core. +* Some previous versions of the core only reset the +* Interrupt Logic/Registers, please refer to the HW +* specification for futher details. +* 2.00a ktn 10/22/09 Converted all register accesses to 32 bit access. +* Updated to use the HAL APIs/macros. +* Some of the macros have been renamed to remove _m from +* the name and some of the macros have been renamed to be +* consistent, see the xiic_i.h and xiic_l.h files for further +* information +*+* +****************************************************************************/ + +/***************************** Include Files *******************************/ + +#include "xiic.h" +#include "xiic_i.h" + +/************************** Constant Definitions ***************************/ + + +/**************************** Type Definitions *****************************/ + + +/***************** Macros (Inline Functions) Definitions *******************/ + + +/************************** Function Prototypes ****************************/ + + +/************************** Variable Definitions **************************/ + + +/*****************************************************************************/ +/** +* +* Runs a limited self-test on the driver/device. This test does a read/write +* test of the Interrupt Registers There is no loopback capabilities for the +* device such that this test does not send or receive data. +* +* @param InstancePtr is a pointer to the XIic instance to be worked on. +* +* @return +* - XST_SUCCESS if no errors are found +* - XST_FAILURE if errors are found +* +* @note None. +* +****************************************************************************/ +int XIic_SelfTest(XIic *InstancePtr) +{ + int Status = XST_SUCCESS; + int GlobalIntrStatus; + u32 IntrEnableStatus; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* + * Store the Global Interrupt Register and the Interrupt Enable Register + * contents. + */ + GlobalIntrStatus = XIic_IsIntrGlobalEnabled(InstancePtr->BaseAddress); + IntrEnableStatus = XIic_ReadIier(InstancePtr->BaseAddress); + + /* + * Reset the device so it's in a known state and the default state of + * the interrupt registers can be tested. + */ + XIic_Reset(InstancePtr); + + if (XIic_IsIntrGlobalEnabled(InstancePtr->BaseAddress)!= 0) { + Status = XST_FAILURE; + } + + if (XIic_ReadIier(InstancePtr->BaseAddress)!= 0) { + Status = XST_FAILURE; + } + + /* + * Test Read/Write to the Interrupt Enable register. + */ + XIic_WriteIier(InstancePtr->BaseAddress, XIIC_TX_RX_INTERRUPTS); + if (XIic_ReadIier(InstancePtr->BaseAddress)!= XIIC_TX_RX_INTERRUPTS) { + Status = XST_FAILURE; + } + + /* + * Reset device to remove the affects of the previous test. + */ + XIic_Reset(InstancePtr); + + /* + * Restore the Global Interrupt Register and the Interrupt Enable + * Register contents. + */ + if (GlobalIntrStatus == TRUE) { + XIic_IntrGlobalEnable(InstancePtr->BaseAddress); + } + XIic_WriteIier(InstancePtr->BaseAddress, IntrEnableStatus); + + return Status; +} diff --git a/XilinxProcessorIPLib/drivers/iic/src/xiic_sinit.c b/XilinxProcessorIPLib/drivers/iic/src/xiic_sinit.c new file mode 100644 index 00000000..633f7fc6 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/iic/src/xiic_sinit.c @@ -0,0 +1,163 @@ +/****************************************************************************** +* +* Copyright (C) 2005 - 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 THE +* XILINX CONSORTIUM 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 xiic_sinit.c +* +* The implementation of the Xiic component's static initialzation functionality. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- --- ------- ----------------------------------------------- +* 1.02a jvb 10/13/05 release +* 1.13a wgr 03/22/07 Converted to new coding style. +* 2.00a ktn 10/22/09 Converted all register accesses to 32 bit access. +* Updated to use the HAL APIs/macros. +* Some of the macros have been renamed to remove _m from +* the name and some of the macros have been renamed to be +* consistent, see the xiic_i.h and xiic_l.h files for further +* information +*+* +****************************************************************************/ + +/***************************** Include Files *******************************/ + +#include "xstatus.h" +#include "xparameters.h" +#include "xiic_i.h" + +/************************** Constant Definitions ***************************/ + + +/**************************** Type Definitions *****************************/ + + +/***************** Macros (Inline Functions) Definitions *******************/ + + +/************************** Function Prototypes ****************************/ + +/************************** Variable Definitions **************************/ + + +/*****************************************************************************/ +/** +* +* Looks up the device configuration based on the unique device ID. The table +* IicConfigTable contains the configuration info for each device in the system. +* +* @param DeviceId is the unique device ID to look for +* +* @return A pointer to the configuration data of the device, +* or NULL if no match is found. +* +* @note None. +* +******************************************************************************/ +XIic_Config *XIic_LookupConfig(u16 DeviceId) +{ + XIic_Config *CfgPtr = NULL; + u32 Index; + + for (Index = 0; Index < XPAR_XIIC_NUM_INSTANCES; Index++) { + if (XIic_ConfigTable[Index].DeviceId == DeviceId) { + CfgPtr = &XIic_ConfigTable[Index]; + break; + } + } + + return CfgPtr; +} + +/*****************************************************************************/ +/** +* +* Initializes a specific XIic instance. The initialization entails: +* +* - Check the device has an entry in the configuration table. +* - Initialize the driver to allow access to the device registers and +* initialize other subcomponents necessary for the operation of the device. +* - Default options to: +* - 7-bit slave addressing +* - Send messages as a slave device +* - Repeated start off +* - General call recognition disabled +* - Clear messageing and error statistics +* +* The XIic_Start() function must be called after this function before the device +* is ready to send and receive data on the IIC bus. +* +* Before XIic_Start() is called, the interrupt control must connect the ISR +* routine to the interrupt handler. This is done by the user, and not +* XIic_Start() to allow the user to use an interrupt controller of their choice. +* +* @param InstancePtr is a pointer to the XIic instance to be worked on. +* @param DeviceId is the unique id of the device controlled by this XIic +* instance. Passing in a device id associates the generic XIic +* instance to a specific device, as chosen by the caller or +* application developer. +* +* @return +* - XST_SUCCESS when successful +* - XST_DEVICE_NOT_FOUND indicates the given device id isn't found +* - XST_DEVICE_IS_STARTED indicates the device is started +* (i.e. interrupts enabled and messaging is possible). +* Must stop before re-initialization is allowed. +* +* @note None. +* +****************************************************************************/ +int XIic_Initialize(XIic *InstancePtr, u16 DeviceId) +{ + XIic_Config *ConfigPtr; /* Pointer to configuration data */ + + /* + * Asserts test the validity of selected input arguments. + */ + Xil_AssertNonvoid(InstancePtr != NULL); + + /* + * Lookup the device configuration in the temporary CROM table. Use this + * configuration info down below when initializing this component. + */ + ConfigPtr = XIic_LookupConfig(DeviceId); + if (ConfigPtr == NULL) { + return XST_DEVICE_NOT_FOUND; + } + + return XIic_CfgInitialize(InstancePtr, ConfigPtr, + ConfigPtr->BaseAddress); +} diff --git a/XilinxProcessorIPLib/drivers/iic/src/xiic_slave.c b/XilinxProcessorIPLib/drivers/iic/src/xiic_slave.c new file mode 100644 index 00000000..f5f217d1 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/iic/src/xiic_slave.c @@ -0,0 +1,603 @@ +/****************************************************************************** +* +* Copyright (C) 2002 - 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 THE +* XILINX CONSORTIUM 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 xiic_slave.c +* +* Contains slave functions for the XIic component. This file is necessary when +* slave operations, sending and receiving data as a slave on the IIC bus, +* are desired. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- --- ------- ----------------------------------------------- +* 1.01b jhl 3/26/02 repartioned the driver +* 1.01c ecm 12/05/02 new rev +* 1.13a wgr 03/22/07 Converted to new coding style. +* 1.15a ktn 03/18/09 Minor changes to comply to Doxygen +* 2.00a ktn 10/22/09 Converted all register accesses to 32 bit access. +* Updated to use the HAL APIs/macros. +* Removed the macro XIic_mEnterCriticalRegion and used +* XIic_IntrGlobalDisable int its place. +* Removed the macro XIic_mExitCriticalRegion and used +* XIic_IntrGlobalEnable in its place. +* Some of the macros have been renamed to remove _m from +* the name and some of the macros have been renamed to be +* consistent, see the xiic_i.h and xiic_l.h files for further +* information +* 2.03a rkv 01/25/11 Updated in NAAS interrupt handler to support data +* recieved less than FIFO size prior to NAAS interrupt. +* Fixed for CR590212. +* 2.04a sdm 07/22/11 Added IsSlaveSetAckOff flag to the instance structure. +* The IsSlaveSetAckOff is set when the Slave has set the +* Ack Off in the RecvSlaveData function and is cleared in the +* NotAddrAsSlaveHandler when the master has released the +* bus. This flag is to be used by slave applications for +* recovering when it has gone out of sync with the master. +* CR 615004. +*+* +****************************************************************************/ + +/***************************** Include Files *******************************/ + +#include "xiic.h" +#include "xiic_i.h" + +/************************** Constant Definitions ***************************/ + +/**************************** Type Definitions *****************************/ + +/***************** Macros (Inline Functions) Definitions *******************/ + +/************************** Function Prototypes ****************************/ + +static void AddrAsSlaveHandler(XIic *InstancePtr); +static void NotAddrAsSlaveHandler(XIic *InstancePtr); +static void RecvSlaveData(XIic *InstancePtr); +static void SendSlaveData(XIic *InstancePtr); + +/************************** Variable Definitions **************************/ + +/*****************************************************************************/ +/** +* +* This function includes slave code such that slave events will be processsed. +* It is necessary to allow slave code to be optional to reduce the size of +* the driver. This function may be called at any time but must be prior to +* being selected as a slave on the IIC bus. This function may be called prior +* to the Cfg_Initialize() function and must be called before any functions in +* this file are called. +* +* @param None. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XIic_SlaveInclude() +{ + XIic_AddrAsSlaveFuncPtr = AddrAsSlaveHandler; + XIic_NotAddrAsSlaveFuncPtr = NotAddrAsSlaveHandler; + XIic_RecvSlaveFuncPtr = RecvSlaveData; + XIic_SendSlaveFuncPtr = SendSlaveData; +} + +/*****************************************************************************/ +/** +* +* This function sends data as a slave on the IIC bus and should not be called +* until an event has occurred that indicates the device has been selected by +* a master attempting read from the slave (XII_MASTER_READ_EVENT). +* +* @param InstancePtr is a pointer to the XIic instance to be worked on. +* @param TxMsgPtr is a pointer to the data to be transmitted. +* @param ByteCount is the number of message bytes to be sent. +* +* @return +* - XST_SUCCESS indicates the message transmission has been +* initiated. +* - XST_IIC_NOT_SLAVE indicates the device has not been +* selected to be a slave on the IIC bus such that data +* cannot be sent. +* +* @note None. +* +******************************************************************************/ +int XIic_SlaveSend(XIic *InstancePtr, u8 *TxMsgPtr, int ByteCount) +{ + u32 IntrStatus; + u32 Status; + + /* + * If the device is not a slave on the IIC bus then indicate an error + * because data cannot be sent on the bus. + */ + Status = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_SR_REG_OFFSET); + if ((Status & XIIC_SR_ADDR_AS_SLAVE_MASK) == 0) { + return XST_IIC_NOT_SLAVE; + } + + XIic_IntrGlobalDisable(InstancePtr->BaseAddress); + + /* + * Save message state and invalidate the receive buffer pointer to + * indicate the direction of transfer is sending. + */ + InstancePtr->SendByteCount = ByteCount; + InstancePtr->SendBufferPtr = TxMsgPtr; + InstancePtr->RecvBufferPtr = NULL; + + /* + * Start sending the specified data and then interrupt processing will + * complete it. + */ + XIic_TransmitFifoFill(InstancePtr, XIIC_SLAVE_ROLE); + + /* Clear any pending Tx empty, Tx Error and interrupt then enable them. + * The Tx error interrupt indicates when the message is complete. + * If data remaining to be sent, clear and enable Tx � empty interrupt. + */ + IntrStatus = (XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_ERROR_MASK); + if (InstancePtr->SendByteCount > 1) { + IntrStatus |= XIIC_INTR_TX_HALF_MASK; + } + + /* + * Clear the interrupts in the status and then enable them and then + * exit the critical region. + */ + XIic_ClearEnableIntr(InstancePtr->BaseAddress, IntrStatus); + + XIic_IntrGlobalEnable(InstancePtr->BaseAddress); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function sends data as a slave on the IIC bus and should not be called +* until an event has occurred that indicates the device has been selected by +* a master attempting read from the slave (XII_MASTER_READ_EVENT). +* +* If more data is received than specified a No Acknowledge will be sent to +* signal the Master to stop sending data. Any received data is read to prevent +* the slave device from throttling the bus. +* +* @param InstancePtr is a pointer to the Iic instance to be worked on. +* @param RxMsgPtr is a pointer to the data to be transmitted. +* @param ByteCount is the number of message bytes to be sent. +* +* @return +* - XST_SUCCESS indicates the message transmission has been +* initiated. +* - XST_IIC_NOT_SLAVE indicates the device has not been selected +* to be a slave on the IIC bus such that data cannot be received. +* +* @internal +* +* The master signals the message completion differently depending on the +* repeated start options. +* +* When the master is not using repeated start: +* - Not Adressed As Slave NAAS interrupt signals the master has sent a stop +* condition and is no longer sending data. This doesn't imply that the master +* will not send a No Ack. It covers when the master fails to send No +* Ackowledge before releasing the bus. +* - Tx Error interrupt signals end of message. +* +* When the master is using repeated start: +* - the Tx Error interrupt signals the master finished sending the msg. +* - NAAS interrupt will not signal when message is complete as the +* master may want to write or read another message with this device. +* +* To prevent throttling, the slave must contine to read discard the data +* when the receive buffer is full. When unexpected bytes are received, No Ack +* must be set and the Rx buffer continually read until either NAAS +* or Bus Not Busy BND interrupt signals the master is no longer +* interacting with this slave. At this point the Ack is set to ON allowing +* this device to acknowlefge the an address sent to it for the next +* slave message. +* +* The slave will always receive 1 byte before the bus is throttled causing a +* receive pending interrupt before this routine is executed. After one byte +* the bus will throttle. The depth is set to the proper amount immediatelly +* allowing the master to send more bytes and then to again throttle, but at the +* proper fifo depth. The interrupt is a level. Clearing and enabling will cause +* the Rx interrupt to pend at the correct level. +* +******************************************************************************/ +int XIic_SlaveRecv(XIic *InstancePtr, u8 *RxMsgPtr, int ByteCount) +{ + u32 Status; + + /* + * If the device is not a slave on the IIC bus then indicate an error + * because data cannot be received on the bus. + */ + Status = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_SR_REG_OFFSET); + if ((Status & XIIC_SR_ADDR_AS_SLAVE_MASK) == 0) { + return XST_IIC_NOT_SLAVE; + } + + XIic_IntrGlobalDisable(InstancePtr->BaseAddress); + + /* + * Save message state and invalidate the send buffer pointer to indicate + * the direction of transfer is receive. + */ + InstancePtr->RecvByteCount = ByteCount; + InstancePtr->RecvBufferPtr = RxMsgPtr; + InstancePtr->SendBufferPtr = NULL; + + /* + * Set receive FIFO occupancy depth so the Rx interrupt will occur + * when all bytes received or if more bytes than will fit in FIFO, + * set to max depth. + */ + if (ByteCount > IIC_RX_FIFO_DEPTH) { + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_RFD_REG_OFFSET, + IIC_RX_FIFO_DEPTH - 1); + } else { + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_RFD_REG_OFFSET, + ByteCount - 1); + } + + /* + * Clear and enable receive full interrupt except when the bytes to + * receive is only 1, don't clear interrupt as it is the only one your + * going to get. + */ + if (ByteCount > 1) { + XIic_ClearIntr(InstancePtr->BaseAddress, + XIIC_INTR_RX_FULL_MASK); + } + + XIic_EnableIntr(InstancePtr->BaseAddress, XIIC_INTR_RX_FULL_MASK); + + XIic_IntrGlobalEnable(InstancePtr->BaseAddress); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function is called when the IIC device is Addressed As a Slave (AAS). +* This occurs when another device on the bus, a master, has addressed this +* device to receive a message. +* +* @param InstancePtr is a pointer to the XIic instance to be worked on. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void AddrAsSlaveHandler(XIic *InstancePtr) +{ + u32 Status; + int CallValue; + + /* + * Disable AAS interrupt to clear the interrupt condition since this is + * interrupt does not go away and enable the not addressed as a slave + * interrrupt to tell when the master stops data transfer. + */ + XIic_DisableIntr(InstancePtr->BaseAddress, XIIC_INTR_AAS_MASK); + XIic_ClearEnableIntr(InstancePtr->BaseAddress, XIIC_INTR_NAAS_MASK); + + /* + * Determine how the slave is being addressed and call the handler to + * notify the user of the event. + */ + Status = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_SR_REG_OFFSET); + + /* + * Determine if the master is trying to perform a read or write + * operation. + */ + if (Status & XIIC_SR_MSTR_RDING_SLAVE_MASK) { + CallValue = XII_MASTER_READ_EVENT; + } else { + CallValue = XII_MASTER_WRITE_EVENT; + } + + /* + * If being addressed with general call also indicate to handler. + */ + if (Status & XIIC_SR_GEN_CALL_MASK) { + CallValue |= XII_GENERAL_CALL_EVENT; + } + + InstancePtr->StatusHandler(InstancePtr->StatusCallBackRef, CallValue); + return; +} + +/*****************************************************************************/ +/** +* +* This function is called when the IIC device receives Not Addressed As Slave +* (NAAS) interrupt which indicates that the master has released the bus implying +* a data transfer is complete. +* +* @param InstancePtr is a pointer to the XIic instance to be worked on. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void NotAddrAsSlaveHandler(XIic *InstancePtr) +{ + u32 Status; + u32 CntlReg; + u8 BytesToRead; + u8 LoopCnt; + + /* + * Disable NAAS so that the condition will not continue to interrupt + * and enable the addressed as slave interrupt to know when a master + * selects a slave on the bus. + */ + XIic_DisableIntr(InstancePtr->BaseAddress, XIIC_INTR_NAAS_MASK); + XIic_ClearEnableIntr(InstancePtr->BaseAddress, XIIC_INTR_AAS_MASK); + + /* + * Flush Tx FIFO by toggling TxFIFOResetBit. FIFO runs normally at 0 + * Do this incase needed to Tx FIFO with more than expected if what + * was set to Tx was less than what the Master expected - read more + * from this slave so FIFO had junk in it. + */ + XIic_FlushTxFifo(InstancePtr); + + /* + * NAAS interrupt was asserted but received data in recieve FIFO is + * less than Rc_FIFO_PIRQ to assert an receive full interrupt,in this + * condition as data recieved is valid we have to read data before FIFO + * flush. + */ + Status = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_SR_REG_OFFSET); + + if (!(Status & XIIC_SR_RX_FIFO_EMPTY_MASK)) { + BytesToRead = (XIic_ReadReg(InstancePtr->BaseAddress, + XIIC_RFO_REG_OFFSET)) + 1; + if (InstancePtr->RecvByteCount > BytesToRead) { + + for (LoopCnt = 0; LoopCnt < BytesToRead; LoopCnt++) { + XIic_ReadRecvByte(InstancePtr); + } + } + } + + InstancePtr->RecvByteCount = 0; + /* + * Flush Rx FIFO should slave Rx had a problem, sent No ack but + * still received a few bytes. Should the slave receive have disabled + * acknowledgement, clear Rx FIFO. + */ + XIic_FlushRxFifo(InstancePtr); + + /* + * Set FIFO occupancy depth = 1 so that the first byte will throttle + * next recieve msg. + */ + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_RFD_REG_OFFSET, 0); + + /* + * Should the slave receive have disabled acknowledgement, + * enable to allow acknowledgment for receipt of our address to + * again be used as a slave. + */ + CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET); + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, + (CntlReg & ~XIIC_CR_NO_ACK_MASK)); + + InstancePtr->IsSlaveSetAckOff = FALSE; + + /* + * Which callback depends on messaging direction, the buffer pointer NOT + * being used indicates the direction of data transfer. + */ + Status = XIic_ReadIier(InstancePtr->BaseAddress); + if (InstancePtr->RecvBufferPtr == NULL) { + /* + * Slave was sending data so disable all transmit interrupts and + * call the callback handler to indicate the transfer is + * complete. + */ + XIic_WriteIier(InstancePtr->BaseAddress, + (Status & ~XIIC_TX_INTERRUPTS)); + InstancePtr->SendHandler(InstancePtr->SendCallBackRef, + InstancePtr->SendByteCount); + } + else { + /* + * Slave was receiving data so disable receive full interrupt + * and call the callback handler to notify the transfer is + * complete. + */ + XIic_WriteIier(InstancePtr->BaseAddress, + (Status & ~XIIC_INTR_RX_FULL_MASK)); + InstancePtr->RecvHandler(InstancePtr->RecvCallBackRef, + InstancePtr->RecvByteCount); + } + return; +} + +/*****************************************************************************/ +/** +* +* This function handles data received from the IIC bus as a slave. +* +* When the slave expects more than the master has to send, the slave will stall +* waiting for data. +* +* When more data is received than data expected a Nack is done to signal master +* to stop sending data. The excess data is discarded to prevent bus throttling. +* +* The buffer may be full and the master continues to send data if the master +* and slave have different message lengths. This condition is handled by sending +* No Ack to the master and reading Rx data until the master stops sending data +* to prevent but throttling from locking up the bus. To ever receive as a slave +* again, must know when to renable bus ACKs. NAAS is used to detect when the +* master is finished sending messages for any mode. + +* @param InstancePtr is a pointer to the XIic instance to be worked on. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void RecvSlaveData(XIic *InstancePtr) +{ + u32 CntlReg; + u8 BytesToRead; + u8 LoopCnt; + u8 Temp; + + /* + * When receive buffer has no room for the receive data discard it. + */ + if (InstancePtr->RecvByteCount == 0) { + /* + * Set ACKnowlege OFF to signal master to stop sending data. + */ + CntlReg = XIic_ReadReg(InstancePtr->BaseAddress, + XIIC_CR_REG_OFFSET); + CntlReg |= XIIC_CR_NO_ACK_MASK; + XIic_WriteReg(InstancePtr->BaseAddress, XIIC_CR_REG_OFFSET, + CntlReg); + + /* + * Set a Flag to indicate that the Slave has set the ACK Off. + */ + InstancePtr->IsSlaveSetAckOff = TRUE; + + + /* + * Clear excess received data to prevent bus throttling and set + * receive FIFO occupancy to throttle at the 1st byte received. + */ + XIic_FlushRxFifo(InstancePtr); + XIic_WriteReg(InstancePtr->BaseAddress, + XIIC_RFD_REG_OFFSET, 0); + + return; + } + /* + * Use occupancy count to determine how many bytes to read from the + * FIFO, count is zero based so add 1, read that number of bytes from + * the FIFO. + */ + BytesToRead = (XIic_ReadReg(InstancePtr->BaseAddress, + XIIC_RFO_REG_OFFSET)) + 1; + for (LoopCnt = 0; LoopCnt < BytesToRead; LoopCnt++) { + XIic_ReadRecvByte(InstancePtr); + } + + /* + * Set receive FIFO depth for the number of bytes to be received such + * that a receive interrupt will occur, the count is 0 based, the + * last byte of the message has to be received seperately to ack the + * message. + */ + if (InstancePtr->RecvByteCount > IIC_RX_FIFO_DEPTH) { + Temp = IIC_RX_FIFO_DEPTH - 1; + } else { + if (InstancePtr->RecvByteCount == 0) { + Temp = 0; + } else { + Temp = InstancePtr->RecvByteCount - 1; + } + } + XIic_WriteReg(InstancePtr->BaseAddress, + XIIC_RFD_REG_OFFSET, (u32) Temp); + + return; +} + +/*****************************************************************************/ +/** +* +* This function sends data on the IIC bus as a slave. +* +* When message data has been sent, but the master keeps reading data, the FIFO +* is filled to prevent bus throttling. There is no way to notify master of this +* condition. While sending data as a slave a transmit error indicates the +* master has completed the data transfer. +* +* NAAS interrupt signals when repeated start occurred and the msg is finished +* and BNB signals when the master sent a stop. +* +* @param InstancePtr is a pointer to the XIic instance to be worked on. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void SendSlaveData(XIic *InstancePtr) +{ + /* + * When message has been sent, but master keeps reading data, must put a + * byte in the FIFO or bus will throttle. There is no way to notify + * master of this condition. + */ + if (InstancePtr->SendByteCount == 0) { + XIic_WriteReg(InstancePtr->BaseAddress, + XIIC_DTR_REG_OFFSET, 0xFF); + return; + } + + /* + * Send the data by filling the transmit FIFO. + */ + XIic_TransmitFifoFill(InstancePtr, XIIC_SLAVE_ROLE); + /* + * When the amount of data remaining to send is less than the half mark + * of the FIFO making the use of � empty interrupt unnecessary, + * disable it. Is this a problem that it's checking against 1 rather + * than half? + */ + if (InstancePtr->SendByteCount < 1) { + XIic_DisableIntr(InstancePtr->BaseAddress, + XIIC_INTR_TX_HALF_MASK); + } + return; +} diff --git a/XilinxProcessorIPLib/drivers/iic/src/xiic_stats.c b/XilinxProcessorIPLib/drivers/iic/src/xiic_stats.c new file mode 100644 index 00000000..3f0fa8f5 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/iic/src/xiic_stats.c @@ -0,0 +1,133 @@ +/****************************************************************************** +* +* Copyright (C) 2002 - 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 THE +* XILINX CONSORTIUM 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 xiic_stats.c +* +* Contains statistics functions for the XIic component. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- --- ------- ----------------------------------------------- +* 1.01b jhl 3/26/02 repartioned the driver +* 1.01c ecm 12/05/02 new rev +* 1.13a wgr 03/22/07 Converted to new coding style. +* 2.00a ktn 10/22/09 Converted all register accesses to 32 bit access. +* Updated to use the HAL APIs/macros. +* XIic_ClearStats function is updated as the +* macro XIIC_CLEAR_STATS has been removed. +*+* +****************************************************************************/ + +/***************************** Include Files *******************************/ + +#include "xiic.h" +#include "xiic_i.h" + +/************************** Constant Definitions ***************************/ + +/**************************** Type Definitions *****************************/ + +/***************** Macros (Inline Functions) Definitions *******************/ + +/************************** Function Prototypes ****************************/ + +/************************** Variable Definitions **************************/ + +/*****************************************************************************/ +/** +* +* Gets a copy of the statistics for an IIC device. +* +* @param InstancePtr is a pointer to the XIic instance to be worked on. +* @param StatsPtr is a pointer to a XIicStats structure which will get a +* copy of current statistics. +* +* @return None. +* +* @note None. +* +****************************************************************************/ +void XIic_GetStats(XIic *InstancePtr, XIicStats * StatsPtr) +{ + u8 NumBytes; + u8 *SrcPtr; + u8 *DestPtr; + + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(StatsPtr != NULL); + + /* + * Setup pointers to copy the stats structure + */ + SrcPtr = (u8 *) &InstancePtr->Stats; + DestPtr = (u8 *) StatsPtr; + + /* + * Copy the current statistics to the structure passed in + */ + for (NumBytes = 0; NumBytes < sizeof(XIicStats); NumBytes++) { + *DestPtr++ = *SrcPtr++; + } +} + +/*****************************************************************************/ +/** +* +* Clears the statistics for the IIC device by zeroing all counts. +* +* @param InstancePtr is a pointer to the XIic instance to be worked on. +* +* @return None. +* +* @note None. +* +****************************************************************************/ +void XIic_ClearStats(XIic *InstancePtr) +{ + u8 NumBytes; + u8 *DestPtr; + + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertVoid(InstancePtr != NULL); + + DestPtr = (u8 *)&InstancePtr->Stats; + for (NumBytes = 0; NumBytes < sizeof(XIicStats); NumBytes++) { + *DestPtr++ = 0; + } + +}