From 9d39952d25cb8b9958b2f859dd1a5cb87779c3d7 Mon Sep 17 00:00:00 2001 From: orgua Date: Thu, 25 Feb 2016 11:04:17 +0100 Subject: [PATCH] rework the whole timing of the bus if needed you can configure overdrive speed (arduino would probably be to slow) --- README.md | 4 +- src/Arduino.h | 2 +- src/OneWireHub.cpp | 118 +++++++++++++++++++++++---------------------- src/OneWireHub.h | 41 +++++++++------- 4 files changed, 89 insertions(+), 76 deletions(-) diff --git a/README.md b/README.md index 0701ceb..39b9a3d 100644 --- a/README.md +++ b/README.md @@ -29,13 +29,14 @@ The main goal is to use modern sensors (mainly [I2C](https://github.com/orgua/iL - good documentation, numerous examples, easy interface for hub and sensors ### Recent development (latest at the top): +- rework of the whole timings, if needed you can configure overdrive speed (arduino would probably be to slow) - bug fix: non conformal behaviour as a onewire-slave (hopefully) - raise the maximal slave limit from 8 to 32, takes ~100b extra program-space - open up for a lot more platforms with "platform.h" (taken from onewire-lib) - fix bug: open-drain violation on slave side - per-bit-CRC16 with sendAndCRC16() and sendAndCRC16() for load-balancing, 900ns/bit instead of 7µs/byte on Atmega328@16MHz - add examples for onewire-master, for testing the bus -- rework of checkReset(), showPresence(), send(), recv() and the hole timings - Hub is much more reliable now and it saves ~120 byte program-space +- rework of checkReset(), showPresence(), send(), recv() - Hub is much more reliable now and it saves ~120 byte program-space - faster CRC16 (ds2450 and ds2408 and ds2423), takes 5-7µs/byte instead of 10µs - refactored the interface: hub.poll() replaces hub.waitForRequest() - extended ds2890 to up to 4CH (datasheet has it covered), ds2413, ds2413 --> feature-complete @@ -49,6 +50,7 @@ The main goal is to use modern sensors (mainly [I2C](https://github.com/orgua/iL - test each example with real onewire-masters, for now it's tested with the onewire-lib and a loxone-system (ds18b20 passed) - ~~DS1963S 0x18 iButton, datasheet under NDA~~ - [List of all Family-Codes](http://owfs.sourceforge.net/family.html) +- [List of Maxim Sensors](https://www.maximintegrated.com/en/app-notes/index.mvp/id/3989) (at the bottom) ### Connecting the HUB with the Network: diff --git a/src/Arduino.h b/src/Arduino.h index c166f0d..7227fda 100644 --- a/src/Arduino.h +++ b/src/Arduino.h @@ -40,7 +40,7 @@ uint8_t digitalPinToBitMask(uint8_t x); uint32_t microsecondsToClockCycles(uint32_t x); uint32_t micros(void); // takes about 3 µs to process @ 16 MHz -void delayMicroseconds(uint32_t x); +//void delayMicroseconds(uint32_t x); void cli(void); void sei(void); diff --git a/src/OneWireHub.cpp b/src/OneWireHub.cpp index 88b0c3b..6e89347 100644 --- a/src/OneWireHub.cpp +++ b/src/OneWireHub.cpp @@ -11,6 +11,8 @@ OneWireHub::OneWireHub(uint8_t pin) baseReg = portInputRegister(digitalPinToPort(pin)); + allow_long_pause = 0; + slave_count = 0; slave_selected = nullptr; @@ -239,6 +241,7 @@ bool OneWireHub::poll(void) } + bool OneWireHub::checkReset(uint16_t timeout_us) // TODO: is there a specific high-time needed before a reset may occur? { volatile uint8_t *reg asm("r30") = baseReg; @@ -248,32 +251,22 @@ bool OneWireHub::checkReset(uint16_t timeout_us) // TODO: is there a specific hi DIRECT_MODE_INPUT(reg, pin_bitMask); sei(); - delayMicroseconds(ONEWIRE_TIME_BUS_CHANGE_MAX); // let the input settle + waitWhilePinIs(false, ONEWIRE_TIME_BUS_CHANGE_MAX); // let the input settle - // check if bus is low, since we are polling we don't know for how long it was zero - uint32_t time_trigger = micros() + timeout_us; - while (DIRECT_READ(reg, pin_bitMask)) - { - if (micros() > time_trigger) return false; - // if reached this point (bus was high), this could be an indicator for a sleep after bus goes low - // was in code: https://github.com/orgua/OneWireHub/commit/f8e6bc2981581b333bda87b1034b0e69bf18a3b5 - } + // wait for the bus to become low (master-controlled), since we are polling we don't know for how long it was zero + if (!waitWhilePinIs(1, timeout_us)) return false; - // wait for bus-release by master - time_trigger = micros() + ONEWIRE_TIME_RESET_MAX; + uint32_t time_start = micros(); - while (!DIRECT_READ(reg, pin_bitMask)) + // wait for bus-release by master + if (!waitWhilePinIs(0, ONEWIRE_TIME_RESET_MAX)) { - if (micros() > time_trigger) - { - _error = ONEWIRE_VERY_LONG_RESET; - return false; - } + _error = ONEWIRE_VERY_LONG_RESET; + return false; } // If the master pulled low for to short this will trigger an error - time_trigger -= ONEWIRE_TIME_RESET_MAX - ONEWIRE_TIME_RESET_MIN; - if (time_trigger > micros()) + if ((time_start + ONEWIRE_TIME_RESET_MIN) > micros()) { _error = ONEWIRE_VERY_SHORT_RESET; return false; @@ -288,7 +281,7 @@ bool OneWireHub::showPresence(void) volatile uint8_t *reg asm("r30") = baseReg; // Master will delay it's "Presence" check (bus-read) after the reset - delayMicroseconds(ONEWIRE_TIME_PRESENCE_SAMPLE_MIN); + waitWhilePinIs( 1, ONEWIRE_TIME_PRESENCE_SAMPLE_MIN); // no pincheck needed, but this avoids using "delay" // pull the bus low and hold it some time cli(); @@ -296,24 +289,22 @@ bool OneWireHub::showPresence(void) DIRECT_MODE_OUTPUT(reg, pin_bitMask); // drive output low sei(); - delayMicroseconds(ONEWIRE_TIME_PRESENCE_LOW_STD); + waitWhilePinIs( 0, ONEWIRE_TIME_PRESENCE_LOW_STD); // no pincheck needed, but this avoids using "delay" cli(); DIRECT_MODE_INPUT(reg, pin_bitMask); // allow it to float sei(); // When the master or other slaves release the bus within a given time everything is fine - uint32_t time_trigger = micros() + (ONEWIRE_TIME_PRESENCE_LOW_MAX - ONEWIRE_TIME_PRESENCE_LOW_STD); - while (!DIRECT_READ(reg, pin_bitMask)) + if (!waitWhilePinIs( 0, (ONEWIRE_TIME_PRESENCE_LOW_MAX - ONEWIRE_TIME_PRESENCE_LOW_STD))) { - if (micros() > time_trigger) - { - _error = ONEWIRE_PRESENCE_LOW_ON_LINE; - return false; - } + _error = ONEWIRE_PRESENCE_LOW_ON_LINE; + return false; } + // TODO: legacy code sleeps here a while _error = ONEWIRE_NO_ERROR; + allow_long_pause = 1; return true; } @@ -494,13 +485,14 @@ bool OneWireHub::sendBit(const bool value) sei(); return false; } - if (value) delayMicroseconds(32); + if (value) waitWhilePinIs( 0, ONEWIRE_TIME_READ_ONE_LOW_MAX); // no pincheck needed, but this avoids using "delay" else { cli(); DIRECT_WRITE_LOW(reg, pin_bitMask); DIRECT_MODE_OUTPUT(reg, pin_bitMask); - delayMicroseconds(32); + sei(); + waitWhilePinIs( 0, ONEWIRE_TIME_WRITE_ZERO_LOW_STD); // no pincheck needed, but this avoids using "delay" DIRECT_MODE_INPUT(reg, pin_bitMask); } sei(); @@ -559,16 +551,16 @@ uint8_t OneWireHub::recvBit(void) cli(); DIRECT_MODE_INPUT(reg, pin_bitMask); + // wait for a low to high transition followed by a high to low within the time-out if (!waitTimeSlot()) { sei(); return false; } - - delayMicroseconds(30); - value = DIRECT_READ(reg, pin_bitMask); sei(); + waitWhilePinIs( 0, ONEWIRE_TIME_READ_STD); // no pincheck needed, but this avoids using "delay" + value = DIRECT_READ(reg, pin_bitMask); return value; } @@ -597,42 +589,48 @@ uint8_t OneWireHub::recvAndCRC16(uint16_t &crc16) return value; } +bool OneWireHub::waitWhilePinIs(const bool value, const uint16_t timeout_us) +{ + volatile uint8_t *reg asm("r30") = baseReg; + if (DIRECT_READ(reg, pin_bitMask) != value) return true; // shortcut + + uint32_t time_trigger = micros() + timeout_us; + while (DIRECT_READ(reg, pin_bitMask) == value) + { + if (micros() > time_trigger) return false; + } + return true; +} + #define NEW_WAIT 0 // TODO: does not work as expected #if (NEW_WAIT > 0) // wait for a low to high transition followed by a high to low within the time-out bool OneWireHub::waitTimeSlot(void) { - volatile uint8_t *reg asm("r30") = baseReg; - sei(); + //cli(); + //volatile uint8_t *reg asm("r30") = baseReg; + //DIRECT_MODE_INPUT(reg, pin_bitMask); + //sei(); //While bus is low, retry until HIGH - if (!DIRECT_READ(reg, pin_bitMask)) + if (!waitWhilePinIs( 0, ONEWIRE_TIME_SLOT_MAX)) { - uint32_t time_trigger = micros() + ONEWIRE_TIME_SLOT_MAX; - while (!DIRECT_READ(reg, pin_bitMask)) - { - if (micros() > time_trigger) - { - _error = ONEWIRE_READ_TIMESLOT_TIMEOUT_LOW; - return false; - } - } + _error = ONEWIRE_READ_TIMESLOT_TIMEOUT_LOW; + return false; } - if (DIRECT_READ(reg, pin_bitMask)) + if (allow_long_pause) { - //Wait for bus to fall form 1 to 0 - uint32_t time_trigger = micros() + ONEWIRE_TIME_SLOT_MAX; - while (DIRECT_READ(reg, pin_bitMask)) - { - if (micros() > time_trigger) - { - _error = ONEWIRE_READ_TIMESLOT_TIMEOUT_HIGH; - return false; - } - } + waitWhilePinIs( 1, 2000 ); + allow_long_pause = 0; } - cli(); + + if (!waitWhilePinIs( 1, ONEWIRE_TIME_SLOT_MAX )) + { + _error = ONEWIRE_READ_TIMESLOT_TIMEOUT_HIGH; + return false; + } + return true; } @@ -648,7 +646,10 @@ bool OneWireHub::waitTimeSlot(void) while (!DIRECT_READ(reg, pin_bitMask)) { if (--retries == 0) + { + _error = ONEWIRE_READ_TIMESLOT_TIMEOUT_LOW; return false; + } } //Wait for bus to fall form 1 to 0 @@ -656,7 +657,10 @@ bool OneWireHub::waitTimeSlot(void) while (DIRECT_READ(reg, pin_bitMask)) { if (--retries == 0) + { + _error = ONEWIRE_READ_TIMESLOT_TIMEOUT_HIGH; return false; + } } return true; } diff --git a/src/OneWireHub.h b/src/OneWireHub.h index 1b81d62..2ac4dba 100644 --- a/src/OneWireHub.h +++ b/src/OneWireHub.h @@ -38,11 +38,11 @@ class OneWireHub /// the following TIME-values are in us and are taken from the ds2408 datasheet // should be --> datasheet - // was --> in shagrat-legacy + // was --> shagrat-legacy static constexpr uint16_t ONEWIRE_TIME_BUS_CHANGE_MAX = 5; // used static constexpr uint16_t ONEWIRE_TIME_RESET_MIN = 380; // used, should be 480, and was 470 - static constexpr uint16_t ONEWIRE_TIME_RESET_MAX = 720; // used + static constexpr uint16_t ONEWIRE_TIME_RESET_MAX = 960; // used, from ds2413 static constexpr uint16_t ONEWIRE_TIME_PRESENCE_HIGH_MIN = 15; static constexpr uint16_t ONEWIRE_TIME_PRESENCE_HIGH_MAX = 60; @@ -52,22 +52,27 @@ class OneWireHub static constexpr uint16_t ONEWIRE_TIME_PRESENCE_LOW_MAX = 480; // used, should be 280, was 480 !!!! why static constexpr uint16_t ONEWIRE_TIME_SLOT_MIN = 65; - static constexpr uint16_t ONEWIRE_TIME_SLOT_MAX =2000; // used, should be 120, was ~1050 - - static constexpr uint16_t ONEWIRE_TIME_WRITE_ZERO_LOW_MIN = 60; - static constexpr uint16_t ONEWIRE_TIME_WRITE_ZERO_LOW_MAX = 120; - static constexpr uint16_t ONEWIRE_TIME_WRITE_ONE_LOW_MIN = 15; - static constexpr uint16_t ONEWIRE_TIME_WRITE_ONE_LOW_MAX = 60; - - static constexpr uint16_t ONEWIRE_TIME_READ_LOW_MIN = 5; - static constexpr uint16_t ONEWIRE_TIME_READ_LOW_MAX = 15; - static constexpr uint16_t ONEWIRE_TIME_READ_ZERO_LOW_MIN = 15; - static constexpr uint16_t ONEWIRE_TIME_READ_ZERO_LOW_MAX = 60; + static constexpr uint16_t ONEWIRE_TIME_SLOT_MAX = 240; // used, should be 120, was ~1050 + + // read and write from the viewpoint of the slave!!!! + static constexpr uint16_t ONEWIRE_TIME_READ_ZERO_LOW_MIN = 60; + static constexpr uint16_t ONEWIRE_TIME_READ_ZERO_LOW_MAX = 120; + static constexpr uint16_t ONEWIRE_TIME_READ_ONE_LOW_MIN = 15; + static constexpr uint16_t ONEWIRE_TIME_READ_ONE_LOW_MAX = 60; // used + static constexpr uint16_t ONEWIRE_TIME_READ_STD = 30; // used + + static constexpr uint16_t ONEWIRE_TIME_WRITE_LOW_MIN = 5; + static constexpr uint16_t ONEWIRE_TIME_WRITE_LOW_MAX = 15; + static constexpr uint16_t ONEWIRE_TIME_WRITE_ZERO_LOW_MIN = 15; + static constexpr uint16_t ONEWIRE_TIME_WRITE_ZERO_LOW_STD = 35; // used + static constexpr uint16_t ONEWIRE_TIME_WRITE_ZERO_LOW_MAX = 60; + // TODO: define to switch to overdrive mode uint8_t _error; uint8_t pin_bitMask; volatile uint8_t *baseReg; + uint8_t allow_long_pause; uint8_t slave_count; OneWireItem *slave_list[ONEWIRESLAVE_LIMIT]; // private slave-list (use attach/detach) @@ -86,16 +91,18 @@ class OneWireHub uint8_t getNrOfFirstBitSet(const uint32_t mask); uint8_t getNrOfFirstFreeIDTreeElement(void); - bool recvAndProcessCmd(); - - bool waitTimeSlot(); - bool checkReset(uint16_t timeout_us); bool showPresence(void); bool search(void); + bool recvAndProcessCmd(); + + bool waitTimeSlot(); + + bool waitWhilePinIs(const bool value, const uint16_t timeout_us); + public: explicit OneWireHub(uint8_t pin);