Wire and OneWire conflicts?

Hi all,
I thought I'd see if anyone else has had this problem. I've got a sketch that uses the OneWire library to read a ds18s20 temperature sensor and display it on a serial lcd. Works great! I've got another little sketch that can do a test read & write to an I2C connected EEPROM, (a microchip 24LC256). It also seems to work.
I was working on integrating the two together into one sketch to be able to log a lot of temp data but I get lock ups when I try to include the wire.h library in the sketch using the OneWire.h library.

I can include the OneWire.h in the simple eeprom reading sketch and it still runs, however the onewire routines are never accessed in that sketch.
If I include wire.h in the OneWire using sketch, even with all call to the wire functions commented out, it will upload but never output anything.

Thanks for any tips !

Here's the two sketches:

read/write a 24LC256 eeprom:

#include <OneWire.h>  // This include is for library compat testing
#include <Wire.h>

// Simple read & write to a 24LC256 via the TWI library 
// Using the Wire library (created by Nicholas Zambetti)
// http://wiring.org.co/reference/libraries/Wire/index.html
// On the Arduino board, Analog In 4 is SDA, Analog In 5 is SCL
// These correspond to pin 27 (PC4/ADC4/SDA) and pin 28 (PC5/ADC5/SCL) on the Atmega8
// The Wire class handles the TWI transactions, abstracting the nitty-gritty to make
// prototyping easy.
 

void writestuff(){
  Wire.beginTransmission(0x10);
  Wire.send(0x00); 
  Wire.send(0x01);
  Wire.send(0x02);
  Wire.send(0x03);
  Wire.send(0x04);
  Wire.send(0x05); 
  Wire.send("h");
  Wire.send("i");
  Wire.endTransmission();
}

void readstuff(){
 Wire.beginTransmission(0x11);
  Wire.send(0x00); 
  Wire.send(0x01);
  Wire.endTransmission();
  Wire.requestFrom(0x11, 10);
 while(Wire.available()){
   Serial.print("  ");
   Serial.print(Wire.receive());
 };
  Wire.endTransmission();
} 
void setup()

{
  Wire.begin(); // join i2c bus (address optional for master)
  Serial.begin(9600);
}

void loop()
{
  Serial.print(" writing ");
writestuff();
  Serial.println(".");
  
    Serial.print(" reading ");
readstuff();
    Serial.println(".");
 
  Serial.println(" done ");

  delay(250000);
}

Code to read a ds18s20

#include <OneWire.h>
#include <Wire.h>   // delete old .o files in the library folder if no output

#define p_sens 0

OneWire  ds(7);  // on pin 7

void setup(void) {
  Serial.begin(9600);
  //Wire.begin();            // start the TWI hardware
}

void lcdPos(int x, int y){
  if (y==0)  y=128;
  if (y==1)  y=192;
  Serial.print(0xFE, BYTE);
  Serial.print(x+y, BYTE);
}

void lcdLight(int x){   // takes argument from 1 (off) to 30 (on)
  Serial.print(0x7C, BYTE);
  Serial.print(x+127, BYTE);
}

void lcdCode(int x){   //a general function to call the command flag for issuing all other commands   
  Serial.print(0xFE, BYTE);
  Serial.print(x, BYTE);
}

#define lcdwipe           0x01  

void loop(void) {
  byte i;
  byte present = 0;
  byte data[12];
  int  temp_c;
  int temp_f;
  long time_sec;
  byte addr[8];

  if ( !ds.search(addr)) {
    //Serial.print("No more addresses.\n");
    ds.reset_search();
    return;
  }

  //Serial.print("SensorAddress=");
  //for( i = 0; i < 8; i++) {
  //  Serial.print(addr[i], HEX);
  //  Serial.print(" ");
  //}

  if ( OneWire::crc8( addr, 7) != addr[7]) {
    Serial.print("CRC is not valid!\n");
    return;
  }

  if ( addr[0] != 0x10) {
    Serial.print("Device is not a DS18S20 family device.\n");
    return;
  }

  ds.reset();
  ds.select(addr);
  ds.write(0x44,1);         // start conversion, with parasite power on at the end

  delay(1000);     // maybe 750ms is enough, maybe not

  present = ds.reset();
  //Serial.print("DS Chip ID=");    // Show IDs found for debug
  //Serial.print(present,HEX);
  
  ds.select(addr);    
  ds.write(0xBE);                    // Read Scratchpad

  for ( i = 0; i < 9; i++) {         // we need 9 bytes
    data[i] = ds.read();     
    //Serial.print(data[i], HEX);    //show raw data for debug
    //Serial.print(" ");
  }


  temp_c = 5*data[0];
  temp_f = 9*data[0] +320;
  time_sec=millis()/1000;

  lcdCode(lcdwipe);

  lcdPos(0,0);
  Serial.print("C="); 
  Serial.print(temp_c/10,DEC);
  Serial.print(".");
  Serial.print(temp_c%10, DEC);

  lcdPos(8,0);  
  Serial.print("F="); 
  Serial.print(temp_f/10,DEC);
  Serial.print(".");
  Serial.print(temp_f%10, DEC);

  lcdPos(1,1);   
  Serial.print("T=");
  Serial.print(time_sec/60);
  Serial.print(":");
  if (time_sec%60<10) Serial.print("0");
  Serial.print(time_sec%60); 

  lcdPos(11,1);

  Serial.print("P=");
  Serial.print(analogRead(p_sens));

}

I forgot to mention that the hardware involved is an arduino NG board that's had the atmega8 replaced w/ an atmega16. I reflashed it using an olimex AVR-PG1 on a windows box w/ real serial port, an adapter to go from the 10-pin icsp header to the NG boards 6-pin header (see here: http://ipodnytt.com/2006/12/06/programming-the-atmel-attiny2313-in-mac-os-x/ and also here http://www.atmel.com/dyn/resources/prod_documents/doc2521.pdf). Instructions and code from http://wolfpaulus.com/journal/embedded/arduino2.html .

Hi bdmatic,

I tried out your code for the ds18s20 sensor, and it worked fine with OneWire - thanks!. I am having some trouble with i2c, so I tried your code with the 24LC256, and it seemed to work fine, but I realized Wire uses the same buffer for write and read, so I zeroed it out after the write, and it came back zero. Maybe my eeprom is hooked up wrong, but could you try this and verify the eeprom read is working?

The ds18s20 is a really cool device!

D.

To improve readability, I changed the readstuff and writestuff a bit:

void writestuff(){
  Wire.beginTransmission(0x10);
  Wire.send(0x00); 
  Wire.send(0x01);
  Wire.send("testing");
  Wire.endTransmission();
}

void readstuff(){
 Wire.beginTransmission(0x11);
  Wire.send(0x00); 
  Wire.send(0x04);
  Wire.requestFrom(0x11, 9);
 while(Wire.available()){
   Serial.print("  ");
   Serial.print(Wire.receive(), DEC);
 };
  Wire.endTransmission();
}

Here's the serial output I get from these changes:

 writing .

 reading   0  1  116  101  115  116  105  110  103.

 done

It appears that it's not using the first two bytes to set the address to write to/read from correctly.

Here's how I have it wired in:

Pin#   
1  A0  Groud
2  A1  Ground
3  A2  Ground
4  Vss Ground
5  SDA analog4 w/ 1.6k pullup resistor to +5v
6  SCL analog5 w/1.6k pullup resistor to +5v
7  WP  Ground
8  Vcc  +5v

Oops,
I'm still having problems doing random reads from the eeprom. I now see that you can only set the address location pointer in a write command, not in a read command. In the first version posted I think the pointer keeps moving out in the address space sequentially and never accepts a new location. Actually, it's taking the address bytes as data and writing them into memory instead of resetting the pointer location. This would explain why just doing a read without a write cycle returns all zeroes. Since doing a write doesn't move the address pointer it will then read back what was just written, but only once.

I don't think this has anything to do with the lock up when including both wire.ha and onewire.h .

Here's a new version:

#include <Wire.h>

void writestuff(){
  Wire.beginTransmission(0x10);  // write control byte (cb)
  Wire.send(0x00);
  Wire.send(0x05);
  Wire.send("0321test1234");
  Wire.endTransmission();
}

void readstuff(){
 Wire.beginTransmission(0x10);  //write cb to set address
  Wire.send(0x00); 
  Wire.send(0x05);
  Wire.beginTransmission(0x11);  //read cb
  Wire.requestFrom(0x11, 20);    // get 20 bytes
 while(Wire.available()){
   Serial.print("  ");
   Serial.print(Wire.receive(),DEC);
 };
  Wire.endTransmission();
} 
void setup()

{
  Wire.begin(); // join i2c bus (address optional for master)
  Serial.begin(9600);
}

void loop()
{
  Serial.print(" writing ");
writestuff();
  Serial.println(".");
  
  delay(800);
  
    Serial.print(" reading ");
readstuff();
    Serial.println(".");

     Serial.print(" reading again ");
readstuff();
    Serial.println(".");
  
  Serial.println(" done ");

  delay(250000);
}

Output from above:

 writing .

 reading   0  5  48  51  50  49  116  101  115  116  49  50  51  52  0  0  0  0  0  0.

 reading again   0  5  48  51  50  49  116  101  115  116  49  50  51  52  0  0  0  0  0  0.

 done

Hi bdmatic,

I am still having trouble making the 24lc256 work. I have it hooked up the same way you do, only my datasheet seems to want 0xA0 for an address. Either way it won't work. What I did was run your code once, then comment out the call to writestuff and try it again. The data should still be there, but it isn't - only the address bytes I wrote to the eeprom. I'd be interested to see if you get the same result or not. One difference is I have 3 devices on my i2c bus, and I'm trying to make them all work at once. Wire will work with one (a ds1307 clock) but not with the eeprom or a compass module. Some other i2c code I am trying works with the compass, but not the clock or the eeprom.

Have you tried any other i2c devices?

D.

I slipped a hexadecimal in there somewhere - You'
re right that the address should be 0xA0 and 0xA1 instead of 0x10 0x11.
Very strangely however I get the exact same results using either address or random addresses for the wire.beginTransmission statements. Something is fishy.
I also get only zeroes back from the eeprom after commenting out the write function in the loop after a 'sucessful' run.

Also note that the first two bytes read back 0 5 are the ones that are supposed to be read as the address, not as data to store.

I'd assumed that the wire.beginTransmission(id) just sent the start signal and the id as a byte.
I'm not sure how wire.send(byte) handles the ack bit.
I'd also assumed that endTransmission() just sends the stop condition.

I'm not sure how to use the library to listen for an ack from the slave device.

I haven't got any other twi devices to try, but I have some ds1631 s on order.

OK - at least we are both getting similar results. I looked at the Wire code and it seems to happily give you the buffer back even if it never received anything. I will keep working on this.

BTW - were you able to find DS1631 in DIP format? Where??

I ordered three from maxim as free samples:).

I Finally found the thread about the I2C and the timing issues with the gyro today. Looks like there are some issues with wire.h or the hardware in general. I guess it's time for me to poke around in the wire library and see about understanding the next layer down. I was hoping to avoid that as I'm a bit slow at interpreting the code - been a while since I did much C.

Kind of silly about the buffer not emptying on an attempted send.

I'm also looking for a onewire eeprom since that lib seems to work fairly smoothly.

Thanks

I agree - OneWire seems to work smoothly, although I have only tried it with 3 ds18S20's. But they have a number of other devices that use onewire - I ordered a few and will try them out when they arrive.

The problems with i2c using wire are device-specific. It works fine with the ds1307 clock, but not with the eeprom or the compass sensor I'm using. Next week I'll have an oscilloscope and I'll keep working on i2c until figure out what's funky.

It was your post that made me aware that OneWire exists, and it is really neat and workable for Arduino. Thanks!

All, any status on these issues? I have the exact same problems. I have the DS1337 working great as my clock, a PCF8457 as an IO expander - all on I2C working fine. I also tried the DS1631 temp sensor and the 24LC256 which both dont work as you describe (always just returns whatever is in the buffer). I have looked through the TwoWire code and TWI from wiring and I cant find anything wrong yet. I'll let you all know if I find anything, but was wondering if you all had found anything yet.

I just received my 1631's today and will do some fiddling. Doesn't sound promising, though. Drd, if you have made any modifications to files from the avrlib, such as i2c.c i2ceeprom.c ds1631.c i2csw.c to get them to work or partly work on arduino I'd really love to get copies posted in the playground, even if incomplete to have something further to fiddle with.
Anyone else have an idea how tricky it is to port things from avrlib?

Thanks!

Ok, an update. Just get the address correct and I'm betting it will work. See the last page of this thread:

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1170973485/30

I have not re-tried my DS1631 yet, but I bet I can get it to work now if needed.

-- Josh

Just tried the 24lc256 with the address of 0x50 for both the wire.beginTransmission and wire.endTransmission statements and it works! Can read and write to arbitrary locations and the data is still there after a reset.

Thanks to you and drd for this clever diagnosing.

In retrospect there's something in the wire library documentation stating that address is a value from 0 to 127 implying the 7-bit address, but it doesn't mention that wire sets the read/write bit itself in any of the online docs.

I'm going to set up a 1631 now.

Also, there still seems to be the problem with wire and oneWire coexisting in the same sketch.

Glad to hear it is working for you now as well. I had some problems with both Wire.h and OneWire.h for a while, but I trimmed out my code and removed some Serial.print and Serial.println I had interspersed and it cleared it up and the problem went away. Makes me think there may be a third component of the problem involving Serial and possibly timing or interrupts. Since mine has started working fine now, I cant find the problem. Good luck on your work, and let us know if the 1631 works fine as well.

-- Josh

I generally suspect running out of SRAM when combining things makes them fail. All those strings that you Serial.print take SRAM, so those are suspect as well. A cruel twist that the very thing you might use to debug causes the bugs.

I looked back over OneWire now that I have more experience in the Arduino environment. It is probably sensitive to interrupts. I'd wrap the read bit and write bit routines in cli() and sei() calls to disable interrupts in them, but you would also need a tweeked delayMicroseconds because the one in 0007 turns on interrupts as it exits.

Other than that I don't see any resource that would conflict. I suspect SRAM usage.

I got DS1631 behaving both with Wire and software i2c. Here's the Wire code:

#include <Wire.h>
void setup()
{
  Wire.begin();
  Serial.begin(19200);
}

void loop() {
  ds1631();
}

void ds1631() {
  uint8_t ret, dhi, dlo; 
  Wire.beginTransmission(0x48);
  Wire.send(0x51);
  Wire.endTransmission();
  delay(750);
  Wire.beginTransmission(0x48);
  Wire.send(0xAA);  // read temperature command...
  Wire.endTransmission();
  Wire.requestFrom(0x48, 2);
  dhi = Wire.receive();
  dlo = Wire.receive();
  Wire.endTransmission();
  int ihi = (int) (dhi);
  int ilo = (int) (dlo);
  int frac =  ihi * 256 + ilo;
  if (dhi > 0x80) frac = frac - 65536;
  int temp = frac/256;
  frac = frac - temp*256; 
  Serial.print(" Temp (C) = ");
  Serial.print(temp);
  Serial.print(".");
  if(frac < 100) Serial.print("0");
  if(frac < 10) Serial.print("0");
  Serial.println(frac);
}


Wire has no means to do a repeated start, as the 1631 wants, it won'd send anything unless you do a stop, but it works OK even with the stop.

D.