pstolarz / OneWireNg

Arduino 1-wire service library. OneWire compatible. Dallas thermometers support.
BSD 2-Clause "Simplified" License
80 stars 18 forks source link

[Feature Request] Library supporting advanced circuitry as shown in Maxim AppNote 244 #1

Closed gnalbandian closed 4 years ago

gnalbandian commented 4 years ago

Hi, I have been studing your library but haven't tested it yet. It is very interesting.

I believe we could take this library to the next level by including the necesssary code to support the circuitry detailed in this app note Advanced 1-Wire Network Driver

Let me know what you think so as to coordinate the work. Regards.

pstolarz commented 4 years ago

Sure. I'll look at the doc later on - the driver circuit looks quite complicated. I'll need some time to digest the idea behind it. At the first glance I see an approach by providing a new class implementing the OneWireNg interface basing on the described driver architecture (e.g. OneWireNg_NetDriver class).

Have you access to HW to check the implementation?

gnalbandian commented 4 years ago

Hi @pstolarz, glad you answer back. Yes, I'll have the circuitry ready next week.

As regards the circuitry, it feels complex at first but looking into deep, it's simples than it looks.

The one wire bus is set only as a read input (SENSE PIN). The circuitry has slew rate control and impedance matching at the master end.

The SPU pin logic is already the same as the library PWR_CTRL_PIN. It's a strong pull-up. The mosfet logic is active low. The DPU pin logic is a dynamic pull-up that drives the bus high. The mosfet logic is active low. The DRIVE pin logic is a dynamic pull-down that drives the bus low. The mosfet logic is active high. Those are basics.

The document goes deep into detail. For what is worth, I'm building the hardware around an ESP8266.

pstolarz commented 4 years ago

My understanding of this driver's circuit is as follows:

pstolarz commented 4 years ago

Now the question arises about quality of this driver in the real world applications. If it's such good as advertised why Maxim doesn't sell it as a separate IC. Or maybe they do?

gnalbandian commented 4 years ago

Next week I believe I'll have the circuitry ready for testing.

bulentperktas commented 2 years ago

Hello All, Are there any improvement about this topic? Maxim AN244 app note is good solution about impedance matching, I wonder that is there any solution? Thank you.

pstolarz commented 2 years ago

Currently I don't consider working on this driver mainly for these reasons:

peufeu2 commented 2 years ago

I'm running a 1wire network in the whole house. The longest cable is about 20m, and there are 25 DS18B20s in total, measuring ambient temperatures, and water temperatures on the input and output of underfloor heating loops in all rooms. An ESP32 reads them and does what's needed with valves to regulate the temperatures.

The advanced driver mentioned in the appnote is unnecessary for this application. I'm not sure it would help for anything, because it may be an upgrade on the micro driver side, but it doesn't help when the sensors are driving the wire.

Parasite power is useless and star topology does not work. As Maxim says, if you have several "onewire cables" coming to your micro from different places, you need a mux so the micro talks to only one cable at a time. Otherwise, with all the cables in parallel and the star topology, this creates too many signal reflections and signal integrity problems, and it fails. The advanced driver won't help here with that.

With the mux, it works fine.

I found using an active pullup really helps with the long cables. The onewire pin is connected to the mux through a resistor (75R or so) and the the micro outputs a hard 1 level for 1µs (setting the pin to output) which charges the cable capacitance, then sets the pin back to input and waits a few µs before reading. So if the DS18B20 at the end of the cable is driving it low, it will read a zero, but if it is not, it will read a strong one, because it charged the cable.

It's pretty simple and doesn't need any extra pins, except for the mux.

uzi18 commented 2 years ago

You can check ltc 4311

pstolarz commented 2 years ago

The advanced driver mentioned in the appnote is unnecessary for this application. I'm not sure it would help for anything, because it may be an upgrade on the micro driver side, but it doesn't help when the sensors are driving the wire.

I wouldn't say it'd not help in anything. The driver has some interesting solutions for low-to-high signal drive and provides components to match impedance of the bus line. The problem with it is - it's not sell as separate IC and it's hard to check it out on real setups.

I found using an active pullup really helps with the long cables. The onewire pin is connected to the mux through a resistor (75R or so) and the the micro outputs a hard 1 level for 1µs (setting the pin to output) which charges the cable capacitance, then sets the pin back to input and waits a few µs before reading.

I'm skeptical with such solutions on the open-drain type of buses like the 1-wire one. The 1-wire protocol strictly specifies in what conditions the strong pull-up shall be provided on the bus and this is not the case you provided. in this context I like the driver solution since it provides elegant electrical approach to reduce and match bus impedance. Also in my lib I provide CONFIG_BUS_BLINK_PROTECTION config param which may help to work with long 1-wire buses (although it's main purpose was different). The param is not intended to charge connected slaves capacitors, rather than reduce bus impedance. in parasitic mode the strong pull-up occurs in strictly defined period of 1-wire communication where connected slaves expect more power. Of course the line charge may also occurs when 1-wire bus is inactive (high state).

peufeu2 commented 2 years ago

Basically my point was, gnalbandian said "you should implement the advanced driver feature", I'm saying don't waste your time, it works fine without it.

The advanced driver has a PMOS on top to pull up, and a NMOS on the bottom to pull down. It is quite similar to the structure of a microcontroller GPIO pin, which is why it can be replaced with a microcontroller IO pin and a resistor wired in series for reasonable cable lengths. The main difference is in the slew rate limiting, which should work better in the discrete version. I haven't noticed any problems on the scope.

Discrete FETs have lower RdsON than GPIO FETs, but in the driver schematic, the discrete resistors are wired in series, so RdsON doesn't matter much.

I don't use the strong pull-up. That one doesn't have a series resistor at all, so it's a bit dangerous. Circuits connected to long cables should be able to survive short-circuits.

The micro's pin can put an active pullup on the bus if it drives a logic high through the series resistor. That's what I use.

pstolarz commented 2 years ago

Basically my point was, gnalbandian said "you should implement the advanced driver feature", I'm saying don't waste your time, it works fine without it.

I'm not gonna do for the reason I provided above. My point was - it's not a bad idea. It contains elegant solution for matching line impedance (R1, R2), controlling slew rate for low-high (R6, C2) and high-low (R5, C1) transitions, ESD protection (D1, D2) along with, as an extra feature, strong pull-up support (SPU via Q3). Basically, a nice example of active pull-up implementation built on 2 MOSFETS with controlled pull-up, pull-down terminators. I like it.

I don't use the strong pull-up. That one doesn't have a series resistor at all, so it's a bit dangerous.

That was may point. I'm not convinced with the statement "should survive".

The micro's pin can put an active pullup on the bus if it drives a logic high through the series resistor. That's what I use.

Looking at your code:

#define DIRECT_WRITE_HIGH(base, pin)    directWriteHigh(pin)

static inline __attribute__((always_inline))
void directWriteHigh(IO_REG_TYPE pin)
{
    if ( pin < 32 )
        GPIO.out_w1ts = ((uint32_t)1 << pin);
    else if ( pin < 34 )
        GPIO.out1_w1ts.val = ((uint32_t)1 << (pin - 32));
}

void OneWire::write_bit(uint8_t v)
{
    IO_REG_TYPE mask IO_REG_MASK_ATTR = bitmask;
    volatile IO_REG_TYPE *reg IO_REG_BASE_ATTR = baseReg;

    if (v & 1) {
        noInterrupts();
        DIRECT_WRITE_LOW(reg, mask);
        DIRECT_MODE_OUTPUT(reg, mask);  // drive output low
        fastDelayMicroseconds( tLOW1 );       
        DIRECT_WRITE_HIGH(reg, mask);   // drive output high
        interrupts();
        fastDelayMicroseconds( tSLOT - tLOW1 );      // total slot time tSLOT = 60-120µs = tLOW1 + this delay
    } else {
        noInterrupts();
        DIRECT_WRITE_LOW(reg, mask);
        DIRECT_MODE_OUTPUT(reg, mask);  // drive output low
        fastDelayMicroseconds( tLOW0 );      // tLOW0 is 60-120µs
        DIRECT_WRITE_HIGH(reg, mask);   // drive output high
        interrupts();
        fastDelayMicroseconds( tSLOT - tLOW0 );     // total slot time tSLOT = 60-120µs = tLOW0 + this delay
    }
}

you provide direct voltage source on the bus via DIRECT_MODE_OUTPUT() followed by DIRECT_WRITE_HIGH() (aka strong pull-up) or I missed something?

peufeu2 commented 2 years ago

There's a resistor in series with the pin (unlike the strong pullup in the driver).

That said I hadn't touched this bit of code from P. Stoffregen, and now that you pointed at it, I don't like it. I changed it to apply an active pullup for 2µs to straighten the rising edge, and then return to input mode:

    if (v & 1) {
        noInterrupts();
        DIRECT_WRITE_LOW(reg, mask);
        DIRECT_MODE_OUTPUT(reg, mask);  // drive output low
        fastDelayMicroseconds( tLOW1 );       
        DIRECT_WRITE_HIGH(reg, mask);   // drive output high
        fastDelayMicroseconds( tAPU );  // active pullup time    
        DIRECT_MODE_INPUT(reg, mask);   // return to input mode and let the pullup do the job (safer)
        interrupts();
        fastDelayMicroseconds( tSLOT - tLOW1 - tAPU);      // total slot time tSLOT = 60-120µs = tLOW1 + this delay
    }

I was talking about using an active pullup for reads, because that's when the timing is tightest. The way I'm doing it is a bit off-spec, but it gives much less errors than the timings described in the advanced driver appnote...

#define tDRIVElow 4
#define tRDV 11
uint8_t OneWire::read_bit(void)
{
    IO_REG_TYPE mask IO_REG_MASK_ATTR = bitmask;
    volatile IO_REG_TYPE *reg IO_REG_BASE_ATTR = baseReg;
    uint8_t r;
    unsigned slot_end_time;

    noInterrupts();

    slot_end_time = fastmicros() + tSLOT;

    DIRECT_MODE_OUTPUT(reg, mask);      // drive output low
    DIRECT_WRITE_LOW(reg, mask);
    fastDelayMicroseconds( tDRIVElow );

    DIRECT_WRITE_HIGH(reg, mask);     // drive output high (active pullup) to charge wire if slave is not outputting 0
    fastDelayMicroseconds( tAPU );    
    DIRECT_MODE_INPUT(reg, mask);     // let pin float, resistor pull up only
    fastDelayMicroseconds( tRDV - tAPU - tDRIVElow ); // substract active pullup time

    r = DIRECT_READ(reg, mask);
    interrupts();

    bool pulled_up = false;

    // Wait for next cycle, and while doing so, turn on active pullup 
    // when slave releases wire
    while( (int)(slot_end_time-fastmicros()) >= 0 )
    {
        if( !pulled_up && DIRECT_READ(reg, mask) )
        {
            DIRECT_WRITE_HIGH(reg, mask);            
            DIRECT_MODE_OUTPUT(reg, mask);
            fastDelayMicroseconds(tAPU);    
            DIRECT_MODE_INPUT(reg, mask);
            pulled_up = true;
        }
    }
    return r;
}
pstolarz commented 2 years ago

There's a resistor in series with the pin (unlike the strong pullup in the driver).

In what point the driver uses strong pull-up?

I was talking about using an active pullup for reads, because that's when the timing is tightest.

write-1 and read-1 use the same timing. The only difference is bus sampling by read-1. See here fig. 16

The way I'm doing it is a bit off-spec, but it gives much less errors than the timings described in the advanced driver appnote...

I wonder how you asses the driver as more error prone if you haven't checked it out?

bulentperktas commented 2 years ago

Hello, Thank you for discuss about Advanced circuitry, @gnalbandian @pstolarz

Here i want to share what i found FED Wiz-C compiler OneWire driver, The driver forked from Dallas Semiconductor Corporation. I thought that Forest Electronic Developments uses this driver for their iButtons applications.

here is OneWire library for fedC and wizC.

Their Driver SYNOPSIS is;

     BYTE owFirst(BYTE portnum, BYTE do_reset, BYTE alarm_only);
     BYTE owNext(BYTE portnum, BYTE do_reset, BYTE alarm_only);
     void owSerialNum(BYTE portnum, BYTE *serialnum_buf, BYTE do_read);
     void owFamilySearchSetup(BYTE portnum, BYTE search_family);
     void owSkipFamily(BYTE portnum);
     BYTE owAccess(BYTE portnum);
     BYTE owVerify(BYTE portnum, BYTE alarm_only);
     BYTE owOverdriveAccess(BYTE portnum);
     BYTE owAcquire(BYTE portnum, BYTE *port_zstr);
     void owRelease(BYTE portnum);
     void owSetCurrentPort(BYTE portnum);
     BYTE owTouchReset(BYTE portnum);
     BYTE owTouchBit(BYTE portnum, BYTE sendbit);
     BYTE owTouchByte(BYTE portnum, BYTE sendbyte);
     BYTE owWriteByte(BYTE portnum, BYTE sendbyte);
     BYTE owReadByte(BYTE portnum);
     BYTE owSpeed(BYTE portnum, BYTE new_speed);
     BYTE owLevel(BYTE portnum, BYTE new_level);
     BYTE owProgramPulse(BYTE portnum);
     BYTE owWriteBytePower(BYTE portnum, BYTE sendbyte);
     BYTE owReadBytePower(BYTE portnum);
     BYTE owHasPowerDelivery(BYTE portnum);
     BYTE owHasProgramPulse(BYTE portnum);
     BYTE owHasOverDrive(BYTE portnum);
     BYTE owReadBitPower(BYTE portnum, BYTE applyPowerResponse);
     BYTE owBlock(BYTE portnum, BYTE do_reset, BYTE *tran_buf, BYTE tran_len);
     BYTE owReadPacketStd(BYTE portnum, BYTE do_access, int start_page, BYTE *read_buf);
     BYTE owWritePacketStd(BYTE portnum, int start_page, BYTE *write_buf,
                              BYTE write_len, BYTE is_eprom, BYTE crc_type);
     BYTE owProgramByte(BYTE portnum, BYTE write_byte, int addr, BYTE write_cmd,
                           BYTE crc_type, BYTE do_access);
     void setcrc16(BYTE portnum, WORD reset);
     WORD docrc16(BYTE portnum, WORD cdata);
     void setcrc8(BYTE portnum, BYTE reset);
     BYTE docrc8(BYTE portnum, BYTE x);

They use 4 Digital pin for Advanced circuitry as shown in maxim AppNote 244 such as SENSE(DQ), DRIVE, DPU (Dynamic PullUp), SPU (Strong PullUp) and 1 Digital pin PPU (Program Pulse), In this case seems that we do not need this PPU pin for the Advanced circuirty which pin is used for EEPROM iButtons.

Pin definition Stracture here.

DPU and DRIVE Digital pins used only on reset presence function (BYTE owTouchReset(void)), here.

and Write/Read 1 bit function (BYTE owTouchBit(BYTE sendbit)), here.

and initialization function (BYTE owAcquire(BYTE *port_zstr)) here.

SPU pin is used on (BYTE owWriteBytePower(BYTE sendbyte)) (BYTE SowReadBitPower(BYTE applyPowerResponse)) functions. here and here.

and also I saw that this driver give a chance that software selectable choices which used FET/Transistor channel Types (N-Type/P-Type or NPN/PNP) with these lines.

// Drive the bus low
#ifdef OWNET_DPU_PORT
  // Disable it
  #if OWNET_DPU_POLARITY == OWLEVEL_IDLE_LOW
    OWNET_DPU_PORT &= ~(1 << OWNET_DPU_PIN);
  #else
    OWNET_DPU_PORT |=  (1 << OWNET_DPU_PIN);
  #endif
#endif

#ifdef OWNET_DRIVE_PORT  
  // Use Drive for driving the net
  #if OWNET_DRIVE_POLARITY == OWLEVEL_IDLE_LOW
      OWNET_DRIVE_PORT |=  (1 << OWNET_DRIVE_PIN);
  #else
      OWNET_DRIVE_PORT &= ~(1 << OWNET_DRIVE_PIN);
  #endif
  }
#else
  // Use Sense for driving the net
  OWNET_SENSE_TRIS &= ~(1 << OWNET_SENSE_PIN);
#endif

OneWire Bus due to FED 1Wire Library documentation

OneWire (also known as 1wire or Microlan) is a bus network system developed by Dallas Semiconductor (Dallas semiconductor has been aquired by Maxim Integrated Products in 2001). The OneWire bus is the heart of the OneWire simulation system. It serves as the main interface between the MCU and all OneWire devices on this bus. The need for a separate busdevice in the simulator was caused by the inherent structure of the FED simulation system which has no concept of impedance. Next to serving as the only MCU-coupled device, it also serves as central logging system for all devices on the bus. The pinnames are derived from Maxim’s application note 244: “Advanced 1-Wire Network Driver”.

Connections Parameters Notes
DQ / Sense None The main OneWire network connection. It is used to sense the bus by the MCU. When the Drive-pin is not connected, this pin is also to be used to drive the bus.
Drive Polarity When it is desirable to deparate the Sense-pin from the Drive-pin, connect this pin to the appropiate MCU-pin. For a true OneWire network, this pin can be left unconnected.
Dynamic PullUp Polarity For large networks, a simple resistor pullup may not suffice. Use the Dynamic PullUp (DPU) pin to provide a better alternative. Leave it unconnected if not needed. Of course, the simulator has no knowledge of the actual circuitry that is going to be attached. But the simulator will check signal timing on this pin. Usage of this pin is optional.
Strong PullUp Polarity Several OneWire devices from time to time need more power then can be delivered through the OneWire pullup resistor. This additional power is delivered by a special Strong PullUp circuit, activated by this pin. Of course, the simulator has no knowledge of the actual circuitry that is going to be attached. But the simulator will check signal timing on this pin. Usage of this pin is optional.
Program Pulse Polarity Activating this pin will pull the bus to a 12V level needed by several devices to program their EEPROM’s. Of course, the simulator has no knowledge of the actual circuitry that is going to be attached. But the simulator will check signal timing on this pin. Usage of this pin is optional.
Parameters Options Notes
BusNr 0-7 The number of the OneWire bus. It is used to connect actual OneWire devices to the correct bus. Up to 8 OneWire buses (= 8 independent networks) can be defined in a single simulation.
Log Level Disabled Select the messagelevels to be displayed in the
- Errors Log window. Errors are displayed in red,
- Errors + Warnings warnings in blue and informational messages in
- Errors + Warnings + Info black.
Log Size From 16 to 1024 The size of the log, expressed in lines.

These are my coincidences which i would like to share here, may these help improve the library for further usages. I thought that may easily implement those digital pins on the driver.

Thank you, Bulent PERKTAS

pstolarz commented 2 years ago

@bulentperktas Thanks for the clarification. I didn't know someone is using this driver on production. Is there a chance to get the driver HW? Do you have access to such?

bulentperktas commented 2 years ago

Hi, i tryed to reach offically hw but unfortunately maxim does not provide this, I wonder why,

Here is knowledgebase entry.

I think idea is wonderful that control slew rate with a couple passive component using onewire driver which over 500m cable capable,

bulentperktas commented 10 months ago

@bulentperktas Thanks for the clarification. I didn't know someone is using this driver on production. Is there a chance to get the driver HW? Do you have access to such?

@pstolarz @gnalbandian yes, there are some production using this driver and also it is mentioned that Application Note #244.

Link45 - DB9F to RJ-45

iButton Masters & Adapters

1-Wire Interfaces

Link45i Advanced 1-Wire COM Port Adapter with ID-Chip

Link45 - Maximus Technologies

iButtonLink Link45 DB9F to RJ45 1-Wire Interface

Regards; Bulent PERKTAS