//***************************************************************************** // // 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 #include #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. //! @} // //*****************************************************************************