DS2438 library

Hi all,

I'm using the DS2438 library from Guilherme Barros at Google Code Archive - Long-term storage for Google Code Project Hosting. along with the 1-wire library. I am reading temp and humidity using the example that came with the DS2438 library. Everything is fine until the temp drops below 32.00 degrees F. At that point both temp and humidity jump to over 200 degrees and 150% rh. Is anyone using this library and have you had problems. BTW, I have tried 2 different 1-wire sensor boards with the same problem. As soon as the temp rises to 32 again everything is good.

32.00 degrees F is zero Celsius, so maybe there is an overflow or divide by zero or such condition. zero's are nasty numbers in programming as they are the lowest unsigned number. Strange things happened before.

Have to dive into the lib. may take a while .....

update 1: checking the datasheet http://pdfserv.maxim-ic.com/en/ds/DS2438.pdf
DS2438 is a smart Battery Monitor, with a 13 bit temperature sensor, 8 bit before digital point and 5 thereafter, giving a precision of 1/32 degree. (nice IC). Temperature is in Celsius. So it is not a restriction of the sensor, it must be in the lib.

Q: Can you share your code in which it happens?

update 2: Just looking at the lib shows that readHum() uses readTempC() so if the latter is wrong the first one will be too.

update 3: readTempC()

float ds2438::readTempC()
{
  //override for now, [glow][b]plsfixkthx[/b][/glow]
  _parasite = 1;

  //request temp conversion
  _wire->reset();
  _wire->select(_deviceAddress);
  _wire->write(CONVERTT, _parasite);
  delay(20);

  //copy data from eeprom to scratchpad & read scratchpad
  ScratchPad _scratchPad;
  _readMem(_scratchPad);
  

  //return tempC (ignore 3 lsb as they are always 0);
  int16_t rawTemp = ( ((int16_t)_scratchPad[TEMP_MSB]) << 5) | (_scratchPad[TEMP_LSB] >> 3);

  return (float)rawTemp * 0.03125;
}

Could the highlighted "Please Fix This" related to your problem? Do you use parasite power?

From datasheet:

PARASITE POWER
The block diagram (Figure 1) shows the parasite-powered circuitry. This circuitry “steals” power whenever the DQ pin is high. DQ will provide sufficient power as long as the specified timing and voltage requirements are met (see the section titled “1-Wire Bus System”). The advantage of parasite power is that the ROM may be read in absence of normal power, i.e., if the battery pack is completely
discharged.

Hi robtillaart
First, thanks for looking at this.
Look at the example code with the library. I ran that last night and as soon as the outdoor temp went below 32f or 0c it gave me the strange results. Like you I suspect the calculation used to convert the temperature is at fault but I'm not well versed in C or library building to figure it out.

plsfixkthx

no I did not add that. And no I am not using parasite power

From datasheet:

Convert T [44h]
This command begins a temperature conversion. No further data is required. The temperature conversion will be performed, setting the TB flag in the Status/Configuration register to a “1” during conversion. When the temperature conversion is done, the TB flag will clear to a “0”. If the bus master issues read time slots following this command, the DS2438 will output “0” on the bus as long as it is busy making a temperature conversion; it will return a “1” when the temperature conversion is complete.

When I look at the code of the library it just does a delay(20); after the call for convert. As I am familiar with the DS18B20 temp sensor, that takes 750 msec for 12 bit, so 13 bit may even take longer (OK Assumption with big A) but it seems to me that the library just waits to short for conversion.

Rob

Could you please try to replace readTempC in the library with this one. It waits until the TB flag (Temperature Busy) is cleared. Code is not compiled or tested :wink:

Rob

float ds2438::readTempC()
{
  //override for now, plsfixkthx
  _parasite = 1;

  //request temp conversion
  _wire->reset();
  _wire->select(_deviceAddress);
  _wire->write(CONVERTT, _parasite);
  // delay(20);   


  ScratchPad _scratchPad;

  // wait until TB register clears, see page 15/29 datasheet
  // iso delay(20);
  boolean ready = false;
  while (!ready)
  {
     //copy data from eeprom to scratchpad & read scratchpad
    _readMem(_scratchPad);
    ready = ( _scratchPad[STATUS]  & 0x10) == 0x00;
    delay(10);  // wait before reread of the scratchpad
  }
  // TB is cleared so conversion is ready

  //return tempC (ignore 3 lsb as they are always 0);
  int16_t rawTemp = ( ((int16_t)_scratchPad[TEMP_MSB]) << 5) | (_scratchPad[TEMP_LSB] >> 3);

  return (float)rawTemp * 0.03125;
}

Should I make that delay say 750ms and see if that helps

Bill

I"ll try you fix and let you know. Thanks for your help!

Bill

If you just want to tweak the delay I would propose to start with 2000 millisec iso 750. that's quite long but if the IC behaves similar to the DS18B20 2000 is a reasonable value. The DS18B20 doubles the delay time for every extra bit ( it can be configured from 9-12 bits with a max of 750 msec)

If 2000 works you might go down in steps of 100 msec until it fails.

Rob

@Rob
Why would the delay become a factor only when the temperature drops below 0C/32F?

I had a similar problem on the TC74 temp sensors, it overflows back to 255 when the temp drops below 0. Pretty simple to solve in code though as the max temp is 125C (I think) so anything above that is mapped to minus values in code.

Mowcius

@PaulS
Just don't know, but I have seen too many bugs caused by zero or -signs changing the behaviour unexpectedly.
e.g. Software Bug Halts F-22 Flight - Slashdot or The RISKS Digest Volume 3 Issue 44

Technically, I can imagine that with lower temperatures the ADC goes slower but never that much slower. So that's not the cause.
My current line of thought is that as long as the TB flag is not cleared the scratchpad reads an undefined value ... (based upon datasheet)

Better ideas allways welcome.
Rob

Found cause for the bug, please confirm as I have no sensor to test with.

The scratchpad is defined as array of unsigned int 8 (see ds2438.h)

typedef uint8_t ScratchPad[9];

in readTempC(); the temperature reading is done and two shifts are used to merge the value of the MSB and LSB register. As the value of MSB is an unsigned int, the value casting it to an int_16_t does not do a sign extension. Therefor as the value becomes (should be) negative, it is interpreted as 255 instead of -1.

The problem reveals itself in this line:

int16_t rawTemp = ( ((int16_t)_scratchPad[TEMP_MSB]) << 5) | (_scratchPad[TEMP_LSB] >> 3);

Solution: Change readTempC() to

float ds2438::readTempC()
{
  //override for now, plsfixkthx
  _parasite = 1;

  //request temp conversion
  _wire->reset();
  _wire->select(_deviceAddress);
  _wire->write(CONVERTT, _parasite);
  delay(20);

  //copy data from eeprom to scratchpad & read scratchpad
  ScratchPad _scratchPad;
  _readMem(_scratchPad);
  
  //return tempC (ignore 3 lsb as they are always 0);
  uint8_t x = _scratchPad[TEMP_MSB];
  int rawTemp = (x & 0x80)?(-256+x): x;  // uint8_t => int
  float f = rawTemp + (_scratchPad[TEMP_LSB] >> 3) * 0.03125;

  return f;
}

Rob

Note: Other solution could be the changing the type of the scratchpad to signed but I did not investigate the impact of that change to the rest of the DS2438 class.

Reported this as a bug on http://code.google.com/p/gfb/source/browse/#svn/arduino/DS2438

Also reported the delay(20) iso waiting for TB clear flag instatus register as bug.

Just looked at the DallasTemperature lib to see how they do the readings as the code for reading temp looks quite similar.

// DallasTemperature lib
int16_t rawTemperature = (((int16_t)scratchPad[TEMP_MSB]) << 8) | scratchPad[TEMP_LSB];

// DS2438 lib
int16_t rawTemp = ( ((int16_t)_scratchPad[TEMP_MSB]) << 5) | (_scratchPad[TEMP_LSB] >> 3);

The shift works in the Dallas lib as the signbit fells in place. This means that the DS2438 lib could be patched easier by the following code:

int16_t rawTemperature = (((int16_t) _scratchPad[TEMP_MSB]) << 8) | _scratchPad[TEMP_LSB])  >> 3;

return (float)rawTemp * 0.03125;

Thanks Rob! Didn't mean for u to spend a lot of time on this but it is appreciated. Only one more simple question. What program do I use to edit this with? Notepad won't work. It adds stray chars. Get all kinds of errors.

Thanks,
Bill

BTW... I have several DS2438s. If you want a couple send me a personal message with you address.

It was fun to investigate, I hope the proposed changes work for you.

For coding libraries is use notepad++, it is lightweigth and does syntax highlighting, can open multiple files (tabs). It is not the greatest but very fast also for large logfiles (100.000++ lines) You can find it at http://notepad-plus-plus.org/

wrt the 2438's I appreciate the gesture but I think you have to pay more on postage than the costs of the sensors :slight_smile:

Hi Rob,

Sadly your last fix didn't work. Temp stays at 277 deg F. But the humidity still reads properly. Will try the other code you suggested later tonight.

@Bill
Could you confirm that the the first patch works?

Strange that the second patch, which stays more to the original code, doesn't work. My testcode with same datatypes did. Could you test a rewrite of the last patch as proposed below? I have moved the rightshift 3 to a division in the return statement, to be sure the signbit is kept...

int16_t rawTemperature = (((int16_t) _scratchPad[TEMP_MSB]) << 8) | _scratchPad[TEMP_LSB]);

return (float)rawTemp * 0.03125 / 8;

Rob