Dallas' 1-Wire bus protocol library using mbed debug logs

Fork of OneWire by Zoltan Hudak

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers OneWire.cpp Source File

OneWire.cpp

00001 /*
00002 Copyright (c) 2007, Jim Studt  (original old version - many contributors since)
00003 
00004 The latest version of this library may be found at:
00005   http://www.pjrc.com/teensy/td_libs_OneWire.html
00006 
00007 OneWire has been maintained by Paul Stoffregen (paul@pjrc.com) since
00008 January 2010.  At the time, it was in need of many bug fixes, but had
00009 been abandoned the original author (Jim Studt).  None of the known
00010 contributors were interested in maintaining OneWire.  Paul typically
00011 works on OneWire every 6 to 12 months.  Patches usually wait that
00012 long.  If anyone is interested in more actively maintaining OneWire,
00013 please contact Paul.
00014 
00015 Version 2.2:
00016   Teensy 3.0 compatibility, Paul Stoffregen, paul@pjrc.com
00017   Arduino Due compatibility, http://arduino.cc/forum/index.php?topic=141030
00018   Fix DS18B20 example negative temperature
00019   Fix DS18B20 example's low res modes, Ken Butcher
00020   Improve reset timing, Mark Tillotson
00021   Add const qualifiers, Bertrik Sikken
00022   Add initial value input to crc16, Bertrik Sikken
00023   Add target_search() function, Scott Roberts
00024 
00025 Version 2.1:
00026   Arduino 1.0 compatibility, Paul Stoffregen
00027   Improve temperature example, Paul Stoffregen
00028   DS250x_PROM example, Guillermo Lovato
00029   PIC32 (chipKit) compatibility, Jason Dangel, dangel.jason AT gmail.com
00030   Improvements from Glenn Trewitt:
00031   - crc16() now works
00032   - check_crc16() does all of calculation/checking work.
00033   - Added read_bytes() and write_bytes(), to reduce tedious loops.
00034   - Added ds2408 example.
00035   Delete very old, out-of-date readme file (info is here)
00036 
00037 Version 2.0: Modifications by Paul Stoffregen, January 2010:
00038 http://www.pjrc.com/teensy/td_libs_OneWire.html
00039   Search fix from Robin James
00040     http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295/27#27
00041   Use direct optimized I/O in all cases
00042   Disable interrupts during timing critical sections
00043     (this solves many random communication errors)
00044   Disable interrupts during read-modify-write I/O
00045   Reduce RAM consumption by eliminating unnecessary
00046     variables and trimming many to 8 bits
00047   Optimize both crc8 - table version moved to flash
00048 
00049 Modified to work with larger numbers of devices - avoids loop.
00050 Tested in Arduino 11 alpha with 12 sensors.
00051 26 Sept 2008 -- Robin James
00052 http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295/27#27
00053 
00054 Updated to work with arduino-0008 and to include skip() as of
00055 2007/07/06. --RJL20
00056 
00057 Modified to calculate the 8-bit CRC directly, avoiding the need for
00058 the 256-byte lookup table to be loaded in RAM.  Tested in arduino-0010
00059 -- Tom Pollard, Jan 23, 2008
00060 
00061 Jim Studt's original library was modified by Josh Larios.
00062 
00063 Tom Pollard, pollard@alum.mit.edu, contributed around May 20, 2008
00064 
00065 Permission is hereby granted, free of charge, to any person obtaining
00066 a copy of this software and associated documentation files (the
00067 "Software"), to deal in the Software without restriction, including
00068 without limitation the rights to use, copy, modify, merge, publish,
00069 distribute, sublicense, and/or sell copies of the Software, and to
00070 permit persons to whom the Software is furnished to do so, subject to
00071 the following conditions:
00072 
00073 The above copyright notice and this permission notice shall be
00074 included in all copies or substantial portions of the Software.
00075 
00076 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00077 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00078 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00079 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
00080 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
00081 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00082 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00083 
00084 Much of the code was inspired by Derek Yerger's code, though I don't
00085 think much of that remains.  In any event that was..
00086     (copyleft) 2006 by Derek Yerger - Free to distribute freely.
00087 
00088 The CRC code was excerpted and inspired by the Dallas Semiconductor
00089 sample code bearing this copyright.
00090 //---------------------------------------------------------------------------
00091 // Copyright (C) 2000 Dallas Semiconductor Corporation, All Rights Reserved.
00092 //
00093 // Permission is hereby granted, free of charge, to any person obtaining a
00094 // copy of this software and associated documentation files (the "Software"),
00095 // to deal in the Software without restriction, including without limitation
00096 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
00097 // and/or sell copies of the Software, and to permit persons to whom the
00098 // Software is furnished to do so, subject to the following conditions:
00099 //
00100 // The above copyright notice and this permission notice shall be included
00101 // in all copies or substantial portions of the Software.
00102 //
00103 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00104 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00105 // MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00106 // IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES
00107 // OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00108 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00109 // OTHER DEALINGS IN THE SOFTWARE.
00110 //
00111 // Except as contained in this notice, the name of Dallas Semiconductor
00112 // shall not be used except as stated in the Dallas Semiconductor
00113 // Branding Policy.
00114 //--------------------------------------------------------------------------
00115 */
00116 
00117 #include "OneWire.h"
00118 
00119 OneWire::OneWire(PinName pin):
00120     wire(pin)
00121 {   
00122 #if ONEWIRE_SEARCH
00123     reset_search();
00124 #endif
00125 }
00126 
00127 
00128 // Perform the onewire reset function.  We will wait up to 250uS for
00129 // the bus to come high, if it doesn't then it is broken or shorted
00130 // and we return a 0;
00131 //
00132 // Returns 1 if a device asserted a presence pulse, 0 otherwise.
00133 //
00134 uint8_t OneWire::reset(void)
00135 {
00136    uint8_t r;
00137    uint8_t retries = 125;
00138 
00139     wire.input();
00140     // wait until the wire is high... just in case
00141     do {
00142         if (--retries == 0) {
00143              return 0;
00144         }
00145         wait_us(2);
00146     } while (wire.read() != 1);
00147 
00148     wire.output();
00149     wire = 0;
00150     wait_us(480);
00151     wire.input();
00152     wait_us(70);
00153     r = !wire.read();
00154     wait_us(410);
00155     return r;
00156 }
00157 
00158 //
00159 // Write a bit. Port and bit is used to cut lookup time and provide
00160 // more certain timing.
00161 //
00162 void OneWire::write_bit(uint8_t v)
00163 {
00164     wire.output();
00165     if (v & 1) {
00166         wire = 0;   // drive output low
00167         wait_us(10);
00168         wire = 1;   // drive output high
00169         wait_us(55);
00170     } else {
00171         wire = 0;   // drive output low
00172         wait_us(65);
00173         wire = 1;   // drive output high
00174         wait_us(5);
00175     }
00176 }
00177 
00178 //
00179 // Read a bit. Port and bit is used to cut lookup time and provide
00180 // more certain timing.
00181 //
00182 uint8_t OneWire::read_bit(void)
00183 {
00184     uint8_t r;
00185 
00186     wire.output();
00187     wire = 0;
00188     //wait_us(1);
00189     wire.input();
00190     wait_us(5);
00191     r = wire.read();
00192     wait_us(54);
00193     return r;
00194 }
00195 
00196 //
00197 // Write a byte. The writing code uses the active drivers to raise the
00198 // pin high, if you need power after the write (e.g. DS18S20 in
00199 // parasite power mode) then set 'power' to 1, otherwise the pin will
00200 // go tri-state at the end of the write to avoid heating in a short or
00201 // other mishap.
00202 //
00203 void OneWire::write(uint8_t v, uint8_t power /* = 0 */) {
00204     uint8_t bitMask;
00205 
00206     for (bitMask = 0x01; bitMask; bitMask <<= 1) {
00207     OneWire::write_bit( (bitMask & v)?1:0);
00208     }
00209     if ( !power) {
00210         wire.input();
00211     }
00212 }
00213 
00214 void OneWire::write_bytes(const uint8_t *buf, uint16_t count, bool power /* = 0 */) {
00215   for (uint16_t i = 0 ; i < count ; i++)
00216     write(buf[i]);
00217   if (!power) {
00218         wire.input();
00219   }
00220 }
00221 
00222 //
00223 // Read a byte
00224 //
00225 uint8_t OneWire::read() {
00226     uint8_t bitMask;
00227     uint8_t r = 0;
00228 
00229     for (bitMask = 0x01; bitMask; bitMask <<= 1) {
00230     if ( OneWire::read_bit()) r |= bitMask;
00231     }
00232     return r;
00233 }
00234 
00235 void OneWire::read_bytes(uint8_t *buf, uint16_t count) {
00236   for (uint16_t i = 0 ; i < count ; i++)
00237     buf[i] = read();
00238 }
00239 
00240 //
00241 // Do a ROM select
00242 //
00243 void OneWire::select(const uint8_t rom[8])
00244 {
00245     uint8_t i;
00246 
00247     write(0x55);           // Choose ROM
00248 
00249     for (i = 0; i < 8; i++) write(rom[i]);
00250 }
00251 
00252 //
00253 // Do a ROM skip
00254 //
00255 void OneWire::skip()
00256 {
00257     write(0xCC);           // Skip ROM
00258 }
00259 
00260 void OneWire::depower()
00261 {
00262     wire.input();
00263 }
00264 
00265 #if ONEWIRE_SEARCH
00266 
00267 //
00268 // You need to use this function to start a search again from the beginning.
00269 // You do not need to do it for the first search, though you could.
00270 //
00271 void OneWire::reset_search()
00272 {
00273   // reset the search state
00274   LastDiscrepancy = 0;
00275   LastDeviceFlag = false;
00276   LastFamilyDiscrepancy = 0;
00277   for(int i = 7; ; i--) {
00278     ROM_NO[i] = 0;
00279     if ( i == 0) break;
00280   }
00281 }
00282 
00283 // Setup the search to find the device type 'family_code' on the next call
00284 // to search(*newAddr) if it is present.
00285 //
00286 void OneWire::target_search(uint8_t family_code)
00287 {
00288    // set the search state to find SearchFamily type devices
00289    ROM_NO[0] = family_code;
00290    for (uint8_t i = 1; i < 8; i++)
00291       ROM_NO[i] = 0;
00292    LastDiscrepancy = 64;
00293    LastFamilyDiscrepancy = 0;
00294    LastDeviceFlag = false;
00295 }
00296 
00297 //
00298 // Perform a search. If this function returns a '1' then it has
00299 // enumerated the next device and you may retrieve the ROM from the
00300 // OneWire::address variable. If there are no devices, no further
00301 // devices, or something horrible happens in the middle of the
00302 // enumeration then a 0 is returned.  If a new device is found then
00303 // its address is copied to newAddr.  Use OneWire::reset_search() to
00304 // start over.
00305 //
00306 // --- Replaced by the one from the Dallas Semiconductor web site ---
00307 //--------------------------------------------------------------------------
00308 // Perform the 1-Wire Search Algorithm on the 1-Wire bus using the existing
00309 // search state.
00310 // Return true  : device found, ROM number in ROM_NO buffer
00311 //        false : device not found, end of search
00312 //
00313 uint8_t OneWire::search(uint8_t *newAddr)
00314 {
00315    uint8_t id_bit_number;
00316    uint8_t last_zero, rom_byte_number, search_result;
00317    uint8_t id_bit, cmp_id_bit;
00318 
00319    unsigned char rom_byte_mask, search_direction;
00320 
00321    // initialize for search
00322    id_bit_number = 1;
00323    last_zero = 0;
00324    rom_byte_number = 0;
00325    rom_byte_mask = 1;
00326    search_result = 0;
00327 
00328    // if the last call was not the last one
00329    if (!LastDeviceFlag)
00330    {
00331       // 1-Wire reset
00332       if (!reset())
00333       {
00334          // reset the search
00335          LastDiscrepancy = 0;
00336          LastDeviceFlag = false;
00337          LastFamilyDiscrepancy = 0;
00338          return false;
00339       }
00340 
00341       // issue the search command
00342       write(0xF0);
00343 
00344       // loop to do the search
00345       do
00346       {
00347          // read a bit and its complement
00348          id_bit = read_bit();
00349          cmp_id_bit = read_bit();
00350 
00351          // check for no devices on 1-wire
00352          if ((id_bit == 1) && (cmp_id_bit == 1))
00353             break;
00354          else
00355          {
00356             // all devices coupled have 0 or 1
00357             if (id_bit != cmp_id_bit)
00358                search_direction = id_bit;  // bit write value for search
00359             else
00360             {
00361                // if this discrepancy if before the Last Discrepancy
00362                // on a previous next then pick the same as last time
00363                if (id_bit_number < LastDiscrepancy)
00364                   search_direction = ((ROM_NO[rom_byte_number] & rom_byte_mask) > 0);
00365                else
00366                   // if equal to last pick 1, if not then pick 0
00367                   search_direction = (id_bit_number == LastDiscrepancy);
00368 
00369                // if 0 was picked then record its position in LastZero
00370                if (search_direction == 0)
00371                {
00372                   last_zero = id_bit_number;
00373 
00374                   // check for Last discrepancy in family
00375                   if (last_zero < 9)
00376                      LastFamilyDiscrepancy = last_zero;
00377                }
00378             }
00379 
00380             // set or clear the bit in the ROM byte rom_byte_number
00381             // with mask rom_byte_mask
00382             if (search_direction == 1)
00383               ROM_NO[rom_byte_number] |= rom_byte_mask;
00384             else
00385               ROM_NO[rom_byte_number] &= ~rom_byte_mask;
00386 
00387             // serial number search direction write bit
00388             write_bit(search_direction);
00389 
00390             // increment the byte counter id_bit_number
00391             // and shift the mask rom_byte_mask
00392             id_bit_number++;
00393             rom_byte_mask <<= 1;
00394 
00395             // if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask
00396             if (rom_byte_mask == 0)
00397             {
00398                 rom_byte_number++;
00399                 rom_byte_mask = 1;
00400             }
00401          }
00402       }
00403       while(rom_byte_number < 8);  // loop until through all ROM bytes 0-7
00404 
00405       // if the search was successful then
00406       if (!(id_bit_number < 65))
00407       {
00408          // search successful so set LastDiscrepancy,LastDeviceFlag,search_result
00409          LastDiscrepancy = last_zero;
00410 
00411          // check for last device
00412          if (LastDiscrepancy == 0)
00413             LastDeviceFlag = true;
00414 
00415          search_result = true;
00416       }
00417    }
00418 
00419    // if no device found then reset counters so next 'search' will be like a first
00420    if (!search_result || !ROM_NO[0])
00421    {
00422       LastDiscrepancy = 0;
00423       LastDeviceFlag = false;
00424       LastFamilyDiscrepancy = 0;
00425       search_result = false;
00426    }
00427    for (int i = 0; i < 8; i++) newAddr[i] = ROM_NO[i];
00428    return search_result;
00429   }
00430 
00431 #endif
00432 
00433 #if ONEWIRE_CRC
00434 // The 1-Wire CRC scheme is described in Maxim Application Note 27:
00435 // "Understanding and Using Cyclic Redundancy Checks with Maxim iButton Products"
00436 // Compute a Dallas Semiconductor 8 bit CRC directly.
00437 //
00438 uint8_t OneWire::crc8(const uint8_t *addr, uint8_t len)
00439 {
00440     uint8_t crc = 0;
00441     
00442     while (len--) {
00443         uint8_t inbyte = *addr++;
00444         for (uint8_t i = 8; i; i--) {
00445             uint8_t mix = (crc ^ inbyte) & 0x01;
00446             crc >>= 1;
00447             if (mix) crc ^= 0x8C;
00448             inbyte >>= 1;
00449         }
00450     }
00451     return crc;
00452 }
00453 #endif