Browse files

Part 1 of Christopher K. Johnson's patch for the i2c library. See htt…

…p://code.google.com/p/arduino/issues/detail?id=28

Adding following functions:
  requestFromAt
  requestFromAt2
  • Loading branch information...
1 parent dca1dc4 commit 4d7cb24b2f04e3532c806badcacb9d5b25d81c81 @karlbackstrom committed Dec 5, 2011
Showing with 228 additions and 16 deletions.
  1. +41 −0 libraries/Wire/Wire.cpp
  2. +5 −0 libraries/Wire/Wire.h
  3. +2 −0 libraries/Wire/keywords.txt
  4. +173 −13 libraries/Wire/utility/twi.c
  5. +7 −3 libraries/Wire/utility/twi.h
View
41 libraries/Wire/Wire.cpp
@@ -1,6 +1,7 @@
/*
TwoWire.cpp - TWI/I2C library for Wiring & Arduino
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
+ Revised 9 June 2009 Christopher K. Johnson.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -93,6 +94,46 @@ uint8_t TwoWire::requestFrom(int address, int quantity)
return requestFrom((uint8_t)address, (uint8_t)quantity);
}
+uint8_t TwoWire::requestFromAt(uint8_t address, uint8_t offset, uint8_t quantity)
+{
+ // clamp to buffer length
+ if(quantity > BUFFER_LENGTH){
+ quantity = BUFFER_LENGTH;
+ }
+ // perform blocking read into buffer
+ uint8_t read = twi_readFromAt(address, offset, rxBuffer, quantity);
+ // set rx buffer iterator vars
+ rxBufferIndex = 0;
+ rxBufferLength = read;
+
+ return read;
+}
+
+uint8_t TwoWire::requestFromAt(int address, int offset, int quantity)
+{
+ return requestFromAt((uint8_t)address, (uint8_t)offset, (uint8_t)quantity);
+}
+
+uint8_t TwoWire::requestFromAt2(uint8_t address, int offset, uint8_t quantity)
+{
+ // clamp to buffer length
+ if(quantity > BUFFER_LENGTH){
+ quantity = BUFFER_LENGTH;
+ }
+ // perform blocking read into buffer
+ uint8_t read = twi_readFromAt2(address, offset, rxBuffer, quantity);
+ // set rx buffer iterator vars
+ rxBufferIndex = 0;
+ rxBufferLength = read;
+
+ return read;
+}
+
+uint8_t TwoWire::requestFromAt2(int address, int offset, int quantity)
+{
+ return requestFromAt2((uint8_t)address, offset, (uint8_t)quantity);
+}
+
void TwoWire::beginTransmission(uint8_t address)
{
// indicate that we are transmitting
View
5 libraries/Wire/Wire.h
@@ -1,6 +1,7 @@
/*
TwoWire.h - TWI/I2C library for Arduino & Wiring
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
+ Revised 31 May 2009 Christopher K. Johnson.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -52,6 +53,10 @@ class TwoWire : public Stream
uint8_t endTransmission(void);
uint8_t requestFrom(uint8_t, uint8_t);
uint8_t requestFrom(int, int);
+ uint8_t requestFromAt(uint8_t, uint8_t, uint8_t);
+ uint8_t requestFromAt(int, int, int);
+ uint8_t requestFromAt2(uint8_t, int, uint8_t);
+ uint8_t requestFromAt2(int, int, int);
virtual size_t write(uint8_t);
virtual size_t write(const uint8_t *, size_t);
virtual int available(void);
View
2 libraries/Wire/keywords.txt
@@ -14,6 +14,8 @@ begin KEYWORD2
beginTransmission KEYWORD2
endTransmission KEYWORD2
requestFrom KEYWORD2
+requestFromAt KEYWORD2
+requestFromAt2 KEYWORD2
send KEYWORD2
receive KEYWORD2
onReceive KEYWORD2
View
186 libraries/Wire/utility/twi.c
@@ -1,6 +1,7 @@
/*
twi.c - TWI/I2C library for Wiring & Arduino
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
+ Revised 9 June 2009 Christopher K. Johnson.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -38,7 +39,10 @@
static volatile uint8_t twi_state;
static uint8_t twi_slarw;
-
+static volatile uint8_t twi_slAtBytes;
+static uint8_t twi_slAtLSB;
+static uint8_t twi_slAtMSB;
+
static void (*twi_onSlaveTransmit)(void);
static void (*twi_onSlaveReceive)(uint8_t*, int);
@@ -85,9 +89,9 @@ void twi_init(void)
}
/*
- * Function twi_slaveInit
- * Desc sets slave address and enables interrupt
- * Input none
+ * Function twi_setAddress
+ * Desc sets slave address, relying on twi_init() to enable interrupt
+ * Input address: 7bit i2c slave address we answer to
* Output none
*/
void twi_setAddress(uint8_t address)
@@ -131,7 +135,7 @@ uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length)
// received, causing that NACK to be sent in response to receiving the last
// expected byte of data.
- // build sla+w, slave device address + w bit
+ // build sla+r, slave device address + r bit
twi_slarw = TW_READ;
twi_slarw |= address << 1;
@@ -143,18 +147,146 @@ uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length)
continue;
}
- if (twi_masterBufferIndex < length)
- length = twi_masterBufferIndex;
-
// copy twi buffer to data
- for(i = 0; i < length; ++i){
+ for(i = 0; i < twi_masterBufferIndex; ++i){
data[i] = twi_masterBuffer[i];
}
- return length;
+ return twi_masterBufferIndex;
}
/*
+ * Function twi_readFromAt
+ * Desc attempts to become twi bus master and write a data (register or memory) offset
+ * to a slave device on the bus, then repeat start and read a
+ * series of bytes from the slave at the slave-side offset
+ * IOW this is the bus behaviour for reading i2c GPIO or EEPROM chips
+ * Input address: 7bit i2c device address
+ * offset: slave-side data offset for read
+ * data: pointer to byte array
+ * length: number of bytes to read into array
+ * Output number of bytes read
+ */
+uint8_t twi_readFromAt(uint8_t address, uint8_t offset, uint8_t* data, uint8_t length)
+{
+ uint8_t i;
+
+ // ensure data will fit into buffer
+ if(TWI_BUFFER_LENGTH < length){
+ return 0;
+ }
+
+ // wait until twi is ready, become master receiver
+ while(TWI_READY != twi_state){
+ continue;
+ }
+ twi_state = TWI_MRXR;
+ // reset error state (0xFF.. no error occured)
+ twi_error = 0xFF;
+
+// save the slave register offset for later use
+ twi_slAtLSB = offset;
+ twi_slAtBytes = 1;
+
+ // initialize buffer iteration vars
+ twi_masterBufferIndex = 0;
+ twi_masterBufferLength = length-1; // This is not intuitive, read on...
+ // On receive, the previously configured ACK/NACK setting is transmitted in
+ // response to the received byte before the interrupt is signalled.
+ // Therefor we must actually set NACK when the _next_ to last byte is
+ // received, causing that NACK to be sent in response to receiving the last
+ // expected byte of data.
+
+ // build sla+w, slave device address + w bit
+ // NOT A TYPO - we need to write the register offset as data before sending
+ // repeat start and sla+r later to perform the read from the slave-side
+ // register offset
+ twi_slarw = TW_WRITE;
+ twi_slarw |= address << 1;
+
+ // send start condition
+ TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA);
+
+ // wait for read operation to complete
+ while(TWI_MRXR == twi_state){
+ continue;
+ }
+
+ // copy twi buffer to data
+ for(i = 0; i < twi_masterBufferIndex; ++i){
+ data[i] = twi_masterBuffer[i];
+ }
+
+ return twi_masterBufferIndex;
+}
+
+/*
+ * Function twi_readFromAt2
+ * Desc attempts to become twi bus master and write a data (register or memory) offset
+ * to a slave device on the bus, then repeat start and read a
+ * series of bytes from the slave at the slave-side offset
+ * IOW this is the bus behaviour for reading i2c GPIO or EEPROM chips
+ * Input address: 7bit i2c device address
+ * offset: slave-side 16-bit data offset for read
+ * data: pointer to byte array
+ * length: number of bytes to read into array
+ * Output number of bytes read
+ */
+uint8_t twi_readFromAt2(uint8_t address, uint16_t offset, uint8_t* data, uint8_t length)
+{
+ uint8_t i;
+
+ // ensure data will fit into buffer
+ if(TWI_BUFFER_LENGTH < length){
+ return 0;
+ }
+
+ // wait until twi is ready, become master receiver
+ while(TWI_READY != twi_state){
+ continue;
+ }
+ twi_state = TWI_MRXR;
+ // reset error state (0xFF.. no error occured)
+ twi_error = 0xFF;
+
+// save the slave register offset for later use
+ twi_slAtMSB = offset >> 8;
+ twi_slAtLSB = offset & 0xFF;
+ twi_slAtBytes = 2;
+
+ // initialize buffer iteration vars
+ twi_masterBufferIndex = 0;
+ twi_masterBufferLength = length-1; // This is not intuitive, read on...
+ // On receive, the previously configured ACK/NACK setting is transmitted in
+ // response to the received byte before the interrupt is signalled.
+ // Therefor we must actually set NACK when the _next_ to last byte is
+ // received, causing that NACK to be sent in response to receiving the last
+ // expected byte of data.
+
+ // build sla+w, slave device address + w bit
+ // NOT A TYPO - we need to write the register offset as data before sending
+ // repeat start and sla+r later to perform the read from the slave-side
+ // register offset
+ twi_slarw = TW_WRITE;
+ twi_slarw |= address << 1;
+
+ // send start condition
+ TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA);
+
+ // wait for read operation to complete
+ while(TWI_MRXR == twi_state){
+ continue;
+ }
+
+ // copy twi buffer to data
+ for(i = 0; i < twi_masterBufferIndex; ++i){
+ data[i] = twi_masterBuffer[i];
+ }
+
+ return twi_masterBufferIndex;
+ }
+
+/*
* Function twi_writeTo
* Desc attempts to become twi bus master and write a
* series of bytes to a device on the bus
@@ -225,6 +357,9 @@ uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait
* Output 1 length too long for buffer
* 2 not slave transmitter
* 0 ok
+ * NOTE: This function relies upon being called by twi_onSlaveTransmit handler,
+ * itself called within the TWI interrupt handler such that the buffer
+ * contents provided here will subsequently be transmitted.
*/
uint8_t twi_transmit(const uint8_t* data, uint8_t length)
{
@@ -273,7 +408,11 @@ void twi_attachSlaveTxEvent( void (*function)(void) )
/*
* Function twi_reply
- * Desc sends byte or readys receive line
+ * Desc Write TWCR with TWINT bit, thus acknowledging it, which causes
+ * the next logical TW operation to occur. If TW is in MT or ST
+ * mode and a byte loaded in TWDR it is transmitted. Otherwise only
+ * the ACK/NACK is sent per the 'ack' input. The TWEN and TWIE bits
+ * are on merely to keep them enabled.
* Input ack: byte indicating to ack or to nack
* Output none
*/
@@ -323,9 +462,9 @@ void twi_releaseBus(void)
twi_state = TWI_READY;
}
-SIGNAL(TWI_vect)
+ISR(TWI_vect)
{
- switch(TW_STATUS){
+ switch(TW_STATUS){ // TWSR with prescaler bits masked
// All Master
case TW_START: // sent start condition
case TW_REP_START: // sent repeated start condition
@@ -336,7 +475,28 @@ SIGNAL(TWI_vect)
// Master Transmitter
case TW_MT_SLA_ACK: // slave receiver acked address
+ if (twi_state == TWI_MRXR){
+ // tell the slave what register offset to use for subsequent read
+ if (twi_slAtBytes-- == 2) {
+ TWDR = twi_slAtMSB;
+ } else {
+ TWDR = twi_slAtLSB;
+ }
+ twi_reply(1);
+ break;
+ }
case TW_MT_DATA_ACK: // slave receiver acked data
+ if (twi_state == TWI_MRXR){
+ if (twi_slAtBytes-- == 1) {
+ TWDR = twi_slAtLSB;
+ twi_reply(1);
+ } else {
+ twi_slarw |= TW_READ; // Configure subsequent operation to be a read
+ // send a repeat start
+ TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA);
+ }
+ break;
+ }
// if there is data to send, send it, otherwise stop
if(twi_masterBufferIndex < twi_masterBufferLength){
// copy data to output register and ack
View
10 libraries/Wire/utility/twi.h
@@ -1,6 +1,7 @@
/*
twi.h - TWI/I2C library for Wiring & Arduino
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
+ Revised 9 June 2009 Christopher K. Johnson.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -34,13 +35,16 @@
#define TWI_READY 0
#define TWI_MRX 1
- #define TWI_MTX 2
- #define TWI_SRX 3
- #define TWI_STX 4
+ #define TWI_MRXR 2
+ #define TWI_MTX 3
+ #define TWI_SRX 4
+ #define TWI_STX 5
void twi_init(void);
void twi_setAddress(uint8_t);
uint8_t twi_readFrom(uint8_t, uint8_t*, uint8_t);
+ uint8_t twi_readFromAt(uint8_t, uint8_t, uint8_t*, uint8_t);
+ uint8_t twi_readFromAt2(uint8_t,uint16_t, uint8_t*, uint8_t);
uint8_t twi_writeTo(uint8_t, uint8_t*, uint8_t, uint8_t);
uint8_t twi_transmit(const uint8_t*, uint8_t);
void twi_attachSlaveRxEvent( void (*)(uint8_t*, int) );

0 comments on commit 4d7cb24

Please sign in to comment.