danjperron
Posts: 2833
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: DS18B20 Low Refresh Rate

Mon May 26, 2014 5:14 pm

Robert,

This means that you have already your compressor controller board at it is using voltage signal between 0,5 and 4,5 V to change the compressor speed.


You could use like Ivan says a PWM signal directly from the RPI. You will need to convert the signal to 5V.

Simply use Adafruit voltage converter (3.3 to 5V converter) or build your own with a mosfet.
http://www.adafruit.com/products/757


At the output of the converter , just add a RC filter to remove the PWM frequency.

If the input impedance of your drive make your pwm signal drop , add an amplifier or reduce the resistances values of the RC network and add a pull-up resistance to the 5V converter.

You could use the 5V of the PI but it will be noisy. It will be better to use a dedicated 5V regulator.

There is one PWM hardware PIN available on the GPIO. It is use for the audio signal.

But you could use WiringPI or PIGPIO to generate the wanted PWM by software on any GPIO.
Both work great.

Daniel

User avatar
FLYFISH TECHNOLOGIES
Posts: 1750
Joined: Thu Oct 03, 2013 7:48 am
Location: Ljubljana, Slovenia
Contact: Website

Re: DS18B20 Low Refresh Rate

Mon May 26, 2014 5:41 pm

Hi Daniel,
danjperron wrote:Simply use Adafruit voltage converter (3.3 to 5V converter) or build your own with a mosfet...
So, the setup is growing... Arduino, A/D board, Voltage converter board, code for PWM generator, etc.

How about replacing all this hardware with one chip, one resistor, two capacitors and one connector ?
Check the link from my signature for details... ;-)


Best wishes, Ivan Zilic.
Running out of GPIO pins and/or need to read analog values?
Solution: http://www.flyfish-tech.com/FF32

danjperron
Posts: 2833
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: DS18B20 Low Refresh Rate

Mon May 26, 2014 7:11 pm

Hi Ivan,

I know about your chip. I'm doing something similar but using a old protocol with RS-485. The big difference is distance, number of module, and boxes. I design mine for green house with multi-drop in mind on long distance with everything already in a box.(Just need to screw the wire)

Your design is an extension hook into the usb port. I think your system will be great for him.

But he could use the Rasperry Pi by itself or an arduino by itself .


His big problem is the temperature rate, which is for me, not an issue at all.
I think that it should do some experimentation first and I'm sure that he will find out that a longer sampling rate will do. I don't believe that all the mass around the compressor heat up in one second. I think is a question of 10's of second.


All roads lead to Rome but some are easier and faster and I'm not the one on the stearing wheel.


Daniel

User avatar
Jufo
Posts: 25
Joined: Fri May 23, 2014 11:49 am
Location: Warsaw, Poland
Contact: Website

Re: DS18B20 Low Refresh Rate

Tue May 27, 2014 7:12 am

Why not use PCF8591?, it very cheap and available in Poland (Mini PCF8591 AD DA Shell Module V2.0 and YL-40). This module bringing me solution 2 in 1 - reading input voltage and sending output voltage. PWM I would like to use to control speed FAN's in condenser 1 and 2.

EDIT 05.06.2014:
Sending output voltage in PCF8591 - it works perfect for my scope (0,5-4,5V) !:
http://www.bristolwatch.com/rpi/pcf8591.html
Best Regards
Robert

rikkert
Posts: 1
Joined: Sun Jun 22, 2014 2:06 pm

Re: DS18B20 Low Refresh Rate

Sun Jun 22, 2014 2:26 pm

I've tried your C-code, and it works without a hickup, no misses at all. Great job!

I like the Unix paradigma that everything is a file, but I guess there is still a lot of work to be done on the current kernel module w1_therm. For the future, it would be nice to be able to load it with a set of parameters, like in: gpio=10, resolution=9.

I was not able to use parasitic mode, but I do not care about that at all. Owners of DS18B20-PAR will not agree with me on this.

For testing purposes, I have minimised the original program a bit. After the call to setup_io(), I've added:

Code: Select all

ReadSensor(); exit(0)
. The changed program then only yields the temperature reading.

Surprisingly, its response is very quick, always, independent of the actual resolution setting. I like this pre-emptive behaviour.

Currently I only have only one sensor. I think some addressing must take place for multiple sensors.

danjperron
Posts: 2833
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: DS18B20 Low Refresh Rate

Thu Jun 26, 2014 2:27 am

Hi Rikkert,


I made small changes in the C code. The new code will start a conversion using the "skip rom command" to all probes connected to the specific pin and will use the "search code command" to find all sensors on the pin and when one is found, it will report the temperature.

It is fast , since it is only one start acquisition command for all devices, and it will report the temperature of 5 sensors in less than 1 second.

Code: Select all

pi@raspberrypiB ~ $ time sudo ./DS18B20Scan -gpio 4
28-000004575F0A : 12 bits  Temperature:  20.50 +/- 0.062500 Celsius
28-00000457ECAA : 12 bits  Temperature:  22.75 +/- 0.062500 Celsius
28-000004575419 : 12 bits  Temperature:  21.44 +/- 0.062500 Celsius
28-000004583355 : 12 bits  Temperature:  20.62 +/- 0.062500 Celsius
28-0000045D387D : 12 bits  Temperature:  22.19 +/- 0.062500 Celsius

real	0m0.719s
user	0m0.020s
sys	0m0.150s
pi@raspberrypiB ~ $ 
The code have some bugs. The biggest one is the user space timing and sometimes the "start conversion" command won't work. The reading is not to bad since I put looping function if the response is not ok. the second bug is the pin selection, If you don't have a probe connected ,it will stay there for long long time.

And this is the code.

Code: Select all

// modified version to read DS18B20 in bit banging
//
//  25 June 2014
// 
// Updated version
// Search rom  code command added
// More than one sensor  on the same pin
//
// Argument:
//  -s        =>  just scan and display the 64 bits rom code of the probe
//  -gpio n   =>  Specify pin other than GPIO10
//
//  Step process
//  1- Start Conversion using SKIP ROM  (all devices)
//  2- Search for sensor. When one is found, Display the temperature


//  24 May 2014
//  Daniel Perron
//
// Use At your own risk




//
//  How to access GPIO registers from C-code on the Raspberry-Pi
//  Example program
//  15-January-2012
//  Dom and Gert
//  Revised: 15-Feb-2013


// Access from ARM Running Linux

#define BCM2708_PERI_BASE        0x20000000
#define GPIO_BASE                (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */


#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <time.h>
#include <string.h>

#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)

int  mem_fd;
void *gpio_map;

// I/O access
volatile unsigned *gpio;


// GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
#define OUT_GPIO(g) *(gpio+((g)/10)) |=  (1<<(((g)%10)*3))
#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))

#define GPIO_SET *(gpio+7)  // sets   bits which are 1 ignores bits which are 0
#define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0

#define GPIO_READ(g)  (*(gpio + 13) &= (1<<(g)))


#define DS18B20_SKIP_ROM 		0xCC
#define DS18B20_CONVERT_T 		0x44
#define DS18B20_MATCH_ROM               0x55
#define DS18B20_SEARCH_ROM		0XF0
#define DS18B20_READ_SCRATCHPAD         0xBE
#define DS18B20_WRITE_SCRATCHPAD        0x4E
#define DS18B20_COPY_SCRATCHPAD         0x48


unsigned char ScratchPad[9];
double  temperature;
int   resolution;

void setup_io();



unsigned short DS_PIN=10;
unsigned short ArgScan=0;
unsigned short ArgFile=0;
char FileName[256];

int  DoReset(void)
{
 int loop;

   INP_GPIO(DS_PIN);


   usleep(1000);

   INP_GPIO(DS_PIN);
   OUT_GPIO(DS_PIN);

   // pin low for 480 us
   GPIO_CLR=1<<DS_PIN;
   usleep(480);
   INP_GPIO(DS_PIN);
   usleep(60);
   if(GPIO_READ(DS_PIN)==0)
   {
     usleep(420);
     return 1;
   }
  return 0;
}

#define DELAY1US  smalldelay();

void  smalldelay(void)
{
  int loop2;
   for(loop2=0;loop2<50;loop2++);
}



void WriteByte(unsigned char value)
{
  unsigned char Mask=1;
  int loop;

   for(loop=0;loop<8;loop++)
     {
       INP_GPIO(DS_PIN);
       OUT_GPIO(DS_PIN);
       GPIO_CLR= 1 <<DS_PIN;

       if((value & Mask)!=0)
        {
           DELAY1US
            INP_GPIO(DS_PIN);
           usleep(60);

        }
        else
        {
           usleep(60);
           INP_GPIO(DS_PIN);
           usleep(1);
        }
      Mask*=2;
      usleep(60);
    }


   usleep(100);
}

void WriteBit(unsigned char value)
{
   INP_GPIO(DS_PIN);
   OUT_GPIO(DS_PIN);
   GPIO_CLR=1 <<DS_PIN;
   if(value)
    {
      DELAY1US
      INP_GPIO(DS_PIN);
      usleep(60);
    }
   else
    {
      usleep(60);
      INP_GPIO(DS_PIN);
      usleep(1);
     }
   usleep(60);
}
 




unsigned char ReadBit(void)
{
   unsigned char rvalue=0;
   INP_GPIO(DS_PIN);
   OUT_GPIO(DS_PIN);
   // PIN LOW
   GPIO_CLR= 1 << DS_PIN;
   DELAY1US
   // set INPUT
   INP_GPIO(DS_PIN);
   DELAY1US
   DELAY1US
   DELAY1US
   if(GPIO_READ(DS_PIN)!=0)
    rvalue=1;
   usleep(60);
   return rvalue;
}

unsigned char ReadByte(void)
{

   unsigned char Mask=1;
   int loop;
   unsigned  char data=0;

  int loop2;


   for(loop=0;loop<8;loop++)
     {
       //  set output
       INP_GPIO(DS_PIN);
       OUT_GPIO(DS_PIN);
       //  PIN LOW
       GPIO_CLR= 1<<DS_PIN;
       DELAY1US
       //  set input
       INP_GPIO(DS_PIN);
       // Wait  2 us
       DELAY1US
       DELAY1US
       DELAY1US
       if(GPIO_READ(DS_PIN)!=0)
       data |= Mask;
       Mask*=2;
       usleep(60);
      }

    return data;
}



int ReadScratchPad(void)
{
   int loop;

       WriteByte(DS18B20_READ_SCRATCHPAD);
       for(loop=0;loop<9;loop++)
         {
          ScratchPad[loop]=ReadByte();
        }
}

unsigned char  CalcCRC(unsigned char * data, unsigned char  byteSize)
{
   unsigned char  shift_register = 0;
   unsigned char  loop,loop2;
   char  DataByte;
 
   for(loop = 0; loop < byteSize; loop++)
   {
      DataByte = *(data + loop);
      for(loop2 = 0; loop2 < 8; loop2++)
      {
         if((shift_register ^ DataByte)& 1)
         {
            shift_register = shift_register >> 1;
            shift_register ^=  0x8C;
         }
         else
            shift_register = shift_register >> 1;
         DataByte = DataByte >> 1;
      }
   }
   return shift_register;
}

char  IDGetBit(unsigned long long *llvalue, char bit)
{
  unsigned long long Mask = 1ULL << bit;

  return ((*llvalue & Mask) ? 1 : 0);
}


unsigned long long   IDSetBit(unsigned long long *llvalue, char bit, unsigned char newValue)
{
  unsigned long long Mask = 1ULL << bit;

  if((bit >= 0) && (bit < 64))
  {
  if(newValue==0)
   *llvalue &= ~Mask;
  else
   *llvalue |= Mask;
   }
  return *llvalue;
}


void SelectSensor(unsigned  long long ID)
{
int BitIndex;
char Bit;


WriteByte(DS18B20_MATCH_ROM);

for(BitIndex=0;BitIndex<64;BitIndex++)
   WriteBit(IDGetBit(&ID,BitIndex));

}

int  SearchSensor(unsigned long long * ID, int * LastBitChange)
{
 int BitIndex;
  char Bit , NoBit;


if(*LastBitChange <0) return 0;

// Set bit at LastBitChange Position to 1
// Every bit after LastbitChange will be 0

if(*LastBitChange <64)
{

   IDSetBit(ID,*LastBitChange,1);
   for(BitIndex=*LastBitChange+1;BitIndex<64;BitIndex++)
    IDSetBit(ID,BitIndex,0);
}

*LastBitChange=-1;

if(!DoReset()) return -1;


WriteByte(DS18B20_SEARCH_ROM);

  for(BitIndex=0;BitIndex<64;BitIndex++)
    {

      NoBit = ReadBit();
      Bit = ReadBit();

     if(Bit && NoBit)
        return -2;

     if(!Bit && !NoBit)
        {
          // ok 2 possibilities
//          printf("B");
          if(IDGetBit(ID,BitIndex))
            {
               // Bit High already set 
                WriteBit(1);
             }
          else
             {
               // ok let's try LOW value first
               *LastBitChange=BitIndex;
                WriteBit(0);
             }
         }
      else if(!Bit)
        { 
//	printf("1");
         WriteBit(1);
         IDSetBit(ID,BitIndex,1);
        }
      else
        {
        //printf("0");
        WriteBit(0);
        IDSetBit(ID,BitIndex,0);
        }
//   if((BitIndex % 4)==3)printf(" ");
    }
//
// printf("\n");
  return 1;



}







int ReadSensor(unsigned long long ID)
{
  int RetryCount;
  int loop;
  unsigned char  CRCByte;
  union {
   short SHORT;
   unsigned char CHAR[2];
  }IntTemp;


  time_t t = time(NULL);
  struct tm tm = *localtime(&t);

  temperature=-9999.9;

  for(RetryCount=0;RetryCount<10;RetryCount++)
  {

   if(!DoReset()) continue;

   // start a conversion
   SelectSensor(ID);

  if(!ReadScratchPad()) continue;

//     for(loop=0;loop<9;loop++)
//       printf("%02X ",ScratchPad[loop]);
//     printf("\n");fflush(stdout);

  // OK Check sum Check;
  CRCByte= CalcCRC(ScratchPad,8);

  if(CRCByte!=ScratchPad[8]) continue;;

  //Check Resolution
   resolution=0;
   switch(ScratchPad[4])
   {

     case  0x1f: resolution=9;break;
     case  0x3f: resolution=10;break;
     case  0x5f: resolution=11;break;
     case  0x7f: resolution=12;break;
   }

   if(resolution==0) continue;
    // Read Temperature

    IntTemp.CHAR[0]=ScratchPad[0];
    IntTemp.CHAR[1]=ScratchPad[1];


    temperature =  0.0625 * (double) IntTemp.SHORT;

    ID &= 0x00FFFFFFFFFFFFFFULL;
    printf("%02llX-%012llX : ",ID & 0xFFULL, ID >>8);

    printf("%02d bits  Temperature: %6.2f +/- %f Celsius\n", resolution ,temperature, 0.0625 * (double)  (1<<(12 - resolution)));

    return 1;
    }

  return 0;

}



int GlobalStartConversion(void)
{
   int retry=0;
   int maxloop;

   while(retry<10)
   {
     if(!DoReset())
      usleep(10000);
     else
      {
       usleep(1000);
       WriteByte(DS18B20_SKIP_ROM);
       WriteByte(DS18B20_CONVERT_T);
       maxloop=0;
      // wait until ready
      while(!ReadBit())
      {
       maxloop++;
       if(maxloop>100000) break;
      }

      if(maxloop<=100000)  return 1;
     }
    retry++;
   }
   return 0;


}


void WriteScratchPad(unsigned char TH, unsigned char TL, unsigned char config)
{
int loop;

    // First reset device

    DoReset();

    usleep(1000);
    // Skip ROM command
     WriteByte(DS18B20_SKIP_ROM);


     // Write Scratch pad

    WriteByte(DS18B20_WRITE_SCRATCHPAD);

    // Write TH

    WriteByte(TH);

    // Write TL

    WriteByte(TL);

    // Write config

    WriteByte(config);
}

void  CopyScratchPad(void)
{

   // Reset device
    DoReset();
    usleep(1000);

   // Skip ROM Command

    WriteByte(DS18B20_SKIP_ROM);

   //  copy scratch pad

    WriteByte(DS18B20_COPY_SCRATCHPAD);
    usleep(100000);
}



void ScanForSensor(void)
{
  unsigned long long  ID=0ULL;
  int  NextBit=64;
  int  _NextBit;
  int  rcode;
  int retry=0;
  unsigned long long  _ID;
  unsigned char  _ID_CRC;
  unsigned char _ID_Calc_CRC;
  unsigned char  _ID_Family;

  while(retry<10){
   _ID=ID;
   _NextBit=NextBit;
   rcode=SearchSensor(&_ID,&_NextBit);
    if(rcode==1)
     {
        _ID_CRC =  (unsigned char)  (_ID>>56);
        _ID_Calc_CRC =  CalcCRC((unsigned char *) &_ID,7);
        if(_ID_CRC == _ID_Calc_CRC)
        {
//         ID=_ID;
//         NextBit=_NextBit;
//         _ID= _ID & 0x00FFFFFFFFFFFFFFULL;
         if(ArgScan==0)
          {
//            printf("%02llX-%012llX\n",_ID & 0xFFULL, _ID >>8);
           if(ReadSensor(_ID))
            {
              ID=_ID;
              NextBit=_NextBit;
              retry=0;
            }
           else
             retry=0;
          }
          else
           {
            ID=_ID;
            NextBit=_NextBit;
            printf("%016llX\n",ID);
           }
        }
        else retry++;
     }
    else if(rcode==0 )
     break;
    else
     retry++;
}
}



void DecodeArg(int argc, char ** argv)
{

   int idx=1;

   while(idx<argc)
    {
       if(strcmp(argv[idx],"-gpio")==0)
            DS_PIN = atoi(argv[++idx]);
       else if(strcmp(argv[idx],"-s")==0)
         ArgScan=1;
       else if(strcmp(argv[idx],"-f")==0)
        {
          ArgFile=1;
          strcpy(FileName,argv[++idx]);
        }
       else
        {
         printf("Unknown argument %s! ",argv[idx]);
         exit(0);
        }
       idx++;
     }
}


int main(int argc, char **argv)
{
  int loop;
  int config;
  // Set up gpi pointer for direct register access

  DecodeArg(argc,argv);

  setup_io();


     GlobalStartConversion();
     ScanForSensor();

  return 0;

} // main


//
// Set up a memory regions to access GPIO
//
void setup_io()
{
   /* open /dev/mem */
   if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
      printf("can't open /dev/mem \n");
      exit(-1);
   }

   /* mmap GPIO */
   gpio_map = mmap(
      NULL,             //Any adddress in our space will do
      BLOCK_SIZE,       //Map length
      PROT_READ|PROT_WRITE,// Enable reading & writting to mapped memory
      MAP_SHARED,       //Shared with other processes
      mem_fd,           //File to map
      GPIO_BASE         //Offset to GPIO peripheral
   );

   close(mem_fd); //No need to keep mem_fd open after mmap

   if (gpio_map == MAP_FAILED) {
      printf("mmap error %d\n", (int)gpio_map);//errno also set!
      exit(-1);
   }

   // Always use volatile pointer!
   gpio = (volatile unsigned *)gpio_map;


} // setup_io

danjperron
Posts: 2833
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: DS18B20 Low Refresh Rate

Thu Jun 26, 2014 11:03 am

After a good night sleep, I know how to resolve the no sensor pin hang from the previous "c" code post.

The problem is the pull-up resistor. I will have to add a check at the beginning for high level signal. If no high level signal is detected, the application will have to quit. Also I should stop on "Global start acquisition" if there is no sensor response.

The check for end of acquisition is not working all the times. Maybe just using a 750ms will do the trick.

Tonight I will add the fix into the code.

Daniel

danjperron
Posts: 2833
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: DS18B20 Low Refresh Rate

Thu Jun 26, 2014 11:28 am

The fix is done !

if you set the resolution lower than 12 bits, you could change the constant delay of 750ms for faster response.

With a constant delay of 750 ms after the start conversion, it takes 1.5 seconds to read 5 sensors (including the 750ms).


Speed could be increase if you use ReadSensor(unsigned long long ID) function for each sensor instead of the scan detection . If you put the argument -s , the application will display the 64 bits ID of each sensor.

The Pull-up or no sensor is not an issue anymore.

this is the corrected source code.

Code: Select all

// modified version to read DS18B20 in bit banging
//
// 26 June 2014
// Add fix for no input pull-up or sensor
// Set Start Acquistion waiting delay  using a constant of 750ms

//  25 June 2014
// 
// Updated version
// Search rom  code command added
// More than one sensor  on the same pin
//
// Argument:
//  -s        =>  just scan and display the 64 bits rom code of the probe
//  -gpio n   =>  Specify pin other than GPIO10
//
//  Step process
//  1- Start Conversion using SKIP ROM  (all devices)
//  2- Search for sensor. When one is found, Display the temperature


//  24 May 2014
//  Daniel Perron
//
// Use At your own risk




//
//  How to access GPIO registers from C-code on the Raspberry-Pi
//  Example program
//  15-January-2012
//  Dom and Gert
//  Revised: 15-Feb-2013


// Access from ARM Running Linux

#define BCM2708_PERI_BASE        0x20000000
#define GPIO_BASE                (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */


#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <time.h>
#include <string.h>

#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)

int  mem_fd;
void *gpio_map;

// I/O access
volatile unsigned *gpio;


// GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
#define OUT_GPIO(g) *(gpio+((g)/10)) |=  (1<<(((g)%10)*3))
#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))

#define GPIO_SET *(gpio+7)  // sets   bits which are 1 ignores bits which are 0
#define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0

#define GPIO_READ(g)  (*(gpio + 13) &= (1<<(g)))


#define DS18B20_SKIP_ROM 		0xCC
#define DS18B20_CONVERT_T 		0x44
#define DS18B20_MATCH_ROM               0x55
#define DS18B20_SEARCH_ROM		0XF0
#define DS18B20_READ_SCRATCHPAD         0xBE
#define DS18B20_WRITE_SCRATCHPAD        0x4E
#define DS18B20_COPY_SCRATCHPAD         0x48


unsigned char ScratchPad[9];
double  temperature;
int   resolution;

void setup_io();



unsigned short DS_PIN=10;
unsigned short ArgScan=0;
unsigned short ArgFile=0;
char FileName[256];

int  DoReset(void)
{
 int loop;

   INP_GPIO(DS_PIN);


   usleep(10);

   INP_GPIO(DS_PIN);
   OUT_GPIO(DS_PIN);

   // pin low for 480 us
   GPIO_CLR=1<<DS_PIN;
   usleep(480);
   INP_GPIO(DS_PIN);
   usleep(60);
   if(GPIO_READ(DS_PIN)==0)
   {
     usleep(420);
     return 1;
   }
  return 0;
}

#define DELAY1US  smalldelay();

void  smalldelay(void)
{
  int loop2;
   for(loop2=0;loop2<50;loop2++);
}



void WriteByte(unsigned char value)
{
  unsigned char Mask=1;
  int loop;

   for(loop=0;loop<8;loop++)
     {
       INP_GPIO(DS_PIN);
       OUT_GPIO(DS_PIN);
       GPIO_CLR= 1 <<DS_PIN;

       if((value & Mask)!=0)
        {
           DELAY1US
            INP_GPIO(DS_PIN);
           usleep(60);

        }
        else
        {
           usleep(60);
           INP_GPIO(DS_PIN);
           usleep(1);
        }
      Mask*=2;
      usleep(60);
    }


   usleep(100);
}

void WriteBit(unsigned char value)
{
   INP_GPIO(DS_PIN);
   OUT_GPIO(DS_PIN);
   GPIO_CLR=1 <<DS_PIN;
   if(value)
    {
      DELAY1US
      INP_GPIO(DS_PIN);
      usleep(60);
    }
   else
    {
      usleep(60);
      INP_GPIO(DS_PIN);
      usleep(1);
     }
   usleep(60);
}
 




unsigned char ReadBit(void)
{
   unsigned char rvalue=0;
   INP_GPIO(DS_PIN);
   OUT_GPIO(DS_PIN);
   // PIN LOW
   GPIO_CLR= 1 << DS_PIN;
   DELAY1US
   // set INPUT
   INP_GPIO(DS_PIN);
   DELAY1US
   DELAY1US
   DELAY1US
   if(GPIO_READ(DS_PIN)!=0)
    rvalue=1;
   usleep(60);
   return rvalue;
}

unsigned char ReadByte(void)
{

   unsigned char Mask=1;
   int loop;
   unsigned  char data=0;

  int loop2;


   for(loop=0;loop<8;loop++)
     {
       //  set output
       INP_GPIO(DS_PIN);
       OUT_GPIO(DS_PIN);
       //  PIN LOW
       GPIO_CLR= 1<<DS_PIN;
       DELAY1US
       //  set input
       INP_GPIO(DS_PIN);
       // Wait  2 us
       DELAY1US
       DELAY1US
       DELAY1US
       if(GPIO_READ(DS_PIN)!=0)
       data |= Mask;
       Mask*=2;
       usleep(60);
      }

    return data;
}



int ReadScratchPad(void)
{
   int loop;

       WriteByte(DS18B20_READ_SCRATCHPAD);
       for(loop=0;loop<9;loop++)
         {
          ScratchPad[loop]=ReadByte();
        }
}

unsigned char  CalcCRC(unsigned char * data, unsigned char  byteSize)
{
   unsigned char  shift_register = 0;
   unsigned char  loop,loop2;
   char  DataByte;
 
   for(loop = 0; loop < byteSize; loop++)
   {
      DataByte = *(data + loop);
      for(loop2 = 0; loop2 < 8; loop2++)
      {
         if((shift_register ^ DataByte)& 1)
         {
            shift_register = shift_register >> 1;
            shift_register ^=  0x8C;
         }
         else
            shift_register = shift_register >> 1;
         DataByte = DataByte >> 1;
      }
   }
   return shift_register;
}

char  IDGetBit(unsigned long long *llvalue, char bit)
{
  unsigned long long Mask = 1ULL << bit;

  return ((*llvalue & Mask) ? 1 : 0);
}


unsigned long long   IDSetBit(unsigned long long *llvalue, char bit, unsigned char newValue)
{
  unsigned long long Mask = 1ULL << bit;

  if((bit >= 0) && (bit < 64))
  {
  if(newValue==0)
   *llvalue &= ~Mask;
  else
   *llvalue |= Mask;
   }
  return *llvalue;
}


void SelectSensor(unsigned  long long ID)
{
int BitIndex;
char Bit;


WriteByte(DS18B20_MATCH_ROM);

for(BitIndex=0;BitIndex<64;BitIndex++)
   WriteBit(IDGetBit(&ID,BitIndex));

}

int  SearchSensor(unsigned long long * ID, int * LastBitChange)
{
 int BitIndex;
  char Bit , NoBit;


if(*LastBitChange <0) return 0;

// Set bit at LastBitChange Position to 1
// Every bit after LastbitChange will be 0

if(*LastBitChange <64)
{

   IDSetBit(ID,*LastBitChange,1);
   for(BitIndex=*LastBitChange+1;BitIndex<64;BitIndex++)
    IDSetBit(ID,BitIndex,0);
}

*LastBitChange=-1;

if(!DoReset()) return -1;


WriteByte(DS18B20_SEARCH_ROM);

  for(BitIndex=0;BitIndex<64;BitIndex++)
    {

      NoBit = ReadBit();
      Bit = ReadBit();

     if(Bit && NoBit)
        return -2;

     if(!Bit && !NoBit)
        {
          // ok 2 possibilities
//          printf("B");
          if(IDGetBit(ID,BitIndex))
            {
               // Bit High already set 
                WriteBit(1);
             }
          else
             {
               // ok let's try LOW value first
               *LastBitChange=BitIndex;
                WriteBit(0);
             }
         }
      else if(!Bit)
        { 
//	printf("1");
         WriteBit(1);
         IDSetBit(ID,BitIndex,1);
        }
      else
        {
        //printf("0");
        WriteBit(0);
        IDSetBit(ID,BitIndex,0);
        }
//   if((BitIndex % 4)==3)printf(" ");
    }
//
// printf("\n");
  return 1;



}







int ReadSensor(unsigned long long ID)
{
  int RetryCount;
  int loop;
  unsigned char  CRCByte;
  union {
   short SHORT;
   unsigned char CHAR[2];
  }IntTemp;


  time_t t = time(NULL);
  struct tm tm = *localtime(&t);

  temperature=-9999.9;

  for(RetryCount=0;RetryCount<10;RetryCount++)
  {

   if(!DoReset()) continue;

   // start a conversion
   SelectSensor(ID);

  if(!ReadScratchPad()) continue;

//     for(loop=0;loop<9;loop++)
//       printf("%02X ",ScratchPad[loop]);
//     printf("\n");fflush(stdout);

  // OK Check sum Check;
  CRCByte= CalcCRC(ScratchPad,8);

  if(CRCByte!=ScratchPad[8]) continue;;

  //Check Resolution
   resolution=0;
   switch(ScratchPad[4])
   {

     case  0x1f: resolution=9;break;
     case  0x3f: resolution=10;break;
     case  0x5f: resolution=11;break;
     case  0x7f: resolution=12;break;
   }

   if(resolution==0) continue;
    // Read Temperature

    IntTemp.CHAR[0]=ScratchPad[0];
    IntTemp.CHAR[1]=ScratchPad[1];


    temperature =  0.0625 * (double) IntTemp.SHORT;

    ID &= 0x00FFFFFFFFFFFFFFULL;
    printf("%02llX-%012llX : ",ID & 0xFFULL, ID >>8);

    printf("%02d bits  Temperature: %6.2f +/- %f Celsius\n", resolution ,temperature, 0.0625 * (double)  (1<<(12 - resolution)));

    return 1;
    }

  return 0;

}



int GlobalStartConversion(void)
{
   int retry=0;
   int maxloop;

   while(retry<10)
   {
     if(!DoReset())
      usleep(10000);
     else
      {
       WriteByte(DS18B20_SKIP_ROM);
       WriteByte(DS18B20_CONVERT_T);
       maxloop=0;

#define USE_CONSTANT_DELAY
#ifdef USE_CONSTANT_DELAY
       usleep(750000);
       return 1;
#else
      // wait until ready
      while(!ReadBit())
      {
       maxloop++;
       if(maxloop>100000) break;
      }

      if(maxloop<=100000)  return 1;
#endif
     }
    retry++;
   }
   return 0;


}


void WriteScratchPad(unsigned char TH, unsigned char TL, unsigned char config)
{
int loop;

    // First reset device

    DoReset();

    usleep(10);
    // Skip ROM command
     WriteByte(DS18B20_SKIP_ROM);


     // Write Scratch pad

    WriteByte(DS18B20_WRITE_SCRATCHPAD);

    // Write TH

    WriteByte(TH);

    // Write TL

    WriteByte(TL);

    // Write config

    WriteByte(config);
}

void  CopyScratchPad(void)
{

   // Reset device
    DoReset();
    usleep(1000);

   // Skip ROM Command

    WriteByte(DS18B20_SKIP_ROM);

   //  copy scratch pad

    WriteByte(DS18B20_COPY_SCRATCHPAD);
    usleep(100000);
}



void ScanForSensor(void)
{
  unsigned long long  ID=0ULL;
  int  NextBit=64;
  int  _NextBit;
  int  rcode;
  int retry=0;
  unsigned long long  _ID;
  unsigned char  _ID_CRC;
  unsigned char _ID_Calc_CRC;
  unsigned char  _ID_Family;

  while(retry<10){
   _ID=ID;
   _NextBit=NextBit;
   rcode=SearchSensor(&_ID,&_NextBit);
    if(rcode==1)
     {
        _ID_CRC =  (unsigned char)  (_ID>>56);
        _ID_Calc_CRC =  CalcCRC((unsigned char *) &_ID,7);
        if(_ID_CRC == _ID_Calc_CRC)
        {
//         ID=_ID;
//         NextBit=_NextBit;
//         _ID= _ID & 0x00FFFFFFFFFFFFFFULL;
         if(ArgScan==0)
          {
//            printf("%02llX-%012llX\n",_ID & 0xFFULL, _ID >>8);
           if(ReadSensor(_ID))
            {
              ID=_ID;
              NextBit=_NextBit;
              retry=0;
            }
           else
             retry=0;
          }
          else
           {
            ID=_ID;
            NextBit=_NextBit;
            printf("%016llX\n",ID);
           }
        }
        else retry++;
     }
    else if(rcode==0 )
     break;
    else
     retry++;
}
}



void DecodeArg(int argc, char ** argv)
{

   int idx=1;

   while(idx<argc)
    {
       if(strcmp(argv[idx],"-gpio")==0)
            DS_PIN = atoi(argv[++idx]);
       else if(strcmp(argv[idx],"-s")==0)
         ArgScan=1;
//       else if(strcmp(argv[idx],"-f")==0)
//        {
//          ArgFile=1;
//          strcpy(FileName,argv[++idx]);
//        }
       else
        {
         printf("Unknown argument %s! ",argv[idx]);
         exit(0);
        }
       idx++;
     }
}


int main(int argc, char **argv)
{
  int loop;
  int config;
  int Flag=0;
  // Set up gpi pointer for direct register access

  DecodeArg(argc,argv);

  setup_io();

  // Check for pull up resistor
  // Signal  input should be high

  // Set PIN to INPUT MODe
  INP_GPIO(DS_PIN);

  Flag=0;
  for(loop=0;loop<100;loop++)
   {
     usleep(1000);
     if(GPIO_READ(DS_PIN)!=0)
        {
          Flag=1;
          break;
        }
   }

   if(Flag==0)
    {
      printf("*** Error Unable to detect Logic level 1. No pull-up ?\n");
      exit(-1);
    }

    if(GlobalStartConversion()==0)
    {
      printf("*** Error Unable to detect any DS18B20 sensor\n");
      exit(-2);
    }

     ScanForSensor();

  return 0;

} // main


//
// Set up a memory regions to access GPIO
//
void setup_io()
{
   /* open /dev/mem */
   if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
      printf("can't open /dev/mem \n");
      exit(-1);
   }

   /* mmap GPIO */
   gpio_map = mmap(
      NULL,             //Any adddress in our space will do
      BLOCK_SIZE,       //Map length
      PROT_READ|PROT_WRITE,// Enable reading & writting to mapped memory
      MAP_SHARED,       //Shared with other processes
      mem_fd,           //File to map
      GPIO_BASE         //Offset to GPIO peripheral
   );

   close(mem_fd); //No need to keep mem_fd open after mmap

   if (gpio_map == MAP_FAILED) {
      printf("mmap error %d\n", (int)gpio_map);//errno also set!
      exit(-1);
   }

   // Always use volatile pointer!
   gpio = (volatile unsigned *)gpio_map;


} // setup_io


Daniel

danjperron
Posts: 2833
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: DS18B20 Low Refresh Rate

Thu Jun 26, 2014 5:13 pm

I add the resolution argument into the application.

you could change all the sensors resolution using one of these arguments -9bits, -10bits, -11bits or -12bits (default).

In 9 bits mode, the system will read 5 sensors between 0.4 and 0.8 sec.

First let's put the sensors to 9 bits. (Just to do it once since the configuration is recorded into each sensor eerom).

Code: Select all

pi@raspberrypiB ~ $ sudo ./DS18B20Scan -gpio 4 -9bits
28-000004575F0A : 09 bits  Temperature:  20.00 +/- 0.500000 Celsius
28-00000457ECAA : 09 bits  Temperature:  25.00 +/- 0.500000 Celsius
28-000004575419 : 09 bits  Temperature:  21.50 +/- 0.500000 Celsius
28-000004583355 : 09 bits  Temperature:  20.50 +/- 0.500000 Celsius
28-0000045D387D : 09 bits  Temperature:  22.50 +/- 0.500000 Celsius
Now let's record the 64 bits rom code into a file

Code: Select all

pi@raspberrypiB ~ $ sudo ./DS18B20Scan -gpio 4 -s >Sensors.txt
pi@raspberrypiB ~ $
And now let's see how fast it is in 9 bits mode

Code: Select all

pi@raspberrypiB ~ $ time sudo ./DS18B20Scan -gpio 4 -t 100 -f Sensors.txt
28-000004575F0A : 09 bits  Temperature:  20.00 +/- 0.500000 Celsius
28-00000457ECAA : 09 bits  Temperature:  25.00 +/- 0.500000 Celsius
28-000004575419 : 09 bits  Temperature:  21.50 +/- 0.500000 Celsius
28-000004583355 : 09 bits  Temperature:  20.50 +/- 0.500000 Celsius
28-0000045D387D : 09 bits  Temperature:  22.50 +/- 0.500000 Celsius

real    0m0.528s
user    0m0.060s
sys     0m0.060s
pi@raspberrypiB ~ $ time sudo ./DS18B20Scan -gpio 4 -t 100 -f Sensors.txt
28-000004575F0A : 09 bits  Temperature:  20.00 +/- 0.500000 Celsius
28-00000457ECAA : 09 bits  Temperature:  25.00 +/- 0.500000 Celsius
28-000004575419 : 09 bits  Temperature:  21.50 +/- 0.500000 Celsius
28-000004583355 : 09 bits  Temperature:  20.50 +/- 0.500000 Celsius
28-0000045D387D : 09 bits  Temperature:  22.50 +/- 0.500000 Celsius

real    0m0.472s
user    0m0.020s
sys     0m0.110s
pi@raspberrypiB ~ $ time sudo ./DS18B20Scan -gpio 4 -t 100 -f Sensors.txt
28-000004575F0A : 09 bits  Temperature:  20.00 +/- 0.500000 Celsius
28-00000457ECAA : 09 bits  Temperature:  24.50 +/- 0.500000 Celsius
28-000004575419 : 09 bits  Temperature:  21.50 +/- 0.500000 Celsius
28-000004583355 : 09 bits  Temperature:  20.50 +/- 0.500000 Celsius
28-0000045D387D : 09 bits  Temperature:  22.50 +/- 0.500000 Celsius

real    0m0.482s
user    0m0.020s
sys     0m0.090s
pi@raspberrypiB ~ $
and 10 bits

Code: Select all

pi@raspberrypiB ~ $ time sudo ./DS18B20Scan -gpio 4 -t 200 -f Sensors.txt
28-000004575F0A : 10 bits  Temperature:  20.25 +/- 0.250000 Celsius
28-00000457ECAA : 10 bits  Temperature:  25.00 +/- 0.250000 Celsius
28-000004575419 : 10 bits  Temperature:  21.75 +/- 0.250000 Celsius
28-000004583355 : 10 bits  Temperature:  20.75 +/- 0.250000 Celsius
28-0000045D387D : 10 bits  Temperature:  22.50 +/- 0.250000 Celsius

real    0m0.706s
user    0m0.010s
sys     0m0.140s
And of course the new Source code

Code: Select all

// modified version to read DS18B20 in bit banging
//
// 26 June 2014
//
// Add fix for no input pull-up or sensor
// Set Start Acquistion waiting delay  using a constant of 750ms
// Add set aquisition resolution into the eerom config (-9bits,-10bits,-11bits,-12bits(default)
// Add parameter to change the Wait time after start of aquisition (check pdf info for correct timing).
// Add possibility to use 64bits sensor ID from a file.

//  25 June 2014
// 
// Updated version
// Search rom  code command added
// More than one sensor  on the same pin
//
//
//  Step process
//  1- Start Conversion using SKIP ROM  (all devices)
//  2- Search for sensor. When one is found, Display the temperature


//  24 May 2014
//  Daniel Perron
//
// Use At your own risk



// Argument:
//  -s        =>  just scan and display the 64 bits rom code of the probe
//  -gpio n   =>  Specify pin other than GPIO 10
//  -t   n    =>  Wait time in ms after start of acquisition
//  -9bits
//  -10bits
//  -11bits
//  -12bits   =>  Sensor Aquisition resolution. This will be set into the eerom of the sensor
//                just need to do it once.
//  -f file   =>  Instead of searching for sensor, the system will read sensor corresponding to the 64 bits code in file.




//
//  How to access GPIO registers from C-code on the Raspberry-Pi
//  Example program
//  15-January-2012
//  Dom and Gert
//  Revised: 15-Feb-2013


// Access from ARM Running Linux

#define BCM2708_PERI_BASE        0x20000000
#define GPIO_BASE                (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */


#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <time.h>
#include <string.h>

#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)

int  mem_fd;
void *gpio_map;

// I/O access
volatile unsigned *gpio;


// GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
#define OUT_GPIO(g) *(gpio+((g)/10)) |=  (1<<(((g)%10)*3))
#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))

#define GPIO_SET *(gpio+7)  // sets   bits which are 1 ignores bits which are 0
#define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0

#define GPIO_READ(g)  (*(gpio + 13) &= (1<<(g)))


#define DS18B20_SKIP_ROM 		0xCC
#define DS18B20_CONVERT_T 		0x44
#define DS18B20_MATCH_ROM               0x55
#define DS18B20_SEARCH_ROM		0XF0
#define DS18B20_READ_SCRATCHPAD         0xBE
#define DS18B20_WRITE_SCRATCHPAD        0x4E
#define DS18B20_COPY_SCRATCHPAD         0x48


unsigned char ScratchPad[9];
double  temperature;
int   resolution;

void setup_io();



unsigned short DS_PIN=10;
unsigned short ArgResolution=0;
unsigned short ArgScan=0;
unsigned short ArgFile=0;
unsigned short ArgWaitTime=750;
char FileName[256];

int  DoReset(void)
{
 int loop;

   INP_GPIO(DS_PIN);


   usleep(10);

   INP_GPIO(DS_PIN);
   OUT_GPIO(DS_PIN);

   // pin low for 480 us
   GPIO_CLR=1<<DS_PIN;
   usleep(480);
   INP_GPIO(DS_PIN);
   usleep(60);
   if(GPIO_READ(DS_PIN)==0)
   {
     usleep(420);
     return 1;
   }
  return 0;
}

#define DELAY1US  smalldelay();

void  smalldelay(void)
{
  int loop2;
   for(loop2=0;loop2<50;loop2++);
}



void WriteByte(unsigned char value)
{
  unsigned char Mask=1;
  int loop;

   for(loop=0;loop<8;loop++)
     {
       INP_GPIO(DS_PIN);
       OUT_GPIO(DS_PIN);
       GPIO_CLR= 1 <<DS_PIN;

       if((value & Mask)!=0)
        {
           DELAY1US
            INP_GPIO(DS_PIN);
           usleep(60);

        }
        else
        {
           usleep(60);
           INP_GPIO(DS_PIN);
           usleep(1);
        }
      Mask*=2;
      usleep(60);
    }


   usleep(100);
}

void WriteBit(unsigned char value)
{
   INP_GPIO(DS_PIN);
   OUT_GPIO(DS_PIN);
   GPIO_CLR=1 <<DS_PIN;
   if(value)
    {
      DELAY1US
      INP_GPIO(DS_PIN);
      usleep(60);
    }
   else
    {
      usleep(60);
      INP_GPIO(DS_PIN);
      usleep(1);
     }
   usleep(60);
}
 




unsigned char ReadBit(void)
{
   unsigned char rvalue=0;
   INP_GPIO(DS_PIN);
   OUT_GPIO(DS_PIN);
   // PIN LOW
   GPIO_CLR= 1 << DS_PIN;
   DELAY1US
   // set INPUT
   INP_GPIO(DS_PIN);
   DELAY1US
   DELAY1US
   DELAY1US
   if(GPIO_READ(DS_PIN)!=0)
    rvalue=1;
   usleep(60);
   return rvalue;
}

unsigned char ReadByte(void)
{

   unsigned char Mask=1;
   int loop;
   unsigned  char data=0;

  int loop2;


   for(loop=0;loop<8;loop++)
     {
       //  set output
       INP_GPIO(DS_PIN);
       OUT_GPIO(DS_PIN);
       //  PIN LOW
       GPIO_CLR= 1<<DS_PIN;
       DELAY1US
       //  set input
       INP_GPIO(DS_PIN);
       // Wait  2 us
       DELAY1US
       DELAY1US
       DELAY1US
       if(GPIO_READ(DS_PIN)!=0)
       data |= Mask;
       Mask*=2;
       usleep(60);
      }

    return data;
}



int ReadScratchPad(void)
{
   int loop;

       WriteByte(DS18B20_READ_SCRATCHPAD);
       for(loop=0;loop<9;loop++)
         {
          ScratchPad[loop]=ReadByte();
        }
}

unsigned char  CalcCRC(unsigned char * data, unsigned char  byteSize)
{
   unsigned char  shift_register = 0;
   unsigned char  loop,loop2;
   char  DataByte;
 
   for(loop = 0; loop < byteSize; loop++)
   {
      DataByte = *(data + loop);
      for(loop2 = 0; loop2 < 8; loop2++)
      {
         if((shift_register ^ DataByte)& 1)
         {
            shift_register = shift_register >> 1;
            shift_register ^=  0x8C;
         }
         else
            shift_register = shift_register >> 1;
         DataByte = DataByte >> 1;
      }
   }
   return shift_register;
}

char  IDGetBit(unsigned long long *llvalue, char bit)
{
  unsigned long long Mask = 1ULL << bit;

  return ((*llvalue & Mask) ? 1 : 0);
}


unsigned long long   IDSetBit(unsigned long long *llvalue, char bit, unsigned char newValue)
{
  unsigned long long Mask = 1ULL << bit;

  if((bit >= 0) && (bit < 64))
  {
  if(newValue==0)
   *llvalue &= ~Mask;
  else
   *llvalue |= Mask;
   }
  return *llvalue;
}


void SelectSensor(unsigned  long long ID)
{
int BitIndex;
char Bit;


WriteByte(DS18B20_MATCH_ROM);

for(BitIndex=0;BitIndex<64;BitIndex++)
   WriteBit(IDGetBit(&ID,BitIndex));

}

int  SearchSensor(unsigned long long * ID, int * LastBitChange)
{
 int BitIndex;
  char Bit , NoBit;


if(*LastBitChange <0) return 0;

// Set bit at LastBitChange Position to 1
// Every bit after LastbitChange will be 0

if(*LastBitChange <64)
{

   IDSetBit(ID,*LastBitChange,1);
   for(BitIndex=*LastBitChange+1;BitIndex<64;BitIndex++)
    IDSetBit(ID,BitIndex,0);
}

*LastBitChange=-1;

if(!DoReset()) return -1;


WriteByte(DS18B20_SEARCH_ROM);

  for(BitIndex=0;BitIndex<64;BitIndex++)
    {

      NoBit = ReadBit();
      Bit = ReadBit();

     if(Bit && NoBit)
        return -2;

     if(!Bit && !NoBit)
        {
          // ok 2 possibilities
//          printf("B");
          if(IDGetBit(ID,BitIndex))
            {
               // Bit High already set 
                WriteBit(1);
             }
          else
             {
               // ok let's try LOW value first
               *LastBitChange=BitIndex;
                WriteBit(0);
             }
         }
      else if(!Bit)
        { 
//	printf("1");
         WriteBit(1);
         IDSetBit(ID,BitIndex,1);
        }
      else
        {
        //printf("0");
        WriteBit(0);
        IDSetBit(ID,BitIndex,0);
        }
//   if((BitIndex % 4)==3)printf(" ");
    }
//
// printf("\n");
  return 1;



}







int ReadSensor(unsigned long long ID)
{
  int RetryCount;
  int loop;
  unsigned char  CRCByte;
  union {
   short SHORT;
   unsigned char CHAR[2];
  }IntTemp;


  time_t t = time(NULL);
  struct tm tm = *localtime(&t);

  temperature=-9999.9;

  for(RetryCount=0;RetryCount<10;RetryCount++)
  {

   if(!DoReset()) continue;

   // start a conversion
   SelectSensor(ID);

  if(!ReadScratchPad()) continue;

//     for(loop=0;loop<9;loop++)
//       printf("%02X ",ScratchPad[loop]);
//     printf("\n");fflush(stdout);

  // OK Check sum Check;
  CRCByte= CalcCRC(ScratchPad,8);

  if(CRCByte!=ScratchPad[8]) continue;;

  //Check Resolution
   resolution=0;
   switch(ScratchPad[4])
   {

     case  0x1f: resolution=9;break;
     case  0x3f: resolution=10;break;
     case  0x5f: resolution=11;break;
     case  0x7f: resolution=12;break;
   }

   if(resolution==0) continue;
    // Read Temperature

    IntTemp.CHAR[0]=ScratchPad[0];
    IntTemp.CHAR[1]=ScratchPad[1];


    temperature =  0.0625 * (double) IntTemp.SHORT;

    ID &= 0x00FFFFFFFFFFFFFFULL;
    printf("%02llX-%012llX : ",ID & 0xFFULL, ID >>8);

    printf("%02d bits  Temperature: %6.2f +/- %f Celsius\n", resolution ,temperature, 0.0625 * (double)  (1<<(12 - resolution)));

    return 1;
    }

  return 0;

}



int GlobalStartConversion(void)
{
   int retry=0;
   int maxloop;

   while(retry<10)
   {
     if(!DoReset())
      usleep(10000);
     else
      {
       WriteByte(DS18B20_SKIP_ROM);
       WriteByte(DS18B20_CONVERT_T);
       maxloop=0;

#define USE_CONSTANT_DELAY
#ifdef USE_CONSTANT_DELAY
       usleep(ArgWaitTime * 1000);
       return 1;
#else
      // wait until ready
      while(!ReadBit())
      {
       maxloop++;
       if(maxloop>100000) break;
      }

      if(maxloop<=100000)  return 1;
#endif
     }
    retry++;
   }
   return 0;


}


void WriteScratchPad(unsigned char TH, unsigned char TL, unsigned char config)
{

    // First reset device

    DoReset();

    usleep(10);
    // Skip ROM command
     WriteByte(DS18B20_SKIP_ROM);


     // Write Scratch pad

    WriteByte(DS18B20_WRITE_SCRATCHPAD);

    // Write TH

    WriteByte(TH);

    // Write TL

    WriteByte(TL);

    // Write config

    WriteByte(config);
}


void  CopyScratchPad(void)
{

   // Reset device
    DoReset();
    usleep(1000);

   // Skip ROM Command

    WriteByte(DS18B20_SKIP_ROM);

   //  copy scratch pad

    WriteByte(DS18B20_COPY_SCRATCHPAD);
    usleep(100000);
}

void ChangeSensorsResolution(int resolution)
{
   int config=0;

        switch(resolution)
         {
           case 9:  config=0x1f;break;
           case 10: config=0x3f;break;
           case 11: config=0x5f;break;
           default: config=0x7f;break;
         }
      WriteScratchPad(0xff,0xff,config);
      usleep(1000);
      CopyScratchPad();
}



void ScanForSensor(void)
{
  unsigned long long  ID=0ULL;
  int  NextBit=64;
  int  _NextBit;
  int  rcode;
  int retry=0;
  unsigned long long  _ID;
  unsigned char  _ID_CRC;
  unsigned char _ID_Calc_CRC;
  unsigned char  _ID_Family;

  while(retry<10){
   _ID=ID;
   _NextBit=NextBit;
   rcode=SearchSensor(&_ID,&_NextBit);
    if(rcode==1)
     {
        _ID_CRC =  (unsigned char)  (_ID>>56);
        _ID_Calc_CRC =  CalcCRC((unsigned char *) &_ID,7);
        if(_ID_CRC == _ID_Calc_CRC)
        {
         if(ArgScan==0)
          {
           if(ReadSensor(_ID))
            {
              ID=_ID;
              NextBit=_NextBit;
              retry=0;
            }
           else
             retry=0;
          }
          else
           {
            ID=_ID;
            NextBit=_NextBit;
            printf("%016llX\n",ID);
           }
        }
        else retry++;
     }
    else if(rcode==0 )
     break;
    else
     retry++;
}
}



void DecodeArg(int argc, char ** argv)
{

   int idx=1;

   while(idx<argc)
    {
       if(strcmp(argv[idx],"-gpio")==0)
            DS_PIN = atoi(argv[++idx]);
       else if(strcmp(argv[idx],"-9bits")==0)
            ArgResolution=9;
       else if(strcmp(argv[idx],"-10bits")==0)
            ArgResolution=10;
       else if(strcmp(argv[idx],"-11bits")==0)
            ArgResolution=11;
       else if(strcmp(argv[idx],"-12bits")==0)
            ArgResolution=12;
       else if(strcmp(argv[idx],"-s")==0)
         ArgScan=1;
       else if(strcmp(argv[idx],"-t")==0)
           ArgWaitTime = atoi(argv[++idx]);
       else if(strcmp(argv[idx],"-f")==0)
        {
          ArgFile=1;
          strcpy(FileName,argv[++idx]);
        }
       else
        {
         printf("Unknown argument %s! ",argv[idx]);
         exit(0);
        }
       idx++;
     }
}


void ReadSensorsFromFile(char * Filename)
{
   FILE * src;
   char LineBuffer[256];
   unsigned long long SensorID;

   src = fopen(Filename,"rt");
   if(src==NULL) return;
   while(1)
   {
    if(fgets(LineBuffer,256,src)==NULL) break;
    if(sscanf(LineBuffer,"%llx",&SensorID)==1)
        ReadSensor(SensorID);
   }
  fclose(src);
}



int main(int argc, char **argv)
{
  int loop;
  int Flag=0;
  // Set up gpi pointer for direct register access

  DecodeArg(argc,argv);

  setup_io();

  // Check for pull up resistor
  // Signal  input should be high

  // Set PIN to INPUT MODe
  INP_GPIO(DS_PIN);

  Flag=0;
  for(loop=0;loop<100;loop++)
   {
     usleep(1000);
     if(GPIO_READ(DS_PIN)!=0)
        {
          Flag=1;
          break;
        }
   }

   if(Flag==0)
    {
      printf("*** Error Unable to detect Logic level 1. No pull-up ?\n");
      exit(-1);
    }

    if(ArgResolution>0)
      {
        // need to change resolution
        ChangeSensorsResolution(ArgResolution);
        // do it twice just in case
        ChangeSensorsResolution(ArgResolution);
     }


    if(GlobalStartConversion()==0)
    {
      printf("*** Error Unable to detect any DS18B20 sensor\n");
      exit(-2);
    }

   if(ArgFile)
   {
     ReadSensorsFromFile(FileName);
   }
   else
     ScanForSensor();

  return 0;

} // main


//
// Set up a memory regions to access GPIO
//
void setup_io()
{
   /* open /dev/mem */
   if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
      printf("can't open /dev/mem \n");
      exit(-1);
   }

   /* mmap GPIO */
   gpio_map = mmap(
      NULL,             //Any adddress in our space will do
      BLOCK_SIZE,       //Map length
      PROT_READ|PROT_WRITE,// Enable reading & writting to mapped memory
      MAP_SHARED,       //Shared with other processes
      mem_fd,           //File to map
      GPIO_BASE         //Offset to GPIO peripheral
   );

   close(mem_fd); //No need to keep mem_fd open after mmap

   if (gpio_map == MAP_FAILED) {
      printf("mmap error %d\n", (int)gpio_map);//errno also set!
      exit(-1);
   }

   // Always use volatile pointer!
   gpio = (volatile unsigned *)gpio_map;


} // setup_io


danjperron
Posts: 2833
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: DS18B20 Low Refresh Rate

Sat Jun 28, 2014 1:10 am

Looking at my code, it could be possible to hook up one sensor on every gpio pin and get
all the sensors acquisition in less than 0.25 second.

Just use the word access instead of bit access. Set a mask for all bit hook up to a DS18B20 for the SET and CLEAR GPIO.

This way When we set or clear bit, we will set/clear all the bits hook up to a DS18B20 in one shot.

Only the output/input mode will be made with 3 registers since 3 bits per GPIO pin is needed to set the mode.

And the read command will record the the gpio word on a table. It will be just a question to decode by bit position to get the actual value of each sensor.

This way it is possible, in 9 bits resolution, to start acquisition and read up to 21 DS18B20 sensors in less than 0.25 seconds.

Daniel

danjperron
Posts: 2833
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: DS18B20 Low Refresh Rate

Sun Jun 29, 2014 8:10 pm

This is the fastest method to start aquisition and read temperature for more than one sensors.

I'm using bit banging in parallel mode. One sensor per pin and I Write and read the sensor in 32bits word format.

This mean that I all the data are read from all sensors in one shot.


Every time you reading or writing a gpio pin, you always read the other one also. This way I don't have to read each sensor individually but use this method to read all of them in the same command and extract individual sensor using bit position.


This is the result of 2 sensors connected. Reading 1 or 21 sensors will take the same amount of times (less the printf).

Code: Select all

pi@WebPi ~ $ time sudo ./DS18B20P 4 10
GPIO 4 : 09 bits  Temperature:  27.00 +/- 0.50 Celsius
GPIO 10 : 09 bits  Temperature:  24.00 +/- 0.50 Celsius

real	0m0.193s
user	0m0.010s
sys	0m0.040s
pi@WebPi ~ $ time sudo ./DS18B20P 4 10
GPIO 4 : 09 bits  Temperature:  27.00 +/- 0.50 Celsius
GPIO 10 : 09 bits  Temperature:  24.50 +/- 0.50 Celsius

real	0m0.181s
user	0m0.040s
sys	0m0.020s

And this is the source code

Code: Select all

// Read DS18B20 sensor using one DS18B20 sensor per GPIO PIN using
// parallel method to speed up process
// 29 June 2014  Daniel Perron
//
// Need to install pull-up resistor

// 1 - Create mask for  Set/clear Bit
// 2 - Create mask for  PIO MODE
// 3-  Reset DS18B20
// 4-  send SKIP_ROM command
// 5-  send START_ACQUISITION
// 6-  wait until acquisition is done
// 7-  Reset DS18B20
// 8-  Send SKIP_ROM command
// 9-  Send read register command
// 10-  Collect GPIO word into table
// 11-  Decode individual bit to get sensor temperature
// 12- End


// Access from ARM Running Linux

#define BCM2708_PERI_BASE        0x20000000
#define GPIO_BASE                (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */


#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <time.h>
#include <string.h>

#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)

int  mem_fd;
void *gpio_map;

// I/O access
volatile unsigned long *gpio;


// GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
#define OUT_GPIO(g) *(gpio+((g)/10)) |=  (1<<(((g)%10)*3))
#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))

#define GPIO_SET *(gpio+7)  // sets   bits which are 1 ignores bits which are 0
#define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0
#define GPIO_READ  *(gpio + 13)


#define DS18B20_SKIP_ROM 		0xCC
#define DS18B20_CONVERT_T 		0x44
#define DS18B20_MATCH_ROM               0x55
#define DS18B20_SEARCH_ROM		0XF0
#define DS18B20_READ_SCRATCHPAD         0xBE
#define DS18B20_WRITE_SCRATCHPAD        0x4E
#define DS18B20_COPY_SCRATCHPAD         0x48



unsigned char ScratchPad[9];
double  temperature;
int   resolution;

void setup_io();

// 32 bits bitdatatable[72];  // 9 register of  8 bits
unsigned long bitdatatable[72];





// pin definition use for sensor

int  DS18B20_Pins[32]= {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; 


//  mask bit definition


unsigned long PinMask;

unsigned long  ModeMaskInput[3];
unsigned long  ModeMaskOutput[4];

unsigned long  BadSensor=0;


void SetInputMode(void)
{
  int loop;

  *(gpio) &= ModeMaskInput[0];
  *(gpio+1) &= ModeMaskInput[1];
  *(gpio+2) &= ModeMaskInput[2];
  *(gpio+3) &= ModeMaskInput[3];
};

void SetOutputMode(void)
{
  *gpio &= ModeMaskInput[0];
  *gpio |= ModeMaskOutput[0];
  *(gpio+1) &= ModeMaskInput[1];
  *(gpio+1) |= ModeMaskOutput[1];
  *(gpio+2) &= ModeMaskInput[2];
  *(gpio+2) |= ModeMaskOutput[2];
  *(gpio+3) &= ModeMaskInput[3];
  *(gpio+3) |= ModeMaskOutput[3];
};



// If everything  is ok it will return 0
// otherwise  BadSensor will have the  bit corresponding to the bad sensor set
int   DoReset(void)
{
 unsigned long gpio_pin;


  SetInputMode();
  usleep(10);

  SetOutputMode();
   // pin low for 480 us

   GPIO_CLR = PinMask;

   usleep(480);

   SetInputMode();

   usleep(60);

   gpio_pin = GPIO_READ;

   usleep(420);

   gpio_pin &= PinMask;

   if(gpio_pin ==0) return 1;

   BadSensor|= gpio_pin;
   return 0;
}



#define DELAY1US  smalldelay();

void  smalldelay(void)
{
  int loop2;
   for(loop2=0;loop2<50;loop2++);
}



void WriteByte(unsigned char value)
{
  unsigned char Mask=1;
  int loop;

   for(loop=0;loop<8;loop++)
     {

      SetOutputMode();
      GPIO_CLR= PinMask;

       if((value & Mask)!=0)
        {
           DELAY1US
           SetInputMode();
           usleep(60);

        }
        else
        {
           usleep(60);
           SetInputMode();
           usleep(1);
        }
      Mask*=2;
      usleep(60);
    }


   usleep(100);
}


void  ReadByte(unsigned long *datatable)
{
   int loop;

   for(loop=0;loop<8;loop++)
     {
       //  set output
       SetOutputMode();
       //  PIN LOW
       GPIO_CLR= PinMask;
       DELAY1US
       //  set input
       SetInputMode();
       // Wait  2 us
       DELAY1US
       DELAY1US
//       DELAY1US
       *(datatable++)= GPIO_READ;
       usleep(60);
      }
}


// extract information by bit position from  table of 72  unsigned long 
void ExtractScratchPad( unsigned long bitmask, unsigned char *ScratchPad)
{
    int loop,loopr,Idx;
    unsigned char Mask=1;

    unsigned char databyte=0;
    unsigned long *pointer= &bitdatatable[0];
    for(loopr=0;loopr<9;loopr++)
     {
       Mask=1;
       databyte=0;
       for(loop=0;loop<8;loop++)
       {
         if((*(pointer++) & bitmask)!=0)
           databyte|=Mask;
         Mask*=2;
       }
      *(ScratchPad++)=databyte;
     }
}




unsigned char  CalcCRC(unsigned char * data, unsigned char  byteSize)
{
   unsigned char  shift_register = 0;
   unsigned char  loop,loop2;
   char  DataByte;
 
   for(loop = 0; loop < byteSize; loop++)
   {
      DataByte = *(data + loop);
      for(loop2 = 0; loop2 < 8; loop2++)
      {
         if((shift_register ^ DataByte)& 1)
         {
            shift_register = shift_register >> 1;
            shift_register ^=  0x8C;
         }
         else
            shift_register = shift_register >> 1;
         DataByte = DataByte >> 1;
      }
   }
   return shift_register;
}


int main(int argc, char **argv)
{
  int loop;
  int temp;
  int Flag=0;

  unsigned char  CRCByte;

  union {
   short SHORT;
   unsigned char CHAR[2];
  }IntTemp;


  if(argc==1)
  {
    printf("Usage:  DS18B20  GPIOFirst, GPIOSecond, ...,  GPIOLast\n");
    return -1;
  }

  for(loop=1;loop<argc;loop++)
     DS18B20_Pins[loop-1]=atoi(argv[loop]);



  // Set up gpi pointer for direct register access

  //  set default mask


  PinMask = 0;

  for(loop=0;loop<4;loop++)
   {
     ModeMaskInput[loop]=0xffffffffL;
     ModeMaskOutput[loop]=0;
   }



  // set mask for every pin

  for(loop=0;;loop++)
   {
     temp = DS18B20_Pins[loop];
      if(temp<0) break;

      PinMask|= 1<<temp;

     ModeMaskInput[temp/10] &= ~(7<<((temp % 10) * 3));
     ModeMaskOutput[temp/10] |= (1<<((temp % 10) * 3)); 
   }

   setup_io();

   // Do Reset

  DoReset();




  // Start Acquisition

  WriteByte(DS18B20_SKIP_ROM);
  WriteByte(DS18B20_CONVERT_T);

  //  wait 94 ms (9 bits);
  usleep(94000);

  // DoReset()

  DoReset();


  // Read scratch pad

  WriteByte(DS18B20_SKIP_ROM);
  WriteByte(DS18B20_READ_SCRATCHPAD);

  for(loop=0;loop<72;loop+=8)
   ReadByte(&bitdatatable[loop]);


  // extract bit info fro valid gpio pin
   for(loop=0;;loop++)
      {
       temp = DS18B20_Pins[loop];
       if(temp<0) break;

       printf("GPIO %d : ",temp);
       ExtractScratchPad(1UL<<temp,ScratchPad);
       CRCByte= CalcCRC(ScratchPad,8);
       if(CRCByte!=ScratchPad[8])
         printf("Bad CRC   %02x!=%02X\n\n", CRCByte,ScratchPad[8]);
        else
         {
          //Check Resolution
          resolution=0;
          switch(ScratchPad[4])
           {
            case  0x1f: resolution=9;break;
            case  0x3f: resolution=10;break;
            case  0x5f: resolution=11;break;
            case  0x7f: resolution=12;break;
           }

           if(resolution==0)
            printf("---\n");
           else
            {
             // Read Temperature

             IntTemp.CHAR[0]=ScratchPad[0];
             IntTemp.CHAR[1]=ScratchPad[1];

             temperature =  0.0625 * (double) IntTemp.SHORT;

             printf("%02d bits  Temperature: %6.2f +/- %4.2f Celsius\n", resolution ,temperature, 0.0625 * (double)  (1<<(12 - resolution)));
            }
          }
      }
  return 0;
} // main
Daniel

danjperron
Posts: 2833
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: DS18B20 Low Refresh Rate

Tue Jul 01, 2014 4:38 pm

Oops the previous post has been removed.

I don't see how it could be faster ! How long it takes to process 2 sensors?

I did check the https://www.kickstarter.com/projects/16 ... roller-hub

Looks to me to be an add-on board and still use the Rpi to process. I don't know how it is possible to be faster with that board!

it is possible to optimize to get few ms out but i'm close to the maximum specification of the sensor and I gave you the code to run them in parallel which will reduce the acquisition time to be exactly like one sensor. Also using one GPIO per sensor decrease the transaction time since the serial ID is not transfer.


Daniel

bitlogger
Posts: 3
Joined: Sun Aug 03, 2014 7:58 am

Re: DS18B20 Low Refresh Rate

Sun Aug 03, 2014 8:01 am

Thanks for your code, danjperron, it can be very useful. But I can't compile it:

Code: Select all

# gcc -o DS18B20 DS18B20.c
/tmp/ccNPxjp2.o: In function `main':
DS18B20.c:(.text+0x88c): undefined reference to `setup_io'
collect2: ld returned 1 exit status

danjperron
Posts: 2833
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: DS18B20 Low Refresh Rate

Sun Aug 03, 2014 11:49 am

the setup_io() function is on the previous post. You could just cut and paste.


http://www.raspberrypi.org/forums/viewt ... 55#p569755

I will post the full version later.

Looking at the Adafruit DHT22 code , the latest version, I will modify the code to boost the priority. This should help
and reduces false reading.

I will post it tonight.


Daniel

danjperron
Posts: 2833
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: DS18B20 Low Refresh Rate

Sun Aug 03, 2014 10:36 pm

Ok I added the missing function.

I also implement the priority booster. I still have some bad readings but it should help.

Don't forget to add a pull-up resistor, 4K7 will do, on each GPIO connected to DS18B20. I tried to enable the internal pull-up but this is not enough.

B.T.W. Only one DS18B20 per GPIO when you use this code since the purpose of it is to read all DS18B20 in one shot using parallel mode.

Code: Select all

// Read DS18B20 sensor using one DS18B20 sensor per GPIO PIN using
// parallel method to speed up process
// Copyright (c) 29 June 2014  Daniel Perron
//
// Need to install pull-up resistor

// 1 - Create mask for  Set/clear Bit
// 2 - Create mask for  PIO MODE
// 3-  Reset DS18B20
// 4-  send SKIP_ROM command
// 5-  send START_ACQUISITION
// 6-  wait until acquisition is done
// 7-  Reset DS18B20
// 8-  Send SKIP_ROM command
// 9-  Send read register command
// 10-  Collect GPIO word into table
// 11-  Decode individual bit to get sensor temperature
// 12- End



//  August 3 , 2014
// Priority added 
// code base on Adafruit DHT22  source code  for  
// set_max_priority and set_default_priority
// Copyright (c) 2014 Adafruit Industries
// Author: Tony DiCola

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.






// Access from ARM Running Linux

#define BCM2708_PERI_BASE        0x20000000
#define GPIO_BASE                (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */


#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sched.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>




#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)

int  mem_fd;
void *gpio_map;

// I/O access
volatile unsigned long *gpio;

// GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
#define OUT_GPIO(g) *(gpio+((g)/10)) |=  (1<<(((g)%10)*3))
#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))


#define GPIO_SET *(gpio+7)  // sets   bits which are 1 ignores bits which are 0
#define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0
#define GPIO_READ  *(gpio + 13)


#define DS18B20_SKIP_ROM 		0xCC
#define DS18B20_CONVERT_T 		0x44
#define DS18B20_MATCH_ROM               0x55
#define DS18B20_SEARCH_ROM		0XF0
#define DS18B20_READ_SCRATCHPAD         0xBE
#define DS18B20_WRITE_SCRATCHPAD        0x4E
#define DS18B20_COPY_SCRATCHPAD         0x48



unsigned char ScratchPad[9];
double  temperature;
int   resolution;

void setup_io();

// 32 bits bitdatatable[72];  // 9 register of  8 bits
unsigned long bitdatatable[72];





// pin definition use for sensor

int  DS18B20_Pins[32]= {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; 


//  mask bit definition


unsigned long PinMask;

unsigned long  ModeMaskInput[3];
unsigned long  ModeMaskOutput[4];

unsigned long  BadSensor=0;


void SetInputMode(void)
{
  int loop;

  *(gpio) &= ModeMaskInput[0];
  *(gpio+1) &= ModeMaskInput[1];
  *(gpio+2) &= ModeMaskInput[2];
  *(gpio+3) &= ModeMaskInput[3];
};

void SetOutputMode(void)
{
  *gpio &= ModeMaskInput[0];
  *gpio |= ModeMaskOutput[0];
  *(gpio+1) &= ModeMaskInput[1];
  *(gpio+1) |= ModeMaskOutput[1];
  *(gpio+2) &= ModeMaskInput[2];
  *(gpio+2) |= ModeMaskOutput[2];
  *(gpio+3) &= ModeMaskInput[3];
  *(gpio+3) |= ModeMaskOutput[3];
};



// If everything  is ok it will return 0
// otherwise  BadSensor will have the  bit corresponding to the bad sensor set
int   DoReset(void)
{
 unsigned long gpio_pin;


  SetInputMode();
  usleep(10);

  SetOutputMode();
   // pin low for 480 us

   GPIO_CLR = PinMask;

   usleep(480);

   SetInputMode();

   usleep(60);

   gpio_pin = GPIO_READ;

   usleep(420);

   gpio_pin &= PinMask;

   if(gpio_pin ==0) return 1;

   BadSensor|= gpio_pin;
   return 0;
}



#define DELAY1US  smalldelay();

void  smalldelay(void)
{
  int loop2;
   for(loop2=0;loop2<100;loop2++);
}



void WriteByte(unsigned char value)
{
  unsigned char Mask=1;
  int loop;

   for(loop=0;loop<8;loop++)
     {

      SetOutputMode();
      GPIO_CLR= PinMask;

       if((value & Mask)!=0)
        {
           DELAY1US
           SetInputMode();
           usleep(60);

        }
        else
        {
           usleep(60);
           SetInputMode();
           usleep(1);
        }
      Mask*=2;
      usleep(60);
    }


   usleep(100);
}


void  ReadByte(unsigned long *datatable)
{
   int loop;

   for(loop=0;loop<8;loop++)
     {
       //  set output
       SetOutputMode();
       //  PIN LOW
       GPIO_CLR= PinMask;
       DELAY1US
       //  set input
       SetInputMode();
       // Wait  2 us
       DELAY1US
       DELAY1US
//       DELAY1US
       *(datatable++)= GPIO_READ;
       usleep(60);
      }
}


// extract information by bit position from  table of 72  unsigned long 
void ExtractScratchPad( unsigned long bitmask, unsigned char *ScratchPad)
{
    int loop,loopr,Idx;
    unsigned char Mask=1;

    unsigned char databyte=0;
    unsigned long *pointer= &bitdatatable[0];
    for(loopr=0;loopr<9;loopr++)
     {
       Mask=1;
       databyte=0;
       for(loop=0;loop<8;loop++)
       {
         if((*(pointer++) & bitmask)!=0)
           databyte|=Mask;
         Mask*=2;
       }
      *(ScratchPad++)=databyte;
     }
}




unsigned char  CalcCRC(unsigned char * data, unsigned char  byteSize)
{
   unsigned char  shift_register = 0;
   unsigned char  loop,loop2;
   char  DataByte;
 
   for(loop = 0; loop < byteSize; loop++)
   {
      DataByte = *(data + loop);
      for(loop2 = 0; loop2 < 8; loop2++)
      {
         if((shift_register ^ DataByte)& 1)
         {
            shift_register = shift_register >> 1;
            shift_register ^=  0x8C;
         }
         else
            shift_register = shift_register >> 1;
         DataByte = DataByte >> 1;
      }
   }
   return shift_register;
}






// Adafruit   set_max_priority and set_default priority add-on

void set_max_priority(void) {
  struct sched_param sched;
  memset(&sched, 0, sizeof(sched));
  // Use FIFO scheduler with highest priority for the lowest chance of the kernel context switching.
  sched.sched_priority = sched_get_priority_max(SCHED_FIFO);
  sched_setscheduler(0, SCHED_FIFO, &sched);
}

void set_default_priority(void) {
  struct sched_param sched;
  memset(&sched, 0, sizeof(sched));
  // Go back to default scheduler with default 0 priority.
  sched.sched_priority = 0;
  sched_setscheduler(0, SCHED_OTHER, &sched);
}






int main(int argc, char **argv)
{
  int loop;
  int temp;
  int Flag=0;

  unsigned char  CRCByte;


  union {
   short SHORT;
   unsigned char CHAR[2];
  }IntTemp;


  if(argc==1)
  {
    printf("Usage:  DS18B20  GPIOFirst, GPIOSecond, ...,  GPIOLast\n");
    return -1;
  }

  for(loop=1;loop<argc;loop++)
     DS18B20_Pins[loop-1]=atoi(argv[loop]);



  // Set up gpi pointer for direct register access

  //  set default mask


  PinMask = 0;

  for(loop=0;loop<4;loop++)
   {
     ModeMaskInput[loop]=0xffffffffL;
     ModeMaskOutput[loop]=0;
   }



  // set mask for every pin

  for(loop=0;;loop++)
   {
     temp = DS18B20_Pins[loop];
      if(temp<0) break;

      PinMask|= 1<<temp;

     ModeMaskInput[temp/10] &= ~(7<<((temp % 10) * 3));
     ModeMaskOutput[temp/10] |= (1<<((temp % 10) * 3)); 
   }

   setup_io();


   // Do Reset

  set_max_priority();

  DoReset();



  // Start Acquisition

  WriteByte(DS18B20_SKIP_ROM);
  WriteByte(DS18B20_CONVERT_T);

  //  wait 94 ms (9 bits);
  usleep(94000);


  // DoReset()

  DoReset();


  // Read scratch pad

  WriteByte(DS18B20_SKIP_ROM);
  WriteByte(DS18B20_READ_SCRATCHPAD);

  for(loop=0;loop<72;loop+=8)
   ReadByte(&bitdatatable[loop]);

  set_default_priority();

  // extract bit info fro valid gpio pin
   for(loop=0;;loop++)
      {
       temp = DS18B20_Pins[loop];
       if(temp<0) break;

       printf("GPIO %d : ",temp);
       ExtractScratchPad(1UL<<temp,ScratchPad);
       CRCByte= CalcCRC(ScratchPad,8);
       if(CRCByte!=ScratchPad[8])
         printf("Bad CRC   %02x!=%02X\n\n", CRCByte,ScratchPad[8]);
        else
         {
          //Check Resolution
          resolution=0;
          switch(ScratchPad[4])
           {
            case  0x1f: resolution=9;break;
            case  0x3f: resolution=10;break;
            case  0x5f: resolution=11;break;
            case  0x7f: resolution=12;break;
           }

           if(resolution==0)
            printf("---\n");
           else
            {
             // Read Temperature

             IntTemp.CHAR[0]=ScratchPad[0];
             IntTemp.CHAR[1]=ScratchPad[1];

             temperature =  0.0625 * (double) IntTemp.SHORT;

             printf("%02d bits  Temperature: %6.2f +/- %4.2f Celsius\n", resolution ,temperature, 0.0625 * (double)  (1<<(12 - resolution)));
            }
          }
      }
  return 0;
} // main


//
// Set up a memory regions to access GPIO
//
void setup_io()
{
   /* open /dev/mem */
   if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
      printf("can't open /dev/mem \n");
      exit(-1);
   }

   /* mmap GPIO */
   gpio_map = mmap(
      NULL,             //Any adddress in our space will do
      BLOCK_SIZE,       //Map length
      PROT_READ|PROT_WRITE,// Enable reading & writting to mapped memory
      MAP_SHARED,       //Shared with other processes
      mem_fd,           //File to map
      GPIO_BASE         //Offset to GPIO peripheral
   );

   close(mem_fd); //No need to keep mem_fd open after mmap

   if (gpio_map == MAP_FAILED) {
      printf("mmap error %d\n", (int)gpio_map);//errno also set!
      exit(-1);
   }

   // Always use volatile pointer!
   gpio = (volatile unsigned long *)gpio_map;

} // setup_io

Daniel

bitlogger
Posts: 3
Joined: Sun Aug 03, 2014 7:58 am

Re: DS18B20 Low Refresh Rate

Wed Aug 06, 2014 8:15 am

danjperron wrote:I also implement the priority booster. I still have some bad readings but it should help.
Hi, danjperron! Under bad readings did you mean this:

Code: Select all

# ./DS18B20 4
GPIO 4 : Bad CRC   c9!=FF
I'm receiving that message quite frequently.

danjperron
Posts: 2833
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: DS18B20 Low Refresh Rate

Wed Aug 06, 2014 10:50 am

Exactly!
Under bad readings did you mean this:
CODE: SELECT ALL
# ./DS18B20 4
GPIO 4 : Bad CRC c9!=FF
This is user space !

But we could change the code to re-read the sensor.

I will modify the code to detect bad timing. This will be fast since we don't start a conversion.

The Idea will be to re-insert read command if none of the sensors return a valid temperature up to a maximum of n loop.

Daniel

danjperron
Posts: 2833
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: DS18B20 Low Refresh Rate

Wed Aug 06, 2014 4:48 pm

This is a newly modified version with retry on error.

I change the time out delay by reading the sensor at the start and figure out which one has the highest resolution. This way the acquisition delay will be correct for all.


I also loop the result data forever until you press control c.

B.T.W. you will need to compile the code using the -lrt parameters since i'm using the clock_gettime function.

Code: Select all

gcc -lrt -o DS18B20V2 DS18B20V2.c
this is the code

Code: Select all

// Read DS18B20 sensor using one DS18B20 sensor per GPIO PIN using
// parallel method to speed up process
// Copyright (c) 29 June 2014  Daniel Perron
//
// Need to install pull-up resistor

// 1 - Create mask for  Set/clear Bit
// 2 - Create mask for  PIO MODE
// 3-  Reset DS18B20
// 4-  send SKIP_ROM command
// 5-  send START_ACQUISITION
// 6-  wait until acquisition is done
// 7-  Reset DS18B20
// 8-  Send SKIP_ROM command
// 9-  Send read register command
// 10-  Collect GPIO word into table
// 11-  Decode individual bit to get sensor temperature
// 12- End



//  August 3 , 2014
// Priority added 
// code base on Adafruit DHT22  source code  for  
// set_max_priority and set_default_priority
// Copyright (c) 2014 Adafruit Industries
// Author: Tony DiCola

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

// August 5, 2014
// - Add retried on fail
// - Add bit resolution checking at the start to set the correct acquisition waiting time
// - Add loop scanning.




// Access from ARM Running Linux

#define BCM2708_PERI_BASE        0x20000000
#define GPIO_BASE                (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */


#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sched.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>




#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)

int  mem_fd;
void *gpio_map;

// I/O access
volatile unsigned long *gpio;

// GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
#define OUT_GPIO(g) *(gpio+((g)/10)) |=  (1<<(((g)%10)*3))
#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))


#define GPIO_SET *(gpio+7)  // sets   bits which are 1 ignores bits which are 0
#define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0
#define GPIO_READ  *(gpio + 13)


#define DS18B20_SKIP_ROM 		0xCC
#define DS18B20_CONVERT_T 		0x44
#define DS18B20_MATCH_ROM               0x55
#define DS18B20_SEARCH_ROM		0XF0
#define DS18B20_READ_SCRATCHPAD         0xBE
#define DS18B20_WRITE_SCRATCHPAD        0x4E
#define DS18B20_COPY_SCRATCHPAD         0x48



unsigned char ScratchPad[9];
double  temperature;
int   resolution;

void setup_io();

// 32 bits bitdatatable[72];  // 9 register of  8 bits
unsigned long bitdatatable[72];





// pin definition use for sensor

int  DS18B20_Pins[32]= {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; 


// Data Sensor result info

typedef struct {
unsigned char valid;
unsigned char resolution;
double temperature;
}SensorInfoStruct;

SensorInfoStruct DS18B20_Data[32];

//  mask bit definition


unsigned long PinMask;

unsigned long  ModeMaskInput[4];
unsigned long  ModeMaskOutput[4];

unsigned long  BadSensor=0;


// time interval calculation

struct timespec  mystart,myacqstart,myend;


double clock_diff(struct timespec start,struct  timespec end)
{
  double dtime;;

  dtime = (double) end.tv_sec- start.tv_sec;
  dtime += (double) ((end.tv_nsec - start.tv_nsec)/ 1.0e9);
  return dtime;
}


void SetInputMode(void)
{
  int loop;

  *(gpio) &= ModeMaskInput[0];
  *(gpio+1) &= ModeMaskInput[1];
  *(gpio+2) &= ModeMaskInput[2];
  *(gpio+3) &= ModeMaskInput[3];
};

void SetOutputMode(void)
{
  *gpio &= ModeMaskInput[0];
  *gpio |= ModeMaskOutput[0];
  *(gpio+1) &= ModeMaskInput[1];
  *(gpio+1) |= ModeMaskOutput[1];
  *(gpio+2) &= ModeMaskInput[2];
  *(gpio+2) |= ModeMaskOutput[2];
  *(gpio+3) &= ModeMaskInput[3];
  *(gpio+3) |= ModeMaskOutput[3];
};



// If everything  is ok it will return 0
// otherwise  BadSensor will have the  bit corresponding to the bad sensor set
int   DoReset(void)
{
 unsigned long gpio_pin;


  SetInputMode();
  usleep(10);

  SetOutputMode();
   // pin low for 480 us

   GPIO_CLR = PinMask;

   usleep(480);

   SetInputMode();

   usleep(60);

   gpio_pin = GPIO_READ;

   usleep(420);

   gpio_pin &= PinMask;

   if(gpio_pin ==0) return 1;

   BadSensor|= gpio_pin;
   return 0;
}



#define DELAY1US  smalldelay();

void  smalldelay(void)
{
  int loop2;
   for(loop2=0;loop2<100;loop2++);
}



void WriteByte(unsigned char value)
{
  unsigned char Mask=1;
  int loop;

   for(loop=0;loop<8;loop++)
     {

      SetOutputMode();
      GPIO_CLR= PinMask;

       if((value & Mask)!=0)
        {
           DELAY1US
           SetInputMode();
           usleep(60);

        }
        else
        {
           usleep(60);
           SetInputMode();
           usleep(1);
        }
      Mask*=2;
      usleep(60);
    }


   usleep(100);
}


void  ReadByte(unsigned long *datatable)
{
   int loop;

   for(loop=0;loop<8;loop++)
     {
       //  set output
       SetOutputMode();
       //  PIN LOW
       GPIO_CLR= PinMask;
       DELAY1US
       //  set input
       SetInputMode();
       // Wait  2 us
       DELAY1US
       DELAY1US
//       DELAY1US
       *(datatable++)= GPIO_READ;
       usleep(60);
      }
}


// extract information by bit position from  table of 72  unsigned long 
void ExtractScratchPad( unsigned long bitmask, unsigned char *ScratchPad)
{
    int loop,loopr,Idx;
    unsigned char Mask=1;

    unsigned char databyte=0;
    unsigned long *pointer= &bitdatatable[0];
    for(loopr=0;loopr<9;loopr++)
     {
       Mask=1;
       databyte=0;
       for(loop=0;loop<8;loop++)
       {
         if((*(pointer++) & bitmask)!=0)
           databyte|=Mask;
         Mask*=2;
       }
      *(ScratchPad++)=databyte;
     }
}




unsigned char  CalcCRC(unsigned char * data, unsigned char  byteSize)
{
   unsigned char  shift_register = 0;
   unsigned char  loop,loop2;
   char  DataByte;
 
   for(loop = 0; loop < byteSize; loop++)
   {
      DataByte = *(data + loop);
      for(loop2 = 0; loop2 < 8; loop2++)
      {
         if((shift_register ^ DataByte)& 1)
         {
            shift_register = shift_register >> 1;
            shift_register ^=  0x8C;
         }
         else
            shift_register = shift_register >> 1;
         DataByte = DataByte >> 1;
      }
   }
   return shift_register;
}






// Adafruit   set_max_priority and set_default priority add-on

void set_max_priority(void) {
  struct sched_param sched;
  memset(&sched, 0, sizeof(sched));
  // Use FIFO scheduler with highest priority for the lowest chance of the kernel context switching.
  sched.sched_priority = sched_get_priority_max(SCHED_FIFO);
  sched_setscheduler(0, SCHED_FIFO, &sched);
}

void set_default_priority(void) {
  struct sched_param sched;
  memset(&sched, 0, sizeof(sched));
  // Go back to default scheduler with default 0 priority.
  sched.sched_priority = 0;
  sched_setscheduler(0, SCHED_OTHER, &sched);
}




int ReadSensors(void)
{
  int temp;
  int loop;
  int GotOneResult;
  int GotAllResults;
  unsigned char  CRCByte;

  union {
   short SHORT;
   unsigned char CHAR[2];
  }IntTemp;


   int retryloop;
  // ok now read until we got a least one valid crc up to n times

  #define RETRY_MAX 5

  for(retryloop=0;retryloop<RETRY_MAX;retryloop++)
  {
  GotOneResult=0;  // this will indicate if we have one reading with a good crc 
  GotAllResults=1; // this will indicate if we have all readins from all sensors

  set_max_priority();
  DoReset();

  // Read scratch pad

  WriteByte(DS18B20_SKIP_ROM);
  WriteByte(DS18B20_READ_SCRATCHPAD);

  for(loop=0;loop<72;loop+=8)
   ReadByte(&bitdatatable[loop]);

  set_default_priority();

  // extract bit info fro valid gpio pin
   for(loop=0;;loop++)
      {
       temp = DS18B20_Pins[loop];
       if(temp<0) break;

       // by default put data invalid
         DS18B20_Data[loop].valid=0;

       ExtractScratchPad(1UL<<temp,ScratchPad);
       CRCByte= CalcCRC(ScratchPad,8);
       if(CRCByte!=ScratchPad[8])
        {
         GotAllResults=0;
        }
        else
         {
          //Check Resolution
          resolution=0;

          if((ScratchPad[4] & 0x9F)== 0x1f)
           {
            GotOneResult=1;

            DS18B20_Data[loop].valid=1;
          switch(ScratchPad[4])
           {
            case  0x1f: resolution=9;break;
            case  0x3f: resolution=10;break;
            case  0x5f: resolution=11;break;
            default: resolution=12;break;
           }

          DS18B20_Data[loop].resolution=resolution;
          // Read Temperature

          IntTemp.CHAR[0]=ScratchPad[0];
          IntTemp.CHAR[1]=ScratchPad[1];

          temperature =  0.0625 * (double) IntTemp.SHORT;
          DS18B20_Data[loop].temperature= temperature;
          }
         else
            GotAllResults=0;
         }
       }
   // if(GotOneResult) return(1);
   if(GotAllResults) return(1);
     usleep(10000);
}
return 0;
}





int main(int argc, char **argv)
{
  int temp;
  int loop;
  int Flag=0;
  unsigned long AcqDelay; // Acquisition time delay needed
  unsigned char Hresolution;




  if(argc==1)
  {
    printf("Usage:  DS18B20  GPIOFirst, GPIOSecond, ...,  GPIOLast\n");
    return -1;
  }

  for(loop=1;loop<argc;loop++)
     DS18B20_Pins[loop-1]=atoi(argv[loop]);



  // Set up gpi pointer for direct register access

  //  set default mask


  PinMask = 0;

  for(loop=0;loop<4;loop++)
   {
     ModeMaskInput[loop]=0xffffffffL;
     ModeMaskOutput[loop]=0;
   }



  // set mask for every pin

  for(loop=0;;loop++)
   {
     temp = DS18B20_Pins[loop];
      if(temp<0) break;

      PinMask|= 1<<temp;

     ModeMaskInput[temp/10] &= ~(7<<((temp % 10) * 3));
     ModeMaskOutput[temp/10] |= (1<<((temp % 10) * 3)); 
   }

   setup_io();



// first thing to do is to check all sensor to determine which is the highest resolution
//


   Hresolution=9;

   ReadSensors();

   for(loop=0;;loop++)
    {
      if(DS18B20_Pins[loop]<0) break;
      if(DS18B20_Data[loop].valid)
       if(DS18B20_Data[loop].resolution > Hresolution)
          Hresolution=DS18B20_Data[loop].resolution;
    }

// now set timing according to the highesh resolution sensor.

   switch(Hresolution)
   {

     case 9: AcqDelay= 94000;break;
     case 10: AcqDelay= 188000;break;
     case 11: AcqDelay= 375000;break;
     default: AcqDelay= 750000;
   }


   printf("Highest resolution is %d bits. Acquisition delay will be %dms.\n",Hresolution,AcqDelay/1000);fflush(stdout);
   printf("Hit enter to continue. Ctrl-c to break.\n");
   fflush(stdout);
   getchar();
   clock_gettime(CLOCK_MONOTONIC,&mystart);


// and now the real stuff

    do
   {
   // Do Reset

   clock_gettime(CLOCK_MONOTONIC,&myacqstart);


  set_max_priority();


  DoReset();



  // Start Acquisition

  WriteByte(DS18B20_SKIP_ROM);
  WriteByte(DS18B20_CONVERT_T);

  set_default_priority();

  //  wait  for the highest resolution probe
  usleep(AcqDelay);


  ReadSensors();

   // now let's print result

   clock_gettime(CLOCK_MONOTONIC,&myend);

   printf("====\n%.3f sec  acquisition time = %.3f sec\n",clock_diff(mystart, myacqstart),clock_diff(myacqstart,myend));

   for(loop=0;;loop++)
   {
    if(DS18B20_Pins[loop]<0) break;

    printf("GPIO %d : ",DS18B20_Pins[loop]);

    if(DS18B20_Data[loop].valid)
        printf("%02d bits  Temperature: %6.2f +/- %4.2f Celsius\n", DS18B20_Data[loop].resolution ,DS18B20_Data[loop].temperature, 0.0625 * (double)  (1<<(12 - DS18B20_Data[loop].resolution)));
    else
         printf("Bad CRC!\n");
   }
    fflush(stdout);
  }while(1);
  return 0;
} // main


//
// Set up a memory regions to access GPIO
//
void setup_io()
{
   /* open /dev/mem */
   if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
      printf("can't open /dev/mem \n");
      exit(-1);
   }

   /* mmap GPIO */
   gpio_map = mmap(
      NULL,             //Any adddress in our space will do
      BLOCK_SIZE,       //Map length
      PROT_READ|PROT_WRITE,// Enable reading & writting to mapped memory
      MAP_SHARED,       //Shared with other processes
      mem_fd,           //File to map
      GPIO_BASE         //Offset to GPIO peripheral
   );

   close(mem_fd); //No need to keep mem_fd open after mmap

   if (gpio_map == MAP_FAILED) {
      printf("mmap error %d\n", (int)gpio_map);//errno also set!
      exit(-1);
   }

   // Always use volatile pointer!
   gpio = (volatile unsigned long *)gpio_map;

} // setup_io

and this is the new format for result.

Code: Select all

pi@WebPi ~ $ sudo ./DS18B20V2 4 10
Highest resolution is 10 bits. Acquisition delay will be 188ms.
Hit enter to continue. Ctrl-c to break.

====
0.000 sec  acquisition time = 0.226 sec
GPIO 4 : 09 bits  Temperature:  23.50 +/- 0.50 Celsius
GPIO 10 : 10 bits  Temperature:  23.00 +/- 0.25 Celsius
====
0.227 sec  acquisition time = 0.227 sec
GPIO 4 : 09 bits  Temperature:  23.50 +/- 0.50 Celsius
GPIO 10 : 10 bits  Temperature:  23.25 +/- 0.25 Celsius
====
0.454 sec  acquisition time = 0.205 sec
GPIO 4 : 09 bits  Temperature:  23.50 +/- 0.50 Celsius
GPIO 10 : 10 bits  Temperature:  23.25 +/- 0.25 Celsius
====
0.659 sec  acquisition time = 0.205 sec
GPIO 4 : 09 bits  Temperature:  23.50 +/- 0.50 Celsius
GPIO 10 : 10 bits  Temperature:  23.25 +/- 0.25 Celsius
====
0.865 sec  acquisition time = 0.205 sec
GPIO 4 : 09 bits  Temperature:  23.50 +/- 0.50 Celsius
GPIO 10 : 10 bits  Temperature:  23.25 +/- 0.25 Celsius
====
1.070 sec  acquisition time = 0.205 sec
GPIO 4 : 09 bits  Temperature:  23.50 +/- 0.50 Celsius
GPIO 10 : 10 bits  Temperature:  23.00 +/- 0.25 Celsius
...
...

B.T.W. I'm using 700Mhz clock . If you are using higher speed , please change the "smalldelay" function.

Daniel
Last edited by danjperron on Thu Jul 16, 2015 8:00 pm, edited 2 times in total.

bitlogger
Posts: 3
Joined: Sun Aug 03, 2014 7:58 am

Re: DS18B20 Low Refresh Rate

Thu Aug 07, 2014 6:38 am

Thanks again! How do you think, how hard it could be to modify, for example, kernel module for the TSIC 306 Digital Temperature Sensor to work with DS18B20?

danjperron
Posts: 2833
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: DS18B20 Low Refresh Rate

Thu Aug 07, 2014 11:14 am

Well on first hand the timing looks different and the clock is provided by the sensor.

The driver only needs to check for the edge detection.

For the DS18B20 you will need to provided the clock and check the edge. This will be a little more complicated since you will need to create timing interrupt and this is not my domain of expertise.

With my looping on error, I think the user space version is good enough anyway.

Daniel

BTW I modified the configDS18B20 version. It is now using a parameter to select which sensor you want to change the resolution by selecting the GPIO pin.

This is the source code of configDS18B20.c

Code: Select all

// modified version to read DS18B20 in bit banging
//
//  24 May 2014
//  Daniel Perron
//
// Use At your own risk

// 7 August 2014
// Add arg parameter to select the GPIO pin



// Add the priority function from Adafruit DHT22 c code
//  August 3 , 2014
// Priority added 
// code base on Adafruit DHT22  source code  for  
// set_max_priority and set_default_priority
// Copyright (c) 2014 Adafruit Industries
// Author: Tony DiCola
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALI



//
//  How to access GPIO registers from C-code on the Raspberry-Pi
//  Example program
//  15-January-2012
//  Dom and Gert
//  Revised: 15-Feb-2013


// Access from ARM Running Linux

#define BCM2708_PERI_BASE        0x20000000
#define GPIO_BASE                (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */


#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <time.h>
#include <sched.h>

#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)

int  mem_fd;
void *gpio_map;

// I/O access
volatile unsigned *gpio;


// GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
#define OUT_GPIO(g) *(gpio+((g)/10)) |=  (1<<(((g)%10)*3))
#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))

#define GPIO_SET *(gpio+7)  // sets   bits which are 1 ignores bits which are 0
#define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0

#define GPIO_READ(g)  (*(gpio + 13) &= (1<<(g)))


#define DS18B20_SKIP_ROM 		0xCC
#define DS18B20_CONVERT_T 		0x44
#define DS18B20_READ_SCRATCHPAD         0xBE
#define DS18B20_WRITE_SCRATCHPAD        0x4E
#define DS18B20_COPY_SCRATCHPAD         0x48

unsigned char ScratchPad[9];
double  temperature;
int   resolution;

void setup_io();


unsigned int DS_PIN=4;

void set_max_priority(void) {
  struct sched_param sched;
  memset(&sched, 0, sizeof(sched));
  // Use FIFO scheduler with highest priority for the lowest chance of the kernel context switching.
  sched.sched_priority = sched_get_priority_max(SCHED_FIFO);
  sched_setscheduler(0, SCHED_FIFO, &sched);
}

void set_default_priority(void) {
  struct sched_param sched;
  memset(&sched, 0, sizeof(sched));
  // Go back to default scheduler with default 0 priority.
  sched.sched_priority = 0;
  sched_setscheduler(0, SCHED_OTHER, &sched);
}


int  DoReset(void)
{
 int loop;

   INP_GPIO(DS_PIN);


   usleep(1000);

   INP_GPIO(DS_PIN);
   OUT_GPIO(DS_PIN);
   
   // pin low for 480 us
   GPIO_CLR=1<<DS_PIN;
   usleep(480);
   INP_GPIO(DS_PIN);
   usleep(60);
   if(GPIO_READ(DS_PIN)==0)
   {
     usleep(380);
     return 1;
   }
 
  return 0;
}

#define DELAY1US  smalldelay();

void  smalldelay(void)
{
  int loop2;
   for(loop2=0;loop2<100;loop2++);
}



void WriteByte(unsigned char value)
{
  unsigned char Mask=1;
  int loop;

   for(loop=0;loop<8;loop++)
     {
       INP_GPIO(DS_PIN);
       OUT_GPIO(DS_PIN);
       GPIO_CLR= 1 <<DS_PIN;

       if((value & Mask)!=0)
        {
           DELAY1US
            INP_GPIO(DS_PIN);
           usleep(60);

        }
        else
        {
           usleep(60);
           INP_GPIO(DS_PIN);
           usleep(1);
        }
      Mask*=2;
      usleep(60);
    }


   usleep(100);
}


unsigned char ReadBit(void)
{
   INP_GPIO(DS_PIN);
   OUT_GPIO(DS_PIN);
   // PIN LOW
   GPIO_CLR= 1 << DS_PIN;
   DELAY1US
   // set INPUT
   INP_GPIO(DS_PIN);
   DELAY1US
   DELAY1US
   DELAY1US
   if(GPIO_READ(DS_PIN)!=0)
     return 1;
   return 0;
}

unsigned char ReadByte(void)
{

   unsigned char Mask=1;
   int loop;
   unsigned  char data=0;

  int loop2;


   for(loop=0;loop<8;loop++)
     {
       //  set output
       INP_GPIO(DS_PIN);
       OUT_GPIO(DS_PIN);
       //  PIN LOW
       GPIO_CLR= 1<<DS_PIN;
       DELAY1US
       //  set input
       INP_GPIO(DS_PIN);
       // Wait  2 us
       DELAY1US
       DELAY1US
       DELAY1US
       if(GPIO_READ(DS_PIN)!=0)
       data |= Mask;
       Mask*=2;
       usleep(60);
      }

    return data;
}



int ReadScratchPad(void)
{
   int loop;

    if(DoReset())
     {
       WriteByte(DS18B20_SKIP_ROM);
       WriteByte(DS18B20_READ_SCRATCHPAD);
       for(loop=0;loop<9;loop++)
         {
          ScratchPad[loop]=ReadByte();
        }
    return 1;
  }
  return 0;
}

unsigned char  CalcCRC(unsigned char * data, unsigned char  byteSize)
{
   unsigned char  shift_register = 0;
   unsigned char  loop,loop2;
   char  DataByte;

   for(loop = 0; loop < byteSize; loop++)
   {
      DataByte = *(data + loop);
      for(loop2 = 0; loop2 < 8; loop2++)
      {
         if((shift_register ^ DataByte)& 1)
         {
            shift_register = shift_register >> 1;
            shift_register ^=  0x8C;
         }
         else
            shift_register = shift_register >> 1;
         DataByte = DataByte >> 1;
      }
   }
   return shift_register;
}

int ReadSensor(void)
{
  int maxloop;
  int RetryCount;
  int loop;
  unsigned char  CRCByte;
  union {
   short SHORT;
   unsigned char CHAR[2];
  }IntTemp;


  time_t t = time(NULL);
  struct tm tm = *localtime(&t);

  temperature=-9999.9;


  for(RetryCount=0;RetryCount<5;RetryCount++)
  {



  if(!DoReset()) continue;

  // start a conversion
  WriteByte(DS18B20_SKIP_ROM);
  WriteByte(DS18B20_CONVERT_T);


  maxloop=0;
  // wait until ready
   while(!ReadBit())
   {
    putchar('.');
     maxloop++;
    if(maxloop>100000) break;
   }

  if(maxloop>100000) continue;


  if(!ReadScratchPad()) continue;

     for(loop=0;loop<9;loop++)
       printf("%02X ",ScratchPad[loop]);
     printf("\n");fflush(stdout);

  // OK Check sum Check;
  CRCByte= CalcCRC(ScratchPad,8);

  if(CRCByte!=ScratchPad[8]) continue;

  //Check Resolution
   resolution=0;
   switch(ScratchPad[4])
   {

     case  0x1f: resolution=9;break;
     case  0x3f: resolution=10;break;
     case  0x5f: resolution=11;break;
     case  0x7f: resolution=12;break;
   }

   if(resolution==0) continue;
    // Read Temperature

    IntTemp.CHAR[0]=ScratchPad[0];
    IntTemp.CHAR[1]=ScratchPad[1];


    temperature =  0.0625 * (double) IntTemp.SHORT;

      printf("%02d bits  Temperature: %6.2f +/- %f Celsius\n", resolution ,temperature, 0.0625 * (double)  (1<<(12 - resolution)));

    return 1;
   }
  return 0;
}




void WriteScratchPad(unsigned char TH, unsigned char TL, unsigned char config)
{
int loop;

    // First reset device

    DoReset();

    usleep(1000);
    // Skip ROM command
     WriteByte(DS18B20_SKIP_ROM);


     // Write Scratch pad

    WriteByte(DS18B20_WRITE_SCRATCHPAD);

    // Write TH

    WriteByte(TH);

    // Write TL

    WriteByte(TL);

    // Write config

    WriteByte(config);
}

void  CopyScratchPad(void)
{

   // Reset device
    DoReset();
    usleep(1000);

   // Skip ROM Command

    WriteByte(DS18B20_SKIP_ROM);

   //  copy scratch pad

    WriteByte(DS18B20_COPY_SCRATCHPAD);
    usleep(100000);
}


int main(int argc, char **argv)
{
  int loop;
  int config;
  // Set up gpi pointer for direct register access
  
  if(argc==2)
{
 DS_PIN = atoi(argv[1]);
}

 printf("GPIO %d\n",DS_PIN);

 if((DS_PIN < 1) || (DS_PIN>32))
  {
  printf("Invalid GPIO PIN\n");
  return -1;
  }

  setup_io();
  set_max_priority();

  if(ReadSensor())
    {
     printf("DS18B20 Resolution (9,10,11 or 12) ?");fflush(stdout);

    config=0;
  set_default_priority();

    if(scanf("%d",&resolution)==1)
      {
        switch(resolution)
         {
           case 9:  config=0x1f;break;
           case 10: config=0x3f;break;
           case 11: config=0x5f;break;
           case 12: config=0x7f;break;
         }
      }

    if(config==0)
         printf("Invalid Value! Nothing done.\n");
    else
    {
      printf("Try to set %d bits  config=%2X\n",resolution,config);
      usleep(1000);
        set_max_priority();
 
     WriteScratchPad(ScratchPad[2],ScratchPad[3],config);
      usleep(1000);
      CopyScratchPad();

    }

  }
  set_default_priority();

  return 0;

} // main


//
// Set up a memory regions to access GPIO
//
void setup_io()
{
   /* open /dev/mem */
   if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
      printf("can't open /dev/mem \n");
      exit(-1);
   }

   /* mmap GPIO */
   gpio_map = mmap(
      NULL,             //Any adddress in our space will do
      BLOCK_SIZE,       //Map length
      PROT_READ|PROT_WRITE,// Enable reading & writting to mapped memory
      MAP_SHARED,       //Shared with other processes
      mem_fd,           //File to map
      GPIO_BASE         //Offset to GPIO peripheral
   );

   close(mem_fd); //No need to keep mem_fd open after mmap

   if (gpio_map == MAP_FAILED) {
      printf("mmap error %d\n", (int)gpio_map);//errno also set!
      exit(-1);
   }

   // Always use volatile pointer!
   gpio = (volatile unsigned *)gpio_map;


} // setup_io


And How to use it

Code: Select all

pi@WebPi ~ $ sudo ./configDS18B20 4
GPIO 4
.....80 01 9F CC 1F FF 10 10 38 
09 bits  Temperature:  24.00 +/- 0.500000 Celsius
DS18B20 Resolution (9,10,11 or 12) ?10
Try to set 10 bits  config=3F
pi@WebPi ~ $ sudo ./DS18B20V2 4
Highest resolution is 10 bits. Acquisition delay will be 188ms.
Hit enter to continue. Ctrl-c to break.

====
0.000 sec  acquisition time = 0.226 sec
GPIO 4 : 10 bits  Temperature:  24.00 +/- 0.25 Celsius
====
0.227 sec  acquisition time = 0.228 sec
GPIO 4 : 10 bits  Temperature:  24.00 +/- 0.25 Celsius
====
0.455 sec  acquisition time = 0.205 sec
GPIO 4 : 10 bits  Temperature:  24.00 +/- 0.25 Celsius

Daniel

no1knows89
Posts: 4
Joined: Tue Oct 07, 2014 11:13 pm

Re: DS18B20 Low Refresh Rate

Tue Oct 07, 2014 11:42 pm

Hey,

I'm using your code to read 5 sensors off one GPIO pin. It's great. :D 95% of the time it works really well and fast, but sometimes it will miss one or two sensors. Also, it seems like the first read after a reboot is always 180. It goes back to normal after re-reading a few times. I know all the sensors are working correctly because I used the MUCH slower w1-therm/python code to read the sensors for a few weeks without any misses.

Anyways, I noticed you added error checking and other options to your later code, but it only seems to work with one sensor per GPIO? Would it be possible to add all the newest features of your code to the single GPIO, multiple sensor, version? Maybe a way to define a list of sensor serial numbers to aid in re-trying missed readings? I understand if its too much work.. I have no idea how to code in C so I thought I would ask. :)

danjperron
Posts: 2833
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: DS18B20 Low Refresh Rate

Wed Oct 08, 2014 11:19 am

Yes the first reading is always bad because there is no acquisition on the first one. The approach is to read the first reading and toss it away when you powered the sensor. I'm will have to check my code because normally we start a acquisition, wait for completion and then read it. Looks like that the reading is done before completion.

I will see what I could do to add the re-read loop when the data is invalid for simple GPIO with multiple sensors. But I'm working right now on my MultiIO so it could could take a while.

Daniel

danjperron
Posts: 2833
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: DS18B20 Low Refresh Rate

Wed Oct 08, 2014 11:30 am

Just a quick look and I should include the priority change function into it. Also could you increase the timing to delay the sensor a little bit more , the -t arguments. Are you using the full resolution?

Daniel

no1knows89
Posts: 4
Joined: Tue Oct 07, 2014 11:13 pm

Re: DS18B20 Low Refresh Rate

Wed Oct 08, 2014 11:44 pm

Wow, thanks for the quick reply. I tried a few levels, but right now it's set to 11. I may end up going with 10. I have been using -t 300. Is that bad?

danjperron
Posts: 2833
Joined: Thu Dec 27, 2012 4:05 am
Location: Québec, Canada

Re: DS18B20 Low Refresh Rate

Thu Oct 09, 2014 2:30 am

The delay is for the conversion times.

This is the table from the datasheet

Resolution Vs Max conversion time
9 bits => 94 ms
10 bits => 188 ms
11 bits => 375 ms
12 bits => 750ms.

If your sensor is on 12 bits mode you need a minimum of 750ms for the delay (-t 750).
This could explain why you have a false reading at the first acquisition.

Daniel

Return to “Automation, sensing and robotics”

Who is online

Users browsing this forum: Exabot [Bot] and 6 guests