##################################################################################################### # # # IPMC and Shelf Manager Guide # # Author: Spencer Lee - leespen1@msu.edu # # # # Rev: December 6th, 2019 # # # ##################################################################################################### Changes made from previous version: Improved labeling of sections Improved table of contents Reference to IPMI specification in 3.1.5 Changes to be made in next version: Description of package structure of ICARE (Section 4) Instructions for creating a new package Description of writing to IOPins (Section 5, possibly example subsection of section 4) Table of Contents: Overview Resources & Links Shelf Manager IPMC/ICARE |---- 1 - Overview | |---- 2 - ICARE Setup | | | |---- 2.1 - Downloading/Configuring ICARE | |---- 2.2 - Creating a Project | |---- 2.3 - Downloading Firmware to IPMC | |---- 3 - Adding Sensors | |---- 3.1 - Relevant Files | |---- 3.1.1 - Release Side - ICARE/releases/ICARE-00-03-01/sensors/src | |---- 3.1.2 - Release Side - ICARE/releases/ICARE-00-03-01/sensors/sensors/sensors.h | |---- 3.1.3 - Project Side - cfg_data.h | |---- 3.1.4 - Project Side - sensors.c | |---- 3.1.5 - Project Side - sdr_data.c | |---- 3.2 - Working Example - IQ60533 Temperature sensor |---- 3.3 - Adding another IQ65033 Sensor #################################################################################################### # Overview # #################################################################################################### This document will serve as an introduction and guide to the usage of the shelf managers and LAPP IPMC at MSU/CERN. This is a working document. It will be added to and corrected over time. Feel free to contact me with any corrections or requests for new information. Additions to be made: Description of ICARE package structure #################################################################################################### # Resources & Links # #################################################################################################### ATCA Base Specification https://web.pa.msu.edu/people/edmunds/Do_-_To/va_alpha.pdf IPMI Specification https://web.pa.msu.edu/hep/atlas/l1calo/hub/reference/ipmc/ipmi/ipmi_mgt_interface_specification_2ndgen-v2p0-rev1p1_2013_10_01.pdf LAPP ICARE Website (currently down) http://lappwiki.in2p3.fr/twiki/bin/view/AtlasLapp/Informatique Pidgeon Point Shelf Manager User Guide https://web.pa.msu.edu/hep/atlas/l1calo/hub/hardware/components/commercial_atca/Shelf_Manager_UG_Aug_2017.pdf Pigdeon Point Shelf Manager External Interface Reference https://web.pa.msu.edu/hep/atlas/l1calo/hub/hardware/components/commercial_atca/Shelf_Manager_EIR_3_4_0_20140515.pdf 14-Slot ATCA AC/DC Shelf User Manual https://web.pa.msu.edu/hep/atlas/l1calo/hub/hardware/components/commercial_atca/Asis_MaXum_14_Slot_User_Manual_rev1.5.pdf #################################################################################################### # Shelf Manager # #################################################################################################### Main Resources: The Shelf Manager User Guide and External Interface Reference are both extremely useful for understanding the shelf manager. Overview: The shelf manager is a device required by the ATCA specification. Its responsibilities include managing the power and cooling of FRUs and the shelf infrastructure. This is done mostly through interactions between the shelf manager and IPMCs (ATCA Spec 3.3). The term shelf manager refers to the role required by the ATCA specification, while the actual piece of hardware that fulfils this role is referred to as the Shelf Management Mezzanine, or ShMM. OS: The ShMMs in use at MSU run some custom, lightweight linux, either Monterery Linux or Pigeon Point Linux, depending on the ShMM variant (User Guide pg 22). As such, they can be ssh'd into like any other linux computer. Furthermore, most standard linux operations work on the shelf manager. However, special care should be taken to consult the user guide and external interface reference on whether performing a certain action will affect shelf manager operations. For example, manual changes in the ShMM network configuration (i.e. using ifconfig) can disrupt Shelf Manager operations. Instead, "clia setlanconfig" should be used to configure the network. System Event Log: Interactions between the shelf manager and the IPMCs on a shelf occur through the generation of IPMI events. For example, an IPMC may report that the temperature of a device is too high by asserting a "Upper Critical (major) - going high" temperature event, which will prompt the shelf manager to increase the fan speed in the corresponding area of the shelf. Interacting with the Shelf Manager: Interaction with the shelf manager is done mostly through clia (command line interpreter agent) commands. They can be executed from the ShMM command line by "clia ". For a list of all clia commands, use "clia help". Some helpful/frequently used commands are: clia sel - Displays the system event log clia sensordata - Get sensor data values clia sendcmd - Sends an arbitrary IPMI command to specified IPMC (IPMI commands can be found in IPMC specification. Generally, clia commands are more conveneient ways of of executing IPMI commands) More information about a command can be displayed by using "clia help ", and for many commands "-v" can be added for verbose output. Detailed descriptions of all clia commands can be found in section 3 of the External Interface Reference. #################################################################################################### # IPMC/ICARE # #################################################################################################### ================================================================================================ 1 - Overview ================================================================================================ ICARE stands for Intelligent platform management Controller softwARE. It is created by LAPP and is used for creating LAPP IPMC firmwares and downloading them to LAPP IPMCs. ================================================================================================ 2 - ICARE Setup ================================================================================================ ------------------------------------------------------------------------------------------------ 2.1 - ICARE Setup - Downloading/Configuring ICARE ------------------------------------------------------------------------------------------------ First download the latest ICARE software stack (ICARE_160519.sh at time of writing). It can be found here at the following locations: http://lappwiki.in2p3.fr/twiki/bin/view/AtlasLapp/Informatique https://mydrive.lapp.in2p3.fr/s/SWXlWLJPjsfl03U/download (link directly to download) Once downloaded, move the the software stack to the desired working directory. This directory will be referred to as . Now run the commands: % cd % /ICARE_160519.sh The software stack may not have executable permission set when downloaded. If so, either use chmod to enable execution and use the above commands, or do % sh /ICARE_160519.sh Instructions for setting up ICARE and downloading firmwares can now be found at: /ICARE/releases/ICARE-00-03-01/doc/README Here, we provide a condensed version describing the setup in our specific use cases (on hubdev2 and hubdev3/pcl1c-stf-00). The specified supported operating systems are Scientific Linux CERN 5 and Scientific Linux CERN 6, but we have successfully configured ICARE on hubdev3 and hubdev3, which use Red Hat Enterprise Linux. Furthermore, we were unable to configure ICARE on pcl1c-stf-00, which uses Scientific Linux. Note for STF at CERN: Since we were unable to configure ICARE on the STF gateway machine, pcl1c-stf-00, we instead configured ICARE on hubdev3. We then used pcl1c-stf-00 First follow step 4.1 of the README (installation is redundant if ICARE has already been configured before, but no harm is done by attempting installation again): 4.1) Re-initialize CMT package % cd /ICARE/contrib/CMT/v1r22/mgr % ./INSTALL % source setup.[c]sh CMT is a configuration management environment that will be used throughout the configuration of ICARE. Since we are using the latest ICARE software stack, we skip steps 4.2 and 4.3. Now perform steps 4.4 and 4.4.1 4.4) Re-generate CMT setup scripts in admin package % cd /ICARE/releases/ICARE-00-03-01/admin/cmt % cmt relocate 4.4.1) Setting up of ICARE development environment - [DEFAULT] Set native compiler 'gcc version 4.1.2/4.4.7' and ARM compiler 'arm-elf-gcc version 4.7.0' with debugging flag % source setup.[c]sh <- use this default setting up - Set native compiler 'gcc version 4.1.2/4.4.7' and ARM compiler 'arm-elf-gcc version 4.7.0' with optimization flag % source setup.[c]sh -tag_add=opt Then execute the following: 4.5) Re-generate CMT setup scripts in ICAREPolicy package % cd ../../ICAREPolicy/cmt % cmt relocate 4.6) Re-generate CMT setup scripts in ICARERelease package % cd ../../ICARERelease/cmt % bcmt cmt relocate <- broadcast 'cmt relocate' command to all packages included in the release Now we build the ICARE release. Step 5.1 should ONLY BE EXECUTED ONCE. If changes are made to any ICARE source files, the modified packages should be rebuilt, as in step 5.2. V) Build 5.1) Build release (...THIS TASK IS EXECUTED ONLY ONCE...) % source /ICARE/releases/ICARE-00-03-01/admin/cmt/setup.[c]sh % cd /ICARE/releases/ICARE-00-03-01/ICARERelease/cmt % make release <- broadcast 'make' command to all packages included in the release 5.2) Re-build any package % source /ICARE/releases/ICARE-00-03-01/admin/cmt/setup.[c]sh % cd /ICARE/releases/ICARE-00-03-01//cmt % make clean all This ICARE release will function as the foundation for all IPMC firmwares you will create. For a specific implementation of the IPMC firmware, you will create a project which contains information specific to each board (i.e. what sensors are available and how to read them). Section VI deals with OpenOCD (Open On-Chip Debugger), which is one tool which can be used to download firmware to the IPMC. We will be downloading firmwares over ethernet instead, so this section is unecessary for us and will be skipped. ------------------------------------------------------------------------------------------------ 2.2 - ICARE Setup - Creating a Project ------------------------------------------------------------------------------------------------ First, create a directory to store the project in. We will refer to this directory as . Now use: % cd % create_project.sh -a -c -n -p FEX_Hub -v -p specifies the package name. Ours is FEX_Hub, but others exist for other IPMC implementations. -n specifies the host name to run the OpenOCD server on. It is a required field, but is not relevant to us since we will not be using OpenOCD. "localhost" should be a suitable placeholder. -v specifies the project version, and serves no functional purpose - it is purely for organization. As such, any version naming scheme works fine. Then follow step 8.1.2: edit file //config/config/boardconfig.h and change the unspecified PEN to: "#define IANA_MSU_PEN 0x000113" Also change the Manufacturer ID (under user settings in the same file) to: "MANUFACTURER_ID(IANA_MSU_PEN)" The do the following: 8.2) Re-build packages and your project % source /ICARE/releases/ICARE-00-03-01/admin/cmt/setup.[c]sh % cd ///cmt % make rebuild NOTE: This broadcast command re-builds the packages and your project 8.3) Build your project % source /ICARE/releases/ICARE-00-03-01/admin/cmt/setup.[c]sh % cd ///cmt % make bmc ------------------------------------------------------------------------------------------------ 2.3 - ICARE Setup - Downloading Firmware to IPMC ------------------------------------------------------------------------------------------------ We will download firmware to the IPMC via ethernet. To do this, we use fwu (FirmWare Upgrade utility). To enable use of fwu, do: % source /ICARE/releases/ICARE-00-03-01/admin/cmt/setup.[c]sh % cd //cmt % source setup.sh Usage information for fwu can be obtained by running "fwu -h". The IPMC is contains two MCUs (MicroController Units): the IPMC MCU and the IOIF MCU. When you build a project, firmware binaries are created for both MCUs. To implement a firmware in the IPMC, we must download the firmware binaries to the IOIF MCU and the IPMC MCU, then issue an upgrade command for the changes to take effect. IMPORTANT: The IOIF MCU should be upgraded before the IPMC MCU. When upgrading the MCUs, wait at least 1 minute between upgrading the IOIF and IPMC MCUs so that the IPMC MCU upgrade does not interrupt the IOIF MCU upgrade. WARNING: Make sure you download the IOIF MCU firmware to the IOIF MCU, and the IPMC MCU firmware to the IPMC MCU. Configuring the IPMC MCU with the IPMC MCU firmware can put the IPMC in a state where it cannot be talked to over ethernet. Then it will be impossible to change the IPMC MCU firmware back using ethernet. NOTE FOR CERN STF USAGE: At CERN there were issues configuring ICARE on the gateway machine pcl1c-stf-00.cern.ch, but not on hubdev3.cern.ch. However, only the gateway machine has ethernet access to the shelves in the STF (Surface Test Facility). So, our procedure was to build firmwares on hubdev3, then download the binaries using the gateway machine. On the gateway machine, fwu can still be used by specifying the path of fwu. So in the commands below replace "fwu" with "/ICARE/releases/ICARE-00-03-01/fwUpgrade/x86_64_slc7-gcc48-dbg/fwu" So, to implement a firmware in the IPMC, perform the following: Download IOIF MCU firmware % fwu -t IOIF -n -f //arm-gcc-47-dbg/bmc_IOIF.bin Download IPMC MCU Firmware % fwu -t IPMC -n -f //arm-gcc-47-dbg/bmc_IPMC.bin Issue IOIF MCU Upgrade % fwu -t IOIF -n -u (wait at least 1 minute) Issue IPMC MCU Upgrade % fwu -t IPMC -n -u ================================================================================================ 3 - Adding Sensors ================================================================================================ ------------------------------------------------------------------------------------------------ 3.1 - Adding Sensors - Relevant Files ------------------------------------------------------------------------------------------------ The files relevant for adding sensors to an ICARE project are divided between two areas. On the release side we have: The files in ICARE/releases/ICARE-00-03-01/sensors/src ICARE/releases/ICARE-00-03-01/sensors/sensors/sensors.h On the project/workarea side we have in the directory /FEX_Hub/src: cfg_data.h sensors.c sdr_data.c All of these files are important for implementing sensors, but to implement a sensor which is on a device which already has other sensors implemented sensors.c and sdr_data.c will be the most important files, and likely the only files you will have to edit. ------------------------------------------------------------------------------------------------ 3.1.1 - Adding Sensors - Relevant Files Release Side - ICARE/releases/ICARE-00-03-01/sensors/src ------------------------------------------------------------------------------------------------ Each file in this directory contains function definitons for configuring, reading, and sometimes writing to/from a specific device. For example, the file iq65033qma10.c contains config and read functions for the power entry module. This device contains multiple sensors, and we will use the same functions to configure or read from each sensor on the device. ------------------------------------------------------------------------------------------------ 3.1.2 - Adding Sensors - Relevant Files Release Side - ICARE/releases/ICARE-00-03-01/sensors/sensors/sensors.h ------------------------------------------------------------------------------------------------ This contains declarations of the functions in the files in sensors/src. ------------------------------------------------------------------------------------------------ 3.1.3 - Adding Sensors - Relevant Files Project Side - cfg_data.h ------------------------------------------------------------------------------------------------ Cfg is short for configuration. The file cfg_data.h does has two purposes: to define the I2C slave addresses of the devices we wish to read sensor information from, and to assign SDR numbers to each sensor. SDR stands for Sensor Data Record. The SDR numbers will be used by the shelf manager to identify each sensor, and will also be used to distinguish between sensors on the same device when performing inits/reads/writes ------------------------------------------------------------------------------------------------ 3.1.4 - Adding Sensors - Relevant Files Project Side - sensors.c ------------------------------------------------------------------------------------------------ SensorsInit() - This function "initializes" each sensor by creating a structure with several attributes. For each sensor, the following attributes are defined: ucChannelId - The I2C Channel the sensor device is on (Management, Sensor, etc.) ucAddress - the I2C Address of the sensor device ucIdentifier - a way to identify the sensor (distinguish it from other sensors on the same device). In the currently implemented devices, the SDR number is used. fnInit - The function in sensors.c to be called to initialize the sensor fnRead - The function in sensors.c to be called to read from the sensor fnWrite - The function in sensors.c to be called to write to the sensor These attributes. are handled by some "Resource Broker". SensorsClean() - This function has the resource broker remove each sensor defined in SensorsInit(). Init/Read/Write Functions - The functions to be called by each sensor are defined in this file. Each sensor should have each of these functions, even if they do not do anything meaningful (for example, in the current implementation of IQ60533 sensors only the read function does anything meaningful). Init Functions - Initialization functions take one parameter, a pointer to a resource broker structure defined in SensorsInit(). These functions should perform any actions necessary to initialize the sensor, if there are any. Read Functions - Read functions take two parameters: a pointer to a resource broker structure defined in SensorsInit() and a pointer to an 8-bit unsigned integer. Write Functions - Write functions take three parameters. We have not yet needed to write to any sensors, so I have not examined what these parameters are (one is a resource broker structure). ------------------------------------------------------------------------------------------------ 3.1.5 - Adding Sensors - Relevant Files Project Side - sdr_data.c Note: See Section 43. Sensor Data Record Formats in IPMI Specification (pg. 550) ------------------------------------------------------------------------------------------------ This file contains the sensor data record information for each sensor implemented. This information is passed to the shelf manager (sensor data records are required by the ATCA specification), where it is used to interpret the each sensor (tell what type of sensor it is, what the critical thresholds are for the sensor data, etc.). The SDR entry for each sensor consists of a sequence of bytes that correspond to different properties and parameters of the sensor. There are 49+ bytes in total (more bytes depending on the length of sensor ID string). ############### The function of each bytes/field is described in "Section 43. Sensor Data Record ## IMPORTANT ## Formats" of the IPMI specification (pg. 550). This is a vital resource for ############### understanding the purpose/usage of this file and the records in it. When creating a new SDR entry, I recommend copying another SDR entry and modifying the necessary bytes. The bytes you will likely want to change (for a full sensor record) are: Byte 5 - Length of record entry (differs depending on length of sensor ID string) Byte 7 [4:7] - Channel_num - The I2C channel of the sensor device Byte 8 [8] - Sensor number - the SDR number of the sensor Byte 13 - Sensor type - temperature, current, voltage, etc Bytes 24-30 - Controls conversion from raw data received from sensor to a meaningful value Bytes 32-44 - Sets sensor max/min readings and upper/lower thresholds Byte 47 - I2C address of sensor device Byte 48 - Length of sensor ID string Byte 49+ - Sensor ID string Most of these parameters are straightforward. One thing I will address in more detail is bytes 24-30. If the raw sensor data value is x (8 bit integer), and y is the meaningful value (temperature in degrees C, voltage, etc), the formula of conversion is: y = L[(M*x+(B*10^(B_exponent)))*10^(R_exponent)] L is the linearization factor, and should be set to 0 if the conversion is linear. I am unsure what other values of L correspond to. M and R_exponent control the rate of change of y with respect to x, and B, B_exponent, and R_exponent control a constant value to add. For example, if we wanted y = 1.96x-50, we would take M = 196, R_exponent = -2, B = -5, and B_exponent = 3. M and B are 10 bit values, so you will have to convert your desired value into binary and put the bit pattern into M_lsb and M_msb (least significant bits and most significant bits) or B_lsb and B_msb. The size of M and B also limits precision. For example, you cannot have M = 1961, and therefore you cannot have a conversion formula y=1.961x-50. B_exponent and R_exponent are each 4-bit values. Keep in mind that these values are all two's complement signed integers. In twos complement, you can convert between positive and negative by flipping all the bits of a number and adding one. I do not yet understand how the tolerance and accuracy parameters work. ------------------------------------------------------------------------------------------------ 3.2 - Working Example - IQ60533 Temperature sensor ------------------------------------------------------------------------------------------------ Here I go over the relevant parts of each file in implementing a temperature sensor on the Synqor IQ65033 Power Interface Module. The technical specification for this can be found at: https://web.pa.msu.edu/hep/atlas/l1calo/hub/hardware/components/power/synqor_300_watt_entry_IQ65033QMA10.pdf /FEX_Hub/src/sensors.c: We define the I2C address of the IQ65033 power entry module > #define SDR_IQ65033_I2C_ADDR 0x2C // I2C @ = 0101111b And we define the SDR numbers of each sensor on the power entry module > SDR_NUM_IQ65033_STATUS, > SDR_NUM_IQ65033_HU_CAP_VOLTAGE, > SDR_NUM_IQ65033_48V_CURRENT, > SDR_NUM_IQ65033_48V_A, > SDR_NUM_IQ65033_48V_B, > SDR_NUM_IQ65033_TEMP, (This is in an enum statement, so this gives integer values for each SDR_NUM in increasing order, i.e. SDR_NUM_IQ65033=36, SDR_NUM_IQ65033_HU_CAP_VOLTAGE=37, etc) /FEX_Hub/src/sensors.c: In SensorsInit(): We set up a resource broker structure for the temperature sensor > // IQ65033 Temperature > stResource.ucChannelId = CHANNEL_I2C_MGT; > stResource.ucAddress = SDR_IQ65033_I2C_ADDR; > stResource.ucIdentifier = SDR_NUM_IQ65033_TEMP; > stResource.fnInit = InitSensorIQ65033; > stResource.fnRead = ReadSensorIQ65033; > stResource.fnWrite = WriteSensorIQ65033; > > if (ResourceBrokerAddResource("IQ65033 Temp", &stResource) == false) > return false; In SensorsClean(): We add the single line: > bRtn &= ResourceBrokerRemoveResourceByName("IQ65033 Temp"); We also add Init, Read, and Write functions: > static bool InitSensorIQ65033(struct RBResource *pstResource) > static bool ReadSensorIQ65033(struct RBResource *pstResource, uint8_t *pucData) > static int WriteSensorIQ65033(struct RBResource *pstResource, void *pvBuffer, > uint32_t uiLength) The read function is the important one here, so I will explain it: > /*----------------------------------------------------------------------------*/ > static bool ReadSensorIQ65033(struct RBResource *pstResource, uint8_t *pucData) > /*----------------------------------------------------------------------------*/ > { > // Sanity check > if ((pstResource == NULL) || (pucData == NULL)) > return false; > > // The four high-order bits of I2C address for the IQ65033 are set to 0101 > if ((pstResource->ucAddress & 0x78) != 0x28) > return false; > > int iRtn; > uint32_t uiI2Cx = auiChannel2Bus[pstResource->ucChannelId]; > uint8_t ucIdx = pstResource->ucIdentifier - SDR_NUM_IQ65033_STATUS; > > if (uiI2Cx == 0xFFFFFFFF) > return false; > > if ((iRtn = iq65033Read(uiI2Cx, pstResource->ucAddress, ucIdx)) == -1) > return false; > > *pucData = (uint8_t)iRtn; > > return true; > } *pstResource is a pointer to the structure for the sensor which we defined in SensorsInit(). *pucData is a pointer to the raw data for the sensor. To modify the raw data reported, we modify *pucData The "Sanity check" makes sure that the function parameters are actually pointer to something. Next we check that the four high-order bits of the I2C address given in the structure *pstResource matches what we expect using the lines > if ((pstResource->ucAddress & 0x78) != 0x28) > return false; The reason we only check the four high-order bits is that the value of the lower bits changes depending on a resistor connected to the power entry module. Next we get the I2C channel of the sensor device as a variable in order to pass it as a parameter to the read function defined on the release side. > uint32_t uiI2Cx = auiChannel2Bus[pstResource->ucChannelId]; The line > uint8_t ucIdx = pstResource->ucIdentifier - SDR_NUM_IQ65033_STATUS; Takes the difference between the SDR number of the sensor and the SDR number of the status bits (another piece of sensor information the power entry module collects and reports). This will be passed as a parameter to the read function on the release side, and we will soon see why this is done. The line > if (uiI2Cx == 0xFFFFFFFF) > return false; Is a check that we have a reasonable I2C address. Next we perform the actual read by calling the iq65033 read function on the release side > if ((iRtn = iq65033Read(uiI2Cx, pstResource->ucAddress, ucIdx)) == -1) > return false; (We also check that the read was succesful, return false if not) Finally we uodate the sensor data with the read value > *pucData = (uint8_t)iRtn; And return true to signify that the read was succesful. ICARE/releases/ICARE-00-03-01/sensors/src/iq65033qma10.c: > u8 channelAddr[IQ65033_MAX_CHANNEL] = {0x1e, 0x1f, 0x21, 0x22, 0x23, 0x28}; > > int iq65033Config(uint32_t i2cChannel, u8 address) { > > return 0; > } > > int iq65033Read(uint32_t i2cChannel, u8 address, u8 dataChannel) { > int iRtn; > u8 buff[2]; > int val = 0; > > buff[0] = channelAddr[dataChannel]; // read register > iRtn = I2C_Write(i2cChannel, I2C_MASTER, buff, 1, address); > if (iRtn == -1) > return (-1); > > iRtn = I2C_Read(i2cChannel, I2C_MASTER, buff, 1, address); > if (iRtn == -1) > return (-1); > > iRtn = I2C_Read(i2cChannel, I2C_MASTER, buff, 1, address); > if (iRtn == -1) > return (-1); > > val = (int)buff[0]; > > return (val); > } channelAddr is an array of 8-bit unsigned integers. In it are the register addresses of each sensor in increasing order. It is important to note here that the SDR numbers of the sensors that get their sensor data from each register location are in the same order. The parameter dataChannel we pass has value SDR_NUM_IQ65033_TEMP - SDR_NUM_IQ65033_STATUS = 5. Then the line > buff[0] = channelAddr[dataChannel]; // read register Gets us the value 0x28, which is the register address of the temperature (which you can find in Table 1 of the Synqor IQ65033 specification). We perform an I2C Write to the power entry module to write the register address of the temperature (which we pass as part of the parameter buff), so that when we next perform an I2C read it will be from that register location. > iRtn = I2C_Write(i2cChannel, I2C_MASTER, buff, 1, address); > if (iRtn == -1) > return (-1); We then perform two I2C reads to read the temperature and the register location directly after it (I2C reads automatically increment). In this case, the temperature is stored in a single 8-bit register, but for other devices the value might be 16-bit, in which case we would want to perform two reads. > iRtn = I2C_Read(i2cChannel, I2C_MASTER, buff, 1, address); > if (iRtn == -1) > return (-1); > > iRtn = I2C_Read(i2cChannel, I2C_MASTER, buff, 1, address); > if (iRtn == -1) > return (-1); Finally, we return the read value > val = (int)buff[0]; > > return (val); /FEX_Hub/src/sdr_data.c: We add a SDR entry for the IQ65033 temperature sensor as such: > // ============================================================================ > // Core temperature sensor > // ============================================================================ > #define SDR_IQ65033_TEMP_STR_LEN 12 > FullSensorRecord_t sdr_iq65033_temp = { // MANDATORY Power Interface Module IQ65033QMA10 > SDR entries are very long, and fairly straightforward, so I do not go into any details here. ------------------------------------------------------------------------------------------------ 3.3 - Adding another IQ65033 Sensor ------------------------------------------------------------------------------------------------ Since init/read/write functions have already been written for other sensors on the power entry module, all you have to do to add another sensor is make the following changes: /FEX_Hub/src/sensors.c - Add resource broker structure for sensor in SensorsInit() - Add cleanup protocol for that structure in SensorsClean() /FEX_Hub/src/sdr_data.c - Make an SDR entry for the sensor (copy another one and edit the fields)