Dallas' 1-Wire bus protocol library
Dependents: DS1825 DISCO-F746-Dessiccateur-V1 watersenor_and_temp_code DS1820 ... more
OneWire.h@17:bbe8bf32e8bc, 2020-12-29 (annotated)
- Committer:
- hudakz
- Date:
- Tue Dec 29 16:06:46 2020 +0000
- Revision:
- 17:bbe8bf32e8bc
- Parent:
- 16:4c3edd30ad6e
1-wre bus: Modified.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
hudakz | 0:acf75feb0947 | 1 | #ifndef OneWire_h |
hudakz | 0:acf75feb0947 | 2 | #define OneWire_h |
hudakz | 0:acf75feb0947 | 3 | |
hudakz | 0:acf75feb0947 | 4 | #include <inttypes.h> |
hudakz | 0:acf75feb0947 | 5 | #include <mbed.h> |
hudakz | 16:4c3edd30ad6e | 6 | #include "SerialBase.h" |
hudakz | 0:acf75feb0947 | 7 | |
hudakz | 17:bbe8bf32e8bc | 8 | #define MODE() _gpio->mode(PullUp) |
hudakz | 17:bbe8bf32e8bc | 9 | #define INPUT() _gpio->input() |
hudakz | 17:bbe8bf32e8bc | 10 | #define OUTPUT() _gpio->output() |
hudakz | 17:bbe8bf32e8bc | 11 | #define READ() _gpio->read() |
hudakz | 17:bbe8bf32e8bc | 12 | #define WRITE(x) _gpio->write(x) |
hudakz | 10:c89b9ad6097c | 13 | |
hudakz | 12:27a1b359b95c | 14 | #ifdef TARGET_NORDIC |
hudakz | 12:27a1b359b95c | 15 | //NORDIC targets (NRF) use software delays since their ticker uses a 32kHz clock |
hudakz | 12:27a1b359b95c | 16 | static uint32_t loops_per_us = 0; |
hudakz | 16:4c3edd30ad6e | 17 | |
hudakz | 12:27a1b359b95c | 18 | #define INIT_WAIT init_soft_delay() |
hudakz | 12:27a1b359b95c | 19 | #define WAIT_US(x) for(int cnt = 0; cnt < (x * loops_per_us) >> 5; cnt++) {__NOP(); __NOP(); __NOP();} |
hudakz | 16:4c3edd30ad6e | 20 | |
hudakz | 12:27a1b359b95c | 21 | void init_soft_delay( void ) { |
hudakz | 12:27a1b359b95c | 22 | if (loops_per_us == 0) { |
hudakz | 12:27a1b359b95c | 23 | loops_per_us = 1; |
hudakz | 16:4c3edd30ad6e | 24 | Timer timey; |
hudakz | 12:27a1b359b95c | 25 | timey.start(); |
hudakz | 16:4c3edd30ad6e | 26 | ONEWIRE_DELAY_US(320000); |
hudakz | 12:27a1b359b95c | 27 | timey.stop(); |
hudakz | 16:4c3edd30ad6e | 28 | loops_per_us = (320000 + timey.read_us() / 2) / timey.read_us(); |
hudakz | 12:27a1b359b95c | 29 | } |
hudakz | 12:27a1b359b95c | 30 | } |
hudakz | 12:27a1b359b95c | 31 | #else |
hudakz | 12:27a1b359b95c | 32 | #define INIT_WAIT |
hudakz | 12:27a1b359b95c | 33 | #define WAIT_US(x) wait_us(x) |
hudakz | 12:27a1b359b95c | 34 | #endif |
hudakz | 12:27a1b359b95c | 35 | |
hudakz | 0:acf75feb0947 | 36 | // You can exclude certain features from OneWire. In theory, this |
hudakz | 0:acf75feb0947 | 37 | // might save some space. In practice, the compiler automatically |
hudakz | 0:acf75feb0947 | 38 | // removes unused code (technically, the linker, using -fdata-sections |
hudakz | 0:acf75feb0947 | 39 | // and -ffunction-sections when compiling, and Wl,--gc-sections |
hudakz | 0:acf75feb0947 | 40 | // when linking), so most of these will not result in any code size |
hudakz | 0:acf75feb0947 | 41 | // reduction. Well, unless you try to use the missing features |
hudakz | 0:acf75feb0947 | 42 | // and redesign your program to not need them! ONEWIRE_CRC8_TABLE |
hudakz | 0:acf75feb0947 | 43 | // is the exception, because it selects a fast but large algorithm |
hudakz | 0:acf75feb0947 | 44 | // or a small but slow algorithm. |
hudakz | 0:acf75feb0947 | 45 | |
hudakz | 0:acf75feb0947 | 46 | // you can exclude onewire_search by defining that to 0 |
hudakz | 0:acf75feb0947 | 47 | #ifndef ONEWIRE_SEARCH |
hudakz | 0:acf75feb0947 | 48 | #define ONEWIRE_SEARCH 1 |
hudakz | 0:acf75feb0947 | 49 | #endif |
hudakz | 0:acf75feb0947 | 50 | |
hudakz | 0:acf75feb0947 | 51 | // You can exclude CRC checks altogether by defining this to 0 |
hudakz | 0:acf75feb0947 | 52 | #ifndef ONEWIRE_CRC |
hudakz | 0:acf75feb0947 | 53 | #define ONEWIRE_CRC 1 |
hudakz | 0:acf75feb0947 | 54 | #endif |
hudakz | 0:acf75feb0947 | 55 | |
hudakz | 16:4c3edd30ad6e | 56 | class UART : |
hudakz | 16:4c3edd30ad6e | 57 | public SerialBase, |
hudakz | 16:4c3edd30ad6e | 58 | private NonCopyable<UART> |
hudakz | 0:acf75feb0947 | 59 | { |
hudakz | 16:4c3edd30ad6e | 60 | UART(const UART&); |
hudakz | 16:4c3edd30ad6e | 61 | public: |
hudakz | 16:4c3edd30ad6e | 62 | UART(PinName tx, PinName rx, int baud) : SerialBase(tx, rx, baud) {} |
hudakz | 16:4c3edd30ad6e | 63 | |
hudakz | 16:4c3edd30ad6e | 64 | using SerialBase::_base_getc; |
hudakz | 16:4c3edd30ad6e | 65 | using SerialBase::_base_putc; |
hudakz | 16:4c3edd30ad6e | 66 | }; |
hudakz | 16:4c3edd30ad6e | 67 | |
hudakz | 16:4c3edd30ad6e | 68 | class OneWire |
hudakz | 16:4c3edd30ad6e | 69 | { |
hudakz | 16:4c3edd30ad6e | 70 | DigitalInOut* _gpio; |
hudakz | 16:4c3edd30ad6e | 71 | UART* _uart; |
hudakz | 16:4c3edd30ad6e | 72 | |
hudakz | 16:4c3edd30ad6e | 73 | int _samplePoint_us; |
hudakz | 16:4c3edd30ad6e | 74 | int _outToInTransition_us; |
hudakz | 0:acf75feb0947 | 75 | |
hudakz | 0:acf75feb0947 | 76 | #if ONEWIRE_SEARCH |
hudakz | 0:acf75feb0947 | 77 | // global search state |
hudakz | 0:acf75feb0947 | 78 | unsigned char ROM_NO[8]; |
hudakz | 0:acf75feb0947 | 79 | uint8_t LastDiscrepancy; |
hudakz | 0:acf75feb0947 | 80 | uint8_t LastFamilyDiscrepancy; |
hudakz | 0:acf75feb0947 | 81 | uint8_t LastDeviceFlag; |
hudakz | 0:acf75feb0947 | 82 | #endif |
hudakz | 0:acf75feb0947 | 83 | |
hudakz | 9:4af0015b0f47 | 84 | public: |
hudakz | 16:4c3edd30ad6e | 85 | |
hudakz | 16:4c3edd30ad6e | 86 | // Constructors |
hudakz | 16:4c3edd30ad6e | 87 | OneWire(PinName gpioPin, int samplePoint_us = 13); // GPIO |
hudakz | 16:4c3edd30ad6e | 88 | OneWire(PinName txPin, PinName rxPin, int baud = 115200); // UART |
hudakz | 16:4c3edd30ad6e | 89 | |
hudakz | 16:4c3edd30ad6e | 90 | // Destructor |
hudakz | 16:4c3edd30ad6e | 91 | ~OneWire(); |
hudakz | 0:acf75feb0947 | 92 | |
hudakz | 0:acf75feb0947 | 93 | // Perform a 1-Wire reset cycle. Returns 1 if a device responds |
hudakz | 0:acf75feb0947 | 94 | // with a presence pulse. Returns 0 if there is no device or the |
hudakz | 0:acf75feb0947 | 95 | // bus is shorted or otherwise held low for more than 250uS |
hudakz | 0:acf75feb0947 | 96 | uint8_t reset(void); |
hudakz | 0:acf75feb0947 | 97 | |
hudakz | 0:acf75feb0947 | 98 | // Issue a 1-Wire rom select command, you do the reset first. |
hudakz | 0:acf75feb0947 | 99 | void select(const uint8_t rom[8]); |
hudakz | 0:acf75feb0947 | 100 | |
hudakz | 0:acf75feb0947 | 101 | // Issue a 1-Wire rom skip command, to address all on bus. |
hudakz | 0:acf75feb0947 | 102 | void skip(void); |
hudakz | 0:acf75feb0947 | 103 | |
hudakz | 0:acf75feb0947 | 104 | // Write a byte. If 'power' is one then the wire is held high at |
hudakz | 0:acf75feb0947 | 105 | // the end for parasitically powered devices. You are responsible |
hudakz | 0:acf75feb0947 | 106 | // for eventually depowering it by calling depower() or doing |
hudakz | 0:acf75feb0947 | 107 | // another read or write. |
hudakz | 9:4af0015b0f47 | 108 | void write_byte(uint8_t v, uint8_t power = 0); |
hudakz | 0:acf75feb0947 | 109 | |
hudakz | 0:acf75feb0947 | 110 | void write_bytes(const uint8_t *buf, uint16_t count, bool power = 0); |
hudakz | 0:acf75feb0947 | 111 | |
hudakz | 0:acf75feb0947 | 112 | // Read a byte. |
hudakz | 9:4af0015b0f47 | 113 | uint8_t read_byte(void); |
hudakz | 0:acf75feb0947 | 114 | |
hudakz | 0:acf75feb0947 | 115 | void read_bytes(uint8_t *buf, uint16_t count); |
hudakz | 0:acf75feb0947 | 116 | |
hudakz | 0:acf75feb0947 | 117 | // Write a bit. The bus is always left powered at the end, see |
hudakz | 0:acf75feb0947 | 118 | // note in write() about that. |
hudakz | 0:acf75feb0947 | 119 | void write_bit(uint8_t v); |
hudakz | 0:acf75feb0947 | 120 | |
hudakz | 0:acf75feb0947 | 121 | // Read a bit. |
hudakz | 0:acf75feb0947 | 122 | uint8_t read_bit(void); |
hudakz | 0:acf75feb0947 | 123 | |
hudakz | 0:acf75feb0947 | 124 | // Stop forcing power onto the bus. You only need to do this if |
hudakz | 0:acf75feb0947 | 125 | // you used the 'power' flag to write() or used a write_bit() call |
hudakz | 0:acf75feb0947 | 126 | // and aren't about to do another read or write. You would rather |
hudakz | 0:acf75feb0947 | 127 | // not leave this powered if you don't have to, just in case |
hudakz | 0:acf75feb0947 | 128 | // someone shorts your bus. |
hudakz | 0:acf75feb0947 | 129 | void depower(void); |
hudakz | 0:acf75feb0947 | 130 | |
hudakz | 0:acf75feb0947 | 131 | #if ONEWIRE_SEARCH |
hudakz | 0:acf75feb0947 | 132 | // Clear the search state so that if will start from the beginning again. |
hudakz | 0:acf75feb0947 | 133 | void reset_search(); |
hudakz | 0:acf75feb0947 | 134 | |
hudakz | 0:acf75feb0947 | 135 | // Setup the search to find the device type 'family_code' on the next call |
hudakz | 0:acf75feb0947 | 136 | // to search(*newAddr) if it is present. |
hudakz | 0:acf75feb0947 | 137 | void target_search(uint8_t family_code); |
hudakz | 0:acf75feb0947 | 138 | |
hudakz | 0:acf75feb0947 | 139 | // Look for the next device. Returns 1 if a new address has been |
hudakz | 0:acf75feb0947 | 140 | // returned. A zero might mean that the bus is shorted, there are |
hudakz | 0:acf75feb0947 | 141 | // no devices, or you have already retrieved all of them. It |
hudakz | 0:acf75feb0947 | 142 | // might be a good idea to check the CRC to make sure you didn't |
hudakz | 0:acf75feb0947 | 143 | // get garbage. The order is deterministic. You will always get |
hudakz | 0:acf75feb0947 | 144 | // the same devices in the same order. |
hudakz | 0:acf75feb0947 | 145 | uint8_t search(uint8_t *newAddr); |
hudakz | 0:acf75feb0947 | 146 | #endif |
hudakz | 0:acf75feb0947 | 147 | |
hudakz | 0:acf75feb0947 | 148 | #if ONEWIRE_CRC |
hudakz | 0:acf75feb0947 | 149 | // Compute a Dallas Semiconductor 8 bit CRC, these are used in the |
hudakz | 0:acf75feb0947 | 150 | // ROM and scratchpad registers. |
hudakz | 0:acf75feb0947 | 151 | static uint8_t crc8(const uint8_t *addr, uint8_t len); |
hudakz | 0:acf75feb0947 | 152 | |
hudakz | 0:acf75feb0947 | 153 | #if ONEWIRE_CRC16 |
hudakz | 0:acf75feb0947 | 154 | // Compute the 1-Wire CRC16 and compare it against the received CRC. |
hudakz | 0:acf75feb0947 | 155 | // Example usage (reading a DS2408): |
hudakz | 0:acf75feb0947 | 156 | // // Put everything in a buffer so we can compute the CRC easily. |
hudakz | 0:acf75feb0947 | 157 | // uint8_t buf[13]; |
hudakz | 0:acf75feb0947 | 158 | // buf[0] = 0xF0; // Read PIO Registers |
hudakz | 0:acf75feb0947 | 159 | // buf[1] = 0x88; // LSB address |
hudakz | 0:acf75feb0947 | 160 | // buf[2] = 0x00; // MSB address |
hudakz | 0:acf75feb0947 | 161 | // WriteBytes(net, buf, 3); // Write 3 cmd bytes |
hudakz | 0:acf75feb0947 | 162 | // ReadBytes(net, buf+3, 10); // Read 6 data bytes, 2 0xFF, 2 CRC16 |
hudakz | 0:acf75feb0947 | 163 | // if (!CheckCRC16(buf, 11, &buf[11])) { |
hudakz | 0:acf75feb0947 | 164 | // // Handle error. |
hudakz | 16:4c3edd30ad6e | 165 | // } |
hudakz | 16:4c3edd30ad6e | 166 | // |
hudakz | 0:acf75feb0947 | 167 | // @param input - Array of bytes to checksum. |
hudakz | 0:acf75feb0947 | 168 | // @param len - How many bytes to use. |
hudakz | 0:acf75feb0947 | 169 | // @param inverted_crc - The two CRC16 bytes in the received data. |
hudakz | 0:acf75feb0947 | 170 | // This should just point into the received data, |
hudakz | 0:acf75feb0947 | 171 | // *not* at a 16-bit integer. |
hudakz | 0:acf75feb0947 | 172 | // @param crc - The crc starting value (optional) |
hudakz | 0:acf75feb0947 | 173 | // @return True, iff the CRC matches. |
hudakz | 0:acf75feb0947 | 174 | static bool check_crc16(const uint8_t* input, uint16_t len, const uint8_t* inverted_crc, uint16_t crc = 0); |
hudakz | 0:acf75feb0947 | 175 | |
hudakz | 0:acf75feb0947 | 176 | // Compute a Dallas Semiconductor 16 bit CRC. This is required to check |
hudakz | 0:acf75feb0947 | 177 | // the integrity of data received from many 1-Wire devices. Note that the |
hudakz | 0:acf75feb0947 | 178 | // CRC computed here is *not* what you'll get from the 1-Wire network, |
hudakz | 0:acf75feb0947 | 179 | // for two reasons: |
hudakz | 0:acf75feb0947 | 180 | // 1) The CRC is transmitted bitwise inverted. |
hudakz | 0:acf75feb0947 | 181 | // 2) Depending on the endian-ness of your processor, the binary |
hudakz | 0:acf75feb0947 | 182 | // representation of the two-byte return value may have a different |
hudakz | 0:acf75feb0947 | 183 | // byte order than the two bytes you get from 1-Wire. |
hudakz | 0:acf75feb0947 | 184 | // @param input - Array of bytes to checksum. |
hudakz | 0:acf75feb0947 | 185 | // @param len - How many bytes to use. |
hudakz | 0:acf75feb0947 | 186 | // @param crc - The crc starting value (optional) |
hudakz | 0:acf75feb0947 | 187 | // @return The CRC16, as defined by Dallas Semiconductor. |
hudakz | 0:acf75feb0947 | 188 | static uint16_t crc16(const uint8_t* input, uint16_t len, uint16_t crc = 0); |
hudakz | 0:acf75feb0947 | 189 | #endif |
hudakz | 0:acf75feb0947 | 190 | #endif |
hudakz | 0:acf75feb0947 | 191 | }; |
hudakz | 0:acf75feb0947 | 192 | |
hudakz | 17:bbe8bf32e8bc | 193 | #endif |
hudakz | 17:bbe8bf32e8bc | 194 | |
hudakz | 17:bbe8bf32e8bc | 195 |