Skip to content

Commit

Permalink
rework the whole timing of the bus
Browse files Browse the repository at this point in the history
if needed you can configure overdrive speed (arduino would probably be
to slow)
  • Loading branch information
orgua committed Feb 25, 2016
1 parent 2343b9b commit 9d39952
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 76 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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:

Expand Down
2 changes: 1 addition & 1 deletion src/Arduino.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
118 changes: 61 additions & 57 deletions src/OneWireHub.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ OneWireHub::OneWireHub(uint8_t pin)

baseReg = portInputRegister(digitalPinToPort(pin));

allow_long_pause = 0;

slave_count = 0;
slave_selected = nullptr;

Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -288,32 +281,30 @@ 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();
DIRECT_WRITE_LOW(reg, pin_bitMask);
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;
}

Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand All @@ -648,15 +646,21 @@ 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
retries = TIMESLOT_WAIT_RETRY_COUNT;
while (DIRECT_READ(reg, pin_bitMask))
{
if (--retries == 0)
{
_error = ONEWIRE_READ_TIMESLOT_TIMEOUT_HIGH;
return false;
}
}
return true;
}
Expand Down
41 changes: 24 additions & 17 deletions src/OneWireHub.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)
Expand All @@ -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);
Expand Down

0 comments on commit 9d39952

Please sign in to comment.