//! Combined i2c send+receive format status_t i2c_send_receive(const i2c_bus *bus, int slaveAddress, const uint8 *writeBuffer, size_t writeLength, uint8 *readBuffer, size_t readLength) { status_t status = send_start_condition(bus); if (status != B_OK) return status; status = send_slave_address(bus, slaveAddress, true); if (status != B_OK) goto err; status = send_bytes(bus, writeBuffer, writeLength); if (status != B_OK) goto err; status = send_start_condition(bus); if (status != B_OK) return status; status = send_slave_address(bus, slaveAddress, false); if (status != B_OK) goto err; status = receive_bytes(bus, readBuffer, readLength); if (status != B_OK) goto err; return send_stop_condition(bus); err: TRACE("%s: Cancelling transmission\n", __func__); send_stop_condition(bus); return status; }
static void handle_tw_status(struct twi_transfer *xfer, uint8_t twstat) { uint8_t *buffer = xfer->buffer; switch (twstat) { default: stop_transfer(xfer, TWI_STAT_BUSERROR); break; case TW_START: case TW_REP_START: if (xfer->status & TWI_XFER_READ) TWDR = (xfer->address << 1) | 1; else TWDR = (xfer->address << 1); TWCR_write(1 << TWIE); break; case TW_MT_DATA_ACK: case TW_MR_DATA_ACK: case TW_MR_DATA_NACK: case TW_MT_SLA_ACK: if (xfer->status & TWI_XFER_READ) { buffer[xfer->offset++] = TWDR; if (xfer->offset == xfer->read_size) { stop_transfer(xfer, TWI_STAT_FINISHED); } else { if (xfer->offset + 1 == xfer->read_size) TWCR_write(1 << TWIE); else TWCR_write((1 << TWIE) | (1 << TWEA)); } } else { if (xfer->offset == xfer->write_size) { if (xfer->read_size) { xfer->status |= TWI_XFER_READ; xfer->offset = 0; send_start_condition(); } else stop_transfer(xfer, TWI_STAT_FINISHED); } else { TWDR = buffer[xfer->offset++]; TWCR_write(1 << TWIE); } } break; case TW_MR_SLA_ACK: if (xfer->offset + 1 == xfer->read_size) TWCR_write(1 << TWIE); else TWCR_write((1 << TWIE) | (1 << TWEA)); break; } }
void twi_transfer(struct twi_transfer *xfer) { #ifdef TWI_SYNC twi_size_t i; uint8_t *buffer = xfer->buffer; if (xfer->write_size) { i2c_start(xfer->address << 1); for (i = 0; i < xfer->write_size; i++) i2c_write(buffer[i]); if (!xfer->read_size) i2c_stop(); } if (xfer->read_size) { i2c_start((xfer->address << 1) | 1); for (i = 0; i < xfer->read_size; i++) { if (i + 1 == xfer->read_size) buffer[i] = i2c_readNak(); else buffer[i] = i2c_readAck(); } i2c_stop(); } if (xfer->callback) xfer->callback(xfer, TWI_STAT_FINISHED); #else /* TWI_SYNC */ uint8_t sreg; xfer->offset = 0; xfer->next = NULL; xfer->status = 0; if (!xfer->write_size) xfer->status |= TWI_XFER_READ; transfer_set_status(xfer, TWI_STAT_INPROGRESS); sreg = irq_disable_save(); if (twi.last_xfer) twi.last_xfer->next = xfer; twi.last_xfer = xfer; if (!twi.first_xfer) { twi.first_xfer = xfer; send_start_condition(); } irq_restore(sreg); #endif }
static void stop_transfer(struct twi_transfer *xfer, enum twi_status new_status) { send_stop_condition(); transfer_set_status(xfer, new_status); twi.first_xfer = xfer->next; if (twi.first_xfer) send_start_condition(); else twi.last_xfer = NULL; if (xfer->callback) xfer->callback(xfer, new_status); }