Руслан Бредун / Mbed 2 deprecated stm32-sensor-base2

Dependencies:   mbed Watchdog

Dependents:   STM32-MC_node

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_Onehtml
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 One  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_Onehtml
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 #include "OneWire.h"
00117 
00118 
00119 /**
00120  * @brief   Constructs a OneWire object.
00121  * @note    GPIO is configured as output and an internal pull up resistor is connected.
00122  *          But because for STM chips it takes very long time to change from output
00123  *          to input an open drain mode is used rather and the GPIO remains output forever.
00124  * @param
00125  * @retval
00126  */
00127 OneWire::OneWire(PinName pin, int sample_point_us /* = 13 */) :
00128     DigitalInOut(pin),
00129     _sample_point_us(sample_point_us)
00130 {
00131     Timer timer;
00132 
00133     MODE(); // set mode to either OpenDrain for STM or PullUp for others
00134 
00135     // Measure bus transition time from ouput to input
00136     timer.reset();
00137     OUTPUT();       // set as output
00138     WRITE(0);       // pull the line down
00139     timer.start();
00140     INPUT();        // set as input (and release the bus)
00141     timer.stop();
00142     _out_to_in_transition_us = timer.read_us();
00143 
00144     MBED_ASSERT(_out_to_in_transition_us < _sample_point_us);
00145 
00146     INIT_WAIT;
00147 #if ONEWIRE_SEARCH
00148     reset_search();
00149 #endif
00150 }
00151 
00152 /**
00153  * @brief   Performs the onewire reset function.
00154  * @note    We will wait up to 250uS for the bus to come high, 
00155  *          if it doesn't then it is broken or shorted and we return a 0;
00156  * @param
00157  * @retval  1 if a device asserted a presence pulse, 0 otherwise.
00158  */
00159 uint8_t OneWire::reset(void)
00160 {
00161     uint8_t present;
00162 
00163     OUTPUT();
00164     WRITE(0);           // pull down the 1-wire bus do create reset pulse
00165     WAIT_US(500);       // wait at least 480 us
00166     INPUT();            // release the 1-wire bus and go into receive mode
00167     WAIT_US(90);        // DS1820 waits about 15 to 60 us and generates a 60 to 240 us presence pulse
00168     present = !READ();  // read the presence pulse
00169     WAIT_US(420);
00170     
00171     return present;
00172 }
00173 
00174 /**
00175  * @brief   Writes a bit.
00176  * @note    GPIO registers are used for STM chips to cut time.
00177  * @param
00178  * @retval
00179  */
00180 void OneWire::write_bit(uint8_t v)
00181 {
00182     OUTPUT();
00183     if (v & 1) {
00184         WRITE(0);   // drive output low
00185         WAIT_US(1);
00186         WRITE(1);   // drive output high
00187         WAIT_US(60);
00188     }
00189     else {
00190         WRITE(0);   // drive output low
00191         WAIT_US(60);
00192         WRITE(1);   // drive output high
00193         WAIT_US(1);
00194     }
00195 }
00196 
00197 /**
00198  * @brief   Reads a bit.
00199  * @note    GPIO registers are used for STM chips to cut time.
00200  * @param
00201  * @retval
00202  */
00203 uint8_t OneWire::read_bit(void)
00204 {
00205     uint8_t r;
00206 
00207     OUTPUT();
00208     WRITE(0);
00209     INPUT();
00210     wait_us(_sample_point_us - _out_to_in_transition_us);    // wait till sample point
00211     r = READ();
00212     WAIT_US(55);
00213     return r;
00214 }
00215 
00216 /**
00217  * @brief   Writes a byte.
00218  * @note    The writing code uses the active drivers to raise the
00219             pin high, if you need power after the write (e.g. DS18S20 in
00220             parasite power mode) then set 'power' to 1, otherwise the pin will
00221             go tri-state at the end of the write to avoid heating in a short or
00222             other mishap.
00223  * @param
00224  * @retval
00225  */
00226 void OneWire::write_byte(uint8_t v, uint8_t power /* = 0 */ )
00227 {
00228     uint8_t bitMask;
00229 
00230     for (bitMask = 0x01; bitMask; bitMask <<= 1)
00231         write_bit((bitMask & v) ? 1 : 0);
00232     if (!power)
00233         INPUT();
00234 }
00235 
00236 /**
00237  * @brief   Writes bytes.
00238  * @note
00239  * @param
00240  * @retval
00241  */
00242 void OneWire::write_bytes(const uint8_t* buf, uint16_t count, bool power /* = 0 */ )
00243 {
00244     for (uint16_t i = 0; i < count; i++)
00245         write_byte(buf[i]);
00246     if (!power)
00247         INPUT();
00248 }
00249 
00250 /**
00251  * @brief   Reads a byte.
00252  * @note
00253  * @param
00254  * @retval
00255  */
00256 uint8_t OneWire::read_byte()
00257 {
00258     uint8_t bitMask;
00259     uint8_t r = 0;
00260 
00261     for (bitMask = 0x01; bitMask; bitMask <<= 1) {
00262         if (read_bit())
00263             r |= bitMask;
00264     }
00265 
00266     return r;
00267 }
00268 
00269 /**
00270  * @brief   Reads bytes.
00271  * @note
00272  * @param
00273  * @retval
00274  */
00275 void OneWire::read_bytes(uint8_t* buf, uint16_t count)
00276 {
00277     for (uint16_t i = 0; i < count; i++)
00278         buf[i] = read_byte();
00279 }
00280 
00281 /**
00282  * @brief   Selects ROM.
00283  * @note
00284  * @param
00285  * @retval
00286  */
00287 void OneWire::select(const uint8_t rom[8])
00288 {
00289     uint8_t i;
00290 
00291     write_byte(0x55);   // Choose ROM
00292     for (i = 0; i < 8; i++)
00293         write_byte(rom[i]);
00294 }
00295 
00296 /**
00297  * @brief   Skips ROM select.
00298  * @note
00299  * @param
00300  * @retval
00301  */
00302 void OneWire::skip()
00303 {
00304     write_byte(0xCC);   // Skip ROM
00305 }
00306 
00307 /**
00308  * @brief   Unpowers the chip.
00309  * @note
00310  * @param
00311  * @retval
00312  */
00313 void OneWire::depower()
00314 {
00315     INPUT();
00316 }
00317 
00318 #if ONEWIRE_SEARCH
00319 //
00320 
00321 /**
00322  * @brief   Resets the search state.
00323  * @note    We need to use this function to start a search again from the beginning.
00324  *          We do not need to do it for the first search, though we could.
00325  * @param
00326  * @retval
00327  */
00328 void OneWire::reset_search()
00329 {
00330     // reset the search state
00331     LastDiscrepancy = 0;
00332     LastDeviceFlag = false;
00333     LastFamilyDiscrepancy = 0;
00334     for (int i = 7;; i--) {
00335         ROM_NO[i] = 0;
00336         if (i == 0)
00337             break;
00338     }
00339 }
00340 
00341 /**
00342  * @brief   Sets the search state to find SearchFamily type devices.
00343  * @note
00344  * @param
00345  * @retval
00346  */
00347 void OneWire::target_search(uint8_t family_code)
00348 {
00349     // set the search state to find SearchFamily type devices
00350     ROM_NO[0] = family_code;
00351     for (uint8_t i = 1; i < 8; i++)
00352         ROM_NO[i] = 0;
00353     LastDiscrepancy = 64;
00354     LastFamilyDiscrepancy = 0;
00355     LastDeviceFlag = false;
00356 }
00357 
00358 /**
00359  * @brief   Performs a search.
00360  * @note    Perform a search. If this function returns a '1' then it has
00361             enumerated the next device and you may retrieve the ROM from the
00362             OneWire::address variable. If there are no devices, no further
00363             devices, or something horrible happens in the middle of the
00364             enumeration then a 0 is returned.  If a new device is found then
00365             its address is copied to newAddr.  Use OneWire::reset_search() to
00366             start over.
00367             
00368             --- Replaced by the one from the Dallas Semiconductor web site ---
00369             -------------------------------------------------------------------------
00370             Perform the 1-Wire Search Algorithm on the 1-Wire bus using the existing
00371             search state.
00372  * @param
00373  * @retval  true  : device found, ROM number in ROM_NO buffer
00374  *          false : device not found, end of search
00375  */
00376 uint8_t OneWire::search(uint8_t* newAddr)
00377 {
00378     uint8_t         id_bit_number;
00379     uint8_t         last_zero, rom_byte_number, search_result;
00380     uint8_t         id_bit, cmp_id_bit;
00381 
00382     unsigned char   rom_byte_mask, search_direction;
00383 
00384     // initialize for search
00385     id_bit_number = 1;
00386     last_zero = 0;
00387     rom_byte_number = 0;
00388     rom_byte_mask = 1;
00389     search_result = 0;
00390     
00391     // if the last call was not the last one
00392     if (!LastDeviceFlag) {
00393         // 1-Wire reset
00394         if (!reset()) {
00395             // reset the search
00396             LastDiscrepancy = 0;
00397             LastDeviceFlag = false;
00398             LastFamilyDiscrepancy = 0;
00399             return false;
00400         }
00401 
00402         // issue the search command
00403         write_byte(0xF0);
00404 
00405         // loop to do the search
00406         do {
00407             // read a bit and its complement
00408             id_bit = read_bit();
00409             cmp_id_bit = read_bit();
00410 
00411             // check for no devices on 1-wire
00412             if ((id_bit == 1) && (cmp_id_bit == 1))
00413                 break;
00414             else {
00415                 // all devices coupled have 0 or 1
00416                 if (id_bit != cmp_id_bit)
00417                     search_direction = id_bit;  // bit write value for search
00418                 else {
00419                     // if this discrepancy if before the Last Discrepancy
00420                     // on a previous next then pick the same as last time
00421                     if (id_bit_number < LastDiscrepancy)
00422                         search_direction = ((ROM_NO[rom_byte_number] & rom_byte_mask) > 0);
00423                     else
00424                         // if equal to last pick 1, if not then pick 0
00425                         search_direction = (id_bit_number == LastDiscrepancy);
00426 
00427                     // if 0 was picked then record its position in LastZero
00428                     if (search_direction == 0) {
00429                         last_zero = id_bit_number;
00430 
00431                         // check for Last discrepancy in family
00432                         if (last_zero < 9)
00433                             LastFamilyDiscrepancy = last_zero;
00434                     }
00435                 }
00436 
00437                 // set or clear the bit in the ROM byte rom_byte_number
00438                 // with mask rom_byte_mask
00439                 if (search_direction == 1)
00440                     ROM_NO[rom_byte_number] |= rom_byte_mask;
00441                 else
00442                     ROM_NO[rom_byte_number] &= ~rom_byte_mask;
00443 
00444                 // serial number search direction write bit
00445                 write_bit(search_direction);
00446 
00447                 // increment the byte counter id_bit_number
00448                 // and shift the mask rom_byte_mask
00449                 id_bit_number++;
00450                 rom_byte_mask <<= 1;
00451 
00452                 // if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask
00453                 if (rom_byte_mask == 0) {
00454                     rom_byte_number++;
00455                     rom_byte_mask = 1;
00456                 }
00457             }
00458         } while (rom_byte_number < 8);
00459         // loop until through all ROM bytes 0-7
00460         // if the search was successful then
00461         if (!(id_bit_number < 65)) {
00462             // search successful so set LastDiscrepancy,LastDeviceFlag,search_result
00463             LastDiscrepancy = last_zero;
00464 
00465             // check for last device
00466             if (LastDiscrepancy == 0)
00467                 LastDeviceFlag = true;
00468 
00469             search_result = true;
00470         }
00471     }
00472 
00473     // if no device found then reset counters so next 'search' will be like a first
00474     if (!search_result || !ROM_NO[0]) {
00475         LastDiscrepancy = 0;
00476         LastDeviceFlag = false;
00477         LastFamilyDiscrepancy = 0;
00478         search_result = false;
00479     }
00480 
00481     for (int i = 0; i < 8; i++)
00482         newAddr[i] = ROM_NO[i];
00483     return search_result;
00484 }
00485 #endif
00486 //
00487 #if ONEWIRE_CRC
00488 //
00489 /**
00490  * @brief   Computes a Dallas Semiconductor 8 bit CRC directly.
00491  * @note    The 1-Wire CRC scheme is described in Maxim Application Note 27:
00492             "Understanding and Using Cyclic Redundancy Checks with Maxim iButton Products"
00493  * @param
00494  * @retval
00495  */
00496 uint8_t OneWire::crc8(const uint8_t* addr, uint8_t len)
00497 {
00498     uint8_t crc = 0;
00499 
00500     while (len--) {
00501         uint8_t inbyte = *addr++;
00502         for (uint8_t i = 8; i; i--) {
00503             uint8_t mix = (crc ^ inbyte) & 0x01;
00504             crc >>= 1;
00505             if (mix)
00506                 crc ^= 0x8C;
00507             inbyte >>= 1;
00508         }
00509     }
00510 
00511     return crc;
00512 }
00513 #endif