diff --git a/README.md b/README.md index 67362f3..f1ee439 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,10 @@ 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): -- detect a reset after a reset (when there should be a timeslot) +- hub is more robust to odd master-behaviour (lazy timings and subsequent resets) +- prepare new timing-method which will replace the old one in the next couple of weeks (a 6µs millis() call at 8MHz is not suitable for OW) +- cleanup send / receive / waitForTimeslot to react faster to bus (better for µC with less than 16 MHz) +- support for skipROM-cmd if only one slave is present (thanks to Giermann) - speed up atmel-crc-functions - tested with DS9490R: ds28b20, ds2401, ds2405, ds2413, more will follow - rework of error system, switch to enum, slaves can raise errors now & and Serial interferes less with OW-timings diff --git a/src/OneWireHub.cpp b/src/OneWireHub.cpp index f6468f6..0f25ced 100644 --- a/src/OneWireHub.cpp +++ b/src/OneWireHub.cpp @@ -485,17 +485,27 @@ bool OneWireHub::send(const uint8_t dataByte) return true; } +uint16_t OneWireHub::sendAndCRC16(uint8_t dataByte, uint16_t crc16) +{ + for (uint8_t counter = 0; counter < 8; ++counter) + { + sendBit((0x01 & dataByte) ? bool(1) : bool(0)); + + uint8_t mix = ((uint8_t) crc16 ^ dataByte) & static_cast(0x01); + crc16 >>= 1; + if (mix) crc16 ^= static_cast(0xA001); + dataByte >>= 1; + + if (_error != Error::NO_ERROR) return 0; // CRC is not important if sending fails + } + return crc16; +} bool OneWireHub::sendBit(const bool value) { - volatile uint8_t *reg asm("r30") = pin_baseReg; - - noInterrupts(); - DIRECT_MODE_INPUT(reg, pin_bitMask); // wait for a low to high transition followed by a high to low within the time-out - if (!awaitTimeSlot()) + if (!awaitTimeSlotAndWrite(!value)) { - interrupts(); _error = Error::WRITE_TIMESLOT_TIMEOUT; return false; // timeslot violation } @@ -504,32 +514,12 @@ bool OneWireHub::sendBit(const bool value) else { // if we wait for release we could detect faulty writing slots --> pedantic Mode not needed for now - noInterrupts(); - DIRECT_WRITE_LOW(reg, pin_bitMask); - DIRECT_MODE_OUTPUT(reg, pin_bitMask); - interrupts(); wait(ONEWIRE_TIME_WRITE_ZERO_LOW_STD); + volatile uint8_t *reg asm("r30") = pin_baseReg; DIRECT_MODE_INPUT(reg, pin_bitMask); } - interrupts(); - return true; -} - - -uint16_t OneWireHub::sendAndCRC16(uint8_t dataByte, uint16_t crc16) -{ - for (uint8_t counter = 0; counter < 8; ++counter) - { - sendBit((0x01 & dataByte) ? bool(1) : bool(0)); - uint8_t mix = ((uint8_t) crc16 ^ dataByte) & static_cast(0x01); - crc16 >>= 1; - if (mix) crc16 ^= static_cast(0xA001); - dataByte >>= 1; - - if (_error != Error::NO_ERROR) return 0; // CRC is not important if sending fails - } - return crc16; + return true; } @@ -557,35 +547,6 @@ uint8_t OneWireHub::recv(void) return value; } -bool OneWireHub::recvBit(void) -{ - volatile uint8_t *reg asm("r30") = pin_baseReg; - - noInterrupts(); - DIRECT_MODE_INPUT(reg, pin_bitMask); - - // wait for a low to high transition followed by a high to low within the time-out - if (!awaitTimeSlot()) - { - interrupts(); - - if (extend_timeslot_detection==2) - { - _error = Error::FIRST_TIMESLOT_TIMEOUT; - extend_timeslot_detection = 0; - } - else - { - _error = Error::READ_TIMESLOT_TIMEOUT; - } - - return 0; - } - interrupts(); - waitWhilePinIs( 0, ONEWIRE_TIME_READ_STD); // no pinCheck demanded, but this additional check can cut waitTime - return DIRECT_READ(reg, pin_bitMask); -} - // TODO: not happy with the interface - call by ref is slow here. maybe use a crc in class and expand with crc-reset and get? uint8_t OneWireHub::recvAndCRC16(uint16_t &crc16) { @@ -610,6 +571,32 @@ uint8_t OneWireHub::recvAndCRC16(uint16_t &crc16) return value; } +bool OneWireHub::recvBit(void) +{ + + // wait for a low to high transition followed by a high to low within the time-out + if (!awaitTimeSlotAndWrite()) + { + if (extend_timeslot_detection==2) + { + _error = Error::FIRST_TIMESLOT_TIMEOUT; + extend_timeslot_detection = 0; + } + else + { + _error = Error::READ_TIMESLOT_TIMEOUT; + } + + return 0; + } + + waitWhilePinIs( 0, ONEWIRE_TIME_READ_STD); // no pinCheck demanded, but this additional check can cut waitTime + volatile uint8_t *reg asm("r30") = pin_baseReg; + DIRECT_MODE_INPUT(reg, pin_bitMask); + + return DIRECT_READ(reg, pin_bitMask); +} + #define USE_DELAY 1 void OneWireHub::wait(const uint16_t timeout_us) @@ -648,11 +635,11 @@ bool OneWireHub::waitWhilePinIs(const bool value, const uint16_t timeout_us) } -#define NEW_WAIT 0 // TODO: NewWait does not work as expected +#define NEW_WAIT 0 // TODO: NewWait does not work as expected (and is deprecated) #if (NEW_WAIT > 0) // wait for a low to high transition followed by a high to low within the time-out -bool OneWireHub::awaitTimeSlot(void) +bool OneWireHub::awaitTimeSlotAndWrite(void) { noInterrupts(); volatile uint8_t *reg asm("r30") = pin_baseReg; @@ -690,9 +677,12 @@ bool OneWireHub::awaitTimeSlot(void) #else #define TIMESLOT_WAIT_RETRY_COUNT static_cast(microsecondsToClockCycles(135)/8) /// :11 is a specif value for 8bit-atmega, still to determine -bool OneWireHub::awaitTimeSlot(void) +bool OneWireHub::awaitTimeSlotAndWrite(const bool writeZero) { volatile uint8_t *reg asm("r30") = pin_baseReg; + noInterrupts(); + DIRECT_WRITE_LOW(reg, pin_bitMask); + DIRECT_MODE_INPUT(reg, pin_bitMask); //While bus is low, retry until HIGH uint16_t retries = TIMESLOT_WAIT_RETRY_COUNT; @@ -709,6 +699,7 @@ bool OneWireHub::awaitTimeSlot(void) { _error = Error::READ_TIMESLOT_TIMEOUT_LOW; } + interrupts(); return false; } } @@ -716,12 +707,13 @@ bool OneWireHub::awaitTimeSlot(void) // extend the wait-time after reset and presence-detection if (extend_timeslot_detection == 1) { - retries = 60000; + retries = 65535; extend_timeslot_detection = 2; // prepare to detect missing timeslot or second reset } else { - retries = TIMESLOT_WAIT_RETRY_COUNT; + //retries = TIMESLOT_WAIT_RETRY_COUNT; + retries = 65535; // TODO: workaround for better compatibility (will be solved later) } //Wait for bus to fall form 1 to 0 @@ -730,10 +722,18 @@ bool OneWireHub::awaitTimeSlot(void) if (--retries == 0) { _error = Error::READ_TIMESLOT_TIMEOUT_HIGH; + interrupts(); return false; } } + if (writeZero) + { + // Low is allready set + DIRECT_MODE_OUTPUT(reg, pin_bitMask); + } + + interrupts(); return true; } #endif diff --git a/src/OneWireHub.h b/src/OneWireHub.h index 9b669d0..6dab1ab 100644 --- a/src/OneWireHub.h +++ b/src/OneWireHub.h @@ -129,7 +129,7 @@ class OneWireHub void wait(const uint16_t timeout_us); __attribute__((always_inline)) - bool awaitTimeSlot(); + bool awaitTimeSlotAndWrite(const bool writeZero = 0); __attribute__((always_inline)) bool waitWhilePinIs(const bool value, const uint16_t timeout_us);