// * imu_i2c_start_transaction ************************************************ // * Start a receive/send' from LM4F to I2C slave device. * // * dev_address should be a 7b right justified number * // * done_callback Will be called when txn done, argument of # bytes remain, * // * if # bytes remain nonzero, an error occured. * // * Returns 0 for success, 1 for bus busy (send could not be started now). * // * * // * Portions for initialization of softi2c library copied/modified from * // * "soft_i2c_atmel.c" example code. * // **************************************************************************** unsigned char imu_i2c_start_transaction(unsigned char dev_address, unsigned char reg_address, unsigned char* data, unsigned int data_byte_count, tBoolean dir_is_receive, imu_i2c_xfer_done_t done_callback) { if(data_byte_count == 0 || data == 0 || done_callback == 0) { // no data to send or no place to take it from return IMU_RET_INVALID_ARGS; // invalid argument(s) } else if(SoftI2CBusy(&g_sI2C)) // if bus busy { return IMU_RET_BUSY; // return bus busy } xfer_done_cb = done_callback; // store callback function pointer imu_i2c_dev_address = dev_address; // store copy of device address for use in interrupt handler imu_i2c_reg_address = reg_address; // store register address SoftI2CSlaveAddrSet(&g_sI2C, dev_address, false); // set the slave address, always transmit first to get register address transmitted imu_i2c_dir_is_receive = dir_is_receive; // make copy of current direction imu_i2c_data_buff = data; // initialize buffer pointer imu_i2c_data_byte_count = data_byte_count; // initialize data byte count - will downcount during send imu_i2c_int_en(); // enable 'interrupts' (callbacks) for I2C imu_i2c_is_addressing = true; // first interrupt will be to finish register addressing stage imu_i2c_in_progress = true; // transaction is currently taking place imu_i2c_is_multibyte = false; // default to single byte if(data_byte_count > 1) { imu_i2c_reg_address |= 0x80; // turn msb on to indicate sequential read to chip imu_i2c_is_multibyte = true; // multi byte txn } // start txn with address and send register address SoftI2CDataPut(&g_sI2C, imu_i2c_reg_address); // load register address as data SoftI2CControl(&g_sI2C, SOFTI2C_CMD_BURST_SEND_START); // instruct softi2c to generate start, send dev address, and 'data' (register address in part) return IMU_RET_SUCCESS; // successfully started transfer of register address! // now we will wait for interrupt to see what happened }
//***************************************************************************** // // Read from the Atmel device. // //***************************************************************************** void AtmelRead(unsigned char *pucData, unsigned long ulOffset, unsigned long ulCount) { // // Save the data buffer to be read. // g_pucData = pucData; g_ulCount = ulCount; // // Set the next state of the callback state machine based on the number of // bytes to read. // if(ulCount == 1) { g_ulState = STATE_READ_ONE; } else { g_ulState = STATE_READ_FIRST; } // // Start with a dummy write to get the address set in the EEPROM. // SoftI2CSlaveAddrSet(&g_sI2C, SLAVE_ADDR | (ulOffset >> 8), false); // // Write the address to be written as the first data byte. // SoftI2CDataPut(&g_sI2C, ulOffset); // // Perform a single send, writing the address as the only byte. // SoftI2CControl(&g_sI2C, SOFTI2C_CMD_SINGLE_SEND); // // Wait until the SoftI2C callback state machine is idle. // while(g_ulState != STATE_IDLE) { } }
//***************************************************************************** // // Write to the Atmel device. // //***************************************************************************** void AtmelWrite(unsigned char *pucData, unsigned long ulOffset, unsigned long ulCount) { // // Save the data buffer to be written. // g_pucData = pucData; g_ulCount = ulCount; // // Set the next state of the callback state machine based on the number of // bytes to write. // if(ulCount != 1) { g_ulState = STATE_WRITE_NEXT; } else { g_ulState = STATE_WRITE_FINAL; } // // Set the slave address and setup for a transmit operation. // SoftI2CSlaveAddrSet(&g_sI2C, SLAVE_ADDR | (ulOffset >> 8), false); // // Write the address to be written as the first data byte. // SoftI2CDataPut(&g_sI2C, ulOffset); // // Start the burst cycle, writing the address as the first byte. // SoftI2CControl(&g_sI2C, SOFTI2C_CMD_BURST_SEND_START); // // Wait until the SoftI2C callback state machine is idle. // while(g_ulState != STATE_IDLE) { } }
//***************************************************************************** // // The callback function for the SoftI2C module. // //***************************************************************************** void SoftI2CCallback(void) { // // Clear the SoftI2C interrupt. // SoftI2CIntClear(&g_sI2C); // // Determine what to do based on the current state. // switch(g_ui32State) { // // The idle state. // case STATE_IDLE: { // // There is nothing to be done. // break; } // // The state for the middle of a burst write. // case STATE_WRITE_NEXT: { // // Write the next data byte. // SoftI2CDataPut(&g_sI2C, *g_pui8Data++); g_ui32Count--; // // Continue the burst write. // SoftI2CControl(&g_sI2C, SOFTI2C_CMD_BURST_SEND_CONT); // // If there is one byte left, set the next state to the final write // state. // if(g_ui32Count == 1) { g_ui32State = STATE_WRITE_FINAL; } // // This state is done. // break; } // // The state for the final write of a burst sequence. // case STATE_WRITE_FINAL: { // // Write the final data byte. // SoftI2CDataPut(&g_sI2C, *g_pui8Data++); g_ui32Count--; // // Finish the burst write. // SoftI2CControl(&g_sI2C, SOFTI2C_CMD_BURST_SEND_FINISH); // // The next state is to wait for the burst write to complete. // g_ui32State = STATE_SEND_ACK; // // This state is done. // break; } // // Wait for an ACK on the read after a write. // case STATE_WAIT_ACK: { // // See if there was an error on the previously issued read. // if(SoftI2CErr(&g_sI2C) == SOFTI2C_ERR_NONE) { // // Read the byte received. // SoftI2CDataGet(&g_sI2C); // // There was no error, so the state machine is now idle. // g_ui32State = STATE_IDLE; // // This state is done. // break; } // // Fall through to STATE_SEND_ACK. // } // // Send a read request, looking for the ACK to indicate that the write // is done. // case STATE_SEND_ACK: { // // Put the I2C master into receive mode. // SoftI2CSlaveAddrSet(&g_sI2C, SLAVE_ADDR, true); // // Perform a single byte read. // SoftI2CControl(&g_sI2C, SOFTI2C_CMD_SINGLE_RECEIVE); // // The next state is the wait for the ack. // g_ui32State = STATE_WAIT_ACK; // // This state is done. // break; } // // The state for a single byte read. // case STATE_READ_ONE: { // // Put the SoftI2C module into receive mode. // SoftI2CSlaveAddrSet(&g_sI2C, SLAVE_ADDR, true); // // Perform a single byte read. // SoftI2CControl(&g_sI2C, SOFTI2C_CMD_SINGLE_RECEIVE); // // The next state is the wait for final read state. // g_ui32State = STATE_READ_WAIT; // // This state is done. // break; } // // The state for the start of a burst read. // case STATE_READ_FIRST: { // // Put the SoftI2C module into receive mode. // SoftI2CSlaveAddrSet(&g_sI2C, SLAVE_ADDR, true); // // Start the burst receive. // SoftI2CControl(&g_sI2C, SOFTI2C_CMD_BURST_RECEIVE_START); // // The next state is the middle of the burst read. // g_ui32State = STATE_READ_NEXT; // // This state is done. // break; } // // The state for the middle of a burst read. // case STATE_READ_NEXT: { // // Read the received character. // *g_pui8Data++ = SoftI2CDataGet(&g_sI2C); g_ui32Count--; // // Continue the burst read. // SoftI2CControl(&g_sI2C, SOFTI2C_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(g_ui32Count == 2) { g_ui32State = STATE_READ_FINAL; } // // This state is done. // break; } // // The state for the end of a burst read. // case STATE_READ_FINAL: { // // Read the received character. // *g_pui8Data++ = SoftI2CDataGet(&g_sI2C); g_ui32Count--; // // Finish the burst read. // SoftI2CControl(&g_sI2C, SOFTI2C_CMD_BURST_RECEIVE_FINISH); // // The next state is the wait for final read state. // g_ui32State = STATE_READ_WAIT; // // This state is done. // break; } // // This state is for the final read of a single or burst read. // case STATE_READ_WAIT: { // // Read the received character. // *g_pui8Data++ = SoftI2CDataGet(&g_sI2C); g_ui32Count--; // // The state machine is now idle. // g_ui32State = STATE_IDLE; // // This state is done. // break; } } }
// * imu_SoftI2CCallback ****************************************************** // * Callback function for soft I2C driver to give us an event. * // * * // * Portions for initialization of softi2c library copied/modified from * // * "soft_i2c_atmel.c" example code. * // **************************************************************************** void imu_SoftI2CCallback(void) { unsigned long errcode; // holds error code SoftI2CIntClear(&g_sI2C); // clear softi2c callback if(!imu_i2c_in_progress) // we shouldn't be here { imu_i2c_int_dis(); // try to make sure we don't spuriously get back here again return; } errcode = SoftI2CErr(&g_sI2C); // grab error code from softi2c if(errcode != SOFTI2C_ERR_NONE) // if error { // could be address nak or data nak imu_i2c_abort_transaction(); // abort current transaction } else if(imu_i2c_is_addressing) // first time here, addressing phase done, now ready for data phase { imu_i2c_is_addressing = false; // handled. clear flag. if(imu_i2c_dir_is_receive) // data is to be received, need to turn direction around then start data phase { SoftI2CSlaveAddrSet(&g_sI2C, imu_i2c_dev_address, imu_i2c_dir_is_receive); // update R/S' if(imu_i2c_is_multibyte == false) // single byte SoftI2CControl(&g_sI2C, SOFTI2C_CMD_SINGLE_RECEIVE); // receive a single byte (START, TRANSMIT, STOP) else // byte stream (>1 bytes) { SoftI2CControl(&g_sI2C, SOFTI2C_CMD_BURST_RECEIVE_START); // start a multi byte receive cycle (START, TRANSMIT...) // (receives first byte as well) } } else // data is to be sent, already in correct direction, can continue with data phase { SoftI2CDataPut(&g_sI2C, *imu_i2c_data_buff); // load first data byte if(imu_i2c_is_multibyte == false) // single byte SoftI2CControl(&g_sI2C, SOFTI2C_CMD_BURST_SEND_FINISH); // single byte send cycle ((already started) TRANSMIT, STOP) else // byte stream (>1 bytes) { SoftI2CControl(&g_sI2C, SOFTI2C_CMD_BURST_SEND_CONT); // continue a multi byte send cycle ((already started) TRANSMIT...) // (sends first byte as well) } } } else // no error, transaction completed successfully, continuing with data after addressing { if(imu_i2c_dir_is_receive) // received a byte { *imu_i2c_data_buff = (unsigned char)SoftI2CDataGet(&g_sI2C); // grab byte from data register imu_i2c_data_buff++; // prepare for next byte imu_i2c_data_byte_count--; // another byte received if(imu_i2c_is_multibyte) // multibyte transaction { if(imu_i2c_data_byte_count == 1) // 1 Byte remaining { SoftI2CControl(&g_sI2C, SOFTI2C_CMD_BURST_RECEIVE_FINISH); // receive one more byte } else if(imu_i2c_data_byte_count == 0) // transfer complete { imu_i2c_complete_transaction(); // complete current transaction } else // more bytes to go { SoftI2CControl(&g_sI2C, SOFTI2C_CMD_BURST_RECEIVE_CONT); // receive next byte } } else // single byte transaction { imu_i2c_complete_transaction(); // complete current transaction } } else // sent a byte { imu_i2c_data_buff++; // prepare to send next byte imu_i2c_data_byte_count--; // another byte sent if(imu_i2c_is_multibyte) // multibyte transaction { if(imu_i2c_data_byte_count > 0) // more byte(s) to go { SoftI2CDataPut(&g_sI2C, *imu_i2c_data_buff); // load next data byte to register if(imu_i2c_data_byte_count == 1) // one more byte to go { SoftI2CControl(&g_sI2C, SOFTI2C_CMD_BURST_SEND_FINISH); // send last byte and stop } else // more than one byte remaining { SoftI2CControl(&g_sI2C, SOFTI2C_CMD_BURST_SEND_CONT); // send next byte and remain in send state } } else // transfer complete { imu_i2c_complete_transaction(); // complete current transaction } } else // single byte transaction { imu_i2c_complete_transaction(); // complete current transaction } } } }