summaryrefslogtreecommitdiff
path: root/utils/smbus.c
diff options
context:
space:
mode:
authorYuval Adam <yuv.adm@gmail.com>2014-03-16 14:41:11 +0200
committerYuval Adam <yuv.adm@gmail.com>2014-03-16 14:41:11 +0200
commit990090a4cc9070837d31e66b58d40f0c3d038741 (patch)
treecf1b905082c364e9b223e0c5058566103138dae5 /utils/smbus.c
parent7f4da522479c0f00126219f0c23b804c3a93d7a6 (diff)
Add usblib and utils
Diffstat (limited to 'utils/smbus.c')
-rw-r--r--utils/smbus.c5173
1 files changed, 5173 insertions, 0 deletions
diff --git a/utils/smbus.c b/utils/smbus.c
new file mode 100644
index 0000000..8ed9c3a
--- /dev/null
+++ b/utils/smbus.c
@@ -0,0 +1,5173 @@
+//*****************************************************************************
+//
+// smbus.c - SMBus protocol layer API.
+//
+// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
+// Software License Agreement
+//
+// Texas Instruments (TI) is supplying this software for use solely and
+// exclusively on TI's microcontroller products. The software is owned by
+// TI and/or its suppliers, and is protected under applicable copyright
+// laws. You may not combine this software with "viral" open-source
+// software in order to form a larger program.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
+// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
+// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
+// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+// DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 2.1.0.12573 of the Tiva Utility Library.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_i2c.h"
+#include "inc/hw_ints.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_sysctl.h"
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/interrupt.h"
+#include "driverlib/i2c.h"
+#include "driverlib/sw_crc.h"
+#include "driverlib/sysctl.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "driverlib/udma.h"
+#include "utils/smbus.h"
+
+//*****************************************************************************
+//
+//! \addtogroup smbus_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The states for the master and slave interrupt handler state machines.
+//
+//*****************************************************************************
+#define SMBUS_STATE_IDLE 0
+#define SMBUS_STATE_SLAVE_POST_COMMAND 1
+#define SMBUS_STATE_WRITE_BLOCK_SIZE 2
+#define SMBUS_STATE_WRITE_NEXT 3
+#define SMBUS_STATE_WRITE_FINAL 4
+#define SMBUS_STATE_WRITE_DONE 5
+#define SMBUS_STATE_READ_ONE 6
+#define SMBUS_STATE_READ_FIRST 7
+#define SMBUS_STATE_READ_BLOCK_SIZE 8
+#define SMBUS_STATE_READ_NEXT 9
+#define SMBUS_STATE_READ_FINAL 10
+#define SMBUS_STATE_READ_WAIT 11
+#define SMBUS_STATE_READ_PEC 12
+#define SMBUS_STATE_READ_DONE 13
+#define SMBUS_STATE_READ_ERROR_STOP 14
+
+//*****************************************************************************
+//
+// Status flags for various instance-specific tasks.
+//
+//*****************************************************************************
+#define FLAG_PEC 0
+#define FLAG_PROCESS_CALL 1
+#define FLAG_BLOCK_TRANSFER 2
+#define FLAG_TRANSFER_IN_PROGRESS 3
+#define FLAG_RAW_I2C 4
+#define FLAG_ADDRESS_RESOLVED 5
+#define FLAG_ADDRESS_VALID 6
+#define FLAG_ARP 7
+//*****************************************************************************
+//
+//! Enables Packet Error Checking (PEC).
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function enables the transmission and checking of a PEC byte in SMBus
+//! transactions.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusPECEnable(tSMBus *psSMBus)
+{
+ //
+ // Set the PEC flag in the configuration structure.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC) = 1;
+}
+
+//*****************************************************************************
+//
+//! Disables Packet Error Checking (PEC).
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function disables the transmission and checking of a PEC byte in SMBus
+//! transactions.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusPECDisable(tSMBus *psSMBus)
+{
+ //
+ // Clear the PEC flag in the configuration structure.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC) = 0;
+}
+
+//*****************************************************************************
+//
+//! Sets the ARP flag in the configuration structure.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function sets the Address Resolution Protocol (ARP) flag in the
+//! configuration structure. This flag can be used to track the state of a
+//! device during the ARP process.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusARPEnable(tSMBus *psSMBus)
+{
+ //
+ // Set the ARP flag in the configuration structure.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_ARP) = 1;
+}
+
+//*****************************************************************************
+//
+//! Clears the ARP flag in the configuration structure.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function clears the Address Resolution Protocol (ARP) flag in the
+//! configuration structure. This flag can be used to track the state of a
+//! device during the ARP process.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusARPDisable(tSMBus *psSMBus)
+{
+ //
+ // Clear the ARP flag in the configuration structure.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_ARP) = 0;
+}
+
+//*****************************************************************************
+//
+//! Returns the number of bytes in the receive buffer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function returns the number of bytes in the active receive buffer.
+//! It can be used to determine how many bytes have been received in the slave
+//! receive or master block read configurations.
+//!
+//! \return Number of bytes in the buffer.
+//
+//*****************************************************************************
+uint8_t
+SMBusRxPacketSizeGet(tSMBus *psSMBus)
+{
+ //
+ // Return the number of bytes received.
+ //
+ return(psSMBus->ui8RxIndex);
+}
+
+//*****************************************************************************
+//
+//! Returns the state of an SMBus transfer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function returns the status of an SMBus transaction. It can be used
+//! to determine whether a transfer is ongoing or complete.
+//!
+//! \return Returns \b SMBUS_TRANSFER_IN_PROGRESS if transfer is ongoing, or
+//! \b SMBUS_TRANSFER_COMPLETE if transfer has completed.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusStatusGet(tSMBus *psSMBus)
+{
+ //
+ // Check to see if there is an ongoing transfer.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS))
+ {
+ //
+ // If the flag is set, return in progress status.
+ //
+ return(SMBUS_TRANSFER_IN_PROGRESS);
+ }
+
+ //
+ // If the transfer complete flag is cleared, transfer is done.
+ //
+ else
+ {
+ //
+ // If the flag isn't set, return complete status.
+ //
+ return(SMBUS_TRANSFER_COMPLETE);
+ }
+}
+
+//*****************************************************************************
+//
+//! Encodes a UDID structure and address into SMBus-transferable byte order.
+//!
+//! \param pUDID specifies the structure to encode.
+//! \param ui8Address specifies the address to send with the UDID (byte 17).
+//! \param pui8Data specifies the location of the destination data buffer.
+//!
+//! This function takes a tSMBusUDID structure and re-orders the bytes so that
+//! it can be transferred on the bus. The destination data buffer must contain
+//! at least 17 bytes.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusARPUDIDPacketEncode(tSMBusUDID *pUDID, uint8_t ui8Address,
+ uint8_t *pui8Data)
+{
+ //
+ // Place data from the UDID structure and address into the data buffer
+ // using the correct MSB->LSB + address order.
+ //
+ pui8Data[0] = pUDID->ui8DeviceCapabilities;
+ pui8Data[1] = pUDID->ui8Version;
+ pui8Data[2] = (uint8_t)((pUDID->ui16VendorID & 0xff00) >> 8);
+ pui8Data[3] = (uint8_t)(pUDID->ui16VendorID & 0x00ff);
+ pui8Data[4] = (uint8_t)((pUDID->ui16DeviceID & 0xff00) >> 8);
+ pui8Data[5] = (uint8_t)(pUDID->ui16DeviceID & 0x00ff);
+ pui8Data[6] = (uint8_t)((pUDID->ui16Interface & 0xff00) >> 8);
+ pui8Data[7] = (uint8_t)(pUDID->ui16Interface & 0x00ff);
+ pui8Data[8] = (uint8_t)((pUDID->ui16SubSystemVendorID & 0xff00) >> 8);
+ pui8Data[9] = (uint8_t)(pUDID->ui16SubSystemVendorID & 0x00ff);
+ pui8Data[10] = (uint8_t)((pUDID->ui16SubSystemDeviceID & 0xff00) >> 8);
+ pui8Data[11] = (uint8_t)(pUDID->ui16SubSystemDeviceID & 0x00ff);
+ pui8Data[12] = (uint8_t)((pUDID->ui32VendorSpecificID & 0xff000000) >>
+ 24);
+ pui8Data[13] = (uint8_t)((pUDID->ui32VendorSpecificID & 0x00ff0000) >>
+ 16);
+ pui8Data[14] = (uint8_t)((pUDID->ui32VendorSpecificID & 0x0000ff00) >>
+ 8);
+ pui8Data[15] = (uint8_t)(pUDID->ui32VendorSpecificID & 0x000000ff);
+ pui8Data[16] = ui8Address;
+}
+
+//*****************************************************************************
+//
+//! Decodes an SMBus packet into a UDID structure and address.
+//!
+//! \param pUDID specifies the structure that is updated with new data.
+//! \param pui8Address specifies the location of the variable that holds the
+//! the address sent with the UDID (byte 17).
+//! \param pui8Data specifies the location of the source data.
+//!
+//! This function takes a data buffer and decodes it into a tSMBusUDID
+//! structure and an address variable. It is assumed that there are 17 bytes
+//! in the data buffer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusARPUDIDPacketDecode(tSMBusUDID *pUDID, uint8_t *pui8Address,
+ uint8_t *pui8Data)
+{
+ //
+ // Populate the UDID structure with data from the input data buffer.
+ //
+ pUDID->ui8DeviceCapabilities = pui8Data[0];
+ pUDID->ui8Version = pui8Data[1];
+ pUDID->ui16VendorID = (uint16_t)((pui8Data[2] << 8) | pui8Data[3]);
+ pUDID->ui16DeviceID = (uint16_t)((pui8Data[4] << 8) | pui8Data[5]);
+ pUDID->ui16Interface = (uint16_t)((pui8Data[6] << 8) | pui8Data[7]);
+ pUDID->ui16SubSystemVendorID = (uint16_t)((pui8Data[8] << 8) |
+ pui8Data[9]);
+ pUDID->ui16SubSystemDeviceID = (uint16_t)((pui8Data[10] << 8) |
+ pui8Data[11]);
+ pUDID->ui32VendorSpecificID = (uint32_t)((pui8Data[12] << 24) |
+ (pui8Data[13] << 16) |
+ (pui8Data[14] << 8) |
+ pui8Data[15]);
+
+ //
+ // Populate the address.
+ //
+ *pui8Address = pui8Data[16];
+}
+
+//*****************************************************************************
+//
+//! Initiates a master Quick Command transfer to an SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param bData is the value of the single data bit sent to the slave.
+//!
+//! Quick Command is an SMBus protocol that sends a single data bit using the
+//! I2C R/S bit. This function issues a single I2C transfer with the slave
+//! address and data bit.
+//!
+//! This protocol does not support PEC. The PEC flag is explicitly cleared
+//! within this function, so if PEC is enabled prior to calling it, it must
+//! be re-enabled afterwards.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterQuickCommand(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ bool bData)
+{
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->ui8TxSize = 0;
+ psSMBus->ui8RxSize = 0;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8CalculatedCRC = 0;
+
+ //
+ // Clear the block transfer, process call and raw I2C flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+
+ //
+ // This protocol does NOT support PEC, so the flag must be cleared. If
+ // PEC is needed again after this transaction, it should be explicitly
+ // enabled again.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC) = 0;
+
+ //
+ // Initialize the buffer index to 0 and the interrupt state machine to
+ // the appropriate state so that there is a known starting point
+ // for each transaction.
+ //
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, bData);
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase, I2C_MASTER_CMD_QUICK_COMMAND);
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a master Host Notify transfer to the SMBus Host.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8OwnSlaveAddress specifies the peripheral's own slave address.
+//! \param pui8Data is a pointer to the two byte data payload.
+//!
+//! The Host Notify protocol is used by SMBus slaves to alert the bus Host
+//! about an event. Most slave devices that operate in this environment only
+//! become a bus master when this packet type is used. Host Notify always
+//! sends two data bytes to the host along with the peripheral's own slave
+//! address so that the Host knows which peripheral requested the Host's
+//! attention.
+//!
+//! This protocol does not support PEC. The PEC flag is explicitly cleared
+//! within this function, so if PEC is enabled prior to calling it, it must
+//! be re-enabled afterwards.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterHostNotify(tSMBus *psSMBus, uint8_t ui8OwnSlaveAddress,
+ uint8_t *pui8Data)
+{
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = SMBUS_ADR_HOST;
+ psSMBus->pui8TxBuffer = pui8Data;
+ psSMBus->ui8TxSize = 2;
+ psSMBus->ui8RxSize = 0;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8CalculatedCRC = 0;
+
+ //
+ // Clear the block transfer, process call and raw I2C flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+
+ //
+ // This protocol does NOT support PEC, so the flag must be cleared. If
+ // PEC is needed again after this transaction, it should be explicitly
+ // enabled again.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC) = 0;
+
+ //
+ // Initialize the buffer index to 0 and the interrupt state machine to
+ // the appropriate state so that there is a known starting point
+ // for each transaction.
+ //
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_NEXT;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, false);
+
+ //
+ // Put the SMBus command code on the bus.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, ui8OwnSlaveAddress);
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a master Send Byte transfer to an SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param ui8Data is the data byte to send to the slave.
+//!
+//! The Send Byte protocol is a basic SMBus protocol that sends a single data
+//! byte to the slave. Unlike most of the other SMBus protocols, Send Byte
+//! does not send a ``command'' byte before the data payload and is intended
+//! for basic communication.
+//!
+//! This protocol supports the optional PEC byte for error checking. To use
+//! PEC, SMBusPECEnable() must be called before this function.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterByteSend(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t ui8Data)
+{
+ uint8_t ui8TempData;
+
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->ui8CurrentCommand = ui8Data;
+ psSMBus->pui8TxBuffer = &ui8Data;
+ psSMBus->ui8TxSize = 0;
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8RxSize = 0;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8CalculatedCRC = 0;
+
+ //
+ // Clear the block transfer, process call and raw I2C flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, false);
+
+ //
+ // Put the data byte on the bus.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, ui8Data);
+
+ //
+ // Calculate the CRC for PEC (if used).
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Place the target slave address into a temporary data variable and
+ // make sure the R/S bit is set to '0' for the CRC calculation.
+ //
+ ui8TempData = (psSMBus->ui8TargetSlaveAddress << 1) & 0xfe;
+
+ //
+ // Start off by calculating the CRC of the target slave address with
+ // an initial value of 0.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);
+
+ //
+ // Add the data to the running CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->pui8TxBuffer[0],
+ 1);
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+ }
+ else
+ {
+ //
+ // Update the state machine. Since it's the only byte being sent,
+ // the state machine's next state is idle.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase, I2C_MASTER_CMD_SINGLE_SEND);
+ }
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a master Receive Byte transfer to an SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param pui8Data is a pointer to the location to store the received data
+//! byte.
+//!
+//! The Receive Byte protocol is a basic SMBus protocol that receives a single
+//! data byte from the slave. Unlike most of the other SMBus protocols,
+//! Receive Byte does not send a ``command'' byte before the data payload and
+//! is intended for basic communication.
+//!
+//! This protocol supports the optional PEC byte for error checking. To use
+//! PEC, SMBusPECEnable() must be called before this function.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterByteReceive(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t *pui8Data)
+{
+ uint8_t ui8TempData;
+
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->ui8TxSize = 0;
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->pui8RxBuffer = pui8Data;
+ psSMBus->ui8RxSize = 1;
+ psSMBus->ui8CalculatedCRC = 0;
+
+ //
+ // Clear the block transfer, process call and raw I2C flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, true);
+
+ //
+ // Calculate the CRC for PEC (if used).
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Place the target slave address into a temporary data variable and
+ // set the R/S bit to '1' for the CRC calculation.
+ //
+ ui8TempData = ((psSMBus->ui8TargetSlaveAddress << 1) & 0xfe) | 1;
+
+ //
+ // Start off by calculating the CRC of the target slave address with
+ // an initial value of 0.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the read operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_RECEIVE_START);
+ }
+ else
+ {
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_WAIT;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the read operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_SINGLE_RECEIVE);
+ }
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a master Write Byte or Write Word transfer to an SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param ui8Command is the command byte sent before the data payload.
+//! \param pui8Data is a pointer to the transmit data buffer.
+//! \param ui8Size is the number of bytes to send to the slave.
+//!
+//! This function supports both the Write Byte and Write Word protocols. The
+//! amount of data to send is user defined, but limited to 1 or 2 bytes.
+//!
+//! This protocol supports the optional PEC byte for error checking. To use
+//! PEC, SMBusPECEnable() must be called before this function.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use,
+//! \b SMBUS_DATA_SIZE_ERROR if ui8Size is greater than 2, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterByteWordWrite(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t ui8Command, uint8_t *pui8Data,
+ uint8_t ui8Size)
+{
+ uint8_t ui8TempData;
+
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // If more than 2 bytes are requested, indicate error.
+ //
+ if(ui8Size > 2)
+ {
+ return(SMBUS_DATA_SIZE_ERROR);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->ui8CurrentCommand = ui8Command;
+ psSMBus->pui8TxBuffer = pui8Data;
+ psSMBus->ui8TxSize = ui8Size;
+ psSMBus->ui8RxSize = 0;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8CalculatedCRC = 0;
+
+ //
+ // Clear the block transfer, process call and raw I2C flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+
+ //
+ // Initialize the buffer index to 0 and the interrupt state machine to
+ // the appropriate state so that there is a known starting point
+ // for each transaction.
+ //
+ psSMBus->ui8TxIndex = 0;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, false);
+
+ //
+ // Calculate the CRC for PEC (if used).
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Place the target slave address into a temporary data variable and
+ // make sure the R/S bit is set to '0' for the CRC calculation.
+ //
+ ui8TempData = (psSMBus->ui8TargetSlaveAddress << 1) & 0xfe;
+
+ //
+ // Start off by calculating the CRC of the target slave address with
+ // an initial value of 0.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);
+
+ //
+ // Add the command to the running CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->ui8CurrentCommand,
+ 1);
+
+ //
+ // Add the data array to the calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ psSMBus->pui8TxBuffer,
+ psSMBus->ui8TxSize);
+
+ //
+ // Set the next state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_NEXT;
+ }
+ else
+ {
+ //
+ // If only one byte to send, move to the final state.
+ //
+ if(ui8Size == 1)
+ {
+ //
+ // Set the next state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;
+ }
+ else
+ {
+ //
+ // Set the next state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_NEXT;
+ }
+ }
+
+ //
+ // Put the SMBus command code on the bus.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->ui8CurrentCommand);
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a master Read Byte or Read Word transfer to an SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param ui8Command is the command byte sent before the data is requested.
+//! \param pui8Data is a pointer to the receive data buffer.
+//! \param ui8Size is the number of bytes to receive from the slave.
+//!
+//! This function supports both the Read Byte and Read Word protocols. The
+//! amount of data to receive is user defined, but limited to 1 or 2 bytes.
+//!
+//! This protocol supports the optional PEC byte for error checking. To use
+//! PEC, SMBusPECEnable() must be called before this function.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use,
+//! \b SMBUS_DATA_SIZE_ERROR if ui8Size is greater than 2, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterByteWordRead(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t ui8Command, uint8_t *pui8Data,
+ uint8_t ui8Size)
+{
+ uint8_t ui8TempData;
+
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // If more than 2 bytes are requested, indicate error.
+ //
+ if(ui8Size > 2)
+ {
+ return(SMBUS_DATA_SIZE_ERROR);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->ui8CurrentCommand = ui8Command;
+ psSMBus->pui8RxBuffer = pui8Data;
+ psSMBus->ui8TxSize = 0;
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8RxSize = ui8Size;
+ psSMBus->ui8CalculatedCRC = 0;
+
+ //
+ // Clear the block transfer, process call and raw I2C flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, false);
+
+ //
+ // Put the SMBus command code on the bus.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->ui8CurrentCommand);
+
+ //
+ // Calculate the CRC for PEC (if used).
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Place the target slave address into a temporary data variable and
+ // set the R/S bit to '1' for the CRC calculation.
+ //
+ ui8TempData = psSMBus->ui8TargetSlaveAddress << 1;
+
+ //
+ // Start off by calculating the CRC of the target slave address with
+ // an initial value of 0.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);
+
+ //
+ // Add the command to the running CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->ui8CurrentCommand,
+ 1);
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FIRST;
+ }
+ else
+ {
+ //
+ // Update the state machine.
+ //
+ if(psSMBus->ui8RxSize == 2)
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FIRST;
+ }
+ else
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_ONE;
+ }
+ }
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a master Block Write transfer to an SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param ui8Command is the command byte sent before the data is requested.
+//! \param pui8Data is a pointer to the transmit data buffer.
+//! \param ui8Size is the number of bytes to send to the slave.
+//!
+//! This function supports the Block Write protocol. The amount of data sent
+//! to the slave is user defined, but limited to 32 bytes per the SMBus spec.
+//!
+//! This protocol supports the optional PEC byte for error checking. To use
+//! PEC, SMBusPECEnable() must be called before this function.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use,
+//! \b SMBUS_DATA_SIZE_ERROR if ui8Size is greater than 32, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterBlockWrite(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t ui8Command, uint8_t *pui8Data,
+ uint8_t ui8Size)
+{
+ uint8_t ui8TempData;
+
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // If more than 32 bytes are requested, indicate error.
+ //
+ if(ui8Size > 32)
+ {
+ return(SMBUS_DATA_SIZE_ERROR);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->ui8CurrentCommand = ui8Command;
+ psSMBus->pui8TxBuffer = pui8Data;
+ psSMBus->ui8TxSize = ui8Size;
+ psSMBus->ui8RxSize = 0;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8CalculatedCRC = 0;
+
+ //
+ // Set the block transfer flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 1;
+
+ //
+ // Clear the process call and raw I2C flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+
+ //
+ // Initialize the buffer index to 0 and the interrupt state machine to
+ // the appropriate state so that there is a known starting point
+ // for each transaction.
+ //
+ psSMBus->ui8TxIndex = 0;
+
+ //
+ // Calculate the CRC for PEC (if used).
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Place the target slave address into a temporary data variable and
+ // make sure the R/S bit is set to '0' for the CRC calculation.
+ //
+ ui8TempData = (psSMBus->ui8TargetSlaveAddress << 1) & 0xfe;
+
+ //
+ // Start off by calculating the CRC of the target slave address with
+ // an initial value of 0.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);
+
+ //
+ // Add the command to the running CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->ui8CurrentCommand,
+ 1);
+
+ //
+ // Add the size to the running CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->ui8TxSize, 1);
+
+ //
+ // Add the data array to the calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ psSMBus->pui8TxBuffer,
+ psSMBus->ui8TxSize);
+ }
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, false);
+
+ //
+ // Write the first byte of the data.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->ui8CurrentCommand);
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_BLOCK_SIZE;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a master Block Read transfer to an SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param ui8Command is the command byte sent before the data is requested.
+//! \param pui8Data is a pointer to the receive data buffer.
+//!
+//! This function supports the Block Read protocol. The amount of data read
+//! is defined by the slave device, but should never exceed 32 bytes per the
+//! SMBus spec. The receive size is the first data byte returned by the slave,
+//! so this function assumes a size of 3 until the actual number is sent by
+//! the slave. In the application interrupt handler, SMBusRxPacketSizeGet()
+//! can be used to obtain the amount of data sent by the slave.
+//!
+//! This protocol supports the optional PEC byte for error checking. To use
+//! PEC, SMBusPECEnable() must be called before this function.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterBlockRead(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t ui8Command, uint8_t *pui8Data)
+{
+ uint8_t ui8TempData;
+
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->ui8CurrentCommand = ui8Command;
+ psSMBus->pui8RxBuffer = pui8Data;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8TxSize = 0;
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8CalculatedCRC = 0;
+
+ //
+ // Set the block transfer flag..
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 1;
+
+ //
+ // Clear the process call and raw I2C flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, false);
+
+ //
+ // Put the SMBus command code on the bus.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->ui8CurrentCommand);
+
+ //
+ // Initially set the RX size to 3 to make the state machine work.
+ // The slave will respond with the actual size of the transfer in the
+ // first byte and that data will replace this initial value.
+ //
+ psSMBus->ui8RxSize = 3;
+
+ //
+ // Calculate the CRC for PEC (if used).
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Place the target slave address into a temporary data variable and
+ // set the R/S bit to '1' for the CRC calculation.
+ //
+ ui8TempData = psSMBus->ui8TargetSlaveAddress << 1;
+
+ //
+ // Start off by calculating the CRC of the target slave address with
+ // an initial value of 0.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);
+
+ //
+ // Add the command to the running CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->ui8CurrentCommand,
+ 1);
+ }
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FIRST;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a master Process Call transfer to an SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param ui8Command is the command byte sent before the data is requested.
+//! \param pui8TxData is a pointer to the transmit data buffer.
+//! \param pui8RxData is a pointer to the receive data buffer.
+//!
+//! This function supports the Process Call protocol. The amount of data sent
+//! to and received from the slave is fixed to 2 bytes per direction (2 sent,
+//! 2 received).
+//!
+//! This protocol supports the optional PEC byte for error checking. To use
+//! PEC, SMBusPECEnable() must be called before this function.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterProcessCall(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t ui8Command, uint8_t *pui8TxData,
+ uint8_t *pui8RxData)
+{
+ uint8_t ui8TempData;
+
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->ui8CurrentCommand = ui8Command;
+ psSMBus->pui8TxBuffer = pui8TxData;
+ psSMBus->pui8RxBuffer = pui8RxData;
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8TxSize = 2;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8RxSize = 2;
+ psSMBus->ui8CalculatedCRC = 0;
+
+ //
+ // Set the process call flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 1;
+
+ //
+ // Clear the block transfer and raw I2C flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, false);
+
+ //
+ // Calculate the CRC for PEC (if used).
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Place the target slave address into a temporary data variable and
+ // make sure the R/S bit is set to '0' for the CRC calculation.
+ //
+ ui8TempData = (psSMBus->ui8TargetSlaveAddress << 1) & 0xfe;
+
+ //
+ // Start off by calculating the CRC of the target slave address with
+ // an initial value of 0.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);
+
+ //
+ // Add the command to the running CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->ui8CurrentCommand,
+ 1);
+
+ //
+ // Add the data array to the calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ psSMBus->pui8TxBuffer,
+ psSMBus->ui8TxSize);
+ }
+
+ //
+ // Put the SMBus command code on the bus.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->ui8CurrentCommand);
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_NEXT;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a master Block Process Call transfer to an SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param ui8Command is the command byte sent before the data is requested.
+//! \param pui8TxData is a pointer to the transmit data buffer.
+//! \param ui8TxSize is the number of bytes to send to the slave.
+//! \param pui8RxData is a pointer to the receive data buffer.
+//!
+//! This function supports the Block Write/Block Read Process Call protocol.
+//! The amount of data sent to the slave is user defined but limited to 32 data
+//! bytes. The amount of data read is defined by the slave device, but should
+//! never exceed 32 bytes per the SMBus spec. The receive size is the first
+//! data byte returned by the slave, so the actual size is populated in
+//! SMBusMasterISRProcess(). In the application interrupt handler,
+//! SMBusRxPacketSizeGet() can be used to obtain the amount of data sent by
+//! the slave.
+//!
+//! This protocol supports the optional PEC byte for error checking. To use
+//! PEC, SMBusPECEnable() must be called before this function.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use,
+//! \b SMBUS_DATA_SIZE_ERROR if ui8TxSize is greater than 32, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterBlockProcessCall(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t ui8Command, uint8_t *pui8TxData,
+ uint8_t ui8TxSize, uint8_t *pui8RxData)
+{
+ uint8_t ui8TempData;
+
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // If more than 32 bytes are requested, indicate error.
+ //
+ if(ui8TxSize > 32)
+ {
+ return(SMBUS_DATA_SIZE_ERROR);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->ui8CurrentCommand = ui8Command;
+ psSMBus->pui8TxBuffer = pui8TxData;
+ psSMBus->pui8RxBuffer = pui8RxData;
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8TxSize = ui8TxSize;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8RxSize = 3;
+ psSMBus->ui8CalculatedCRC = 0;
+
+ //
+ // Set the process call and block transfer flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 1;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 1;
+
+ //
+ // Clear the raw I2C flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+
+ //
+ // Calculate the CRC for PEC (if used).
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Place the target slave address into a temporary data variable and
+ // make sure the R/S bit is set to '0' for the CRC calculation.
+ //
+ ui8TempData = (psSMBus->ui8TargetSlaveAddress << 1) & 0xfe;
+
+ //
+ // Start off by calculating the CRC of the target slave address with
+ // an initial value of 0.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(0, &ui8TempData, 1);
+
+ //
+ // Add the command to the running CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->ui8CurrentCommand,
+ 1);
+
+ //
+ // Add the size to the running CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->ui8TxSize, 1);
+
+ //
+ // Add the data array to the calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ psSMBus->pui8TxBuffer,
+ psSMBus->ui8TxSize);
+ }
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, false);
+
+ //
+ // Put the SMBus command code on the bus.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->ui8CurrentCommand);
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_BLOCK_SIZE;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a ``raw'' I2C write transfer to a slave device.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param pui8Data is a pointer to the transmit data buffer.
+//! \param ui8Size is the number of bytes to send to the slave.
+//!
+//! This function sends a user-defined number of bytes to an I2C slave without
+//! using an SMBus protocol. The data size is only limited to the size of the
+//! ui8Size variable, which is an unsigned character (8 bits, value of 255).
+//!
+//! Because this function uses ``raw'' I2C, PEC is not supported.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterI2CWrite(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t *pui8Data, uint8_t ui8Size)
+{
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->pui8TxBuffer = pui8Data;
+ psSMBus->ui8TxSize = ui8Size;
+ psSMBus->ui8TxIndex = 1;
+ psSMBus->ui8RxSize = 0;
+ psSMBus->ui8RxIndex = 0;
+
+ //
+ // PEC is not supported by raw I2C transfers, so force it to be disabled.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC) = 0;
+
+ //
+ // Clear the block transfer and process call flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+
+ //
+ // Set the raw I2C flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 1;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, false);
+
+ //
+ // Put the first byte on the bus.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->pui8TxBuffer[0]);
+
+ //
+ // Choose what to do based on the transmit size.
+ //
+ if(ui8Size == 1)
+ {
+ //
+ // Update the state machine. Since it's the only byte being sent,
+ // the state machine's next state is idle.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase, I2C_MASTER_CMD_SINGLE_SEND);
+ }
+ else if(ui8Size == 2)
+ {
+ //
+ // If there are only 2 bytes to send just jump to the final write
+ // state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+ }
+ else
+ {
+ //
+ // Set the next state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_NEXT;
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+ }
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a ``raw'' I2C read transfer to a slave device.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param pui8Data is a pointer to the receive data buffer.
+//! \param ui8Size is the number of bytes to send to the slave.
+//!
+//! This function receives a user-defined number of bytes from an I2C slave
+//! without using an SMBus protocol. The data size is only limited to the size
+//! of the ui8Size variable, which is an unsigned character (8 bits, value of
+//! 255).
+//!
+//! Because this function uses ``raw'' I2C, PEC is not supported.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterI2CRead(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t *pui8Data, uint8_t ui8Size)
+{
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->pui8RxBuffer = pui8Data;
+ psSMBus->ui8TxSize = 0;
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8RxSize = ui8Size;
+
+ //
+ // PEC is not supported by raw I2C transfers, so force it to be disabled.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC) = 0;
+
+ //
+ // Clear the block transfer and process call flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+
+ //
+ // Set the raw I2C flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 1;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, true);
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Choose what to do based on the receive size.
+ //
+ if(ui8Size == 1)
+ {
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_WAIT;
+ }
+ else if(ui8Size == 2)
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;
+ }
+ else
+ {
+ //
+ // Set the next state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_NEXT;
+ }
+
+ if(ui8Size == 1)
+ {
+ //
+ // Start the single receive.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_SINGLE_RECEIVE);
+ }
+ else
+ {
+ //
+ // Start the burst receive.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_RECEIVE_START);
+ }
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Initiates a ``raw'' I2C write-read transfer to a slave device.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param pui8TxData is a pointer to the transmit data buffer.
+//! \param ui8TxSize is the number of bytes to send to the slave.
+//! \param pui8RxData is a pointer to the receive data buffer.
+//! \param ui8RxSize is the number of bytes to receive from the slave.
+//!
+//! This function initiates a write-read transfer to an I2C slave without using
+//! an SMBus protocol. The user-defined number of bytes is written to the
+//! slave first, followed by the reception of the user-defined number of bytes.
+//! The transmit and receive data sizes are only limited to the size of the
+//! ui8TxSize and ui8RxSize variables, which are unsigned characters (8 bits,
+//! value of 255).
+//!
+//! Because this function uses ``raw'' I2C, PEC is not supported.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterI2CWriteRead(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t *pui8TxData, uint8_t ui8TxSize,
+ uint8_t *pui8RxData, uint8_t ui8RxSize)
+{
+ //
+ // Make sure that the peripheral is not currently active.
+ //
+ if(MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_PERIPHERAL_BUSY);
+ }
+
+ //
+ // Update the configuration structure with the data for this transfer.
+ //
+ psSMBus->ui8TargetSlaveAddress = ui8TargetAddress;
+ psSMBus->pui8TxBuffer = pui8TxData;
+ psSMBus->pui8RxBuffer = pui8RxData;
+ psSMBus->ui8TxIndex = 1;
+ psSMBus->ui8TxSize = ui8TxSize;
+ psSMBus->ui8RxIndex = 0;
+ psSMBus->ui8RxSize = ui8RxSize;
+
+ //
+ // PEC is not supported by raw I2C transfers, so force it to be disabled.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC) = 0;
+
+ //
+ // Set the process call flag. Even though this is technically not an SMBus
+ // process call, this flag is used in the interrupt state machine for
+ // the bus turn around.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 1;
+
+ //
+ // Clear the block transfer flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+
+ //
+ // Set the raw I2C flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 1;
+
+ //
+ // Set the slave address and R/S bit.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, false);
+
+ //
+ // Write the first byte of the data.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->pui8TxBuffer[0]);
+
+ //
+ // Choose what to do based on the transmit size.
+ //
+ if(ui8TxSize == 1)
+ {
+ //
+ // Move to the read first state for the turn around.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FIRST;
+ }
+ else if(ui8TxSize == 2)
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;
+ }
+ else
+ {
+ //
+ // Set the next state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_NEXT;
+ }
+
+ //
+ // Make sure that the bus is idle.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ return(SMBUS_BUS_BUSY);
+ }
+
+ //
+ // Initiate the write operation.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_START);
+
+ //
+ // Set the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Return to the caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! \internal
+//! Sends a ``general'' Get UDID packet.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param pui8Data is a pointer to the receive data buffer.
+//!
+//! This function sends a ``general'' Get UDID packet, used during Address
+//! Resolution Protocol (ARP). Since SMBus requires that data bytes be
+//! transmitted in a certain order, the raw data in the pui8Data needs to be
+//! treated as such. To put the data in a known order, use
+//! SMBusARPUDIDPacketDecode().
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterARPGetUDIDGen(tSMBus *psSMBus, uint8_t *pui8Data)
+{
+ //
+ // Use the block read protocol to receive the UDID.
+ //
+ return(SMBusMasterBlockRead(psSMBus, SMBUS_ADR_DEFAULT_DEVICE,
+ SMBUS_CMD_ARP_GET_UDID, pui8Data));
+}
+
+//*****************************************************************************
+//
+//! \internal
+//! Sends a ``directed'' Get UDID packet.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8TargetAddress specifies the slave address of the target device.
+//! \param pui8Data is a pointer to the receive data buffer.
+//!
+//! This function sends a ``directed'' Get UDID packet, used during Address
+//! Resolution Protocol (ARP). A directed packet differs from a general packet
+//! in that it targets a specific slave device. Since SMBus requires that data
+//! bytes be transmitted in a certain order, the raw data in the pui8Data needs
+//! to be treated as such. To put the data in a known order, use
+//! SMBusARPUDIDPacketDecode().
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterARPGetUDIDDir(tSMBus *psSMBus, uint8_t ui8TargetAddress,
+ uint8_t *pui8Data)
+{
+ //
+ // Use the block read protocol to receive the UDID.
+ //
+ return(SMBusMasterBlockRead(psSMBus, SMBUS_ADR_DEFAULT_DEVICE,
+ (ui8TargetAddress << 1 | 1), pui8Data));
+}
+
+//*****************************************************************************
+//
+//! \internal
+//! Sends a ``general'' Reset Device packet.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function sends a ``general'' Reset Device packet, used during Address
+//! Resolution Protocol (ARP). This packet is used by an ARP Master to force
+//! all non-PSA (Persistent Slave Address), ARP-capable devices to return to
+//! their initial state. This packet also tells the devices to clear their
+//! Address Resolved (AR) and Address Valid (AV) flags.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterARPResetDeviceGen(tSMBus *psSMBus)
+{
+ //
+ // Use the Send Byte protocol to send the packet.
+ //
+ return(SMBusMasterByteSend(psSMBus, SMBUS_ADR_DEFAULT_DEVICE,
+ SMBUS_CMD_ARP_RESET_DEVICE));
+}
+
+//*****************************************************************************
+//
+//! \internal
+//! Sends a ``directed'' Reset Device packet.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function sends a ``directed'' Reset Device packet, used during Address
+//! Resolution Protocol (ARP). This packet is used by an ARP Master to force
+//! a specific non-PSA (Persistent Slave Address), ARP-capable device to return
+//! to its initial state. This packet also tells the device to clear its
+//! Address Resolved (AR) and Address Valid (AV) flags.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterARPResetDeviceDir(tSMBus *psSMBus, uint8_t ui8TargetAddress)
+{
+ //
+ // Use the Send Byte protocol to send the packet.
+ //
+ return(SMBusMasterByteSend(psSMBus, SMBUS_ADR_DEFAULT_DEVICE,
+ (ui8TargetAddress << 1)));
+}
+
+//*****************************************************************************
+//
+//! Sends an ARP Assign Address packet.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param pui8Data is a pointer to the transmit data buffer. This buffer
+//! should be correctly formatted using SMBusARPUDIDPacketEncode() and
+//! should contain the UDID data and the address for the slave.
+//!
+//! This function sends an Assign Address packet, used during Address
+//! Resolution Protocol (ARP). Because SMBus requires data bytes be sent out
+//! MSB first, the UDID and target address should be formatted correctly by the
+//! application or using SMBusARPUDIDPacketEncode() and placed into a data
+//! buffer pointed to by pui8Data.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterARPAssignAddress(tSMBus *psSMBus, uint8_t *pui8Data)
+{
+ //
+ // Use the Block Write protocol to send the packet.
+ //
+ return(SMBusMasterBlockWrite(psSMBus, SMBUS_ADR_DEFAULT_DEVICE,
+ SMBUS_CMD_ARP_ASSIGN_ADDRESS, pui8Data, 17));
+}
+
+//*****************************************************************************
+//
+//! Sends a Notify ARP Master packet.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param pui8Data is a pointer to the transmit data buffer. The data payload
+//! should be 0x0000 for this packet.
+//!
+//! This function sends a Notify ARP Master packet, used during Address
+//! Resolution Protocol (ARP). This packet is used by a slave to indicate
+//! to the ARP Master that it needs attention.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterARPNotifyMaster(tSMBus *psSMBus, uint8_t *pui8Data)
+{
+ //
+ // Use the Host Notify protocol to send the packet.
+ //
+ return(SMBusMasterHostNotify(psSMBus, (SMBUS_ADR_DEFAULT_DEVICE << 1),
+ pui8Data));
+}
+
+//*****************************************************************************
+//
+//! Sends a Prepare to ARP packet.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function sends a Prepare to ARP packet, used during Address Resolution
+//! Protocol (ARP). This packet is used by an ARP Master to alert devices on
+//! the bus that ARP is about to begin. All ARP-capable devices must
+//! acknowledge all bytes in this packet and clear their Address Resolved (AR)
+//! flag.
+//!
+//! \return Returns \b SMBUS_PERIPHERAL_BUSY if the I2C peripheral is currently
+//! active, \b SMBUS_BUS_BUSY if the bus is already in use, or \b SMBUS_OK if
+//! the transfer has successfully been initiated.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterARPPrepareToARP(tSMBus *psSMBus)
+{
+ //
+ // Use the Send Byte protocol to send the packet.
+ //
+ return(SMBusMasterByteSend(psSMBus, SMBUS_ADR_DEFAULT_DEVICE,
+ SMBUS_CMD_PREPARE_TO_ARP));
+}
+
+//*****************************************************************************
+//
+//! Master ISR processing function for the SMBus application.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function must be called in the application interrupt service routine
+//! (ISR) to process SMBus master interrupts.
+//!
+//! \return Returns \b SMBUS_TIMEOUT if a bus timeout is detected,
+//! \b SMBUS_ARB_LOST if I2C bus arbitration lost is detected,
+//! \b SMBUS_ADDR_ACK_ERROR if the address phase of a transfer results in a
+//! NACK, \b SMBUS_DATA_ACK_ERROR if the data phase of a transfer results in a
+//! NACK, \b SMBUS_DATA_SIZE_ERROR if a receive buffer overrun is detected or
+//! if a transmit operation tries to write more data than is allowed,
+//! \b SMBUS_MASTER_ERROR if an unknown error occurs, \b SMBUS_PEC_ERROR if the
+//! received PEC byte does not match the locally calculated value, or
+//! \b SMBUS_OK if processing finished successfully.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusMasterIntProcess(tSMBus *psSMBus)
+{
+ uint32_t ui32IntStatus;
+ uint32_t ui32ErrorStatus;
+ uint8_t ui8TempData;
+
+ //
+ // Determine which interrupt made us get here.
+ //
+ ui32IntStatus = MAP_I2CMasterIntStatusEx(psSMBus->ui32I2CBase, true);
+
+ //
+ // Check for the timeout interrupt. Since the peripheral will
+ // automatically issue a stop, just clear the interrupt and return.
+ //
+ if(ui32IntStatus & I2C_MASTER_INT_TIMEOUT)
+ {
+ //
+ // Clear all pending interrupts and wait for the bus to become
+ // free so we can issue a STOP.
+ //
+ MAP_I2CMasterIntClearEx(psSMBus->ui32I2CBase, I2C_MASTER_INT_TIMEOUT |
+ I2C_MASTER_INT_DATA);
+
+ //
+ // Clear the transfer in progress flag. New transactions will
+ // be aborted until the bus is free.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;
+
+ //
+ // Return to caller.
+ //
+ return(SMBUS_TIMEOUT);
+ }
+ else
+ {
+ //
+ // Clear the data interrupt.
+ //
+ MAP_I2CMasterIntClearEx(psSMBus->ui32I2CBase, I2C_MASTER_INT_DATA);
+ }
+
+ //
+ // Read the master interrupt status bits.
+ //
+ ui32ErrorStatus = HWREG(psSMBus->ui32I2CBase + I2C_O_MCS);
+
+ //
+ // Check for arbitration lost.
+ //
+ if(ui32ErrorStatus & I2C_MCS_ARBLST)
+ {
+ //
+ // Put the state machine back in the idle state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+
+ //
+ // Clear the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;
+
+ //
+ // Return to caller.
+ //
+ return(SMBUS_ARB_LOST);
+ }
+
+ //
+ // Check for an error.
+ //
+ if(ui32ErrorStatus & I2C_MCS_ERROR)
+ {
+ //
+ // Put the state machine back in the idle state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+
+ //
+ // Check to see if the bus is free. There are two interrupts when a
+ // NACK happens, and the bus should only be free during the second
+ // interrupt. During the first interrupt (when the bus is busy),
+ // generate the necessary STOP condition.
+ //
+ if(MAP_I2CMasterBusBusy(psSMBus->ui32I2CBase))
+ {
+ //
+ // Issue a STOP.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_ERROR_STOP);
+ }
+ else
+ {
+ //
+ // Clear the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;
+ }
+
+ //
+ // Check for ACK errors.
+ //
+ if(ui32ErrorStatus & I2C_MCS_ADRACK)
+ {
+ //
+ // Return to caller.
+ //
+ return(SMBUS_ADDR_ACK_ERROR);
+ }
+ else if(ui32ErrorStatus & I2C_MCS_DATACK)
+ {
+ //
+ // Return to caller.
+ //
+ return(SMBUS_DATA_ACK_ERROR);
+ }
+ else
+ {
+ //
+ // Return to caller. Should never get here.
+ //
+ return(SMBUS_MASTER_ERROR);
+ }
+ }
+
+ //
+ // If no error conditions, determine what to do based on the state.
+ //
+ switch(psSMBus->ui8MasterState)
+ {
+ //
+ // The idle state. This state should only be reached after the last
+ // byte of a master transmit.
+ //
+ case SMBUS_STATE_IDLE:
+ {
+ //
+ // If the peripheral is not busy clear the transfer in progress
+ // flag. This means that the peripheral has given up the bus,
+ // most likely due to the end of a transmit operation.
+ //
+ if(!MAP_I2CMasterBusy(psSMBus->ui32I2CBase))
+ {
+ //
+ // Clear the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;
+ }
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // When using a block write, the transfer size must be sent before the
+ // data payload.
+ //
+ case SMBUS_STATE_WRITE_BLOCK_SIZE:
+ {
+ //
+ // Write the block write size to the data register.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase, psSMBus->ui8TxSize);
+
+ //
+ // Continue the burst write.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_CONT);
+
+ //
+ // The next data byte is from the data payload.
+ //
+ if((psSMBus->ui8TxSize == 1) &&
+ !(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC)))
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;
+ }
+ else
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_NEXT;
+ }
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+ //
+ // The state for the middle of a burst write.
+ //
+ case SMBUS_STATE_WRITE_NEXT:
+ {
+ //
+ // Write the next byte to the data register.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase,
+ psSMBus->pui8TxBuffer[psSMBus->ui8TxIndex++]);
+
+ //
+ // Continue the burst write.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_CONT);
+
+ //
+ // Determine the next state based on the values of the PEC and
+ // process call flags.
+ //
+
+ //
+ // If PEC is active and process call is not active.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // If a process call, there is no PEC byte on the transmit.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL))
+ {
+ //
+ // Check to see if the TX index is equal to size minus 1.
+ //
+ if(psSMBus->ui8TxIndex == (psSMBus->ui8TxSize - 1))
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;
+ }
+ }
+ else
+ {
+ //
+ // If the TX index is the same as the size, we're done.
+ //
+ if(psSMBus->ui8TxIndex == psSMBus->ui8TxSize)
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;
+ }
+ }
+ }
+
+ //
+ // If PEC is not used, regardless of whether this is a process
+ // call.
+ //
+ else
+ {
+ //
+ // Check to see if the TX index is equal to the size minus 1.
+ //
+ if(psSMBus->ui8TxIndex == (psSMBus->ui8TxSize - 1))
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_WRITE_FINAL;
+ }
+ }
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // The state for the final write of a burst sequence.
+ //
+ case SMBUS_STATE_WRITE_FINAL:
+ {
+ //
+ // Determine what data to write to the data register based
+ // on the values of the PEC and process call flags.
+ //
+ //
+ // If PEC is active, write the PEC byte to the data register.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // If a process call is active, send data, not CRC.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL))
+ {
+ //
+ // Write the final byte from TX buffer to the data
+ // register.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase,
+ psSMBus->pui8TxBuffer[psSMBus->
+ ui8TxIndex++]);
+ }
+ else
+ {
+ //
+ // Write the calculated CRC (PEC) byte to the data
+ // register.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase,
+ psSMBus->ui8CalculatedCRC);
+ }
+ }
+ else
+ {
+ //
+ // Write the final byte from TX buffer to the data register.
+ //
+ MAP_I2CMasterDataPut(psSMBus->ui32I2CBase,
+ psSMBus->pui8TxBuffer[psSMBus->
+ ui8TxIndex++]);
+ }
+
+ //
+ // If a process call is active, send out the repeated start to
+ // begin the RX portion.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL))
+ {
+ //
+ // Move to the read first "turnaround" state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FIRST;
+
+ //
+ // Continue the burst write.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_CONT);
+ }
+ else
+ {
+ //
+ // Finish the burst write.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_FINISH);
+
+ //
+ // Since we end the transaction after the last byte is sent,
+ // the next state is idle.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+ }
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // The state for a single byte read.
+ //
+ case SMBUS_STATE_READ_ONE:
+ {
+ //
+ // Put the I2C master into receive mode.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, true);
+
+ //
+ // Perform a single byte read.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_SINGLE_RECEIVE);
+
+ //
+ // The next state is the wait for final read state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_WAIT;
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // The state for the start of a burst read.
+ //
+ case SMBUS_STATE_READ_FIRST:
+ {
+ //
+ // Put the I2C master into receive mode.
+ //
+ MAP_I2CMasterSlaveAddrSet(psSMBus->ui32I2CBase,
+ psSMBus->ui8TargetSlaveAddress, true);
+
+ //
+ // Handle the case where PEC is used.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Add the target address and R/S bit to the running CRC
+ // calculation.
+ //
+ ui8TempData =
+ ((psSMBus->ui8TargetSlaveAddress << 1) & 0xfe) | 1;
+
+ //
+ // Update the calculated CRC value in the configuration
+ // structure.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC, &ui8TempData, 1);
+
+ //
+ // Set the next state in the state machine.
+ //
+ if(psSMBus->ui8RxSize > 1)
+ {
+ //
+ // If this is a block transfer, the next state is to read
+ // back the number of bytes that the slave will be sending.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER))
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_BLOCK_SIZE;
+ }
+
+ //
+ // For every other case...
+ //
+ else
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_NEXT;
+ }
+ }
+
+ //
+ // If 1 byte remains, move to the final read state.
+ //
+ else
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;
+ }
+ }
+ else
+ {
+ //
+ // Set the next state in the state machine.
+ //
+ if(psSMBus->ui8RxSize > 2)
+ {
+ //
+ // If this is a block transfer, the next state is to read
+ // back the number of bytes that the slave will be sending.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER))
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_BLOCK_SIZE;
+ }
+
+ //
+ // For every other case...
+ //
+ else
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_NEXT;
+ }
+ }
+
+ //
+ // If 2 bytes remain, move to the final read state.
+ //
+ else
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;
+ }
+ }
+
+ //
+ // Start the burst receive.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_RECEIVE_START);
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // The state for the size of a block read.
+ //
+ case SMBUS_STATE_READ_BLOCK_SIZE:
+ {
+ //
+ // Update the RX size with the data byte.
+ //
+ psSMBus->ui8RxSize = MAP_I2CMasterDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // If more than 32 bytes are going to be sent, error.
+ //
+ if((psSMBus->ui8RxSize > 32) || (psSMBus->ui8RxSize == 0))
+ {
+ //
+ // Set the next state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_ERROR_STOP;
+
+ //
+ // If too many or too few bytes, error.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_SINGLE_RECEIVE);
+
+ //
+ // Break from this case.
+ //
+ break;
+ }
+
+ //
+ // If PEC is enabled, add the size byte to the calculation and
+ // add one to the size variable to account for the extra PEC byte.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Calculate the new CRC and update configuration structure.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->ui8RxSize, 1);
+ }
+
+ //
+ // Update the state machine.
+ //
+ switch(psSMBus->ui8RxSize)
+ {
+ //
+ // 1 byte remaining.
+ //
+ case 1:
+ {
+ //
+ // If only one byte remains and PEC, go to the second
+ // to last byte state.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;
+ }
+
+ //
+ // If only one byte remains and no PEC, end the burst
+ // transfer.
+ //
+ else
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_WAIT;
+ }
+
+ //
+ // This switch is done.
+ //
+ break;
+ }
+
+ //
+ // 2 bytes remaining.
+ //
+ case 2:
+ {
+ //
+ // If two bytes and PEC remain, move to read next
+ // state.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_NEXT;
+ }
+
+ //
+ // If two bytes remain, move to the final read state.
+ //
+ else
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;
+ }
+
+ //
+ // This switch is done.
+ //
+ break;
+ }
+
+ //
+ // For every other situation (in other words, remaining bytes
+ // is greater than 2).
+ //
+ default:
+ {
+ //
+ // If more than 2 bytes to read, move to the next byte
+ // state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_NEXT;
+
+ //
+ // This switch is done.
+ //
+ break;
+ }
+ }
+
+ //
+ // Determine how to step the I2C state machine.
+ //
+ if((psSMBus->ui8RxSize == 1) &&
+ !HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // If exactly 1 byte remains, read the byte and send a STOP.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_SEND_FINISH);
+ }
+ else
+ {
+ //
+ // Otherwise, continue the burst read.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_RECEIVE_CONT);
+ }
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // The state for the middle of a burst read.
+ //
+ case SMBUS_STATE_READ_NEXT:
+ {
+ //
+ // Check for a buffer overrun.
+ //
+ if(psSMBus->ui8RxIndex >= psSMBus->ui8RxSize)
+ {
+ //
+ // Dummy read of data register.
+ //
+ ui8TempData = MAP_I2CMasterDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // If too many or too few bytes, error.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
+
+ //
+ // Set the next state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_ERROR_STOP;
+
+ //
+ // Break from this case.
+ //
+ break;
+ }
+
+ //
+ // Read the received character.
+ //
+ psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex] =
+ MAP_I2CMasterDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // Continue the burst read.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_RECEIVE_CONT);
+
+ //
+ // If PEC is enabled, add the received byte to the calculation.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Calculate the new CRC and update configuration structure.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex],
+ 1);
+
+ //
+ // Increment the receive buffer index.
+ //
+ psSMBus->ui8RxIndex++;
+
+ //
+ // If there is 1 byte remaining, make next state be the
+ // end of burst read state.
+ //
+ if((psSMBus->ui8RxSize - psSMBus->ui8RxIndex) == 1)
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;
+ }
+ }
+ else
+ {
+ //
+ // Increment the receive buffer index.
+ //
+ psSMBus->ui8RxIndex++;
+
+ //
+ // If there are two bytes remaining, make next state be the
+ // end of burst read state.
+ //
+ if((psSMBus->ui8RxSize - psSMBus->ui8RxIndex) == 2)
+ {
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_FINAL;
+ }
+ }
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // The state for the end of a burst read.
+ //
+ case SMBUS_STATE_READ_FINAL:
+ {
+ //
+ // Check for a buffer overrun.
+ //
+ if(psSMBus->ui8RxIndex >= psSMBus->ui8RxSize)
+ {
+ //
+ // Dummy read of data register.
+ //
+ ui8TempData = MAP_I2CMasterDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // If too many or too few bytes, error.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
+
+ //
+ // Set the next state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_ERROR_STOP;
+
+ //
+ // Break from this case.
+ //
+ break;
+ }
+
+ //
+ // Read the received character.
+ //
+ psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex] =
+ MAP_I2CMasterDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // The next state is the wait for final read state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_READ_WAIT;
+
+ //
+ // Finish the burst read.
+ //
+ MAP_I2CMasterControl(psSMBus->ui32I2CBase,
+ I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
+
+ //
+ // If PEC is enabled, add the received byte to the calculation.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Calculate the new CRC and update configuration structure.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex],
+ 1);
+ }
+
+ //
+ // Increment the receive buffer index.
+ //
+ psSMBus->ui8RxIndex++;
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // This state is for the final read of a single or burst read.
+ //
+ case SMBUS_STATE_READ_WAIT:
+ {
+ //
+ // Read the received byte.
+ //
+ ui8TempData = MAP_I2CMasterDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // If PEC is enabled, check the value that just came in to see
+ // if it matches.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Check for a buffer overrun.
+ //
+ if(psSMBus->ui8RxIndex > psSMBus->ui8RxSize)
+ {
+ //
+ // Clear the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags,
+ FLAG_TRANSFER_IN_PROGRESS) = 0;
+
+ //
+ // Return the error condition.
+ //
+ return(SMBUS_DATA_SIZE_ERROR);
+ }
+
+ //
+ // Store the received CRC byte.
+ //
+ psSMBus->ui8ReceivedCRC = ui8TempData;
+
+ //
+ // If the CRC doesn't match, send a NACK and indicate the
+ // failure to the application.
+ //
+ if(psSMBus->ui8ReceivedCRC != psSMBus->ui8CalculatedCRC)
+ {
+ //
+ // Clear the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags,
+ FLAG_TRANSFER_IN_PROGRESS) = 0;
+
+ //
+ // Return the error condition.
+ //
+ return(SMBUS_PEC_ERROR);
+ }
+ }
+ else
+ {
+ //
+ // Check for a buffer overrun.
+ //
+ if(psSMBus->ui8RxIndex >= psSMBus->ui8RxSize)
+ {
+ //
+ // Clear the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags,
+ FLAG_TRANSFER_IN_PROGRESS) = 0;
+
+ //
+ // Return the error condition.
+ //
+ return(SMBUS_DATA_SIZE_ERROR);
+ }
+
+ //
+ // Read the received byte.
+ //
+ psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex] = ui8TempData;
+
+ //
+ // Increment the receive buffer index.
+ //
+ psSMBus->ui8RxIndex++;
+ }
+
+ //
+ // The state machine is now idle.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+
+ //
+ // Clear the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // This state is for a transaction that needed to end due to a
+ // size error.
+ //
+ case SMBUS_STATE_READ_ERROR_STOP:
+ {
+ //
+ // Dummy read the received byte.
+ //
+ ui8TempData = MAP_I2CMasterDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // The state machine is now idle.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+
+ //
+ // Clear the transfer in progress flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;
+
+ //
+ // Return the error condition.
+ //
+ return(SMBUS_DATA_SIZE_ERROR);
+ }
+ }
+
+ //
+ // Return to caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Enables the appropriate master interrupts for stack processing.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function enables the I2C interrupts used by the SMBus master. Both
+//! the peripheral-level and NVIC-level interrupts are enabled.
+//! SMBusMasterInit() must be called before this function because this function
+//! relies on the I2C base address being defined.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusMasterIntEnable(tSMBus *psSMBus)
+{
+ //
+ // Enable the master interrupts.
+ //
+ MAP_I2CMasterIntEnableEx(psSMBus->ui32I2CBase, I2C_MASTER_INT_DATA |
+ I2C_MASTER_INT_TIMEOUT);
+
+ //
+ // Enable the interrupt in the NVIC.
+ //
+ switch(psSMBus->ui32I2CBase)
+ {
+ case I2C0_BASE:
+ {
+ MAP_IntEnable(INT_I2C0);
+ break;
+ }
+
+ case I2C1_BASE:
+ {
+ MAP_IntEnable(INT_I2C1);
+ break;
+ }
+
+ case I2C2_BASE:
+ {
+ if(CLASS_IS_TM4C123)
+ {
+ MAP_IntEnable(INT_I2C2_TM4C123);
+ }
+ else if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C2_TM4C129);
+ }
+ break;
+ }
+
+ case I2C3_BASE:
+ {
+ if(CLASS_IS_TM4C123)
+ {
+ MAP_IntEnable(INT_I2C3_TM4C123);
+ }
+ else if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C3_TM4C129);
+ }
+ break;
+ }
+
+ case I2C4_BASE:
+ {
+ if(CLASS_IS_TM4C123)
+ {
+ MAP_IntEnable(INT_I2C4_TM4C123);
+ }
+ else if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C4_TM4C129);
+ }
+ break;
+ }
+
+ case I2C5_BASE:
+ {
+ if(CLASS_IS_TM4C123)
+ {
+ MAP_IntEnable(INT_I2C5_TM4C123);
+ }
+ else if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C5_TM4C129);
+ }
+ break;
+ }
+
+ case I2C6_BASE:
+ {
+ if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C6_TM4C129);
+ }
+ break;
+ }
+
+ case I2C7_BASE:
+ {
+ if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C7_TM4C129);
+ }
+ break;
+ }
+
+ case I2C8_BASE:
+ {
+ if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C8_TM4C129);
+ }
+ break;
+ }
+
+ case I2C9_BASE:
+ {
+ if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C9_TM4C129);
+ }
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes an I2C master peripheral for SMBus functionality.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui32I2CBase specifies the base address of the I2C master peripheral.
+//! \param ui32SMBusClock specifies the system clock speed of the MCU.
+//!
+//! This function initializes an I2C peripheral for SMBus master use. The
+//! instance-specific configuration structure is initialized to a set of known
+//! values and the I2C peripheral is configured for 100kHz use, which is
+//! required by the SMBus specification.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusMasterInit(tSMBus *psSMBus, uint32_t ui32I2CBase,
+ uint32_t ui32SMBusClock)
+{
+ //
+ // Initialize the configuration structure.
+ //
+ psSMBus->pUDID = 0;
+ psSMBus->ui32I2CBase = ui32I2CBase;
+ psSMBus->ui16Flags = 0;
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+ psSMBus->ui8OwnSlaveAddress = 0;
+ psSMBus->ui8TargetSlaveAddress = 0;
+ psSMBus->ui8CurrentCommand = 0;
+ psSMBus->ui8CalculatedCRC = 0;
+ psSMBus->ui8TxSize = 0;
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8RxSize = 0;
+ psSMBus->ui8RxIndex = 0;
+
+ //
+ // Enable and initialize the I2C master module Using the system clock.
+ // The I2C transfer rate will always be 100kHz since fast mode is not
+ // supported by SMBus.
+ //
+ MAP_I2CMasterInitExpClk(psSMBus->ui32I2CBase, ui32SMBusClock, false);
+
+ //
+ // Configure bus timeout to 25ms. 12-bit value for 25ms is 0x9C4 (2500
+ // clocks), so round upper 8 bits to 0x9C. Each clock is 10us since
+ // 100kHz I2C is required for SMBus.
+ //
+ MAP_I2CMasterTimeoutSet(psSMBus->ui32I2CBase, 0x9C);
+}
+
+//*****************************************************************************
+//
+//! Slave ISR processing function for the SMBus application.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function must be called in the application interrupt service routine
+//! (ISR) to process SMBus slave interrupts.
+//!
+//! If manual acknowledge is enabled using SMBusSlaveManualACKEnable(), this
+//! function processes the data byte, but does not send the ACK/NACK value. In
+//! this case, the user application is responsible for sending the acknowledge
+//! bit based on the return code of this function.
+//!
+//! When receiving a Quick Command from the master, the slave has some set-up
+//! requirements. When the master sends the R/S (data) bit as '0', nothing
+//! additional needs to be done in the slave and SMBusSlaveIntProcess() returns
+//! \b SMBUS_SLAVE_QCMD_0. However, when the master sends the R/S (data) bit
+//! as '1', the slave must write the data register with data containing a '1'
+//! in bit 7. This means that when receiving a Quick Command, the slave must
+//! set up the TX buffer to either have 1 data byte with bit 7 set to '1' or
+//! set up the TX buffer to be zero length. In the case where 1 data byte is
+//! put in the TX buffer, SMBusSlaveIntProcess() returns \b SMBUS_OK the first
+//! time its called and \b SMBUS_SLAVE_QCMD_0 the second. In the case where
+//! the TX buffer has no data, SMBusSlaveIntProcess() will return
+//! \b SMBUS_SLAVE_ERROR the first time its called, and \b SMBUS_SLAVE_QCMD_1
+//! the second time.
+//!
+//! \return Returns \b SMBUS_SLAVE_FIRST_BYTE if the first byte (typically the
+//! SMBus command) has been received; \b SMBUS_SLAVE_NOT_READY if the slave's
+//! transmit buffer is not yet initialized when the master requests data from
+//! the slave; \b SMBUS_DATA_SIZE_ERROR if during a master block write, the
+//! size sent by the master is greater than the amount of available space in
+//! the receive buffer; \b SMBUS_SLAVE_ERROR if a buffer overrun is detected
+//! during a slave receive operation or if data is sent and was not expected;
+//! \b SMBUS_SLAVE_QCMD_0 if a Quick Command was received with data '0';
+//! \b SMBUS_SLAVE_QCMD_1 if a Quick Command was received with data '1';
+//! \b SMBUS_TRANSFER_COMPLETE if a STOP is detected on the bus, marking the
+//! end of a transfer; \b SMBUS_PEC_ERROR if the received PEC byte does not
+//! match the locally calculated value; or \b SMBUS_OK if processing finished
+//! successfully.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusSlaveIntProcess(tSMBus *psSMBus)
+{
+ uint32_t ui32InterruptStatus;
+ uint32_t ui32SlaveStatus = 0;
+ uint8_t ui8CRCTemp;
+ uint8_t ui8DataTemp;
+
+ //
+ // Determine which interrupt was asserted.
+ //
+ ui32InterruptStatus = I2CSlaveIntStatusEx(psSMBus->ui32I2CBase, true);
+
+ //
+ // Check the status register.
+ //
+ ui32SlaveStatus = I2CSlaveStatus(psSMBus->ui32I2CBase);
+
+ //
+ // Check for the START interrupt.
+ //
+ if(ui32InterruptStatus & I2C_SLAVE_INT_START)
+ {
+ //
+ // Clear the interrupt.
+ //
+ I2CSlaveIntClearEx(psSMBus->ui32I2CBase, I2C_SLAVE_INT_START);
+
+
+ //
+ // This interrupt is not supported outside of using the FIFO.
+ //
+ return(SMBUS_OK);
+ }
+
+ //
+ // Check for the STOP interrupt.
+ //
+ if(ui32InterruptStatus & I2C_SLAVE_INT_STOP)
+ {
+ //
+ // Make sure the transfer in progress flag is cleared. In the case
+ // of Quick Command, it should never be set, so this is safe.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;
+
+ //
+ // Clear the interrupt.
+ //
+ I2CSlaveIntClearEx(psSMBus->ui32I2CBase, I2C_SLAVE_INT_STOP);
+
+ //
+ // Check to see if a Quick Command was sent.
+ //
+ if(ui32SlaveStatus & 0x10)
+ {
+ //
+ // Make sure the TX/RX index is 0. If not, we should not be here.
+ // Other data should not have been sent or received during a Quick
+ // Command.
+ //
+ if((psSMBus->ui8RxIndex != 0) || (psSMBus->ui8TxIndex != 0))
+ {
+ //
+ // Return an error.
+ //
+ return(SMBUS_SLAVE_ERROR);
+ }
+
+ //
+ // Tell caller a Quick Command has occurred and the data value.
+ //
+ if(ui32SlaveStatus & 0x20)
+ {
+ return(SMBUS_SLAVE_QCMD_1);
+ }
+ else
+ {
+ return(SMBUS_SLAVE_QCMD_0);
+ }
+ }
+
+ //
+ // Move to the idle state.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_IDLE;
+
+ //
+ // Return end of transfer.
+ //
+ return(SMBUS_TRANSFER_COMPLETE);
+ }
+
+ //
+ // Check for the DATA interrupt.
+ //
+ if(ui32InterruptStatus & I2C_SLAVE_INT_DATA)
+ {
+ //
+ // Clear the I2C interrupt.
+ //
+ I2CSlaveIntClearEx(psSMBus->ui32I2CBase, I2C_SLAVE_INT_DATA);
+
+ //
+ // Make sure that at least one of the relevant status bits is set.
+ //
+ if(!(ui32SlaveStatus & 0x07))
+ {
+ //
+ // No status bits were set - this is bad. Should never get here.
+ //
+ return(SMBUS_SLAVE_ERROR);
+ }
+
+ //
+ // Every time this interrupt occurs, a transfer is in progress. Make
+ // sure the flag is set appropriately.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 1;
+
+ //
+ // Handle the request type.
+ //
+ switch((ui32SlaveStatus & 0x07))
+ {
+ //
+ // The first byte after the slave's own address has been received.
+ // This is almost always the command byte in SMBus. The only
+ // exception is when the Send Byte protocol is used by the master.
+ //
+ case I2C_SLAVE_ACT_RREQ_FBR:
+ {
+ //
+ // Check which slave address was called out. Set the active
+ // address to the matched address.
+ //
+ if(I2CSlaveStatus(psSMBus->ui32I2CBase) & I2C_SCSR_OAR2SEL)
+ {
+ psSMBus->ui8OwnSlaveAddress =
+ HWREG(psSMBus->ui32I2CBase + I2C_O_SOAR2) & 0x7f;
+ }
+ else
+ {
+ psSMBus->ui8OwnSlaveAddress =
+ HWREG(psSMBus->ui32I2CBase + I2C_O_SOAR);
+ }
+
+ //
+ // If raw I2C, data goes into buffer.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C))
+ {
+ psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex++] =
+ I2CSlaveDataGet(psSMBus->ui32I2CBase);
+ }
+
+ //
+ // Read the first byte into the ui8CurrentCommand member.
+ //
+ else
+ {
+ psSMBus->ui8CurrentCommand =
+ I2CSlaveDataGet(psSMBus->ui32I2CBase);
+ }
+
+ //
+ // If PEC is enabled, add the address to the CRC calculation.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Add the address to the CRC calculation. In this case
+ // R/S will always be 0. Also, this is the start of the
+ // CRC calculation, so the initial value is 0.
+ //
+ ui8CRCTemp = psSMBus->ui8OwnSlaveAddress << 1;
+
+ //
+ // Calculate new CRC.
+ //
+ psSMBus->ui8CalculatedCRC = Crc8CCITT(0, &ui8CRCTemp, 1);
+
+ //
+ // Add the data byte (ui8CurrentCommand) to the CRC
+ // calculation.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &psSMBus->ui8CurrentCommand, 1);
+ }
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_SLAVE_POST_COMMAND;
+
+ //
+ // Actions for this case are complete.
+ //
+ return(SMBUS_SLAVE_FIRST_BYTE);
+ }
+
+ //
+ // A data byte other than the first data byte has been received.
+ //
+ case I2C_SLAVE_ACT_RREQ:
+ {
+ //
+ // Determine what to do based on the current state.
+ //
+ switch(psSMBus->ui8SlaveState)
+ {
+ //
+ // Receive first post-command byte.
+ //
+ case SMBUS_STATE_SLAVE_POST_COMMAND:
+ {
+ //
+ // Read the data into the a temporary variable.
+ //
+ ui8DataTemp = I2CSlaveDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // Check if this is a block transfer.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER))
+ {
+ //
+ // Make sure there is enough space in the buffer.
+ // If not, NACK. If there is, overwrite the
+ // current size with the size sent by the master.
+ //
+ if(ui8DataTemp > psSMBus->ui8RxSize)
+ {
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_READ_DONE;
+
+ //
+ // Indicate a size error.
+ //
+ return(SMBUS_DATA_SIZE_ERROR);
+ }
+ else
+ {
+ //
+ // Update the size.
+ //
+ psSMBus->ui8RxSize = ui8DataTemp;
+
+ //
+ // Check to see if PEC is enabled.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Add the size byte to the CRC
+ // calculation.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &ui8DataTemp, 1);
+ }
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_READ_NEXT;
+ }
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // If there is no data to receive and no PEC, nothing
+ // to do. Software should never get here.
+ //
+ if(psSMBus->ui8RxIndex == psSMBus->ui8RxSize)
+ {
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_READ_DONE;
+
+ //
+ // Report an error.
+ //
+ return(SMBUS_SLAVE_ERROR);
+ }
+ else
+ {
+ //
+ // Put the data in the buffer.
+ //
+ psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex++] =
+ ui8DataTemp;
+
+ //
+ // If this is the last data byte.
+ //
+ if(psSMBus->ui8RxIndex == psSMBus->ui8RxSize)
+ {
+ //
+ // Check for PEC usage.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Add the size byte to the CRC
+ // calculation.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &ui8DataTemp, 1);
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_READ_PEC;
+ }
+ else
+ {
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_READ_DONE;
+ }
+ }
+
+ //
+ // All other cases.
+ //
+ else
+ {
+ //
+ // Check for PEC usage.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Add the size byte to the CRC
+ // calculation.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &ui8DataTemp, 1);
+ }
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_READ_NEXT;
+ }
+ }
+
+ //
+ // Actions for this case are complete.
+ //
+ break;
+ }
+
+ //
+ // Read the next byte into the buffer.
+ //
+ case SMBUS_STATE_READ_NEXT:
+ {
+ //
+ // Read the data into the a temporary variable.
+ //
+ ui8DataTemp = I2CSlaveDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // If there is no data to receive and no PEC, nothing
+ // to do. Software should never get here.
+ //
+ if(psSMBus->ui8RxIndex == psSMBus->ui8RxSize)
+ {
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_READ_DONE;
+
+ //
+ // Report an error.
+ //
+ return(SMBUS_SLAVE_ERROR);
+ }
+ else
+ {
+ //
+ // Put the data in the buffer.
+ //
+ psSMBus->pui8RxBuffer[psSMBus->ui8RxIndex++] =
+ ui8DataTemp;
+
+ //
+ // If this is the last data byte.
+ //
+ if(psSMBus->ui8RxIndex == psSMBus->ui8RxSize)
+ {
+ //
+ // Check for PEC usage.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Add the size byte to the CRC
+ // calculation.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &ui8DataTemp, 1);
+
+ //
+ // Update the state machine.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags,
+ FLAG_PROCESS_CALL))
+ {
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_READ_DONE;
+ }
+ else
+ {
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_READ_PEC;
+ }
+ }
+ else
+ {
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_READ_DONE;
+ }
+ }
+
+ //
+ // All other cases.
+ //
+ else
+ {
+ //
+ // Check for PEC usage.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Add the size byte to the CRC
+ // calculation.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &ui8DataTemp, 1);
+ }
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_READ_NEXT;
+ }
+ }
+
+ break;
+ }
+
+ //
+ // Read the PEC byte and compare it.
+ //
+ case SMBUS_STATE_READ_PEC:
+ {
+ //
+ // Read the data into the a temporary variable.
+ //
+ ui8DataTemp = I2CSlaveDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // Compare PEC.
+ //
+ if(psSMBus->ui8CalculatedCRC != ui8DataTemp)
+ {
+ //
+ // Indicate PEC error.
+ //
+ return(SMBUS_PEC_ERROR);
+ }
+
+ //
+ // Update the state machine.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_READ_DONE;
+
+ break;
+ }
+
+ //
+ // No more data to receive. If we get here, read data
+ // into a dummy variable and NACK.
+ //
+ case SMBUS_STATE_READ_DONE:
+ {
+ //
+ // Read the data into the a temporary variable.
+ //
+ ui8DataTemp = I2CSlaveDataGet(psSMBus->ui32I2CBase);
+
+ //
+ // Report an error.
+ //
+ return(SMBUS_SLAVE_ERROR);
+ }
+ }
+
+ //
+ // Actions for this case are complete.
+ //
+ break;
+ }
+
+ //
+ // The master has requested that the slave transmit data back to
+ // master.
+ //
+ case I2C_SLAVE_ACT_TREQ:
+ {
+ //
+ // Initialize temporary variable that stores transmit byte to
+ // 0xff. If data is not set by another condition, the 0xff
+ // carries through. This happens if ui8TxIndex is equal to or
+ // greater than ui8TxSize.
+ //
+ ui8DataTemp = 0xff;
+
+ //
+ // Determine what to do based on the current state.
+ //
+ switch(psSMBus->ui8SlaveState)
+ {
+ //
+ // The state machine is currently idle, or if the last
+ // state was SMBUS_STATE_SLAVE_POST_COMMAND or
+ // SMBUS_READ_DONE, this is the first byte transmitted. In
+ // the case of slave post command, this means that the
+ // command was received followed by a repeated start (with
+ // R/S = 1). In the case of read next, this means that a
+ // raw I2C master transmit changed direction with a
+ // repeated start and is now a master receive. In the case
+ // of read done, this means that a previous master transmit
+ // was finished (non-command followed by a repeated start).
+ //
+ case SMBUS_STATE_IDLE:
+ case SMBUS_STATE_SLAVE_POST_COMMAND:
+ case SMBUS_STATE_READ_NEXT:
+ case SMBUS_STATE_READ_DONE:
+ {
+ //
+ // Check which slave address was called out. Set the
+ // active address to the matched address.
+ //
+ if(I2CSlaveStatus(psSMBus->ui32I2CBase) &
+ I2C_SCSR_OAR2SEL)
+ {
+ psSMBus->ui8OwnSlaveAddress =
+ (HWREG(psSMBus->ui32I2CBase + I2C_O_SOAR2) &
+ 0x7f);
+ }
+ else
+ {
+ psSMBus->ui8OwnSlaveAddress =
+ HWREG(psSMBus->ui32I2CBase + I2C_O_SOAR);
+ }
+
+ //
+ // Check to see if the TX buffer is populated. If not,
+ // return not ready without writing to the data
+ // register.
+ //
+ if(psSMBus->ui8TxSize == 0)
+ {
+ return(SMBUS_SLAVE_NOT_READY);
+ }
+
+ //
+ // Is this a block transfer?
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER))
+ {
+ //
+ // The first byte to send is the size.
+ //
+ ui8DataTemp = psSMBus->ui8TxSize;
+ }
+ else
+ {
+ //
+ // Is there data to send?
+ //
+ if(psSMBus->ui8TxIndex < psSMBus->ui8TxSize)
+ {
+ //
+ // Set the transmit data to the next item in
+ // the buffer.
+ //
+ ui8DataTemp =
+ psSMBus->pui8TxBuffer[psSMBus->
+ ui8TxIndex++];
+ }
+ else
+ {
+ //
+ // Send 0xff per spec.
+ //
+ ui8DataTemp = 0xff;
+ }
+ }
+
+ //
+ // Check to see if PEC is required.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Start calculating the CRC with the address.
+ //
+ ui8CRCTemp =
+ (psSMBus->ui8OwnSlaveAddress << 1) | 1;
+
+ //
+ // Add the address and R/S bit to the CRC.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &ui8CRCTemp, 1);
+
+ //
+ // Add the data byte to the CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &ui8DataTemp, 1);
+
+ //
+ // Move to the next state.
+ //
+ if(psSMBus->ui8TxIndex == psSMBus->ui8TxSize)
+ {
+ //
+ // Final byte is the CRC byte.
+ //
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_WRITE_FINAL;
+ }
+ else
+ {
+ //
+ // All other cases, move to the next byte
+ // state.
+ //
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_WRITE_NEXT;
+ }
+ }
+ else
+ {
+ //
+ // Move to the next state.
+ //
+ switch(psSMBus->ui8TxSize - psSMBus->ui8TxIndex)
+ {
+ //
+ // If all of the data has been sent, move to
+ // the done state.
+ //
+ case 0:
+ {
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_WRITE_DONE;
+
+ break;
+ }
+
+ //
+ // If 1 left, move to the final byte state.
+ //
+ case 1:
+ {
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_WRITE_FINAL;
+
+ break;
+ }
+
+ //
+ // All other cases, move to the next byte
+ // state.
+ //
+ default:
+ {
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_WRITE_NEXT;
+
+ break;
+ }
+ }
+ }
+
+ //
+ // Send the data.
+ //
+ I2CSlaveDataPut(psSMBus->ui32I2CBase, ui8DataTemp);
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // The first byte has already been sent, handle the rest.
+ //
+ case SMBUS_STATE_WRITE_NEXT:
+ {
+ //
+ // Set the transmit data to the next item in the
+ // buffer.
+ //
+ ui8DataTemp =
+ psSMBus->pui8TxBuffer[psSMBus->ui8TxIndex++];
+
+ //
+ // Check to see if PEC is required.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Add the byte to the CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC =
+ MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &ui8DataTemp, 1);
+
+ //
+ // Check if it's time to move to the next state.
+ //
+ if(psSMBus->ui8TxIndex == psSMBus->ui8TxSize)
+ {
+ //
+ // Final byte is the CRC byte.
+ //
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_WRITE_FINAL;
+ }
+ }
+ else
+ {
+ //
+ // Move to the next state.
+ //
+ if((psSMBus->ui8TxSize - psSMBus->ui8TxIndex) == 1)
+ {
+ //
+ // If only 1 byte remains, move to the final
+ // state.
+ //
+ psSMBus->ui8SlaveState =
+ SMBUS_STATE_WRITE_FINAL;
+ }
+ }
+
+ //
+ // Send the data.
+ //
+ I2CSlaveDataPut(psSMBus->ui32I2CBase, ui8DataTemp);
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // Write the final byte, whether PEC or data.
+ //
+ case SMBUS_STATE_WRITE_FINAL:
+ {
+ //
+ // Check to see if PEC is required.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Send the CRC byte.
+ //
+ ui8DataTemp = psSMBus->ui8CalculatedCRC;
+ }
+ else
+ {
+ //
+ // Send the last data byte.
+ //
+ ui8DataTemp =
+ psSMBus->pui8TxBuffer[psSMBus->ui8TxIndex++];
+ }
+
+ //
+ // Send the data.
+ //
+ I2CSlaveDataPut(psSMBus->ui32I2CBase, ui8DataTemp);
+
+ //
+ // Move to the write done state.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_WRITE_DONE;
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+
+ //
+ // All data has been sent, send 0xff.
+ //
+ case SMBUS_STATE_WRITE_DONE:
+ {
+ //
+ // Send 0xff because there is no more data to send.
+ //
+ I2CSlaveDataPut(psSMBus->ui32I2CBase, 0xff);
+
+ //
+ // This state is done.
+ //
+ break;
+ }
+ }
+
+ //
+ // Actions for this case are complete.
+ //
+ break;
+ }
+ }
+
+ //
+ // Return OK status.
+ //
+ return(SMBUS_OK);
+ }
+
+ //
+ // Return OK. Should never get here.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Sends data outside of the interrupt processing function.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function sends data outside the interrupt processing function, and
+//! should only be used when SMBusSlaveIntProcess() returns
+//! \b SMBUS_SLAVE_NOT_READY. At this point, the application should set up the
+//! transfer and call this function (it assumes that the transmit buffer has
+//! already been populated when called). When called, this function updates
+//! the slave state machine as if SMBusSlaveIntProcess() were called.
+//!
+//! \return Returns \b SMBUS_SLAVE_NOT_READY if the slave's transmit buffer is
+//! not yet initialized (ui8TxSize is 0), or \b SMBUS_OK if processing finished
+//! successfully.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusSlaveDataSend(tSMBus *psSMBus)
+{
+ uint8_t ui8CRCTemp;
+ uint8_t ui8DataTemp;
+
+ //
+ // Check to see if the TX buffer is populated. If not,
+ // return not ready without writing to the data register.
+ //
+ if(psSMBus->ui8TxSize == 0)
+ {
+ return(SMBUS_SLAVE_NOT_READY);
+ }
+
+ //
+ // Is this a block transfer?
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER))
+ {
+ //
+ // The first byte to send is the size.
+ //
+ ui8DataTemp = psSMBus->ui8TxSize;
+ }
+ else
+ {
+ //
+ // Is there data to send?
+ //
+ if(psSMBus->ui8TxIndex < psSMBus->ui8TxSize)
+ {
+ //
+ // Set the transmit data to the next item in
+ // the buffer.
+ //
+ ui8DataTemp = psSMBus->pui8TxBuffer[psSMBus->ui8TxIndex++];
+ }
+ else
+ {
+ //
+ // Send 0xff per spec. Should not get here.
+ //
+ ui8DataTemp = 0xff;
+ }
+ }
+
+ //
+ // Check to see if PEC is required.
+ //
+ if(HWREGBITB(&psSMBus->ui16Flags, FLAG_PEC))
+ {
+ //
+ // Start calculating the CRC with the address.
+ //
+ ui8CRCTemp = (psSMBus->ui8OwnSlaveAddress << 1) | 1;
+
+ //
+ // Add the address and R/S bit to the CRC.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &ui8CRCTemp, 1);
+
+ //
+ // Add the data byte to the CRC calculation.
+ //
+ psSMBus->ui8CalculatedCRC = MAP_Crc8CCITT(psSMBus->ui8CalculatedCRC,
+ &ui8DataTemp, 1);
+
+ //
+ // Move to the next state.
+ //
+ if(psSMBus->ui8TxIndex == psSMBus->ui8TxSize)
+ {
+ //
+ // Final byte is the CRC byte.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_WRITE_FINAL;
+ }
+ else
+ {
+ //
+ // All other cases, move to the next byte state.
+ //
+ psSMBus->ui8SlaveState = SMBUS_STATE_WRITE_NEXT;
+ }
+ }
+ else
+ {
+ //
+ // Move to the next state.
+ //
+ switch(psSMBus->ui8TxSize - psSMBus->ui8TxIndex)
+ {
+ //
+ // If all of the data has been sent, move to the
+ // done state.
+ //
+ case 0:
+ {
+ psSMBus->ui8SlaveState = SMBUS_STATE_WRITE_DONE;
+
+ break;
+ }
+
+ //
+ // If 1 left, move to the final byte state.
+ //
+ case 1:
+ {
+ psSMBus->ui8SlaveState = SMBUS_STATE_WRITE_FINAL;
+
+ break;
+ }
+
+ //
+ // All other cases, move to the next byte state.
+ //
+ default:
+ {
+ psSMBus->ui8SlaveState = SMBUS_STATE_WRITE_NEXT;
+
+ break;
+ }
+ }
+ }
+
+ //
+ // Send the data.
+ //
+ I2CSlaveDataPut(psSMBus->ui32I2CBase, ui8DataTemp);
+
+ //
+ // Return to caller.
+ //
+ return(SMBUS_OK);
+}
+
+//*****************************************************************************
+//
+//! Set the address and size of the slave transmit buffer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param pui8Data is a pointer to the transmit data buffer.
+//! \param ui8Size is the number of bytes in the buffer.
+//!
+//! This function sets the address and size of the slave transmit buffer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveTxBufferSet(tSMBus *psSMBus, uint8_t *pui8Data,
+ uint8_t ui8Size)
+{
+ //
+ // Set the trasmit buffer.
+ //
+ psSMBus->pui8TxBuffer = pui8Data;
+
+ //
+ // Set the size.
+ //
+ psSMBus->ui8TxSize = ui8Size;
+}
+
+//*****************************************************************************
+//
+//! Set the address and size of the slave receive buffer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param pui8Data is a pointer to the receive data buffer.
+//! \param ui8Size is the number of bytes in the buffer.
+//!
+//! This function sets the address and size of the slave receive buffer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveRxBufferSet(tSMBus *psSMBus, uint8_t *pui8Data,
+ uint8_t ui8Size)
+{
+ //
+ // Set the receive buffer.
+ //
+ psSMBus->pui8RxBuffer = pui8Data;
+
+ //
+ // Set the size.
+ //
+ psSMBus->ui8RxSize = ui8Size;
+}
+
+//*****************************************************************************
+//
+//! Get the current command byte.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! Returns the current value of the ui8CurrentCommand variable in the SMBus
+//! configuration structure. This can be used to help the user application
+//! set up the SMBus slave transmit and receive buffers.
+//!
+//! \return None.
+//
+//*****************************************************************************
+uint8_t
+SMBusSlaveCommandGet(tSMBus *psSMBus)
+{
+ //
+ // Return the current command.
+ //
+ return(psSMBus->ui8CurrentCommand);
+}
+
+//*****************************************************************************
+//
+//! Sets the process call flag for an SMBus slave transfer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! Sets the process call flag in the configuration structure so that the SMBus
+//! slave can respond correctly to a Process Call request. This flag must be
+//! set prior to the data portion of the packet.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveProcessCallEnable(tSMBus *psSMBus)
+{
+ //
+ // Set the block transfer flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 1;
+}
+
+//*****************************************************************************
+//
+//! Clears the process call flag for an SMBus slave transfer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! Clears the process call flag in the configuration structure. The user
+//! application can either call this function to clear the flag, or use
+//! SMBusSlaveTransferInit() to clear out all transfer-specific flags.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveProcessCallDisable(tSMBus *psSMBus)
+{
+ //
+ // Clear the block transfer flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+}
+
+//*****************************************************************************
+//
+//! Sets the block transfer flag for an SMBus slave transfer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! Sets the block transfer flag in the configuration structure so that the
+//! SMBus slave can respond correctly to a Block Write or Block Read request.
+//! This flag must be set prior to the data portion of the packet.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveBlockTransferEnable(tSMBus *psSMBus)
+{
+ //
+ // Set the block transfer flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 1;
+}
+
+//*****************************************************************************
+//
+//! Clears the block transfer flag for an SMBus slave transfer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! Clears the block transfer flag in the configuration structure. The user
+//! application can either call this function to clear the flag, or use
+//! SMBusSlaveTransferInit() to clear out all transfer-specific flags.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveBlockTransferDisable(tSMBus *psSMBus)
+{
+ //
+ // Clear the block transfer flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+}
+
+//*****************************************************************************
+//
+//! Sets the ``raw'' I2C flag for an SMBus slave transfer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! Sets the raw I2C flag in the configuration structure so that the
+//! SMBus slave can respond correctly to raw I2C (non-SMBus protocol) requests.
+//! This flag must be set prior to the transfer, and is a global setting.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveI2CEnable(tSMBus *psSMBus)
+{
+ //
+ // Set the block transfer flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 1;
+}
+
+//*****************************************************************************
+//
+//! Clears the ``raw'' I2C flag for an SMBus slave transfer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! Clears the raw I2C flag in the configuration structure. This flag is a
+//! global setting similar to the PEC flag and cannot be cleared using
+//! SMBusSlaveTransferInit().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveI2CDisable(tSMBus *psSMBus)
+{
+ //
+ // Clear the block transfer flag.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_RAW_I2C) = 0;
+}
+
+//*****************************************************************************
+//
+//! Sets the value of the AR (Address Resolved) flag.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param bValue is the value to set the flag.
+//!
+//! This function allows the application to set the value of the AR flag. All
+//! SMBus slaves must support the AR and AV flags. On POR, the AR flag is
+//! cleared. It is also cleared when a slave receives the ARP Reset Device
+//! command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveARPFlagARSet(tSMBus *psSMBus, bool bValue)
+{
+ //
+ // Set the block address resolved flag to the desired value.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_ADDRESS_RESOLVED) = bValue;
+}
+
+//*****************************************************************************
+//
+//! Returns the current value of the AR (Address Resolved) flag.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This returns the value of the AR (Address Resolved) flag.
+//!
+//! \return Returns \b true if set, \b false if cleared.
+//
+//*****************************************************************************
+bool
+SMBusSlaveARPFlagARGet(tSMBus *psSMBus)
+{
+ //
+ // Get the value of the block address resolved flag.
+ //
+ return(HWREGBITB(&psSMBus->ui16Flags, FLAG_ADDRESS_RESOLVED));
+}
+
+//*****************************************************************************
+//
+//! Sets the value of the AV (Address Valid) flag.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param bValue is the value to set the flag.
+//!
+//! This function allows the application to set the value of the AV flag. All
+//! SMBus slaves must support the AR and AV flags. On POR, the AV flag is
+//! cleared. It is also cleared when a slave receives the ARP Reset Device
+//! command.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveARPFlagAVSet(tSMBus *psSMBus, bool bValue)
+{
+ //
+ // Set the block address valid flag to the desired value.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_ADDRESS_VALID) = bValue;
+}
+
+//*****************************************************************************
+//
+//! Returns the current value of the AV (Address Valid) flag.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This returns the value of the AV (Address Valid) flag.
+//!
+//! \return Returns \b true if set, or \b false if cleared.
+//
+//*****************************************************************************
+bool
+SMBusSlaveARPFlagAVGet(tSMBus *psSMBus)
+{
+ //
+ // Get the value of the block address valid flag.
+ //
+ return(HWREGBITB(&psSMBus->ui16Flags, FLAG_ADDRESS_VALID));
+}
+
+//*****************************************************************************
+//
+//! Sets up the SMBus slave for a new transfer.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function is used to re-initialize the configuration structure for a
+//! new transfer. Once a transfer is complete and the data has been processed,
+//! unused flags, states, the data buffers and buffer indexes should be reset
+//! to a known state before a new transfer.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveTransferInit(tSMBus *psSMBus)
+{
+ //
+ // Clear the block transfer, process call and transfer in progress flags.
+ //
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_BLOCK_TRANSFER) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_PROCESS_CALL) = 0;
+ HWREGBITB(&psSMBus->ui16Flags, FLAG_TRANSFER_IN_PROGRESS) = 0;
+
+ //
+ // Set the configuration structure to a known, zeroed state.
+ //
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+ psSMBus->ui8SlaveState = SMBUS_STATE_IDLE;
+ psSMBus->ui8CurrentCommand = 0;
+ psSMBus->ui8CalculatedCRC = 0;
+ psSMBus->ui8TxSize = 0;
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8RxSize = 0;
+ psSMBus->ui8RxIndex = 0;
+}
+
+//*****************************************************************************
+//
+//! Sets the value of the ACK bit when using manual acknowledgement.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param bACK specifies whether to ACK (\b true) or NACK (\b false).
+//!
+//! This function sets the value of the ACK bit. In order for the ACK bit to
+//! take effect, manual acknowledgement must be enabled on the slave using
+//! SMBusSlaveManualACKEnable().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveACKSend(tSMBus *psSMBus, bool bACK)
+{
+ //
+ // Send ACK or NACK based on the value of bACK.
+ //
+ if(bACK)
+ {
+ I2CSlaveACKValueSet(psSMBus->ui32I2CBase, true);
+ }
+ else
+ {
+ I2CSlaveACKValueSet(psSMBus->ui32I2CBase, false);
+ }
+}
+
+//*****************************************************************************
+//
+//! Enables manual acknowledgement for the SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function enables manual acknowledge capability in the slave. If the
+//! application requires that the slave NACK on a bad command or a bad PEC
+//! calculation, manual acknowledgement allows this to happen.
+//!
+//! In the case of responding to a bad command with a NACK, the application
+//! should use SMBusSlaveACKSend() to ACK/NACK the command. The slave ISR
+//! should check for the SMBUS_SLAVE_FIRST_BYTE return code from
+//! SMBusSlaveISRProcess() and ACK/NACK accordingly. All other cases should be
+//! handled in the application based on the return code of
+//! SMBusSlaveISRProcess().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveManualACKEnable(tSMBus *psSMBus)
+{
+ //
+ // Enable manual acknowledge.
+ //
+ I2CSlaveACKOverride(psSMBus->ui32I2CBase, true);
+}
+
+//*****************************************************************************
+//
+//! Disables manual acknowledgement for the SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function disables manual acknowledge capability in the slave. When
+//! manual acknowledgement is disabled, the slave automatically ACKs every
+//! byte sent by the master.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveManualACKDisable(tSMBus *psSMBus)
+{
+ //
+ // Disable manual acknowledge.
+ //
+ I2CSlaveACKOverride(psSMBus->ui32I2CBase, false);
+}
+
+//*****************************************************************************
+//
+//! Returns the manual acknowledgement status of the SMBus slave.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function returns the state of the I2C ACKOEN bit in the I2CSACKCTL
+//! register. This feature is disabled out of reset and must be enabled
+//! using SMBusSlaveManualACKEnable().
+//!
+//! \return Returns \b true if manual acknowledge is enabled, or \b false if
+//! manual acknowledge is disabled.
+//
+//*****************************************************************************
+bool
+SMBusSlaveManualACKStatusGet(tSMBus *psSMBus)
+{
+ //
+ // Return the value of the bit.
+ //
+ return(HWREG(psSMBus->ui32I2CBase + I2C_O_SACKCTL) & 0x1);
+}
+
+//*****************************************************************************
+//
+//! Determine whether primary or secondary slave address has been requested by
+//! the master.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! Tells the caller whether the I2C slave address requested by the master or
+//! SMBus Host is the primary or secondary I2C slave address of the peripheral.
+//! The primary is defined as the address programmed into I2CSOAR, and the
+//! secondary as the address programmed into I2CSOAR2.
+//!
+//! \return Returns \b SMBUS_SLAVE_ADDR_PRIMARY if the primary address is
+//! called out or \b SMBUS_SLAVE_ADDR_SECONDARY if the secondary address is
+//! called out.
+//
+//*****************************************************************************
+tSMBusStatus
+SMBusSlaveIntAddressGet(tSMBus *psSMBus)
+{
+ //
+ // Determine whether the primary or secondary address was called out.
+ //
+ if(I2CSlaveStatus(psSMBus->ui32I2CBase) & I2C_SCSR_OAR2SEL)
+ {
+ return(SMBUS_SLAVE_ADDR_SECONDARY);
+ }
+ else
+ {
+ return(SMBUS_SLAVE_ADDR_PRIMARY);
+ }
+}
+
+//*****************************************************************************
+//
+//! Enables the appropriate slave interrupts for stack processing.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//!
+//! This function enables the I2C interrupts used by the SMBus slave. Both
+//! the peripheral-level and NVIC-level interrupts are enabled.
+//! SMBusSlaveInit() must be called before this function because this function
+//! relies on the I2C base address being defined.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveIntEnable(tSMBus *psSMBus)
+{
+ //
+ // Enable the slave interrupts.
+ //
+ I2CSlaveIntEnableEx(psSMBus->ui32I2CBase,
+ I2C_SLAVE_INT_DATA | I2C_SLAVE_INT_STOP);
+
+ //
+ // Enable the interrupt in the NVIC.
+ //
+ switch(psSMBus->ui32I2CBase)
+ {
+ case I2C0_BASE:
+ {
+ MAP_IntEnable(INT_I2C0);
+ break;
+ }
+
+ case I2C1_BASE:
+ {
+ MAP_IntEnable(INT_I2C1);
+ break;
+ }
+
+ case I2C2_BASE:
+ {
+ if(CLASS_IS_TM4C123)
+ {
+ MAP_IntEnable(INT_I2C2_TM4C123);
+ }
+ else if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C2_TM4C129);
+ }
+ break;
+ }
+
+ case I2C3_BASE:
+ {
+ if(CLASS_IS_TM4C123)
+ {
+ MAP_IntEnable(INT_I2C3_TM4C123);
+ }
+ else if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C3_TM4C129);
+ }
+ break;
+ }
+
+ case I2C4_BASE:
+ {
+ if(CLASS_IS_TM4C123)
+ {
+ MAP_IntEnable(INT_I2C4_TM4C123);
+ }
+ else if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C4_TM4C129);
+ }
+ break;
+ }
+
+ case I2C5_BASE:
+ {
+ if(CLASS_IS_TM4C123)
+ {
+ MAP_IntEnable(INT_I2C5_TM4C123);
+ }
+ else if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C5_TM4C129);
+ }
+ break;
+ }
+
+ case I2C6_BASE:
+ {
+ if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C6_TM4C129);
+ }
+ break;
+ }
+
+ case I2C7_BASE:
+ {
+ if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C7_TM4C129);
+ }
+ break;
+ }
+
+ case I2C8_BASE:
+ {
+ if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C8_TM4C129);
+ }
+ break;
+ }
+
+ case I2C9_BASE:
+ {
+ if(CLASS_IS_TM4C129)
+ {
+ MAP_IntEnable(INT_I2C9_TM4C129);
+ }
+ break;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Sets the slave address for an SMBus slave peripheral.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui8AddressNum specifies which address (primary or secondary)
+//! \param ui8SlaveAddress is the address of the slave.
+//!
+//! This function sets the slave address. Both the primary and secondary
+//! addresses can be set using this function. To set the primary address
+//! (stored in I2CSOAR), ui8AddressNum should be '0'. To set the secondary
+//! address (stored in I2CSOAR2), ui8AddressNum should be '1'.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveAddressSet(tSMBus *psSMBus, uint8_t ui8AddressNum,
+ uint8_t ui8SlaveAddress)
+{
+ //
+ // Write the slave address.
+ //
+ I2CSlaveAddressSet(psSMBus->ui32I2CBase, ui8AddressNum, ui8SlaveAddress);
+}
+
+//*****************************************************************************
+//
+//! Sets a slave's UDID structure.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param pUDID is a pointer to the UDID configuration for the slave. This
+//! is only needed if the slave is on a bus that uses ARP.
+//!
+//! This function sets the UDID for a slave instance.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveUDIDSet(tSMBus *psSMBus, tSMBusUDID *pUDID)
+{
+ psSMBus->pUDID = pUDID;
+}
+
+//*****************************************************************************
+//
+//! Initializes an I2C slave peripheral for SMBus functionality.
+//!
+//! \param psSMBus specifies the SMBus configuration structure.
+//! \param ui32I2CBase specifies the base address of the I2C slave peripheral.
+//!
+//! This function initializes an I2C peripheral for SMBus slave use. The
+//! instance-specific configuration structure is initialized to a set of known
+//! values and the I2C peripheral is configured based on the input arguments.
+//!
+//! The default configuration of the SMBus slave uses automatic
+//! acknowledgement. If manual acknowledgement is required, call
+//! SMBusSlaveManualACKEnable().
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+SMBusSlaveInit(tSMBus *psSMBus, uint32_t ui32I2CBase)
+{
+ //
+ // Initialize the configuration structure.
+ //
+ psSMBus->pUDID = 0;
+ psSMBus->ui32I2CBase = ui32I2CBase;
+ psSMBus->ui16Flags = 0;
+ psSMBus->ui8MasterState = SMBUS_STATE_IDLE;
+ psSMBus->ui8SlaveState = SMBUS_STATE_IDLE;
+ psSMBus->ui8OwnSlaveAddress = 0;
+ psSMBus->ui8TargetSlaveAddress = 0;
+ psSMBus->ui8CurrentCommand = 0;
+ psSMBus->ui8CalculatedCRC = 0;
+ psSMBus->ui8TxSize = 0;
+ psSMBus->ui8TxIndex = 0;
+ psSMBus->ui8RxSize = 0;
+ psSMBus->ui8RxIndex = 0;
+
+ //
+ // Enable the I2C slave module. The slave is always enabled because the
+ // SMBus spec requires that all devices respond whne their slave address
+ // is put on the bus.
+ //
+ I2CSlaveEnable(psSMBus->ui32I2CBase);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************