Pages: [1] 2 3 4   Go Down
Author Topic: OneWire in Due  (Read 19297 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 84
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi.

I've been porting the onewire lib to work in Due.

I've it working well in my program, but would be nice if some more people would test it also.

Library is attached.

I've built a test sketch with the function I'm using to read the temperature. Sketch as follows:

Code:
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

#include <OneWire.h>

OneWire  ds(54);  // data bus on pin A0

//DS18B20
float celsius;
unsigned int raw_temp;
boolean conversioninprogress=false;
byte data[12];
byte addr[8];
unsigned long tempconvmillis;
unsigned long waitforesultmillis;

float read_temp()
{
  if (!conversioninprogress)
  {
    ds.reset();
    delay(1);
    ds.skip();
    delay(1);
    ds.write(0x44,0);         // start conversion, with parasite power off at the end
    conversioninprogress=true;
    waitforesultmillis=millis();
  }
 
  if (((millis()-waitforesultmillis) > 1000) && conversioninprogress) 
  // maybe 750ms is enough, maybe not
  // we might do a ds.depower() here, but the reset will take care of it.
  {
    byte i;
    byte present = 0;
    present = ds.reset();
    delay(1);
    ds.skip();
    delay(1);   
    ds.write(0xBE,0);         // Read Scratchpad
   
    delay(1);
   
    for ( i = 0; i < 9; i++) {           // we need 9 bytes
      data[i] = ds.read();
    }
    // convert the data to actual temperature
 
    raw_temp = (data[1] << 8) | data[0];
   
    unsigned char t_mask[4] = {0x7, 0x3, 0x1, 0x0};
    byte cfg = (data[4] & 0x60) >> 5;
    raw_temp &= ~t_mask[cfg];
 
    conversioninprogress=false;
    celsius = (float)raw_temp / 16.0;
  }
  tempconvmillis=millis();
  return celsius;
}
void setup()
{
  Serial.begin(115200);
}
void loop()
{
  if ((millis()-tempconvmillis) > 2000)
  Serial.println(read_temp());
}

Regards,

Joao

* OneWire_working_due.zip (13.9 KB - downloaded 184 times.)
Logged


Offline Offline
Newbie
*
Karma: 0
Posts: 24
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

alvesjc,

I tried the library but wasn't able to get it working with my DS18B20 and my Due.  In the serial monitor after dropping your library in the Arduino\Libraries folder I ran you sketch and get the following:

4095.94
4095.94
4095.94
4095.94

If I hold the temp sensor with my finger the numbers don't change a bit, which they obviously should.

I have it wired like the following on my Due but with the data line going to Due line A0 to the middle of the DS18B20 and a 4.7k resistor going from the middle pin to the 5v line.

Sorry bud, I really want this library to work because it's one of the only hold backs keeping me from using the Due instead of the Uno/Leonardo which I have verified good working code on.
Logged

0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 84
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Kcore.

Thank you for testing.

It's working already for me and one coleague, what IDE are you using? We are bought using testing IDE compiled from git.

One thing important I forgot to mention, and is related to IDE version. This lib is set to use ODSR register, meaning this, that you MUST have OWER register set to 1.

This has been fixed in the IDE currently in git, can you compile it and repeat the test please?

There is also other way, in onewire.h, you have the following code for SAM3x.

Code:
#elif defined(__SAM3X8E__)
#define PIN_TO_BASEREG(pin)             (&(digitalPinToPort(pin)->PIO_PER)) //to get Base PORT address
#define PIN_TO_BITMASK(pin)             (digitalPinToBitMask(pin))
#define IO_REG_TYPE uint32_t
#define IO_REG_ASM
#define DIRECT_READ(base, mask)         (((*(base+15)) & (mask)) ? 1 : 0) /*(Pio Offset: 0x003C) Pin Data Status Register */
#define DIRECT_MODE_INPUT(base, mask)   ((*(base+5)) = (mask)) /*(Pio Offset: 0x0014) Output Disable Register */
#define DIRECT_MODE_OUTPUT(base, mask)  ((*(base+4)) = (mask)) /*(Pio Offset: 0x0010) Output Enable Register */
#define DIRECT_WRITE_LOW(base, mask)    ((*(base+14)) &= ~(mask)) /*(Pio Offset: 0x0038) Output Data Status Register */
#define DIRECT_WRITE_HIGH(base, mask)   ((*(base+14)) |= (mask)) /*(Pio Offset: 0x0038) Output Data Status Register */
//#define DIRECT_WRITE_LOW(base, mask)    ((*(base+13)) = (mask)) /*(Pio Offset: 0x0034) Clear Output Data Register */
//#define DIRECT_WRITE_HIGH(base, mask)   ((*(base+12)) = (mask)) /*(Pio Offset: 0x0030) Set Output Data Register */
#include "pgmspace.h"

Replace it with the following lines:

Code:
#define DIRECT_WRITE_LOW(base, mask)    ((*(base+14)) &= ~(mask)) /*(Pio Offset: 0x0038) Output Data Status Register */
#define DIRECT_WRITE_HIGH(base, mask)   ((*(base+14)) |= (mask)) /*(Pio Offset: 0x0038) Output Data Status Register */
//#define DIRECT_WRITE_LOW(base, mask)    ((*(base+13)) = (mask)) /*(Pio Offset: 0x0034) Clear Output Data Register */
//#define DIRECT_WRITE_HIGH(base, mask)   ((*(base+12)) = (mask)) /*(Pio Offset: 0x0030) Set Output Data Register */

with:

Code:
//#define DIRECT_WRITE_LOW(base, mask)    ((*(base+14)) &= ~(mask)) /*(Pio Offset: 0x0038) Output Data Status Register */
//#define DIRECT_WRITE_HIGH(base, mask)   ((*(base+14)) |= (mask)) /*(Pio Offset: 0x0038) Output Data Status Register */
#define DIRECT_WRITE_LOW(base, mask)    ((*(base+13)) = (mask)) /*(Pio Offset: 0x0034) Clear Output Data Register */
#define DIRECT_WRITE_HIGH(base, mask)   ((*(base+12)) = (mask)) /*(Pio Offset: 0x0030) Set Output Data Register */

This way you will be using CODR and SODR to clear and set the bit in the port. This is independent of OWER, and probably solve your problem.

Can you test it again please?

Unfortunately, I have burned my Due yesterday with a electrical hazard, and I can't do any more testes meanwhile...

Thank you.

BR,

Joao
Logged


Offline Offline
Newbie
*
Karma: 0
Posts: 24
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

alvesjc,

I'm running my Due with arduino-1.5.1r2 on Windows.

I modified the OneWire.h file like you said it seems to work now.  I'm getting the following in the serial window:

Code:
0.00
24.94
24.94
24.94
24.94
26.87
26.87
30.19
30.19
31.44
31.44
32.06
32.06

Those numbers are when I was just touching the DS18B20 with my finger so they look about right to me.

I did notice I wasn't able to get valid temps from the example that I'm using below.  It's from the examples folder in the library you uploaded, any idea why?

Code:
#include <OneWire.h>

// OneWire DS18S20, DS18B20, DS1822 Temperature Example
//
// http://www.pjrc.com/teensy/td_libs_OneWire.html
//
// The DallasTemperature library can do all this work for you!
// http://milesburton.com/Dallas_Temperature_Control_Library

OneWire  ds(54);  // on pin 54 which is A0 for the Arduino Due

void setup(void) {
  Serial.begin(9600);
}

void loop(void) {
  byte i;
  byte present = 0;
  byte type_s;
  byte data[12];
  byte addr[8];
  float celsius, fahrenheit;
 
  if ( !ds.search(addr)) {
    Serial.println("No more addresses.");
    Serial.println();
    ds.reset_search();
    delay(250);
    return;
  }
 
  Serial.print("ROM =");
  for( i = 0; i < 8; i++) {
    Serial.write(' ');
    Serial.print(addr[i], HEX);
  }

  if (OneWire::crc8(addr, 7) != addr[7]) {
      Serial.println("CRC is not valid!");
      return;
  }
  Serial.println();
 
  // the first ROM byte indicates which chip
  switch (addr[0]) {
    case 0x10:
      Serial.println("  Chip = DS18S20");  // or old DS1820
      type_s = 1;
      break;
    case 0x28:
      Serial.println("  Chip = DS18B20");
      type_s = 0;
      break;
    case 0x22:
      Serial.println("  Chip = DS1822");
      type_s = 0;
      break;
    default:
      Serial.println("Device is not a DS18x20 family device.");
      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
  // we might do a ds.depower() here, but the reset will take care of it.
 
  present = ds.reset();
  ds.select(addr);   
  ds.write(0xBE);         // Read Scratchpad

  Serial.print("  Data = ");
  Serial.print(present,HEX);
  Serial.print(" ");
  for ( i = 0; i < 9; i++) {           // we need 9 bytes
    data[i] = ds.read();
    Serial.print(data[i], HEX);
    Serial.print(" ");
  }
  Serial.print(" CRC=");
  Serial.print(OneWire::crc8(data, 8), HEX);
  Serial.println();

  // convert the data to actual temperature

  unsigned int raw = (data[1] << 8) | data[0];
  if (type_s) {
    raw = raw << 3; // 9 bit resolution default
    if (data[7] == 0x10) {
      // count remain gives full 12 bit resolution
      raw = (raw & 0xFFF0) + 12 - data[6];
    }
  } else {
    byte cfg = (data[4] & 0x60);
    if (cfg == 0x00) raw = raw << 3;  // 9 bit resolution, 93.75 ms
    else if (cfg == 0x20) raw = raw << 2; // 10 bit res, 187.5 ms
    else if (cfg == 0x40) raw = raw << 1; // 11 bit res, 375 ms
    // default is 12 bit resolution, 750 ms conversion time
  }
  celsius = (float)raw / 16.0;
  fahrenheit = celsius * 1.8 + 32.0;
  Serial.print("  Temperature = ");
  Serial.print(celsius);
  Serial.print(" Celsius, ");
  Serial.print(fahrenheit);
  Serial.println(" Fahrenheit");
}

In the serial output window I get the following:

Quote
ROM = 28 6B C7 49 3 0 0 C1
  Chip = DS18B20
  Data = 1 FF FF FF FF FF FF FF FF FF  CRC=C9
  Temperature = 4095.94 Celsius, 7404.69 Fahrenheit
No more addresses.

Touching the sensor doesn't do anything and the numbers for Celsius and Fahrenheit don't change - They look a little bit hot to me...  smiley-roll-sweat

Let me know, I can do more testing for you and hopefully we can get a working library that everyone can run.  Thanks for your help.
Logged

0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 84
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Kcore.

Thank you for your time testing.

Ok, those are good news!

This leaves me more confident. I Had to tweak the timings in read and write timeslots, and I was affraid that i might be just tweaking the lib for my own probes or probe cable length, etc.

That proves the opposite.

Regarding the original example, I have the same problem, I only get FFFFF. I don't have any clue about that, but I suspect that might be something about the probe discovery process. In my test, I just skip that, because I'm addressing only one prob.

I've left that aside to first conclude if the actual code work with every prob.

We are now 3 with working due with onewire.

Unfortunately, I can't continue to test why it doesn't work with example, has i told before, I've accidentally burned my due...

My suggestion now, is to transport the discovery process to the function that works and test it( and removing ds.skip() ).

If more people joins this effort, maybe we can get to a final library faster.

My test function was first built a very long time ago based on that example, it should work...

Let us know if you move forward with this! smiley-wink

Regards,

João
Logged


Offline Offline
Jr. Member
**
Karma: 9
Posts: 78
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I tested your lib and sketch on linux with IDE 1.5.1 (didn't compile with 1.5).  I edited OneWire.h as suggested.  Sketch worked.  Also tested with no   delay(1);  -- still worked.

I tested the Examples>OneWire>DS18x20_Temperature.  It would work if I replaced ds.select(addr); with ds.skip();  With delay(1);'s it worked each query.  With no delay(1); every other query would return Data with FFs

Code:
    ROM = 28 86 42 5B 3 0 0 84
        Chip = DS18B20
        Data = 1 82 1 4B 46 7F FF E 10 70  CRC=70
        Temperature = 24.12 Celsius, 75.43 Fahrenheit
        No more addresses.


In a later experiment, I got the Example to work by adding delay(1);'s in the ds.select() function  in OneWire.cpp
« Last Edit: January 10, 2013, 01:08:53 pm by mantoui » Logged

0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 84
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Mantoui.

Ok, so if I understand right the delays are needed for your usage also, right?

The only way to get stable readings for long run was with that delays. My function worked without them, but it returns FFF from time to time!

With the delays, I had it running for more then 48hours without a failure.


I tested the Examples>OneWire>DS18x20_Temperature.  It would work if I replaced ds.select(addr); with ds.skip();  With delay(1);'s it worked each query.  With no delay(1); every other query would return Data with FFs

Can you clarify this a bit more?

Thank you for joining! smiley-wink
Logged


Offline Offline
Jr. Member
**
Karma: 9
Posts: 78
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

your sketch, seemed to work consistently with or without delay(1);

the Examples was bad every other query without the delay(1) using ds.skip()

I got Examples to work by adding delay(1) between every write in the select() function in OneWire.cpp,
and no delay(1) in the Examples sketch

I had also tried delayMicroseconds in select() with no luck, so I switched to delay(1); but presumably something
shorter than a millisecond might work ... sort of hit and miss.
« Last Edit: January 10, 2013, 01:14:25 pm by mantoui » Logged

0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 84
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok ok, nice.

So I think that this confirms that the DUE is too fast for the probe.

What I just don't understand, is why it works fine with chipkit....

Can you post your changed onewire.cpp here?

maybe we get more people testing your changes.

Thanks
Logged


Offline Offline
Jr. Member
**
Karma: 9
Posts: 78
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

my select() in OneWire.cpp follows.  I'll let you be master of your library source.  thanks

Code:
void OneWire::select( uint8_t rom[8])
{
    int i;

    write(0x55);           // Choose ROM
    delay(1); // thd

    for( i = 0; i < 8; i++) {
        write(rom[i]);
        delay(1);  // thd
    }
}


Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 285
Posts: 25629
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
void OneWire::select( uint8_t rom[8])
{
    int i;  // overkill
...
    for( i = 0; i < 8; i++) {
}
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 84
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok, thanks.

I'll ask my friend to test this also. smiley-wink

regards,

Joao
Logged


0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 84
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
void OneWire::select( uint8_t rom[8])
{
    int i;  // overkill
...
    for( i = 0; i < 8; i++) {
}

Sorry, I don't understand what you mean!
Logged


Offline Offline
Jr. Member
**
Karma: 9
Posts: 78
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I rewrote  write_bit() in OneWire.cpp to match (more or less) what was working on the maple.  This seems to work for me without any delay(1);!  Works on both the little ds18b20 sketch and the Examples>OneWire>DS18x20_temperature.

Code:
void OneWire::write_bit(uint8_t v)
{
IO_REG_TYPE mask=bitmask;
volatile IO_REG_TYPE *reg IO_REG_ASM = baseReg;

if (v & 1) {
// noInterrupts();
DIRECT_MODE_OUTPUT(reg, mask); // drive output low
DIRECT_WRITE_LOW(reg, mask);
delayMicroseconds(5);
// DIRECT_WRITE_HIGH(reg, mask); // drive output high
DIRECT_MODE_INPUT(reg, mask); // let pin float, pull up will raise
delayMicroseconds(60);
//interrupts();
} else {
//noInterrupts();
DIRECT_MODE_OUTPUT(reg, mask); // drive output low
DIRECT_WRITE_LOW(reg, mask);
delayMicroseconds(60);
DIRECT_MODE_INPUT(reg, mask); // let pin float, pull up will raise
//DIRECT_WRITE_HIGH(reg, mask); // drive output high
//interrupts();
}
delayMicroseconds(10); // 10uSec recovery time
}
« Last Edit: January 10, 2013, 08:22:20 pm by mantoui » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 24
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Great job gentlemen!

I combined mantoui's updated OneWire::write_bit function along with the changes made by alvesjc and I'm now able to run the DS18x20_Temperature right out of the box.

This effort should go a long way in getting other people moved over to the Due because so many projects have requirements to read temperatures and interact with other one wire devices.

Thanks for all your help in getting this working.

I've put all the stuff in a zip file for others to test without having to edit the files.

* OneWire.zip (14.95 KB - downloaded 132 times.)
Logged

Pages: [1] 2 3 4   Go Up
Jump to: