Tasmota: GPIO to high impedance

Created on 1 Jun 2018  路  20Comments  路  Source: arendst/Tasmota

ESP8266EX datasheet says: "Each GPIO can be configured with internal pull-up or pull-down, or set to high impedance". How can I set a GPIO, that is used as a relay, to a high impedance state when it's not triggered?

Most helpful comment

It's non-standard in the sense that it is not natively supported by the Arduino base upon which Tasmota is based and not a concept the current code understands and would require the code to be more complex than it already is. You are correct that charlieplexing leds uses this technique. If you are only interested in making a one off change to support your unique use case, it might not be too hard.

If you are expecting to generalize in the hope it becomes a standard part of Tasmota, that will be much harder. GPIO handling code is sprinkled around and more configuration code/storage would need to be added. For general use support, three states would need to be supported (charlieplexing needs all three). For your specific case perhaps only two states are needed and you could hard-code it. For the general case there would now be four modes needed for each pin. Current: drive high, drive low; what you want: drive high, high-z off; open-collector: high-z on, drive low; charlieplexing: drive high, drive low, high-z.

A long time ago I wrote code that did this for a specific relay board. It was not hard because I had complete control of the code and knew the requirements. Making it general and usable by anyone, not so easy.

If you want to try, all you need to do is switch the pin from output to input when you want to make it high-z. That is easy. Knowing when to do it and finding all the places where you need to change the code is the part "left as an exercise for the reader."

All 20 comments

That means when a GPIO is configured as an Input. When a GPIO is configured as an Output, it is always going to drive the line, high or low.

What are you trying to control, that you need high-z?

My blinds are controlled by a remote with the HCS300, that needs the active high for the inputs. The problem is that the remote's buttons have a conductive layer that isn't enough to bring up the chip's inputs as they are strictly low by the ESP. So the local buttons don't work. The high-impedance state would allow the buttons to function. It's the Sonoff that's powering up the remote.

How do you have things wired?
If you have the "relay" output wired to the input of the remote, you will likely need to have additional hardware and also use pulse time to simulate a push button press and release.

Yes, GPIO 1, 3, 14 are connected directly to the inputs and pulsetimes are set to 6. It works for me without the local buttons, but I need to go to travel for a long time and I need a manual mode as a backup for my wife and kids if something would happen with the Sonoff.

Look here to learn about using an NPN transistor as a switch:
https://www.electronics-tutorials.ws/transistor/tran_4.html

You can hook the GPIO to the base of an NPN transistor (use a 10K Ohm resistor between the two to limit the base current). Hook the emitter to gnd and hook the collector to the pushbutton input. When the GPIO goes high it will turn on the NPN transistor and that will simulate a user pushing the button.

It should be PNP to switch the power. I think I'll use an optocoupler. It's a bit sad that the GPIO state cannot be reprogrammed. Or maybe it can be, but it's not very easy?

So, you are saying that the remote has an internal pull down?
And the remote's switches connect that line to VCC (3V3)?

If so, then yes, you need a PNP transistor. That seems unusual, but it could be done that way.

The GPIO state can be reprogrammed. That's the beauty of a GPIO, when you want to tristate an output, make it an input. Tasmota does not have this capability (as far as I know). I once had to use it to control a relay board that used PNP transistors that were running at 5V and the 3V3 out from my microcontroller was not high enough to turn off the transistors or control the relay. But the microcontroller was 5V tolerant so making the GPIO an input would let the relay turn off and making it an output with 0 would turn on the relay. Once again, this is not a normal configuration so it is not surprising that Tasmota doesn't support it.

Yes, the chip HCS300 has the pull-down resistors 80K on S0-S3. And the voltage is 3v (CR2032).

I saw that Tasmota doesn't support the high-impedance state, that's why I asked how could I achieve it within my compilation. There is need to change registers, but I didn't find any information about it. Hoped there was someone with experience and would give some knacks.

From the datasheet:

Each GPIO can be configured with internal pull-up or pull-down, or set to high impedance,
and _when configured as an input_

That says that only an input can be configured as tri-state/high impedance. I don't know of any Output that can be configured as high-impedance for a low. Some MCUs support open-collector outputs (I2C needs this). But that would not work with the HCS300, since they have a pull down and expect the switch to make it high. You would need a transistor or other switching device to do this with just about any MCU.

The other option is to change the Tasmota GPIO handling code to switch the pin to input mode when it wants to write a 0. This would be VERY non-standard and I would not recommend doing it. Doing it in a general way that would be suitable for inclusion in Tasmota is likely not easy and might need a decent amount of code space for something that is the corner of an edge of a corner case :-) But, that is the beauty of open source, you can do whatever you want.

Oh, my fault, I was blind and didn't see that "_as an input_"! That explains everything. Case closed. Thank you very much for the discussion! An optocoupler will be the solution, I guess.

However, I looked over the sentence on the datasheet:

_Each GPIO can be configured with internal pull-up or pull-down, or set to high impedance,
and when configured as an input, the data are stored in software registers_

_and when configured as an input,_ goes to the next part: _the data are stored..._ For being configured to high impedance, it's not needed to be configured as an input. It's very clear. Maybe there is still someone who knows...

I don't know what you are hoping/expecting to find. The datasheet is clear, it has three choices for the input, and two choices for the output. Now, since it is the same pin, that gives you give choices. Tasmota gives you four of the choices on most pins, two choices for inputs, pull up or high-z and two choices for output, low or high. It does not offer a third choice for output of high-z. It could be made to do that, but that would be left as an exercise for the reader/user 馃榾

So I read more of the datasheet and it does appear to have an output enable and an output disable register. It is not clear what happens if you set both registers. Note that the Arduino core does not support these, so you really need to use the set it to input mode if you want hi-z.

Yes, Frogmore42, I have meant exactly these registers that can be modified and I know it is impossible within Tasmota (maybe not "impossible" but actually not supported). Unfortunately, with Google, I cannot find any information about those registers, so I thought that some programmer, engineer or hacker happens to read this post to give some knacks. I have already resolved the problem with optocouplers for one window, but I have others. And the theme is particularly interesting for me, too.

Additionally, I am going to modify the part of the code that generates the HTML for the web interface - the FOR-sentence for the blue toggle buttons, to rename them for others to be more clear which one is for "Up" or "Down" or "Stop". That will be my personal version of Tasmota for the windows only and it could have very well the modifications in the software registers. Perhaps it's on a lower level than the Tasmotas code where the registers can be programmed, the Sonoff driver maybe. I need to find information about it.

Ok, the function of a pin is selected in PERIPHS_IO_MUX_MTDI_U and high and low states are enabled in GPIO_OUT_W1TC and GPIO_OUT_W1TS, bit[15:0] but there is no mention about a high impedance state. The same goes for the inputs. So, there are only high and low level registers, that could be programmed with 1 or 0, so no choice from here. I understand that high impedance could be programmed only by a function, but it's undocumented. Why they mention high impedance available for all GPIOs but don't give any hint about it?

I think I get closer and it confirms your suggestion:

_The other option is to change the Tasmota GPIO handling code to switch the pin to input mode when it wants to write a 0. This would be VERY non-standard and I would not recommend doing it._

But why it's non-standard? From the datasheet:

_In short, the IO pads are bidirectional, non-inverting and tristate, which includes input and output buffer with tristate control inputs._

So, a tri-state device is designed for becoming INPUT to get high impedance to both VCC and GND. It should work for 1-wire this way too for lowering the power consumption. And of course for Charlieplexing. From its WIKI:

_This can be solved by utilizing the tri-state logic properties of microcontroller pins. Microcontroller pins generally have three states: "high" (5 V), "low" (0 V) and "input". Input mode puts the pin into a high-impedance state, which, electrically speaking, "disconnects" that pin from the circuit, meaning little or no current will flow through it._

So it's not so non-standard and not very uncommon at all. If there is a need to eliminate any external device, like transistors, optocouplers or relays, this is the only way to achieve that famous high-impedance state of a pin. Now the only question is how to implement it.

It's non-standard in the sense that it is not natively supported by the Arduino base upon which Tasmota is based and not a concept the current code understands and would require the code to be more complex than it already is. You are correct that charlieplexing leds uses this technique. If you are only interested in making a one off change to support your unique use case, it might not be too hard.

If you are expecting to generalize in the hope it becomes a standard part of Tasmota, that will be much harder. GPIO handling code is sprinkled around and more configuration code/storage would need to be added. For general use support, three states would need to be supported (charlieplexing needs all three). For your specific case perhaps only two states are needed and you could hard-code it. For the general case there would now be four modes needed for each pin. Current: drive high, drive low; what you want: drive high, high-z off; open-collector: high-z on, drive low; charlieplexing: drive high, drive low, high-z.

A long time ago I wrote code that did this for a specific relay board. It was not hard because I had complete control of the code and knew the requirements. Making it general and usable by anyone, not so easy.

If you want to try, all you need to do is switch the pin from output to input when you want to make it high-z. That is easy. Knowing when to do it and finding all the places where you need to change the code is the part "left as an exercise for the reader."

Good to know that. I'm not expecting in any way this manipulation available for public releases. Just for my own case. And just for an adventure and interest. Thank you for the discussion and the tips.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jensuffhaus picture jensuffhaus  路  3Comments

smadds picture smadds  路  3Comments

kckepz picture kckepz  路  3Comments

Joeyhza picture Joeyhza  路  3Comments

wirelesssolution picture wirelesssolution  路  3Comments