summaryrefslogtreecommitdiff
path: root/sensorlib/i2cm_drv.c
diff options
context:
space:
mode:
Diffstat (limited to 'sensorlib/i2cm_drv.c')
-rw-r--r--sensorlib/i2cm_drv.c2256
1 files changed, 2256 insertions, 0 deletions
diff --git a/sensorlib/i2cm_drv.c b/sensorlib/i2cm_drv.c
new file mode 100644
index 0000000..1e603e2
--- /dev/null
+++ b/sensorlib/i2cm_drv.c
@@ -0,0 +1,2256 @@
+//*****************************************************************************
+//
+// i2cm_drv.c - Interrupt-driven I2C master driver.
+//
+// Copyright (c) 2012-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 Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_i2c.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_types.h"
+#include "driverlib/debug.h"
+#include "driverlib/i2c.h"
+#include "driverlib/interrupt.h"
+#include "driverlib/rom.h"
+#include "driverlib/rom_map.h"
+#include "sensorlib/i2cm_drv.h"
+
+//*****************************************************************************
+//
+//! \addtogroup i2cm_drv_api
+//! @{
+//
+//*****************************************************************************
+
+//*****************************************************************************
+//
+// The states in the interrupt handler state machine.
+//
+//*****************************************************************************
+#define STATE_IDLE 0
+#define STATE_WRITE_NEXT 1
+#define STATE_WRITE_FINAL 2
+#define STATE_WRITE_PAUSE 3
+#define STATE_READ_ONE 4
+#define STATE_READ_FIRST 5
+#define STATE_READ_NEXT 6
+#define STATE_READ_FINAL 7
+#define STATE_READ_PAUSE 8
+#define STATE_READ_WAIT 9
+#define STATE_CALLBACK 10
+
+//*****************************************************************************
+//
+// The states in the I2C read-modify-write state machine.
+//
+//*****************************************************************************
+#define I2CM_RMW_STATE_IDLE 0
+#define I2CM_RMW_STATE_READ 1
+#define I2CM_RMW_STATE_WRITE 2
+
+//*****************************************************************************
+//
+//! Writes data to an I2C device.
+//!
+//! \param psInst is a pointer to the I2C master instance data.
+//! \param ui8Addr is the address of the I2C device to access.
+//! \param pui8Data is a pointer to the data buffer to be written.
+//! \param ui16Count is the number of bytes to be written.
+//! \param pfnCallback is the function to be called when the write has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function adds an I2C write to the queue of commands to be sent. If
+//! successful, the I2C write is then performed in the background using the
+//! interrupt handler. When the write is complete, the callback function, if
+//! provided, is called in the context of the I2C master interrupt handler.
+//!
+//! The first byte of the data buffer contains the I2C address of the device to
+//! access, and the remaining \e ui16Count bytes contain the data to be written
+//! to the device. The \e ui16Count parameter can be zero if there are no
+//! bytes to be written.
+//!
+//! \return Returns 1 if the command was successfully added to the queue and 0
+//! if it was not.
+//
+// The extern here provides a non-inline definition for this function to handle
+// the case where the compiler chooses not to inline the function (which is a
+// valid choice for the compiler to make).
+//
+//*****************************************************************************
+extern uint_fast8_t I2CMWrite(tI2CMInstance *psInst, uint_fast8_t ui8Addr,
+ const uint8_t *pui8Data, uint_fast16_t ui16Count,
+ tSensorCallback pfnCallback,
+ void *pvCallbackData);
+
+//*****************************************************************************
+//
+//! Reads data from an I2C device.
+//!
+//! \param psInst is a pointer to the I2C master instance data.
+//! \param ui8Addr is the address of the I2C device to access.
+//! \param pui8WriteData is a pointer to the data buffer to be written.
+//! \param ui16WriteCount is the number of bytes to be written.
+//! \param pui8ReadData is a pointer to the buffer to be filled with the read
+//! data.
+//! \param ui16ReadCount is the number of bytes to be read.
+//! \param pfnCallback is the function to be called when the transfer has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function adds an I2C read to the queue of commands to be sent. If
+//! successful, the I2C read is then performed in the background using the
+//! interrupt handler. When the read is complete, the callback function, if
+//! provided, is called in the context of the I2C master interrupt handler.
+//!
+//! The first byte of \e pui8WriteData contains the I2C address of the device
+//! to access, the next \e ui16WriteCount bytes contains the data to be written
+//! to the device. The data read from the device is written into the first
+//! \e ui16ReadCount bytes of \e pui8ReadData. The \e ui16WriteCount or
+//! \e ui16ReadCount parameters can be zero if there are no bytes to be read or
+//! written. The write bytes are sent to the device first, and then the read
+//! bytes are read from the device afterward.
+//!
+//! \return Returns 1 if the command was successfully added to the queue and 0
+//! if it was not.
+//
+// The extern here provides a non-inline definition for this function to handle
+// the case where the compiler chooses not to inline the function (which is a
+// valid choice for the compiler to make).
+//
+//*****************************************************************************
+extern uint_fast8_t I2CMRead(tI2CMInstance *psInst, uint_fast8_t ui8Addr,
+ const uint8_t *pui8WriteData,
+ uint_fast16_t ui16WriteCount,
+ uint8_t *pui8ReadData,
+ uint_fast16_t ui16ReadCount,
+ tSensorCallback pfnCallback,
+ void *pvCallbackData);
+
+//*****************************************************************************
+//
+//! Writes data in batches to an I2C device.
+//!
+//! \param psInst is a pointer to the I2C master instance data.
+//! \param ui8Addr is the address of the I2C device to access.
+//! \param pui8Data is a pointer to the data buffer to be written.
+//! \param ui16Count is the number of bytes to be written.
+//! \param ui16BatchSize is the number of bytes in each write batch.
+//! \param pfnCallback is the function to be called when the transfer has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function adds an I2C write to the queue of commands to be sent. If
+//! successful, the I2C write is then performed in the background using the
+//! interrupt handler. When the write is complete, the callback function, if
+//! provided, is called in the context of the I2C master interrupt handler.
+//!
+//! The first byte of the data buffer contains the I2C address of the device to
+//! access, and the remaining \e ui16Count bytes contain the data to be written
+//! to the device. The \e ui16Count parameter can be zero if there are no
+//! bytes to be written.
+//!
+//! The data is written in batches of \e ui16WriteBatchSize. The callback
+//! function is called after each batch is written, and I2CMTransferResume()
+//! must be called when the next batch should be written.
+//!
+//! \return Returns 1 if the command was successfully added to the queue and 0
+//! if it was not.
+//
+// The extern here provides a non-inline definition for this function to handle
+// the case where the compiler chooses not to inline the function (which is a
+// valid choice for the compiler to make).
+//
+//*****************************************************************************
+extern uint_fast8_t I2CMWriteBatched(tI2CMInstance *psInst,
+ uint_fast8_t ui8Addr,
+ const uint8_t *pui8Data,
+ uint_fast16_t ui16Count,
+ uint_fast16_t ui16BatchSize,
+ tSensorCallback pfnCallback,
+ void *pvCallbackData);
+
+//*****************************************************************************
+//
+//! Reads data in batches from an I2C device.
+//!
+//! \param psInst is a pointer to the I2C master instance data.
+//! \param ui8Addr is the address of the I2C device to access.
+//! \param pui8WriteData is a pointer to the data buffer to be written.
+//! \param ui16WriteCount is the number of bytes to be written.
+//! \param ui16WriteBatchSize is the number of bytes in each write batch.
+//! \param pui8ReadData is a pointer to the buffer to be filled with the read
+//! data.
+//! \param ui16ReadCount is the number of bytes to be read.
+//! \param ui16ReadBatchSize is the number of bytes in each read batch.
+//! \param pfnCallback is the function to be called when the transfer has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function adds an I2C read to the queue of commands to be sent. If
+//! successful, the I2C read is then performed in the background using the
+//! interrupt handler. When the read is complete, the callback function, if
+//! provided, is called in the context of the I2C master interrupt handler.
+//!
+//! The first byte of \e pui8WriteData contains the I2C address of the device
+//! to access, the next \e ui16WriteCount bytes contains the data to be written
+//! to the device. The data read from the device is written into the first
+//! \e ui16ReadCount bytes of \e pui8ReadData. The \e ui16WriteCount or
+//! \e ui16ReadCount parameters can be zero if there are no bytes to be read or
+//! written. The write bytes are sent to the device first, and then the read
+//! bytes are read from the device afterward.
+//!
+//! The data is written in batches of \e ui16WriteBatchSize. The callback
+//! function is called after each batch is written, and I2CMTransferResume()
+//! must be called when the next batch should be written.
+//!
+//! The data is read in batches of \e ui16ReadBatchSize. The callback function
+//! is called after each batch is read, and I2CMTransferResume() must be called
+//! when the next batch should be read.
+//!
+//! \return Returns 1 if the command was successfully added to the queue and 0
+//! if it was not.
+//
+// The extern here provides a non-inline definition for this function to handle
+// the case where the compiler chooses not to inline the function (which is a
+// valid choice for the compiler to make).
+//
+//*****************************************************************************
+extern uint_fast8_t I2CMReadBatched(tI2CMInstance *psInst,
+ uint_fast8_t ui8Addr,
+ const uint8_t *pui8WriteData,
+ uint_fast16_t ui16WriteCount,
+ uint_fast16_t ui16WriteBatchSize,
+ uint8_t *pui8ReadData,
+ uint_fast16_t ui16ReadCount,
+ uint_fast16_t ui16ReadBatchSize,
+ tSensorCallback pfnCallback,
+ void *pvCallbackData);
+
+//*****************************************************************************
+//
+//! Performs a read-modify-write of 16 bits of big-endian data in an I2C
+//! device.
+//!
+//! \param psInst is a pointer to the read-modify-write instance data.
+//! \param psI2CInst is a pointer to the I2C master instance data.
+//! \param ui8Addr is the address of the I2C device to access.
+//! \param ui8Reg is the register in the I2C device to access.
+//! \param ui16Mask is the mask indicating the register bits that should be
+//! maintained.
+//! \param ui16Value is the value indicating the new value for the register
+//! bits that are not maintained.
+//! \param pfnCallback is the function to be called when the write has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initiates a read-modify-write transaction of 16 bits of
+//! big-endian data in an I2C device. The modify portion of the operation is
+//! performed by AND-ing the register value with \e ui16Mask and then OR-ing
+//! the result with \e ui16Value. When the read-modify-write is complete, the
+//! callback function, if provided, is called in the context of the I2C master
+//! interrupt handler.
+//!
+//! If the mask (in \e ui16Mask) is zero, then none of the bits in the current
+//! register value are maintained. In this case, the read portion of the
+//! read-modify-write is bypassed, and the new register value (in \e ui16Value)
+//! is directly written to the I2C device.
+//!
+//! \return Returns 1 if the command was successfully added to the queue and 0
+//! if it was not.
+//
+// The extern here provides a non-inline definition for this function to handle
+// the case where the compiler chooses not to inline the function (which is a
+// valid choice for the compiler to make).
+//
+//*****************************************************************************
+extern uint_fast8_t I2CMReadModifyWrite16BE(tI2CMReadModifyWrite16 *psInst,
+ tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8Addr,
+ uint_fast8_t ui8Reg,
+ uint_fast16_t ui16Mask,
+ uint_fast16_t ui16Value,
+ tSensorCallback *pfnCallback,
+ void *pvCallbackData);
+
+//*****************************************************************************
+//
+// This function handles the idle state of the I2C master state machine.
+//
+//*****************************************************************************
+static void
+I2CMStateIdle(tI2CMInstance *psInst, tI2CMCommand *pCommand)
+{
+ //
+ // Do nothing if there is not another transfer in the queue.
+ //
+ if(psInst->ui8ReadPtr == psInst->ui8WritePtr)
+ {
+ return;
+ }
+
+ //
+ // See if there is any data to be written.
+ //
+ if(pCommand->ui16WriteCount != 0)
+ {
+ //
+ // Set the slave address and indicate a write.
+ //
+ MAP_I2CMasterSlaveAddrSet(psInst->ui32Base, pCommand->ui8Addr, false);
+
+ //
+ // Place the first data byte to be written in the data register.
+ //
+ MAP_I2CMasterDataPut(psInst->ui32Base, pCommand->pui8WriteData[0]);
+
+ //
+ // See if there is just a single byte to be written and no bytes to be
+ // read.
+ //
+ if((pCommand->ui16WriteCount == 1) && (pCommand->ui16ReadCount == 0))
+ {
+ //
+ // Perform a single byte send.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base, I2C_MASTER_CMD_SINGLE_SEND);
+
+ //
+ // The next state is the callback state.
+ //
+ psInst->ui8State = STATE_CALLBACK;
+ }
+
+ //
+ // Otherwise, see if there is just a single byte to be written and at
+ // least one byte to be read.
+ //
+ else if(pCommand->ui16WriteCount == 1)
+ {
+ //
+ // Perform a single send, writing the first byte as the only byte.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base,
+ I2C_MASTER_CMD_BURST_SEND_START);
+
+ //
+ // Set the next state of the interrupt state machine based on the
+ // number of bytes to read.
+ //
+ psInst->ui8State = ((pCommand->ui16ReadCount == 1) ?
+ STATE_READ_ONE : STATE_READ_FIRST);
+ }
+
+ //
+ // Otherwise, there is more than one byte to be written.
+ //
+ else
+ {
+ //
+ // Start the burst cycle, writing the first byte.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base,
+ I2C_MASTER_CMD_BURST_SEND_START);
+
+ //
+ // Set the index to indicate that the first byte has been
+ // transmitted.
+ //
+ psInst->ui16Index = 1;
+
+ //
+ // Set the next state of the interrupt state machine based on the
+ // number of bytes to write.
+ //
+ psInst->ui8State = ((pCommand->ui16WriteCount != 2) ?
+ STATE_WRITE_NEXT : STATE_WRITE_FINAL);
+ }
+ }
+ else
+ {
+ //
+ // Set the slave address and indicate a read.
+ //
+ MAP_I2CMasterSlaveAddrSet(psInst->ui32Base, pCommand->ui8Addr, true);
+
+ //
+ // Set the index to indicate that the first byte is being read.
+ //
+ psInst->ui16Index = 0;
+
+ //
+ // See if there is just a single byte to be read.
+ //
+ if(pCommand->ui16ReadCount == 1)
+ {
+ //
+ // Perform a single byte read.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base,
+ I2C_MASTER_CMD_SINGLE_RECEIVE);
+
+ //
+ // The next state is the wait for final read state.
+ //
+ psInst->ui8State = STATE_READ_WAIT;
+ }
+ else
+ {
+ //
+ // Start the burst receive.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base,
+ I2C_MASTER_CMD_BURST_RECEIVE_START);
+
+ //
+ // Set the next state appropriately. If the read count is two, the
+ // next state must finish the transaction. If it is greater than
+ // two, the burst read must be continued.
+ //
+ psInst->ui8State = ((pCommand->ui16ReadCount == 2) ?
+ STATE_READ_FINAL : STATE_READ_NEXT);
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function handles the write next state of the I2C master state machine.
+//
+//*****************************************************************************
+static void
+I2CMStateWriteNext(tI2CMInstance *psInst, tI2CMCommand *pCommand)
+{
+ //
+ // See if the write batch has been sent.
+ //
+ if(psInst->ui16Index == pCommand->ui16WriteBatchSize)
+ {
+ //
+ // Move to the write pause state.
+ //
+ psInst->ui8State = STATE_WRITE_PAUSE;
+
+ //
+ // Call the callback function.
+ //
+ if(pCommand->pfnCallback)
+ {
+ pCommand->pfnCallback(pCommand->pvCallbackData,
+ I2CM_STATUS_BATCH_DONE);
+ }
+ }
+ else
+ {
+ //
+ // Write the next byte to the data register.
+ //
+ MAP_I2CMasterDataPut(psInst->ui32Base,
+ pCommand->pui8WriteData[psInst->ui16Index]);
+ psInst->ui16Index++;
+
+ //
+ // Continue the burst write.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base, I2C_MASTER_CMD_BURST_SEND_CONT);
+
+ //
+ // If there is one byte left, set the next state to the final write
+ // state.
+ //
+ if((pCommand->ui16WriteCount - psInst->ui16Index) == 1)
+ {
+ psInst->ui8State = STATE_WRITE_FINAL;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function handles the write final state of the I2C master state machine.
+//
+//*****************************************************************************
+static void
+I2CMStateWriteFinal(tI2CMInstance *psInst, tI2CMCommand *pCommand)
+{
+ //
+ // See if the write batch has been sent.
+ //
+ if(psInst->ui16Index == pCommand->ui16WriteBatchSize)
+ {
+ //
+ // Move to the write pause state.
+ //
+ psInst->ui8State = STATE_WRITE_PAUSE;
+
+ //
+ // Call the callback function.
+ //
+ if(pCommand->pfnCallback)
+ {
+ pCommand->pfnCallback(pCommand->pvCallbackData,
+ I2CM_STATUS_BATCH_DONE);
+ }
+ }
+ else
+ {
+ //
+ // Write the final byte to the data register.
+ //
+ MAP_I2CMasterDataPut(psInst->ui32Base,
+ pCommand->pui8WriteData[psInst->ui16Index]);
+
+ //
+ // See if there is data to be read after this byte is written.
+ //
+ if(pCommand->ui16ReadCount == 0)
+ {
+ //
+ // Finish the burst write.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base,
+ I2C_MASTER_CMD_BURST_SEND_FINISH);
+
+ //
+ // The next state is the callback state.
+ //
+ psInst->ui8State = STATE_CALLBACK;
+ }
+ else
+ {
+ //
+ // Finish the burst write.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base,
+ I2C_MASTER_CMD_BURST_SEND_CONT);
+
+ //
+ // Set the next state of the interrupt state machine based on the
+ // number of bytes to read.
+ //
+ psInst->ui8State = ((pCommand->ui16ReadCount == 1) ?
+ STATE_READ_ONE : STATE_READ_FIRST);
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function handles the write pause state of the I2C master state machine.
+//
+//*****************************************************************************
+static void
+I2CMStateWritePause(tI2CMInstance *psInst, tI2CMCommand *pCommand)
+{
+ //
+ // Decrement the write count by the batch size.
+ //
+ pCommand->ui16WriteCount -= pCommand->ui16WriteBatchSize;
+
+ //
+ // Write the next byte to the data register.
+ //
+ MAP_I2CMasterDataPut(psInst->ui32Base, pCommand->pui8WriteData[0]);
+
+ //
+ // Set the index to indicate that the first byte has been transmitted.
+ //
+ psInst->ui16Index = 1;
+
+ //
+ // See if there is more than one byte left to be written.
+ //
+ if((pCommand->ui16WriteCount - psInst->ui16Index) == 0)
+ {
+ //
+ // See if there is data to be read after this byte is written.
+ //
+ if(pCommand->ui16ReadCount == 0)
+ {
+ //
+ // Finish the burst write.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base,
+ I2C_MASTER_CMD_BURST_SEND_FINISH);
+
+ //
+ // The next state is the callback state.
+ //
+ psInst->ui8State = STATE_CALLBACK;
+ }
+ else
+ {
+ //
+ // Finish the burst write.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base,
+ I2C_MASTER_CMD_BURST_SEND_CONT);
+
+ //
+ // Set the next state of the interrupt state machine based on the
+ // number of bytes to read.
+ //
+ psInst->ui8State = ((pCommand->ui16ReadCount == 1) ?
+ STATE_READ_ONE : STATE_READ_FIRST);
+ }
+ }
+ else
+ {
+ //
+ // Continue the burst write.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base, I2C_MASTER_CMD_BURST_SEND_CONT);
+
+ //
+ // The next state is the write next state.
+ //
+ if((pCommand->ui16WriteCount - psInst->ui16Index) == 1)
+ {
+ psInst->ui8State = STATE_WRITE_FINAL;
+ }
+ else
+ {
+ psInst->ui8State = STATE_WRITE_NEXT;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function handles the read one state of the I2C master state machine.
+//
+//*****************************************************************************
+static void
+I2CMStateReadOne(tI2CMInstance *psInst, tI2CMCommand *pCommand)
+{
+ //
+ // Put the I2C master into receive mode.
+ //
+ MAP_I2CMasterSlaveAddrSet(psInst->ui32Base, pCommand->ui8Addr, true);
+
+ //
+ // Perform a single byte read.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base, I2C_MASTER_CMD_SINGLE_RECEIVE);
+
+ //
+ // Set the index to indicate that the first byte is being read.
+ //
+ psInst->ui16Index = 0;
+
+ //
+ // The next state is the wait for final read state.
+ //
+ psInst->ui8State = STATE_READ_WAIT;
+}
+
+//*****************************************************************************
+//
+// This function handles the read first state of the I2C master state machine.
+//
+//*****************************************************************************
+static void
+I2CMStateReadFirst(tI2CMInstance *psInst, tI2CMCommand *pCommand)
+{
+ //
+ // Put the I2C master into receive mode.
+ //
+ MAP_I2CMasterSlaveAddrSet(psInst->ui32Base, pCommand->ui8Addr, true);
+
+ //
+ // Start the burst receive.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base, I2C_MASTER_CMD_BURST_RECEIVE_START);
+
+ //
+ // Set the index to indicate that the first byte is being read.
+ //
+ psInst->ui16Index = 0;
+
+ //
+ // Set the next state appropriately. If the count is greater than two it
+ // is the middle of the burst read. If exactly two, the next state must
+ // finish the transaction.
+ //
+ psInst->ui8State = ((pCommand->ui16ReadCount == 2) ?
+ STATE_READ_FINAL : STATE_READ_NEXT);
+}
+
+//*****************************************************************************
+//
+// This function handles the read next state of the I2C master state machine.
+//
+//*****************************************************************************
+static void
+I2CMStateReadNext(tI2CMInstance *psInst, tI2CMCommand *pCommand)
+{
+ //
+ // Read the received character.
+ //
+ pCommand->pui8ReadData[psInst->ui16Index] =
+ MAP_I2CMasterDataGet(psInst->ui32Base);
+ psInst->ui16Index++;
+
+ //
+ // See if the read batch has been filled.
+ //
+ if(psInst->ui16Index == pCommand->ui16ReadBatchSize)
+ {
+ //
+ // Move to the read pause state.
+ //
+ psInst->ui8State = STATE_READ_PAUSE;
+
+ //
+ // Call the callback function.
+ //
+ if(pCommand->pfnCallback)
+ {
+ pCommand->pfnCallback(pCommand->pvCallbackData,
+ I2CM_STATUS_BATCH_READY);
+ }
+ }
+ else
+ {
+ //
+ // Continue the burst read.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base,
+ I2C_MASTER_CMD_BURST_RECEIVE_CONT);
+
+ //
+ // If there are two characters left to be read, make the next state be
+ // the end of burst read state.
+ //
+ if((pCommand->ui16ReadCount - psInst->ui16Index) == 2)
+ {
+ psInst->ui8State = STATE_READ_FINAL;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function handles the read final state of the I2C master state machine.
+//
+//*****************************************************************************
+static void
+I2CMStateReadFinal(tI2CMInstance *psInst, tI2CMCommand *pCommand)
+{
+ //
+ // Read the received character.
+ //
+ pCommand->pui8ReadData[psInst->ui16Index] =
+ MAP_I2CMasterDataGet(psInst->ui32Base);
+ psInst->ui16Index++;
+
+ //
+ // See if the read batch has been filled.
+ //
+ if(psInst->ui16Index == pCommand->ui16ReadBatchSize)
+ {
+ //
+ // Move to the read pause state.
+ //
+ psInst->ui8State = STATE_READ_PAUSE;
+
+ //
+ // Call the callback function.
+ //
+ if(pCommand->pfnCallback)
+ {
+ pCommand->pfnCallback(pCommand->pvCallbackData,
+ I2CM_STATUS_BATCH_READY);
+ }
+ }
+ else
+ {
+ //
+ // Finish the burst read.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base,
+ I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
+
+ //
+ // The next state is the wait for final read state.
+ //
+ psInst->ui8State = STATE_READ_WAIT;
+ }
+}
+
+//*****************************************************************************
+//
+// This function handles the read pause state of the I2C master state machine.
+//
+//*****************************************************************************
+static void
+I2CMStateReadPause(tI2CMInstance *psInst, tI2CMCommand *pCommand)
+{
+ //
+ // Decrement the read count by the batch size.
+ //
+ pCommand->ui16ReadCount -= pCommand->ui16ReadBatchSize;
+
+ //
+ // Reset the read index.
+ //
+ psInst->ui16Index = 0;
+
+ //
+ // See if there is more than one byte left to be read.
+ //
+ if((pCommand->ui16ReadCount - psInst->ui16Index) == 1)
+ {
+ //
+ // Finish the burst read.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base,
+ I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
+
+ //
+ // The next state is the wait for final read state.
+ //
+ psInst->ui8State = STATE_READ_WAIT;
+ }
+ else
+ {
+ //
+ // Continue the burst read.
+ //
+ MAP_I2CMasterControl(psInst->ui32Base,
+ I2C_MASTER_CMD_BURST_RECEIVE_CONT);
+
+ //
+ // Determine the next state based on the number of bytes left to read.
+ //
+ if((pCommand->ui16ReadCount - psInst->ui16Index) == 2)
+ {
+ psInst->ui8State = STATE_READ_FINAL;
+ }
+ else
+ {
+ psInst->ui8State = STATE_READ_NEXT;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function handles the read wait state of the I2C master state machine.
+//
+//*****************************************************************************
+static void
+I2CMStateReadWait(tI2CMInstance *psInst, tI2CMCommand *pCommand)
+{
+ //
+ // Read the received character.
+ //
+ pCommand->pui8ReadData[psInst->ui16Index] =
+ MAP_I2CMasterDataGet(psInst->ui32Base);
+
+ //
+ // The state machine is now in the callback state.
+ //
+ psInst->ui8State = STATE_CALLBACK;
+}
+
+//*****************************************************************************
+//
+// This function handles the callback state of the I2C master state machine.
+//
+//*****************************************************************************
+static void
+I2CMStateCallback(tI2CMInstance *psInst, tI2CMCommand *pCommand,
+ uint32_t ui32Status)
+{
+ tSensorCallback *pfnCallback;
+ void *pvCallbackData;
+
+ //
+ // Save the callback information.
+ //
+ pfnCallback = pCommand->pfnCallback;
+ pvCallbackData = pCommand->pvCallbackData;
+
+ //
+ // This command has been completed, so increment the read pointer.
+ //
+ psInst->ui8ReadPtr++;
+ if(psInst->ui8ReadPtr == NUM_I2CM_COMMANDS)
+ {
+ psInst->ui8ReadPtr = 0;
+ }
+
+ //
+ // If there is a callback function then call it now.
+ //
+ if(pfnCallback)
+ {
+ //
+ // Convert the status from the I2C driver into the I2C master
+ // driver status.
+ //
+ if((ui32Status & (I2C_MCS_ARBLST | I2C_MCS_ERROR)) == 0)
+ {
+ ui32Status = I2CM_STATUS_SUCCESS;
+ }
+ else if(ui32Status & I2C_MCS_ARBLST)
+ {
+ ui32Status = I2CM_STATUS_ARB_LOST;
+ }
+ else if(ui32Status & I2C_MCS_ADRACK)
+ {
+ ui32Status = I2CM_STATUS_ADDR_NACK;
+ }
+ else if(ui32Status & I2C_MCS_DATACK)
+ {
+ ui32Status = I2CM_STATUS_DATA_NACK;
+ }
+ else
+ {
+ ui32Status = I2CM_STATUS_ERROR;
+ }
+
+ //
+ // Call the callback function.
+ //
+ pfnCallback(pvCallbackData, ui32Status);
+ }
+
+ //
+ // The state machine is now idle.
+ //
+ psInst->ui8State = STATE_IDLE;
+}
+
+//*****************************************************************************
+//
+//! Handles I2C master interrupts.
+//!
+//! \param psInst is a pointer to the I2C master instance data.
+//!
+//! This function performs the processing required in response to an I2C
+//! interrupt. The application-supplied interrupt handler should call this
+//! function with the correct instance data in response to the I2C interrupt.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+I2CMIntHandler(tI2CMInstance *psInst)
+{
+ tI2CMCommand *pCommand;
+ uint32_t ui32Status;
+
+ //
+ // Clear the I2C interrupt.
+ //
+ MAP_I2CMasterIntClear(psInst->ui32Base);
+ ui32Status = HWREG(psInst->ui32Base + I2C_O_MCS);
+
+ //
+ // Get a pointer to the current command.
+ //
+ pCommand = &(psInst->pCommands[psInst->ui8ReadPtr]);
+
+ //
+ // See if an error occurred during the last transaction.
+ //
+ if((ui32Status & (I2C_MCS_ERROR | I2C_MCS_ARBLST)) &&
+ (psInst->ui8State != STATE_IDLE))
+ {
+ //
+ // An error occurred, so halt the I2C transaction. The error stop
+ // command for send and receive is identical, so it does not matter
+ // which one is used here. Only issue the stop if the bus is busy.
+ //
+ if(ui32Status & I2C_MCS_BUSBSY)
+ {
+ MAP_I2CMasterControl(psInst->ui32Base,
+ I2C_MASTER_CMD_BURST_SEND_ERROR_STOP);
+ }
+
+ //
+ // Move to the callback state.
+ //
+ psInst->ui8State = STATE_CALLBACK;
+ }
+
+ //
+ // Loop forever. Most states will return when they have completed their
+ // action. However, a few states require multi-state processing, so those
+ // states will break and this loop repeated.
+ //
+ while(1)
+ {
+ //
+ // Determine what to do based on the current state.
+ //
+ switch(psInst->ui8State)
+ {
+ //
+ // The idle state.
+ //
+ case STATE_IDLE:
+ {
+ //
+ // Handle the idle state.
+ //
+ I2CMStateIdle(psInst, pCommand);
+
+ //
+ // This state is done and the next state should be handled at
+ // the next interrupt.
+ //
+ return;
+ }
+
+ //
+ // The state for the middle of a burst write.
+ //
+ case STATE_WRITE_NEXT:
+ {
+ //
+ // Handle the write next state.
+ //
+ I2CMStateWriteNext(psInst, pCommand);
+
+ //
+ // This state is done and the next state should be handled at
+ // the next interrupt.
+ //
+ return;
+ }
+
+ //
+ // The state for the final write of a burst sequence.
+ //
+ case STATE_WRITE_FINAL:
+ {
+ //
+ // Handle the write final state.
+ //
+ I2CMStateWriteFinal(psInst, pCommand);
+
+ //
+ // This state is done and the next state should be handled at
+ // the next interrupt.
+ //
+ return;
+ }
+
+ //
+ // The state for a paused write.
+ //
+ case STATE_WRITE_PAUSE:
+ {
+ //
+ // Handle the write pause state.
+ //
+ I2CMStateWritePause(psInst, pCommand);
+
+ //
+ // This state is done and the next state should be handled at
+ // the next interrupt.
+ //
+ return;
+ }
+
+ //
+ // The state for a single byte read.
+ //
+ case STATE_READ_ONE:
+ {
+ //
+ // Handle the read one state.
+ //
+ I2CMStateReadOne(psInst, pCommand);
+
+ //
+ // This state is done and the next state should be handled at
+ // the next interrupt.
+ //
+ return;
+ }
+
+ //
+ // The state for the start of a burst read.
+ //
+ case STATE_READ_FIRST:
+ {
+ //
+ // Handle the read first state.
+ //
+ I2CMStateReadFirst(psInst, pCommand);
+
+ //
+ // This state is done and the next state should be handled at
+ // the next interrupt.
+ //
+ return;
+ }
+
+ //
+ // The state for the middle of a burst read.
+ //
+ case STATE_READ_NEXT:
+ {
+ //
+ // Handle the read next state.
+ //
+ I2CMStateReadNext(psInst, pCommand);
+
+ //
+ // This state is done and the next state should be handled at
+ // the next interrupt.
+ //
+ return;
+ }
+
+ //
+ // The state for the end of a burst read.
+ //
+ case STATE_READ_FINAL:
+ {
+ //
+ // Handle the read final state.
+ //
+ I2CMStateReadFinal(psInst, pCommand);
+
+ //
+ // This state is done and the next state should be handled at
+ // the next interrupt.
+ //
+ return;
+ }
+
+ //
+ // The state for a paused read.
+ //
+ case STATE_READ_PAUSE:
+ {
+ //
+ // Handle the read pause state.
+ //
+ I2CMStateReadPause(psInst, pCommand);
+
+ //
+ // This state is done and the next state should be handled at
+ // the next interrupt.
+ //
+ return;
+ }
+
+ //
+ // This state is for the final read of a single or burst read.
+ //
+ case STATE_READ_WAIT:
+ {
+ //
+ // Handle the read wait state.
+ //
+ I2CMStateReadWait(psInst, pCommand);
+
+ //
+ // This state is done and the next state needs to be handled
+ // immediately.
+ //
+ break;
+ }
+
+ //
+ // This state is for providing the transaction complete callback.
+ //
+ case STATE_CALLBACK:
+ {
+ //
+ // Handle the callback state.
+ //
+ I2CMStateCallback(psInst, pCommand, ui32Status);
+
+ //
+ // If an error occurred, this state is done. The completion of
+ // the error handling stop condition above, if issued, will
+ // cause the next state to be processed.
+ //
+ if((ui32Status & (I2C_MCS_ERROR | I2C_MCS_ARBLST)) &&
+ (ui32Status & I2C_MCS_BUSBSY))
+ {
+ return;
+ }
+
+ //
+ // Update the pointer to the current command.
+ //
+ pCommand = &(psInst->pCommands[psInst->ui8ReadPtr]);
+
+ //
+ // This state is done and the next state needs to be handled
+ // immediately.
+ //
+ break;
+ }
+ }
+ }
+}
+
+//*****************************************************************************
+//
+//! Initializes the I2C master driver.
+//!
+//! \param psInst is a pointer to the I2C master instance data.
+//! \param ui32Base is the base address of the I2C module.
+//! \param ui8Int is the interrupt number for the I2C module.
+//! \param ui8TxDMA is the uDMA channel number used for transmitting data to
+//! the I2C module.
+//! \param ui8RxDMA is the uDMA channel number used for receiving data from
+//! the I2C module.
+//! \param ui32Clock is the clock frequency of the input clock to the I2C
+//! module.
+//!
+//! This function prepares both the I2C master module and driver for operation,
+//! and must be the first I2C master driver function called for each I2C master
+//! instance. It is assumed that the application has enabled the I2C module,
+//! configured the I2C pins, and provided an I2C interrupt handler that calls
+//! I2CMIntHandler().
+//!
+//! The uDMA module cannot be used at present to transmit/receive data, so the
+//! \e ui8TxDMA and \e ui8RxDMA parameters are unused. They are reserved for
+//! future use and should be set to 0xff in order to ensure future
+//! compatibility.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+I2CMInit(tI2CMInstance *psInst, uint32_t ui32Base, uint_fast8_t ui8Int,
+ uint_fast8_t ui8TxDMA, uint_fast8_t ui8RxDMA, uint32_t ui32Clock)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(psInst);
+ ASSERT((ui32Base == I2C0_BASE) || (ui32Base == I2C1_BASE) ||
+ (ui32Base == I2C2_BASE) || (ui32Base == I2C3_BASE) ||
+ (ui32Base == I2C4_BASE) || (ui32Base == I2C5_BASE) ||
+ (ui32Base == I2C6_BASE) || (ui32Base == I2C7_BASE) ||
+ (ui32Base == I2C8_BASE) || (ui32Base == I2C9_BASE));
+ ASSERT(ui8Int);
+ ASSERT(ui32Clock);
+
+ //
+ // Initialize the state structure.
+ //
+ psInst->ui32Base = ui32Base;
+ psInst->ui8Int = ui8Int;
+ psInst->ui8TxDMA = ui8TxDMA;
+ psInst->ui8RxDMA = ui8RxDMA;
+ psInst->ui8State = STATE_IDLE;
+ psInst->ui8ReadPtr = 0;
+ psInst->ui8WritePtr = 0;
+
+ //
+ // Initialize the I2C master module.
+ //
+ MAP_I2CMasterInitExpClk(ui32Base, ui32Clock, true);
+
+ //
+ // Enable the I2C interrupt.
+ //
+ MAP_IntEnable(ui8Int);
+ MAP_I2CMasterIntEnableEx(ui32Base, I2C_MASTER_INT_DATA);
+}
+
+//*****************************************************************************
+//
+//! Sends a command to an I2C device.
+//!
+//! \param psInst is a pointer to the I2C master instance data.
+//! \param ui8Addr is the address of the I2C device to access.
+//! \param pui8WriteData is a pointer to the data buffer to be written.
+//! \param ui16WriteCount is the number of bytes to be written.
+//! \param ui16WriteBatchSize is the number of bytes in each write batch.
+//! \param pui8ReadData is a pointer to the buffer to be filled with the read
+//! data.
+//! \param ui16ReadCount is the number of bytes to be read.
+//! \param ui16ReadBatchSize is the number of bytes to be read in each batch.
+//! \param pfnCallback is the function to be called when the transfer has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function adds an I2C command to the queue of commands to be sent. If
+//! successful, the I2C command is then transferred in the background using the
+//! interrupt handler. When the transfer is complete, the callback function,
+//! if provided, is called in the context of the I2C master interrupt handler.
+//!
+//! The first byte of \e pui8WriteData contains the I2C address of the device
+//! to access, the next \e ui16WriteCount bytes contains the data to be written
+//! to the device. The data read from the device is written into the first
+//! \e ui16ReadCount bytes of \e pui8ReadData. The \e ui16WriteCount or
+//! \e ui16ReadCount parameters can be zero if there are no bytes to be read or
+//! written. The write bytes are sent to the device first, and then the read
+//! bytes are read from the device afterward.
+//!
+//! If \e ui16WriteBatchSize is less than \e ui16WriteCount, the write portion
+//! of the transfer is broken up into as many \e ui16WriteBatchSize batches as
+//! required to write \e ui16WriteCount bytes. After each batch, the callback
+//! function is called with an \b I2CM_STATUS_BATCH_DONE status, and the
+//! transfer is paused (with the I2C bus held). The transfer is resumed when
+//! I2CMTransferResume() is called. This procedure can be used to perform very
+//! large writes without requiring all the data be available at once, at the
+//! expense of tying up the I2C bus for the extended duration of the transfer.
+//!
+//! If \e ui16ReadBatchSize is less than \e ui16ReadCount, the read portion of
+//! the transfer is broken up into as many \e ui16ReadBatchSize batches as
+//! required to read \e ui16ReadCount bytes. After each batch, the callback
+//! function is called with an \b I2CM_STATUS_BATCH_READY status, and the
+//! transfer is paused (with the I2C bus held). The transfer is resumed when
+//! I2CMTransferResume() is called. This procedure can be used to perform very
+//! large reads without requiring a large SRAM buffer, at the expense of tying
+//! up the I2C bus for the extended duration of the transfer.
+//!
+//! \return Returns 1 if the command was successfully added to the queue and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+I2CMCommand(tI2CMInstance *psInst, uint_fast8_t ui8Addr,
+ const uint8_t *pui8WriteData, uint_fast16_t ui16WriteCount,
+ uint_fast16_t ui16WriteBatchSize, uint8_t *pui8ReadData,
+ uint_fast16_t ui16ReadCount, uint_fast16_t ui16ReadBatchSize,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ uint_fast8_t ui8Next, ui8Enabled;
+ tI2CMCommand *pCommand;
+
+ //
+ // Check the arguments.
+ //
+ ASSERT(psInst);
+ ASSERT(pui8WriteData || !ui16WriteCount);
+ ASSERT(!ui16WriteCount || (ui16WriteBatchSize > 0));
+ ASSERT(pui8ReadData || !ui16ReadCount);
+ ASSERT(!ui16ReadCount || (ui16ReadBatchSize > 0));
+
+ //
+ // Disable the I2C interrupt.
+ //
+ if(MAP_IntIsEnabled(psInst->ui8Int))
+ {
+ ui8Enabled = 1;
+ MAP_IntDisable(psInst->ui8Int);
+ }
+ else
+ {
+ ui8Enabled = 0;
+ }
+
+ //
+ // Compute the new value of the write pointer (after this command is added
+ // to the queue).
+ //
+ ui8Next = psInst->ui8WritePtr + 1;
+ if(ui8Next == NUM_I2CM_COMMANDS)
+ {
+ ui8Next = 0;
+ }
+
+ //
+ // Return a failure if the command queue is full.
+ //
+ if(psInst->ui8ReadPtr == ui8Next)
+ {
+ if(ui8Enabled)
+ {
+ MAP_IntEnable(psInst->ui8Int);
+ }
+ return(0);
+ }
+
+ //
+ // Get a pointer to the command structure.
+ //
+ pCommand = &(psInst->pCommands[psInst->ui8WritePtr]);
+
+ //
+ // Fill in the command structure with the details of this command.
+ //
+ pCommand->ui8Addr = ui8Addr;
+ pCommand->pui8WriteData = pui8WriteData;
+ pCommand->ui16WriteCount = ui16WriteCount;
+ pCommand->ui16WriteBatchSize = ui16WriteBatchSize;
+ pCommand->pui8ReadData = pui8ReadData;
+ pCommand->ui16ReadCount = ui16ReadCount;
+ pCommand->ui16ReadBatchSize = ui16ReadBatchSize;
+ pCommand->pfnCallback = pfnCallback;
+ pCommand->pvCallbackData = pvCallbackData;
+
+ //
+ // Update the write pointer.
+ //
+ psInst->ui8WritePtr = ui8Next;
+
+ //
+ // See if the state machine is idle.
+ //
+ if(psInst->ui8State == STATE_IDLE)
+ {
+ //
+ // Generate a fake I2C interrupt, which will commence the I2C transfer.
+ //
+ IntTrigger(psInst->ui8Int);
+ }
+
+ //
+ // Re-enable the I2C master interrupt.
+ //
+ if(ui8Enabled)
+ {
+ MAP_IntEnable(psInst->ui8Int);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+//! Resumes an I2C transfer.
+//!
+//! \param psInst is a pointer to the I2C master instance data.
+//! \param pui8Data is a pointer to the buffer to be used for the next batch of
+//! data.
+//!
+//! This function resumes an I2C transfer that has been paused via the use of
+//! the write or read batch size capability.
+//!
+//! \return Returns 1 if the transfer was resumed and 0 if there was not a
+//! paused transfer to resume.
+//
+//*****************************************************************************
+uint_fast8_t
+I2CMTransferResume(tI2CMInstance *psInst, uint8_t *pui8Data)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(psInst);
+ ASSERT(pui8Data);
+
+ //
+ // Return an error if there is not a paused transfer.
+ //
+ if((psInst->ui8State != STATE_WRITE_PAUSE) &&
+ (psInst->ui8State != STATE_READ_PAUSE))
+ {
+ return(0);
+ }
+
+ //
+ // Save the pointer for the next buffer.
+ //
+ if(psInst->ui8State == STATE_WRITE_PAUSE)
+ {
+ psInst->pCommands[psInst->ui8ReadPtr].pui8WriteData = pui8Data;
+ }
+ else
+ {
+ psInst->pCommands[psInst->ui8ReadPtr].pui8ReadData = pui8Data;
+ }
+
+ //
+ // Trigger the I2C interrupt, resuming the transfer.
+ //
+ IntTrigger(psInst->ui8Int);
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+// The callback function that is called when I2C transactions as part of of a
+// read-modify-write operation of 8 bits of data have completed.
+//
+//*****************************************************************************
+static void
+I2CMReadModifyWrite8Callback(void *pvCallbackData, uint_fast8_t ui8Status)
+{
+ tI2CMReadModifyWrite8 *psInst;
+
+ //
+ // Convert the instance data into a pointer to a tI2CMReadModifyWrite8
+ // structure.
+ //
+ psInst = pvCallbackData;
+
+ //
+ // If the I2C master driver encountered a failure, force the state machine
+ // to the idle state (which will also result ina callback to propagate the
+ // error).
+ //
+ if(ui8Status != I2CM_STATUS_SUCCESS)
+ {
+ psInst->ui8State = I2CM_RMW_STATE_IDLE;
+ }
+
+ //
+ // Determine the current state of the I2C master read-modify-write state
+ // machine.
+ //
+ switch(psInst->ui8State)
+ {
+ //
+ // The read portion of the read-modify-write has completed.
+ //
+ case I2CM_RMW_STATE_READ:
+ {
+ //
+ // Modify the register data that was just read.
+ //
+ psInst->pui8Buffer[1] = ((psInst->pui8Buffer[1] &
+ psInst->ui8Mask) | psInst->ui8Value);
+
+ //
+ // Write the data back to the device.
+ //
+ I2CMWrite(psInst->psI2CInst, psInst->ui8Addr, psInst->pui8Buffer,
+ 2, I2CMReadModifyWrite8Callback, psInst);
+
+ //
+ // Move to the wait for write state.
+ //
+ psInst->ui8State = I2CM_RMW_STATE_WRITE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ //
+ // The write portion of the read-modify-write has completed.
+ //
+ case I2CM_RMW_STATE_WRITE:
+ {
+ //
+ // Move to the idle state.
+ //
+ psInst->ui8State = I2CM_RMW_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+ }
+
+ //
+ // See if the state machine is now idle and there is a callback function.
+ //
+ if((psInst->ui8State == I2CM_RMW_STATE_IDLE) && psInst->pfnCallback)
+ {
+ //
+ // Call the application-supplied callback function.
+ //
+ psInst->pfnCallback(psInst->pvCallbackData, ui8Status);
+ }
+}
+
+//*****************************************************************************
+//
+//! Performs a read-modify-write of 8 bits of data in an I2C device.
+//!
+//! \param psInst is a pointer to the read-modify-write instance data.
+//! \param psI2CInst is a pointer to the I2C master instance data.
+//! \param ui8Addr is the address of the I2C device to access.
+//! \param ui8Reg is the register in the I2C device to access.
+//! \param ui8Mask is the mask indicating the register bits that should be
+//! maintained.
+//! \param ui8Value is the value indicating the new value for the register bits
+//! that are not maintained.
+//! \param pfnCallback is the function to be called when the write has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initiates a read-modify-write transaction of 8 bits of data
+//! in an I2C device. The modify portion of the operation is performed by
+//! AND-ing the register value with \e ui8Mask and then OR-ing the result with
+//! \e ui8Value. When the read-modify-write is complete, the callback
+//! function, if provided, is called in the context of the I2C master interrupt
+//! handler.
+//!
+//! If the mask (in \e ui8Mask) is zero, then none of the bits in the current
+//! register value are maintained. In this case, the read portion of the
+//! read-modify-write is bypassed, and the new register value (in \e ui8Value)
+//! is directly written to the I2C device.
+//!
+//! \return Returns 1 if the command was successfully added to the queue and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+I2CMReadModifyWrite8(tI2CMReadModifyWrite8 *psInst, tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8Addr, uint_fast8_t ui8Reg,
+ uint_fast8_t ui8Mask, uint_fast8_t ui8Value,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(psInst);
+ ASSERT(psI2CInst);
+
+ //
+ // Fill in the read-modify-write structure with the details of this
+ // request.
+ //
+ psInst->psI2CInst = psI2CInst;
+ psInst->ui8Addr = ui8Addr;
+ psInst->ui8Mask = ui8Mask;
+ psInst->ui8Value = ui8Value;
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Construct the I2C command to access the requested register.
+ //
+ psInst->pui8Buffer[0] = ui8Reg;
+
+ //
+ // See if this is a write or a read-modify-write.
+ //
+ if(ui8Mask == 0)
+ {
+ //
+ // Set the state to waiting for the write portion of the
+ // read-modify-write.
+ //
+ psInst->ui8State = I2CM_RMW_STATE_WRITE;
+
+ //
+ // Set the new register value in the command buffer.
+ //
+ psInst->pui8Buffer[1] = ui8Value;
+
+ //
+ // Add the write command to the I2C master queue.
+ //
+ if(I2CMWrite(psI2CInst, ui8Addr, psInst->pui8Buffer, 2,
+ I2CMReadModifyWrite8Callback, psInst) == 0)
+ {
+ return(0);
+ }
+ }
+ else
+ {
+ //
+ // Set the state to waiting for the read portion of the
+ // read-modify-write.
+ //
+ psInst->ui8State = I2CM_RMW_STATE_READ;
+
+ //
+ // Add the read command to the I2C master queue.
+ //
+ if(I2CMRead(psI2CInst, ui8Addr, psInst->pui8Buffer, 1,
+ psInst->pui8Buffer + 1, 1, I2CMReadModifyWrite8Callback,
+ psInst) == 0)
+ {
+ return(0);
+ }
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+// The callback function that is called when I2C transactions as part of a
+// read-modify-write operation of 16 bits of little-endian data have completed.
+//
+//*****************************************************************************
+static void
+I2CMReadModifyWrite16LECallback(void *pvCallbackData, uint_fast8_t ui8Status)
+{
+ tI2CMReadModifyWrite16 *psInst;
+ uint16_t ui16Value;
+
+ //
+ // Convert the instance data into a pointer to a tI2CMReadModifyWrite16
+ // structure.
+ //
+ psInst = pvCallbackData;
+
+ //
+ // If the I2C master driver encountered a failure, force the state machine
+ // to the idle state (which will also result ina callback to propagate the
+ // error).
+ //
+ if(ui8Status != I2CM_STATUS_SUCCESS)
+ {
+ psInst->ui8State = I2CM_RMW_STATE_IDLE;
+ }
+
+ //
+ // Determine the current state of the I2C master read-modify-write state
+ // machine.
+ //
+ switch(psInst->ui8State)
+ {
+ //
+ // The read portion of the read-modify-write has completed.
+ //
+ case I2CM_RMW_STATE_READ:
+ {
+ //
+ // Modify the register data that was just read.
+ //
+ ui16Value = (psInst->pui8Buffer[2] << 8) | psInst->pui8Buffer[1];
+ ui16Value = (ui16Value & psInst->ui16Mask) | psInst->ui16Value;
+ psInst->pui8Buffer[1] = ui16Value & 0xff;
+ psInst->pui8Buffer[2] = (ui16Value >> 8) & 0xff;
+
+ //
+ // Write the data back to the device.
+ //
+ I2CMWrite(psInst->psI2CInst, psInst->ui8Addr, psInst->pui8Buffer,
+ 3, I2CMReadModifyWrite16LECallback, psInst);
+
+ //
+ // Move to the wait for write state.
+ //
+ psInst->ui8State = I2CM_RMW_STATE_WRITE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+
+ //
+ // The write portion of the read-modify-write has completed.
+ //
+ case I2CM_RMW_STATE_WRITE:
+ {
+ //
+ // Move to the idle state.
+ //
+ psInst->ui8State = I2CM_RMW_STATE_IDLE;
+
+ //
+ // Done.
+ //
+ break;
+ }
+ }
+
+ //
+ // See if the state machine is now idle and there is a callback function.
+ //
+ if((psInst->ui8State == I2CM_RMW_STATE_IDLE) && psInst->pfnCallback)
+ {
+ //
+ // Call the application-supplied callback function.
+ //
+ psInst->pfnCallback(psInst->pvCallbackData, ui8Status);
+ }
+}
+
+//*****************************************************************************
+//
+//! Performs a read-modify-write of 16 bits of little-endian data in an I2C
+//! device.
+//!
+//! \param psInst is a pointer to the read-modify-write instance data.
+//! \param psI2CInst is a pointer to the I2C master instance data.
+//! \param ui8Addr is the address of the I2C device to access.
+//! \param ui8Reg is the register in the I2C device to access.
+//! \param ui16Mask is the mask indicating the register bits that should be
+//! maintained.
+//! \param ui16Value is the value indicating the new value for the register
+//! bits that are not maintained.
+//! \param pfnCallback is the function to be called when the write has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initiates a read-modify-write transaction of 16 bits of
+//! little-endian data in an I2C device. The modify portion of the operation
+//! is performed by AND-ing the register value with \e ui16Mask and then OR-ing
+//! the result with \e ui16Value. When the read-modify-write is complete, the
+//! callback function, if provided, is called in the context of the I2C master
+//! interrupt handler.
+//!
+//! If the mask (in \e ui16Mask) is zero, then none of the bits in the current
+//! register value are maintained. In this case, the read portion of the
+//! read-modify-write is bypassed, and the new register value (in \e ui16Value)
+//! is directly written to the I2C device.
+//!
+//! \return Returns 1 if the command was successfully added to the queue and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+I2CMReadModifyWrite16LE(tI2CMReadModifyWrite16 *psInst,
+ tI2CMInstance *psI2CInst, uint_fast8_t ui8Addr,
+ uint_fast8_t ui8Reg, uint_fast16_t ui16Mask,
+ uint_fast16_t ui16Value, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(psInst);
+ ASSERT(psI2CInst);
+
+ //
+ // Fill in the read-modify-write structure with the details of this
+ // request.
+ //
+ psInst->psI2CInst = psI2CInst;
+ psInst->ui8Addr = ui8Addr;
+ psInst->ui16Mask = ui16Mask;
+ psInst->ui16Value = ui16Value;
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Construct the I2C command to access the requested register.
+ //
+ psInst->pui8Buffer[0] = ui8Reg;
+
+ //
+ // See if this is a write or a read-modify-write.
+ //
+ if(ui16Mask == 0)
+ {
+ //
+ // Set the state to waiting for the write portion of the
+ // read-modify-write.
+ //
+ psInst->ui8State = I2CM_RMW_STATE_WRITE;
+
+ //
+ // Set the new register value in the command buffer.
+ //
+ psInst->pui8Buffer[1] = ui16Value & 0xff;
+ psInst->pui8Buffer[2] = (ui16Value >> 8) & 0xff;
+
+ //
+ // Add the write command to the I2C master queue.
+ //
+ if(I2CMWrite(psI2CInst, ui8Addr, psInst->pui8Buffer, 3,
+ I2CMReadModifyWrite16LECallback, psInst) == 0)
+ {
+ return(0);
+ }
+ }
+ else
+ {
+ //
+ // Set the state to waiting for the read portion of the
+ // read-modify-write.
+ //
+ psInst->ui8State = I2CM_RMW_STATE_READ;
+
+ //
+ // Add the read command to the I2C master queue.
+ //
+ if(I2CMRead(psI2CInst, ui8Addr, psInst->pui8Buffer, 1,
+ psInst->pui8Buffer + 1, 2, I2CMReadModifyWrite16LECallback,
+ psInst) == 0)
+ {
+ return(0);
+ }
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+// The callback function that is called when I2C transactions as part of a
+// write operation of 8-bit data have completed.
+//
+//*****************************************************************************
+static void
+I2CMWrite8Callback(void *pvCallbackData, uint_fast8_t ui8Status)
+{
+ tI2CMWrite8 *psInst;
+
+ //
+ // Convert the instance data into a pointer to a tI2CMWrite8 structure.
+ //
+ psInst = pvCallbackData;
+
+ //
+ // See if the current batch is done and more data is needed.
+ //
+ if(ui8Status == I2CM_STATUS_BATCH_DONE)
+ {
+ //
+ // Place the next two bytes into the write buffer.
+ //
+ psInst->pui8Buffer[0] = psInst->pui8Data[0];
+ if(psInst->ui16Count > 1)
+ {
+ psInst->pui8Buffer[1] = psInst->pui8Data[1];
+ }
+
+ //
+ // Advance past the next two bytes of the input buffer.
+ //
+ psInst->pui8Data += 2;
+ psInst->ui16Count -= 2;
+
+ //
+ // Resume the batched write.
+ //
+ I2CMTransferResume(psInst->psI2CInst, psInst->pui8Buffer);
+ }
+
+ //
+ // The transfer has completed, or an error has occurred. In both cases,
+ // see if there is a callback function.
+ //
+ else if(psInst->pfnCallback)
+ {
+ //
+ // Call the application-supplied callback function.
+ //
+ psInst->pfnCallback(psInst->pvCallbackData, ui8Status);
+ }
+}
+
+//*****************************************************************************
+//
+//! Performs a write of 8-bit data to an I2C device.
+//!
+//! \param psInst is a pointer to the 8-bit write instance data.
+//! \param psI2CInst is a pointer to the I2C master instance data.
+//! \param ui8Addr is the address of the I2C device to access.
+//! \param ui8Reg is the register in the I2C device to access.
+//! \param pui8Data is a pointer to the register data to be written.
+//! \param ui16Count is the number of register values to be written.
+//! \param pfnCallback is the function to be called when the write has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initiates a write transaction of 8-bit data to an I2C device.
+//!
+//! \return Returns 1 if the command was successfully added to the queue and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+I2CMWrite8(tI2CMWrite8 *psInst, tI2CMInstance *psI2CInst, uint_fast8_t ui8Addr,
+ uint_fast8_t ui8Reg, const uint8_t *pui8Data,
+ uint_fast16_t ui16Count, tSensorCallback *pfnCallback,
+ void *pvCallbackData)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(psInst);
+ ASSERT(psI2CInst);
+
+ //
+ // Fill in the write structure with the details of this request.
+ //
+ psInst->psI2CInst = psI2CInst;
+ psInst->pui8Data = pui8Data + 1;
+ psInst->ui16Count = ui16Count - 1;
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Initiate the I2C write to this device.
+ //
+ psInst->pui8Buffer[0] = ui8Reg;
+ psInst->pui8Buffer[1] = pui8Data[0];
+ if(I2CMWriteBatched(psI2CInst, ui8Addr, psInst->pui8Buffer, ui16Count + 1,
+ 2, I2CMWrite8Callback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so return a failure.
+ //
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+// The callback function that is called when I2C transactions as part of a read
+// operation of 16-bit big-endian data have completed.
+//
+//*****************************************************************************
+static void
+I2CMRead16BECallback(void *pvCallbackData, uint_fast8_t ui8Status)
+{
+ tI2CMRead16BE *psInst;
+ uint8_t ui8Temp;
+
+ //
+ // Convert the instance data into a pointer to a tI2CMRead16BE structure.
+ //
+ psInst = pvCallbackData;
+
+ //
+ // See if the transaction completed successfully.
+ //
+ if(ui8Status == I2CM_STATUS_SUCCESS)
+ {
+ //
+ // Loop through the 16-bit values read from the I2C device.
+ //
+ while(psInst->ui16Count--)
+ {
+ //
+ // Byte swap this value.
+ //
+ ui8Temp = psInst->pui8Data[0];
+ psInst->pui8Data[0] = psInst->pui8Data[1];
+ psInst->pui8Data[1] = ui8Temp;
+
+ //
+ // Skip to the next value.
+ //
+ psInst->pui8Data += 2;
+ }
+ }
+
+ //
+ // See if there is a callback function.
+ //
+ if(psInst->pfnCallback)
+ {
+ //
+ // Call the application-supplied callback function.
+ //
+ psInst->pfnCallback(psInst->pvCallbackData, ui8Status);
+ }
+}
+
+//*****************************************************************************
+//
+//! Performs a read of 16-bit big-endian data from an I2C device.
+//!
+//! \param psInst is a pointer to the 16-bit big-endian read instance data.
+//! \param psI2CInst is a pointer to the I2C master instance data.
+//! \param ui8Addr is the address of the I2C device to access.
+//! \param ui8Reg is the register in the I2C device to access.
+//! \param pui16Data is a pointer to the buffer to be filled with the register
+//! data.
+//! \param ui16Count is the number of 16-bit register values to be read.
+//! \param pfnCallback is the function to be called when the read has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initiates a read transaction of 16-bit big-endian data from
+//! an I2C device. The data is provided by the device in big-endian format and
+//! is byte-swapped as it is read from the I2C device, returning the data in
+//! little-endian format.
+//!
+//! \return Returns 1 if the command was successfully added to the queue and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+I2CMRead16BE(tI2CMRead16BE *psInst, tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8Addr, uint_fast8_t ui8Reg,
+ uint16_t *pui16Data, uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(psInst);
+ ASSERT(psI2CInst);
+
+ //
+ // Fill in the read structure with the details of this request.
+ //
+ psInst->psI2CInst = psI2CInst;
+ psInst->pui8Data = (uint8_t *)pui16Data;
+ psInst->ui16Count = ui16Count;
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Initiate the I2C write to this device.
+ //
+ psInst->pui8Data[0] = ui8Reg;
+ if(I2CMRead(psI2CInst, ui8Addr, psInst->pui8Data, 1, psInst->pui8Data,
+ ui16Count * 2, I2CMRead16BECallback, psInst) == 0)
+ {
+ //
+ // The I2C write failed, so return a failure.
+ //
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+// The callback function that is called when I2C transactions as part of a
+// write operation of 16-bit big-endian data have completed.
+//
+//*****************************************************************************
+static void
+I2CMWrite16BECallback(void *pvCallbackData, uint_fast8_t ui8Status)
+{
+ tI2CMWrite16BE *psInst;
+
+ //
+ // Convert the instance data into a pointer to a tI2CMWrite16BE structure.
+ //
+ psInst = pvCallbackData;
+
+ //
+ // See if the current batch is done and more data is needed.
+ //
+ if(ui8Status == I2CM_STATUS_BATCH_DONE)
+ {
+ //
+ // Place the next two bytes into the write buffer.
+ //
+ psInst->pui8Buffer[0] = psInst->pui8Data[0];
+ if(psInst->ui16Count > 1)
+ {
+ psInst->pui8Buffer[1] = psInst->pui8Data[3];
+ }
+
+ //
+ // Advance past the next two bytes of the input buffer.
+ //
+ psInst->pui8Data += 2;
+ psInst->ui16Count--;
+
+ //
+ // Resume the batched write.
+ //
+ I2CMTransferResume(psInst->psI2CInst, psInst->pui8Buffer);
+ }
+
+ //
+ // The transfer has completed, or an error has occurred. In both cases,
+ // see if there is a callback function.
+ //
+ else if(psInst->pfnCallback)
+ {
+ //
+ // Call the application-supplied callback function.
+ //
+ psInst->pfnCallback(psInst->pvCallbackData, ui8Status);
+ }
+}
+
+//*****************************************************************************
+//
+//! Performs a write of 16-bit big-endian data to an I2C device.
+//!
+//! \param psInst is a pointer to the 16-bit big-endian write instance data.
+//! \param psI2CInst is a pointer to the I2C master instance data.
+//! \param ui8Addr is the address of the I2C device to access.
+//! \param ui8Reg is the register in the I2C device to access.
+//! \param pui16Data is a pointer to the register data to be written.
+//! \param ui16Count is the number of 16-bit register values to be written.
+//! \param pfnCallback is the function to be called when the write has
+//! completed (can be \b NULL if a callback is not required).
+//! \param pvCallbackData is a pointer that is passed to the callback function.
+//!
+//! This function initiates a write transaction of 16-bit big-endian data to an
+//! I2C device. The data in the buffer is provided in little-endian format and
+//! is byte-swapped as it is being written to the I2C device.
+//!
+//! \return Returns 1 if the command was successfully added to the queue and 0
+//! if it was not.
+//
+//*****************************************************************************
+uint_fast8_t
+I2CMWrite16BE(tI2CMWrite16BE *psInst, tI2CMInstance *psI2CInst,
+ uint_fast8_t ui8Addr, uint_fast8_t ui8Reg,
+ const uint16_t *pui16Data, uint_fast16_t ui16Count,
+ tSensorCallback *pfnCallback, void *pvCallbackData)
+{
+ //
+ // Check the arguments.
+ //
+ ASSERT(psInst);
+ ASSERT(psI2CInst);
+
+ //
+ // Fill in the write structure with the details of this request.
+ //
+ psInst->psI2CInst = psI2CInst;
+ psInst->pui8Data = (const uint8_t *)pui16Data;
+ psInst->ui16Count = ui16Count;
+ psInst->pfnCallback = pfnCallback;
+ psInst->pvCallbackData = pvCallbackData;
+
+ //
+ // Initiate the I2C write to this device.
+ //
+ psInst->pui8Buffer[0] = ui8Reg;
+ psInst->pui8Buffer[1] = psInst->pui8Data[1];
+ if(I2CMWriteBatched(psI2CInst, ui8Addr, psInst->pui8Buffer,
+ (ui16Count * 2) + 1, 2, I2CMWrite16BECallback,
+ psInst) == 0)
+ {
+ //
+ // The I2C write failed, so return a failure.
+ //
+ return(0);
+ }
+
+ //
+ // Success.
+ //
+ return(1);
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************