-
Notifications
You must be signed in to change notification settings - Fork 3.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Why does ow.write with power=0 pull down the bus? #1130
Comments
Anyone ran into the same problem? |
It's possible nobody is using 1-wire at the moment, or that power=0 wasn't well tested, or something else. From what little I've read of the parasitic vs. non-parasitic power modes, I gather that the bit trains are not supposed to be the same. Then again, what do I know :) |
Thanks @devyte
AFAIK, the bus should hold high when idle, since the transmission is initiated by the falling edge. From the logic analyzer result I can tell the protocol is broken because it cannot parse the bits correctly (The red circle should be HIGH. After writing the bus was falsely set to LOW, causing the slave assume this is a bit. The following bits are therefore misaligned). See after DATA 0xbe. The plateau is not recognized as a bit as that in the above figure. This is the timing series from wiki. If the bus does not stay HIGH after write, the next bit will never be recognized by the slave. The actual implementation of parasite powering mode should be like,
The MOS is referring that in this figure. (Mine is not DS18B20-PAR but it works the same) If we do not even have the gpio that controlling the MOS set, the |
Anyway, maybe I did not give the clear statement of the OW bus. I will build the my firmware to see if it helps |
After commenting out |
Well, that's good news. But then I have to wonder: why was the power argument implemented at all? |
@devyte
If you have any other opinion please let me know.
You cannot brought up before write. Basically when any operation is done, the bus is at HIGH. If you pull down the bus after write like the code I am reporting, the devices will falsely assume this falling edge leads a bit. E.g. If you are writing two bytes: After writing 0xbe, the following falling edge makes the analyzer taking it for a bit. Actually, it is not |
I wonder if the power argument was supposed to indicate if the devices on the bus were externally powered (i.e. all three of VCC, GND and DATA were connected). |
@pjsg I think so, but to implement the power mode, we need to do more. Now even though my module is powered externally, with power=0, it doesn't work. If this argument is meant to be there, I think at least two functionalities should be implemented
My opinion is to remove this argument. |
@wuyuanyi135 what you say makes sense both logically (falling edge) and software-ly :) Even so, I can't help but wonder why the argument was implemented in the first place...
Please correct me if I'm wrong in the following train of thought, I'm still rather new to the ESP, and again, I know next to nothing of 1-wire :p
|
I think that you are probably right. Can you make the changes, verify that they work, and then submit a pull request? |
@pjsg Sure. Do you want me to remove the argument? |
I would think so -- it would effectively become 'true' all the time. You probably want to keep depower() |
@devyte thanks :) //
// Write a byte. The writing code uses the active drivers to raise the
// pin high, if you need power after the write (e.g. DS18S20 in
// parasite power mode) then set 'power' to 1, otherwise the pin will
// go tri-state at the end of the write to avoid heating in a short or
// other mishap.
// In the What you see in the last lines of static void onewire_write_bit(uint8_t pin, uint8_t v)
{
if (v & 1) {
noInterrupts();
DIRECT_WRITE_LOW(pin);
DIRECT_MODE_OUTPUT(pin); // drive output low
delayMicroseconds(10);
DIRECT_WRITE_HIGH(pin); // drive output high
interrupts();
delayMicroseconds(55);
} else {
noInterrupts();
DIRECT_WRITE_LOW(pin);
DIRECT_MODE_OUTPUT(pin); // drive output low
delayMicroseconds(65);
DIRECT_WRITE_HIGH(pin); // drive output high
interrupts();
delayMicroseconds(5);
}
}
static uint8_t onewire_read_bit(uint8_t pin)
{
uint8_t r;
noInterrupts();
DIRECT_MODE_OUTPUT(pin);
DIRECT_WRITE_LOW(pin);
delayMicroseconds(3);
DIRECT_MODE_INPUT(pin); // let pin float, pull up will raise
delayMicroseconds(10);
r = DIRECT_READ(pin);
interrupts();
delayMicroseconds(53);
return r;
} Anyway, I would suggest to set gpio to input state (float) whatever powering mode is used, for the sake of safety.
Actually I also have the question . I used to code the stm32f0/1 mcu, where the gpio pins have more flexible configuration. For example, I can specify the mode to be either push-pull or open-drain. I wonder if we implemented gpio push mode in platform code? |
@devyte You are probably right that float mode will prevent the power consuming and safety issue. But I think, |
@pjsg I think, if I remove the argument, many examples using this library will fail to build. Maybe we leave the argument here but do nothing? |
Someone using an extra argument on the call is fine -- if the C code doesn't look at it, then it doesn't affect anything. |
Basic Ohm's law. The 5V will be connected to the 3.3V through the 4.7K resistor, so: I = V/R = (5-3.3)/4.7K = 0.36mA over the 4.7K res. If you always set to input mode, I think the pin floats. So in that case, what happens to a parasite device? Won't it be powered by a floating pin? Wouldn't that cause trouble for the parasite device? I somehow think that having the power argument is necessary, but I can't really prove it without setting up a testbench :p What do other solutions do for this? I think I read somewhere that arduino also has 1-wire, how do they handle parasite/non-parasite devices? |
There seem to be a number of possible hardware approaches:
From reading the datasheet for the DS18B20, it isn't clear which of the above options are actually within spec. During the temperature conversion cycle, you need to be able to supply at least 1mA at at least 3V on the 1-wire bus. Given that the nodemcu is a 3v3 device, it isn't clear that you can get 3V out of a gpio pin. Without a drive transistor, a 4k7 pullup resistor to 5V is not going to be able to source enough current. The external power supply (i.e. using the 3v3 from the nodemcu) seems the safest. Maybe decide what configurations ought to be supported and then decide whether they ca all be driven in the same way, or whether there needs to be two options..... |
I was thinking sort of the opposite. We're not designing the device, the electrical capabilities of the ESP are fixed, so the supported electrical configurations for 1-wire are also fixed. My line of thought runs along the line of: the 1-wire code was written by someone who had a certain intent, based on the ESP's electrical capabilities. The 1-wire interface must have worked at some point, I somehow don't think that the code was implemented and never tested at all. So what was that intent, and how would it apply to today's version of the code?
This is the simplest electrical configuration, and it is supposed to work at least for some 1-wire devices. I'm wondering: how would this work if the pin is switched to input? Can a floating pin correctly power a parasite device between RW cycles? |
@eyaleb (in #859) @nickandrew and other developers have raised maybe 20 other issues (see this search list) regularly discuss using the DS18B20s, Surely we need the perspective of someone else who has used DS18B20s successfully here. I have seen data logging examples based on the DS18B20, so people do use them in anger connected to the ESP modules. |
I asked my EE friend. He said the PUSH arm (the NPN above) will never be activated, i.e. no current from 5V to 3.3V, because Vbe is negative (I didn't remember clearly the equation he said :( )
No. Although some mcu can drive such a great current, I don't think it is a good idea to draw current from GPIO pin. Just like I2C there is a wire and logic on the bus. When you are using floating mode, if you output high, it is at high-z. The power for parasite device is from the pull up R.
I may look at the library from arduino. |
I think the gpio in float state is still pulled up using internal pull up R. |
@TerryE I will look at if they ran into the similar problem. Basically, if you see anyone reporting the reading like 4095.08125 degc, or calling ow.write(pin, command, 0) will be the same case. |
The datasheet says that, during the conversion, the device may draw up to 1mA and the voltage must not droop below 3V. This says that the regular 4k7 pullup does not work. In fact, the datasheet talks about the strong pullup (as distinct from the regular pullup). The strong pullup can provide the needed power for the conversion. Drawing 1mA out of a GPIO pin is fine. An LED on a pin draws much more.... |
@pjsg Yes. What the GPIO can supply should be far more enough than that required by one module. However, the onewire is a bus protocol. I would probably need more than 4 ds18b20 attached to the bus. Probably the voltage drop will be unacceptable. |
@devyte I found that this ow driver is likely to be a modified version of this from arduino library. They defined the power argument, too. |
@pjsg I completely agree, a gpio pin should be able to supply parasite power to one or maybe 2 devices. From what I've quickly read online, I think that's the whole point of parasite mode: just plug your 1-wire device and go, forget all else. If you need many devices on the same bus, then of course you have to use external power and add the external pullup/drive fet/etc. But for just one device you shouldn't need to do all that. @wuyuanyi135 I suspected that the implementation was ported from elsewhere. I'm glad you found that out! From a quick look at the link, it seems to be an avr. This discussion is centered around the ds18b20, but the issue is really a more generic one: parasite power mode for 1-wire seems broken on the ESP for all 1-wire devices. |
@devyte Exactly. If you are driving only several onewire slaves consuming current within the limit, the GPIO should be configured to directly drive it. void onewire_write(uint8_t pin, uint8_t v, uint8_t power /* = 0 */) {
uint8_t bitMask;
for (bitMask = 0x01; bitMask; bitMask <<= 1) {
onewire_write_bit(pin, (bitMask & v)?1:0);
}
if ( !power) {
noInterrupts();
DIRECT_MODE_INPUT(pin); // Put gpio in float when external power is used.
// DIRECT_WRITE_LOW(pin); // Remove this line.
interrupts();
}
} This would be ideal. We can finally fix it up and keep the integrity of the API: the old example will still work! |
first commit to fix issue nodemcu#1130 If power = 0, after writing the bus is pulled down, and the slave will take it for a bit. One may have problem like the onewire device returning strange response, (for me, ds18b20 sometimes give temperature 4095.8125 degc). This commit will fix the unexpected situation. The power argument is not removed. We believe some use this module without external pull up as the documentation specified. The direct push-pull should be able to drive the slave. In that case, we may not switch the pin to input mode for the push arm supplying the power.
This wiring diagram is incorrect in regards to parasitic mode. When in parasitic mode the VCC should be connected to ground. See figure 6 on page 7 of the datasheet. |
@karrots You are right. Thank you |
Also, the notes on parasitic power say it may be necessary to drive DQ to Vcc with a MOSFET to maintain voltage during temperature reading. Maybe this is what the power = 1 means? So |
@karrots its supposed to be. However in the OneWire library apparently there is no intend to control that MOSFET to power the bus. That is why we discussed if we should remove this parameter. What 'parasite' means here, is that the device is driven by the push-pull GPIO directly. If you look at doc, power=0 actually means external power, and power=1 is parasite mode. The difference is, when power=1, the output maintain high after writing to drive the device. |
What I conclude is, when you have strong pull-up, power=0. If there is no pull-up, power=1. |
The library needs to be modified to control (via a 2nd pin) a strong pull-up, e.g. using a MOSFET. As currently written, the 'power' argument must always be 1 to hold the bus high between commands. I think the code could be modified to tri-state the output pin if 'power==0'; this would be acceptable for designs which use a pullup resistor on the bus. |
Also, nice work on the diagrams, @wuyuanyi135. |
@nickandrew many thanks :)
My PR #1143 fixes exactly the problem. when power==0, the gpio is set to LOW for some reason, which breaks the 1wire protocol. |
Driving external MOSFET or not as @nickandrew noted the GPIO pin used must be kept high if the sensor is wired for parasitic mode. No MOSFET would be needed if the pin can maintain the voltage. If the sensor is wired in 3 pin mode there is no issue with the DQ pin going low after requesting a conversion. In fact, during the conversion, you can be communicating with other sensors on the bus. Per the app note in the PDF I linked. If the sensors Vdd is connected to the GPIO pin instead of GND the capacitor is likely not correctly charging and discharging thus causing failed reads. |
Sure the code assumes there is a pull-up resistor in 3 wire mode. If there isn't then the device is not wired to spec. I just meant that the code didn't have to halt any further communications on the bus during the conversion process. |
@karrots No, the code did not have to wait. :) |
Assuming your right about the library being a clone of the Arduino one the comments state the reason for the
|
@karrots I read this. I could understand the intention but it was the
It becomes difficult to find a piece of information. Maybe I need to arrange these information on the top later. |
I think the power argument is pretty clear based on the notes. But as you note there is an issue. It probably has to do with the line you have noted not having the exact same meaning on other architectures this code can run on. It may be worth trying PaulStoffregen/OneWire#8 first before modifying the code too much. This looks like it may address your issue by rewriting the underlying code to match the type of bus OW is supposed to be. |
@pstolarz pointed out a critical point in this issue: In arduino,
simply turn off the internal pull-up R of the GPIO. In nodemcu, the same code turns out that the pin will be connected to GND. I have confirmed the desired behavior on an Arduino board. This issue is caused by the platform difference! In
|
In NodeMCU, I think it will be more dangerous to change this function than to leave it be. |
Hi all, this is exactly what I meant: a reason behind the original code, and that's why I didn't want to just remove the power arg. I'm glad it's getting sorted out! I agree with @wuyuanyi135 comment about keeping the integrity for the sake of easier porting. Fix should probably be in platform. @nickandrew why dangerous? I would argue that writing a value to a pin should *not * mean setting the pin to output mode. The pin should keep its mode, which in this case is input, and the operation then wouldn't be dangerous. Worst case the value wouldn't physically go out to the pin, so the user would need to explicitly set to output mode first (which is generally the accepted behavior for small mcus anyways). |
@devyte The latter; changing the semantics of |
My last comment should have said PaulStoffregen/OneWire#8 instead of PaulStoffregen/OneWire#11. Unsure if these changes match with the ESP8266 architecture. |
As I wrote in other place cited earlier in this thread - I'd rather suggest to rethink and rewrite low level w1 bus activities of your platform and its alignment with ported ardino w1 lib. This issue is only one sample of problems you may encounter with w1 in the future. Removing the line as @wuyuanyi135 proposed is not a cure in my opinion. |
@wuyuanyi135 did this merge fix your issue? If so this issue can be closed. |
Hello. I just found some strange behavior of the onewire library.
I was using pin 2 to communicate with a DS18B20. In the documentation,
I connected the power wire, so I set power as zero.
However, when issuing the commands
the result was apparently incorrect (4095 degc).
I used my logic analyzer to see the timing, finding that after
write 0xBE
the bus was not held high. The following bits were therefore unreadable.In the source, I spotted
*
line which probably pulled down the bus. I agree after write operation the bus should be at high-z but what is this line for? I think OW bus should always be held high when idle.desired behavior with power=1
when power=0, the bus was pulled down after write 0xbe, which breaks the next two reading commands
The text was updated successfully, but these errors were encountered: