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