//***************************************************************************** // //! Initializes the TMP100 driver. //! //! \param psInst is a pointer to the TMP100 instance data. //! \param psI2CInst is a pointer to the I2C driver instance data. //! \param ui8I2CAddr is the I2C address of the TMP100 device. //! \param pfnCallback is the function to be called when the initialization 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 initializes the TMP100 driver, preparing it for operation, //! and initiates a reset of the TMP100 device, clearing any previous //! configuration data. //! //! \return Returns 1 if the TMP100 driver was successfully initialized and 0 //! if it was not. // //***************************************************************************** uint_fast8_t TMP100Init(tTMP100 *psInst, tI2CMInstance *psI2CInst, uint_fast8_t ui8I2CAddr, tSensorCallback *pfnCallback, void *pvCallbackData) { // // Initialize the TMP100 instance structure // psInst->psI2CInst = psI2CInst; psInst->ui8Addr = ui8I2CAddr; psInst->ui8State = TMP100_STATE_INIT; // // Save the callback information. // psInst->pfnCallback = pfnCallback; psInst->pvCallbackData = pvCallbackData; // // Write the configuration register to its default value. // psInst->pui8Data[0] = TMP100_O_CONFIG; psInst->pui8Data[1] = 0x00; // // Write the reset bit and issue a callback when finished. // if(I2CMWrite(psInst->psI2CInst, ui8I2CAddr, psInst->pui8Data, 2, TMP100Callback, psInst) == 0) { // // I2CMWrite failed so reset TMP100 state and return zero to indicate // failure. // psInst->ui8State = TMP100_STATE_IDLE; return(0); } // // Success // return(1); }
//***************************************************************************** // //! Initializes the SHT21 driver. //! //! \param psInst is a pointer to the SHT21 instance data. //! \param psI2CInst is a pointer to the I2C driver instance data. //! \param ui8I2CAddr is the I2C address of the SHT21 device. //! \param pfnCallback is the function to be called when the initialization 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 initializes the SHT21 driver, preparing it for operation, and //! initiates a reset of the SHT21 device, clearing any previous configuration //! data. //! //! \return Returns 1 if the SHT21 driver was successfully initialized and 0 if //! it was not. // //***************************************************************************** uint_fast8_t SHT21Init(tSHT21 *psInst, tI2CMInstance *psI2CInst, uint_fast8_t ui8I2CAddr, tSensorCallback *pfnCallback, void *pvCallbackData) { // // Initialize the SHT21 instance structure. // psInst->psI2CInst = psI2CInst; psInst->ui8Addr = ui8I2CAddr; psInst->ui8State = SHT21_STATE_INIT; // // Save the callback information. // psInst->pfnCallback = pfnCallback; psInst->pvCallbackData = pvCallbackData; // // Perform a soft reset of the SHT21. // psInst->pui8Data[0] = SHT21_CMD_SOFT_RESET; if(I2CMWrite(psInst->psI2CInst, ui8I2CAddr, psInst->pui8Data, 1, SHT21Callback, psInst) == 0) { // // The I2C write failed, so move to the idle state and return a // failure. // psInst->ui8State = SHT21_STATE_IDLE; return(0); } // // Success // return(1); }
//***************************************************************************** // // The callback function that is called when I2C transations to/from the // MPU9150 have completed. // //***************************************************************************** static void MPU9150Callback(void *pvCallbackData, uint_fast8_t ui8Status) { tMPU9150 *psInst; // // Convert the instance data into a pointer to a tMPU9150 structure. // psInst = pvCallbackData; // // If the I2C master driver encountered a failure, force the state machine // to the idle state (which will also result in a callback to propagate the // error). Except in the case that we are in the reset wait state and the // error is an address NACK. This error is handled by the reset wait // state. // if((ui8Status != I2CM_STATUS_SUCCESS) && !((ui8Status == I2CM_STATUS_ADDR_NACK) && (psInst->ui8State == MPU9150_STATE_INIT_RESET_WAIT))) { psInst->ui8State = MPU9150_STATE_IDLE; } // // Determine the current state of the MPU9150 state machine. // switch(psInst->ui8State) { // // All states that trivially transition to IDLE, and all unknown // states. // case MPU9150_STATE_READ: case MPU9150_STATE_LAST: case MPU9150_STATE_RD_DATA: default: { // // The state machine is now idle. // psInst->ui8State = MPU9150_STATE_IDLE; // // Done. // break; } // // MPU9150 Device reset was issued // case MPU9150_STATE_INIT_RESET: { // // Issue a read of the status register to confirm reset is done. // psInst->uCommand.pui8Buffer[0] = MPU9150_O_PWR_MGMT_1; I2CMRead(psInst->psI2CInst, psInst->ui8Addr, psInst->uCommand.pui8Buffer, 1, psInst->pui8Data, 1, MPU9150Callback, psInst); psInst->ui8State = MPU9150_STATE_INIT_RESET_WAIT; break; } // // Status register was read, check if reset is done before proceeding. // case MPU9150_STATE_INIT_RESET_WAIT: { // // Check the value read back from status to determine if device // is still in reset or if it is ready. Reset state for this // register is 0x40, which has sleep bit set. Device may also // respond with an address NACK during very early stages of the // its internal reset. Keep polling until we verify device is // ready. // if((psInst->pui8Data[0] != MPU9150_PWR_MGMT_1_SLEEP) || (ui8Status == I2CM_STATUS_ADDR_NACK)) { // // Device still in reset so begin polling this register. // psInst->uCommand.pui8Buffer[0] = MPU9150_O_PWR_MGMT_1; I2CMRead(psInst->psI2CInst, psInst->ui8Addr, psInst->uCommand.pui8Buffer, 1, psInst->pui8Data, 1, MPU9150Callback, psInst); // // Intentionally stay in this state to create polling effect. // } else { // // Device is out of reset, bring it out of sleep mode. // psInst->uCommand.pui8Buffer[0] = MPU9150_O_PWR_MGMT_1; psInst->uCommand.pui8Buffer[1] = MPU9150_PWR_MGMT_1_CLKSEL_XG; I2CMWrite(psInst->psI2CInst, psInst->ui8Addr, psInst->uCommand.pui8Buffer, 2, MPU9150Callback, psInst); // // Update state to show we are modifing user control and // power management 1 regs. // psInst->ui8State = MPU9150_STATE_INIT_PWR_MGMT; } break; } // // Reset complete now take device out of sleep mode. // case MPU9150_STATE_INIT_PWR_MGMT: { psInst->uCommand.pui8Buffer[0] = MPU9150_O_USER_CTRL; psInst->uCommand.pui8Buffer[1] = MPU9150_USER_CTRL_I2C_MST_EN; I2CMWrite(psInst->psI2CInst, psInst->ui8Addr, psInst->uCommand.pui8Buffer, 2, MPU9150Callback, psInst); // // Update state to show we are modifing user control and // power management 1 regs. // psInst->ui8State = MPU9150_STATE_INIT_USER_CTRL; break; } // // Change to power mode complete, device is ready for configuration. // case MPU9150_STATE_INIT_USER_CTRL: { // // Load index 0 with the sample rate register number. // psInst->uCommand.pui8Buffer[0] = MPU9150_O_SMPLRT_DIV; // // Set sample rate to 50 hertz. 1000 hz / (1 + 19) // psInst->uCommand.pui8Buffer[1] = 19; I2CMWrite(psInst->psI2CInst, psInst->ui8Addr, psInst->uCommand.pui8Buffer, 2, MPU9150Callback, psInst); // // update state to show are in process of configuring sensors. // psInst->ui8State = MPU9150_STATE_INIT_SAMPLE_RATE_CFG; break; } // // Sensor configuration is complete. // case MPU9150_STATE_INIT_SAMPLE_RATE_CFG: { // // Write the I2C Master delay control so we only sample the AK // every 5th time that we sample accel/gyro. Delay Count itself // handled in next state. // psInst->uCommand.pui8Buffer[0] = MPU9150_O_I2C_MST_DELAY_CTRL; psInst->uCommand.pui8Buffer[1] = (MPU9150_I2C_MST_DELAY_CTRL_I2C_SLV0_DLY_EN | MPU9150_I2C_MST_DELAY_CTRL_I2C_SLV4_DLY_EN); I2CMWrite(psInst->psI2CInst, psInst->ui8Addr, psInst->uCommand.pui8Buffer, 2, MPU9150Callback, psInst); // // Update state to show we are configuring i2c slave delay between // slave events. Slave 0 and Slave 4 transaction only occur every // 5th sample cycle. // psInst->ui8State = MPU9150_STATE_INIT_I2C_SLAVE_DLY; break; } // // Master slave delay configuration complete. // case MPU9150_STATE_INIT_I2C_SLAVE_DLY: { // // Write the configuration for I2C master control clock 400khz // and wait for external sensor before asserting data ready // psInst->uCommand.pui8Buffer[0] = MPU9150_O_I2C_MST_CTRL; psInst->uCommand.pui8Buffer[1] = (MPU9150_I2C_MST_CTRL_I2C_MST_CLK_400 | MPU9150_I2C_MST_CTRL_WAIT_FOR_ES); // // Configure I2C Slave 0 for read of AK8975 (I2C Address 0x0C) // Start at AK8975 register status 1 // Read 8 bytes and enable this slave transaction // psInst->uCommand.pui8Buffer[2] = MPU9150_I2C_SLV0_ADDR_RW | 0x0C; psInst->uCommand.pui8Buffer[3] = AK8975_O_ST1; psInst->uCommand.pui8Buffer[4] = MPU9150_I2C_SLV0_CTRL_EN | 0x08; I2CMWrite(psInst->psI2CInst, psInst->ui8Addr, psInst->uCommand.pui8Buffer, 5, MPU9150Callback, psInst); // // Update state. Now in process of configuring slave 0. // psInst->ui8State = MPU9150_STATE_INIT_I2C_SLAVE_0; break; } // // I2C slave 0 init complete. // case MPU9150_STATE_INIT_I2C_SLAVE_0: { // // Write the configuration for I2C Slave 4 transaction to AK8975 // 0x0c is the AK8975 address on i2c bus. // we want to write the control register with the value for a // starting a single measurement. // psInst->uCommand.pui8Buffer[0] = MPU9150_O_I2C_SLV4_ADDR; psInst->uCommand.pui8Buffer[1] = 0x0C; psInst->uCommand.pui8Buffer[2] = AK8975_O_CNTL; psInst->uCommand.pui8Buffer[3] = AK8975_CNTL_MODE_SINGLE; // // Enable the SLV4 transaction and set the master delay to // 0x04 + 1. This means the slave transactions with delay enabled // will run every fifth accel/gyro sample. // psInst->uCommand.pui8Buffer[4] = MPU9150_I2C_SLV4_CTRL_EN | 0x04; I2CMWrite(psInst->psI2CInst, psInst->ui8Addr, psInst->uCommand.pui8Buffer, 5, MPU9150Callback, psInst); // // Update state. Now in the final init state. // psInst->ui8State = MPU9150_STATE_LAST; break; } // // A write just completed // case MPU9150_STATE_WRITE: { // // Set the accelerometer and gyroscope ranges to the new values. // If the register was not modified, the values will be the same so // this has no effect. // psInst->ui8AccelAfsSel = psInst->ui8NewAccelAfsSel; psInst->ui8GyroFsSel = psInst->ui8NewGyroFsSel; // // The state machine is now idle. // psInst->ui8State = MPU9150_STATE_IDLE; // // Done. // break; } // // A read-modify-write just completed // case MPU9150_STATE_RMW: { // // See if the PWR_MGMT_1 register was just modified. // if(psInst->uCommand.sReadModifyWriteState.pui8Buffer[0] == MPU9150_O_PWR_MGMT_1) { // // See if a soft reset has been issued. // if(psInst->uCommand.sReadModifyWriteState.pui8Buffer[1] & MPU9150_PWR_MGMT_1_DEVICE_RESET) { // // Default range setting is +/- 2 g // psInst->ui8AccelAfsSel = 0; psInst->ui8NewAccelAfsSel = 0; // // Default range setting is +/- 250 degrees/s // psInst->ui8GyroFsSel = 0; psInst->ui8NewGyroFsSel = 0; } } // // See if the GYRO_CONFIG register was just modified. // if(psInst->uCommand.sReadModifyWriteState.pui8Buffer[0] == MPU9150_O_GYRO_CONFIG) { // // Extract the FS_SEL from the GYRO_CONFIG register value. // psInst->ui8GyroFsSel = ((psInst->uCommand.sReadModifyWriteState.pui8Buffer[1] & MPU9150_GYRO_CONFIG_FS_SEL_M) >> MPU9150_GYRO_CONFIG_FS_SEL_S); } // // See if the ACCEL_CONFIG register was just modified. // if(psInst->uCommand.sReadModifyWriteState.pui8Buffer[0] == MPU9150_O_ACCEL_CONFIG) { // // Extract the FS_SEL from the ACCEL_CONFIG register value. // psInst->ui8AccelAfsSel = ((psInst->uCommand.sReadModifyWriteState.pui8Buffer[1] & MPU9150_ACCEL_CONFIG_AFS_SEL_M) >> MPU9150_ACCEL_CONFIG_AFS_SEL_S); } // // The state machine is now idle. // psInst->ui8State = MPU9150_STATE_IDLE; // // Done. // break; }
//***************************************************************************** // // The callback function that is called when I2C transations to/from the // LSM303DLHC have completed. // //***************************************************************************** static void LSM303DLHCCallback(void *pvCallbackData, uint_fast8_t ui8Status) { tLSM303DLHCAccel *psInst; // // Convert the instance data into a pointer to a tLSM303DLHC structure. // psInst = pvCallbackData; // // If the I2C master driver encountered a failure, force the state machine // to the idle state (which will also result in a callback to propagate the // error). // if(ui8Status != I2CM_STATUS_SUCCESS) { psInst->ui8State = LSM303DLHC_STATE_IDLE; } // // Determine the current state of the LSM303DLHC state machine. // switch(psInst->ui8State) { // // All states that trivially transition to IDLE, and all unknown // states. // case LSM303DLHC_STATE_READ: default: { // // The state machine is now idle. // psInst->ui8State = LSM303DLHC_STATE_IDLE; // // Done. // break; } case LSM303DLHC_STATE_INIT: { psInst->ui8State = LSM303DLHC_STATE_IDLE; I2CMWrite(psInst->psI2CInst, psInst->ui8Addr, g_pui8ZeroFifoCtl, 14, LSM303DLHCCallback, pvCallbackData); // // Done. // break; } // // A write just completed // case LSM303DLHC_STATE_WRITE: { // // Set the accelerometer ranges to the new values. If the register // was not modified, the values will be the same so this has no // effect. // psInst->ui8AccelAfsSel = psInst->ui8NewAccelAfsSel; // // The state machine is now idle. // psInst->ui8State = LSM303DLHC_STATE_IDLE; // // Done. // break; } // // A read-modify-write just completed // case LSM303DLHC_STATE_RMW: { // // See if the ACCEL_CONFIG register was just modified. // if(psInst->uCommand.sReadModifyWriteState.pui8Buffer[0] == LSM303DLHC_O_CTRL4) { // // Extract the FS_SEL from the ACCEL_CONFIG register value. // psInst->ui8AccelAfsSel = ((psInst->uCommand.sReadModifyWriteState.pui8Buffer[1] & LSM303DLHC_CTRL4_FS_M) >> LSM303DLHC_CTRL4_FS_S); } // // The state machine is now idle. // psInst->ui8State = LSM303DLHC_STATE_IDLE; // // Done. // break; } }
//***************************************************************************** // // The callback function that is called when I2C transations to/from the KXTI9 // have completed. // //***************************************************************************** static void KXTI9Callback(void *pvCallbackData, uint_fast8_t ui8Status) { tKXTI9 *psInst; // // Convert the instance data into a pointer to a tKXTI9 structure. // psInst = pvCallbackData; // // If the I2C master driver encountered a failure, force the state machine // to the idle state (which will also result in a callback to propagate the // error). // if((ui8Status != I2CM_STATUS_SUCCESS) && (psInst->ui8State != KXTI9_STATE_INIT_WAIT)) { psInst->ui8State = KXTI9_STATE_IDLE; } // // Determine the current state of the KXTI9 state machine. // switch(psInst->ui8State) { // // All states that trivially transition to IDLE, and all unknown // states. // case KXTI9_STATE_LAST: case KXTI9_STATE_READ: default: { // // The state machine is now idle. // psInst->ui8State = KXTI9_STATE_IDLE; // // Done. // break; } case KXTI9_STATE_INIT_RES: { // // Try to read back to determine if reset is done. We expect to see // a NAK. // psInst->uCommand.pui8Buffer[0] = KXTI9_O_CTRL3; I2CMRead(psInst->psI2CInst, psInst->ui8Addr, psInst->uCommand.pui8Buffer, 1, psInst->pui8Data, 1, KXTI9Callback, psInst); psInst->ui8State = KXTI9_STATE_INIT_WAIT; break; } case KXTI9_STATE_INIT_WAIT: { // // Check to see if there was finally an ACK. // if(ui8Status != I2CM_STATUS_SUCCESS) { // // Read again. // psInst->uCommand.pui8Buffer[0] = KXTI9_O_CTRL3; I2CMRead(psInst->psI2CInst, psInst->ui8Addr, psInst->uCommand.pui8Buffer, 1, psInst->pui8Data, 1, KXTI9Callback, psInst); } else { // // Check the read data to make sure it jibes. // if(psInst->pui8Data[0] == 0x4d) { // // Device is out of reset, enable the device. // psInst->uCommand.pui8Buffer[0] = KXTI9_O_CTRL1; psInst->uCommand.pui8Buffer[1] = KXTI9_CTRL1_PC1; I2CMWrite(psInst->psI2CInst, psInst->ui8Addr, psInst->uCommand.pui8Buffer, 2, KXTI9Callback, psInst); } else { ui8Status = I2CM_STATUS_ERROR; } // // This is the last init write. // psInst->ui8State = KXTI9_STATE_LAST; } break; } case KXTI9_STATE_WRITE: { // // Set the accelerometer range and resolution to the new value. // If the register was not modified, the values will be the same so // this has no effect. // psInst->ui8Resolution = psInst->ui8NewResolution; psInst->ui8Range = psInst->ui8NewRange; // // The state machine is now idle. // psInst->ui8State = KXTI9_STATE_IDLE; break; } case KXTI9_STATE_RMW: { // // See if the CTRL3 register was just modified. // if(psInst->uCommand.sReadModifyWriteState.pui8Buffer[0] == KXTI9_O_CTRL3) { // // See if a soft reset has been issued. // if(psInst->uCommand.sReadModifyWriteState.pui8Buffer[1] & KXTI9_CTRL3_SRST) { // // Default range setting is +/- 2 g // psInst->ui8Range = 0; psInst->ui8NewRange = 0; // // Default resolution is 8-bit. // psInst->ui8Resolution = 0; psInst->ui8NewResolution = 0; } } // // See if the CTRL1 register was just modified. // if(psInst->uCommand.sReadModifyWriteState.pui8Buffer[0] == KXTI9_O_CTRL1) { // // Extract the range and resolution from the register value. // psInst->ui8Range = ((psInst->uCommand.sReadModifyWriteState.pui8Buffer[1] & KXTI9_CTRL1_GSEL_M) >> KXTI9_CTRL1_GSEL_S); psInst->ui8Resolution = ((psInst->uCommand.sReadModifyWriteState.pui8Buffer[1] & KXTI9_CTRL1_RES) >> 6); } // // The state machine is now idle. // psInst->ui8State = KXTI9_STATE_IDLE; break; } }
//***************************************************************************** // //! Writes data to TMP100 registers. //! //! \param psInst is a pointer to the TMP100 instance data. //! \param ui8Reg is the first register to write. //! \param pui16Data is a pointer to the 16-bit register data to write. //! \param ui16Count is the number of 16-bit registers to write. //! \param pfnCallback is the function to be called when the data has been //! written (can be \b NULL if a callback is not required). //! \param pvCallbackData is a pointer that is passed to the callback function. //! //! This function writes a sequence of data values to consecutive registers in //! the TMP100. The first value in the \e pui16Data buffer contains the data //! to be written into the \e ui8Reg register, the second value contains the //! data to be written into the next register, and so on. //! //! \note The TMP100 does not auto-increment the register pointer, so writes of //! more than one register are rejected by the TMP100. //! //! \return Returns 1 if the write was successfully started and 0 if it was //! not. // //***************************************************************************** uint_fast8_t TMP100Write(tTMP100 *psInst, uint_fast8_t ui8Reg, const uint16_t *pui16Data, uint_fast16_t ui16Count, tSensorCallback *pfnCallback, void *pvCallbackData) { // // Return a failure if the TMP100 driver is not idle (in other words, there // is already an outstanding request to the TMP100). // if(psInst->ui8State != TMP100_STATE_IDLE) { return(0); } // // Save the callback information. // psInst->pfnCallback = pfnCallback; psInst->pvCallbackData = pvCallbackData; // // Move the state machine to the wait for write state. // psInst->ui8State = TMP100_STATE_WRITE; // // Write the requested registers to the TMP100. // if(ui8Reg == TMP100_O_CONFIG) { // // The configuration register is only one byte, so only a single byte // write is necessary and no endian swapping is required. // psInst->uCommand.pui8Buffer[0] = ui8Reg; psInst->uCommand.pui8Buffer[1] = *pui16Data & 0xff; if(I2CMWrite(psInst->psI2CInst, psInst->ui8Addr, psInst->uCommand.pui8Buffer, 2, TMP100Callback, psInst) == 0) { // // The I2C write failed, so move to the idle state and return a // failure. // psInst->ui8State = TMP100_STATE_IDLE; return(0); } } else { // // This is one of the temperature registers, which are 16-bit // big-endian registers. // if(I2CMWrite16BE(&(psInst->uCommand.sWriteState), psInst->psI2CInst, psInst->ui8Addr, ui8Reg, pui16Data, ui16Count, TMP100Callback, psInst) == 0) { // // The I2C write failed, so move to the idle state and return a // failure. // psInst->ui8State = TMP100_STATE_IDLE; return(0); } } // // Success. // return(1); }