Iot: Cannot read from output pin?

Created on 31 Jan 2019  路  22Comments  路  Source: dotnet/iot

This exception doesn't seem right to me:

https://github.com/dotnet/iot/blob/master/src/System.Device.Gpio/System/Device/Gpio/GpioController.cs#L171-L174

Is this a mistake, or is it my understanding that needs correction?

area-System.Device.Gpio bug up-for-grabs

All 22 comments

I鈥檓 not sure the exact issue you鈥檝e encountered. Could you provide an example? Basically, this code checks and if the pin is an output, it throws to state you鈥檙e reading a output pin. You can only read input pins.

You can only read input pins.

Yes, that's the issue. Why can you only read input pins? I've never used a microcontroller or any other embedded device where reading an output pin was not permitted. What's the justification for it?

To illustrate a use case, one may want to read the output pin when the program first starts in order to update their UI with the output's last state. Initializing the pin to a default value may violate the software's requirements.

I'm not sure that all drivers would be able to support this. For example, the RaspberryPi driver operates with registers in the memory directly, and there are different bits in memory that are used for the value depending if you are in Input vs Output mode, and I would really doubt that the Input bit will be updated when the pin is set to output and the value is changed.

there are different bits in memory that are used for the value depending if you are in Input vs Output mode, and I would really doubt that the Input bit will be updated when the pin is set to output and the value is changed.

I would expect the driver to return the value of the Output bit if it is in Output mode.

That is not how the Output bits work on the RPi driver unfortunately. There are two registers that are used to control an output pin's value in the RPi:

https://github.com/dotnet/iot/blob/c1a3493abc77e6988e8625e2c46b3ea35eac3a91/src/System.Device.Gpio/Interop/Unix/Libc/Interop.mmap.cs#L44-L50

The way this works internally, is that if you want to set the pin value to low then you flip a bit of the GPCLR register, and when you want to set it high then you flip a bit on the GPSET register, and by modifying one register, the other one won't be modified. What this means, is that only internally does the raspberry pi knows which was the register that was last modified in that bit, which would tell it whether the value is high or low. There is now way that by reading those registers one would be able to tell whether the value is high or low.

Only when it is set to Input, it won'd do it the pin is set to Output

Weird! So be it.

I just tested with pigpio and it works fine. Even if I set the state using C# and close the program, I can read the state of the output pin (that was set in the C# program) in C using the pigpio library.

Re-opening because I think it would be valuable to see how pigpio achieves this and implement something similar.

@buyaa-n PTAL

Seems sometimes its really needed to read a value from output pin, and according to Wikipedia

GPIO capabilities may include:[2]

- GPIO pins can be configured to be input or output[4]
- GPIO pins can be enabled/disabled
- Input values are readable (typically high or low)
- Output values are writable/readable

And i have read output pin using SysFs, Libgpiod and Raspberry driver, all worked correctly (i. e. after writing high i read hig, after writing low read low). So i think we should enable reading output pin for controller level and if any driver specific pin not supporting that operation throw the error on driver level.
Please let me know if you have any other idea cc @joshfree @joperezr @krwq

I think in many cases reading an output pin may be by accident and therefore a bug.

I personally haven't had any case where I'd need that but if I see specific scenario where this is useful I'm open to change this behavior

If we decide to change this behavior we should investigate if reading not open pins should also be considered a bug because developer might want to check if the pin is input or output.

Starting to look at the I2C protocol I believe without fixing this implementing software implementation might be hard as it seems to be using that fact for communication - i.e. clock stretching where master sets clock to 1 but slave can pull it low until it is ready to write so master despite controlling the clock should check if value is set to what it is supposed to be. Given that I believe we should fix this and make sure we don't try to cache the value.

I am pretty sure we need to enable reading output pin. @joshfree suggested to add ReadWrite mode instead of making output mode readable, maybe we should name that mode InputOutput so that it follow .Net IO file reading design (Read, Write, ReadWrite mode). I like that idea, if user need to read from output pin they could choose InputOutput (or OutputInput) mode instead of only Output mode. What you think about that

I think it would be nice to have the ability to read the value of an output. I've had a few cases using I/O Expanders where I have to read the value from device (using I2C or SPI) or store the last value written in order to not affect other respective pin bits when writing.

maybe we should name that mode InputOutput

I haven't thought in detail, but this might get a little complex. What happens if/when we add other types of outputs (#135)? Would we have to include InputOutputPullUp, InputPullDownOutput, InputOutputOpenDrain, etc.?

Would we have to include InputOutputPullUp, InputPullDownOutput, InputOutputOpenDrain, etc.

The point of this change is to make Output pin readable, no need make any change to Input pins. (InputPullDown, InputPullUp)

But from the issue #135 i see there could be 4 more output modes (OutputOpenDrain, OtputOpenDrainPullUp, OutputOpenCollector, OutputOpenCollectorPullDown). Not sure if they also need to be readable, if they are then yes its become more complicated, might be better just make Output pins readable instead of new InputOutput mode, maybe we need discuss it in API review

I think the PinMode can be flags - perhaps something along these lines:

  • 1 bit: input/output since those are exclusive
  • 1 bit: allow both directions (for output mode this means reading, for input mode setting pull up/down)
  • ... some other options

that should allow you to compose whatever mode you want (we would need to figure out better names for enum flags and decide if we want all combinations or only basic options which user composes into effective option)

At first i liked idea of using flags, its good to use flags if we use all combinations but in this case not all flag could produce valid combination (like no combination Output+Pull Up). We just need to make output pins readable, not opposite (input pins shouldn't be writable).

We might just make all output modes readable (for now we have only output mode OutputOpenDrain, OtputOpenDrainPullUp, OutputOpenCollector, OutputOpenCollectorPullDown might added later)

Flagging as up-for-grabs so that people can submit PRs for this.

I wonder that why "OpenPin" resets PinMode and PinPower,it seems that the API do too much things which made it difficult to develop.By the way, some case need to get PinPower when the program is going to start up.It's a good way to refer to "WiringPi" because many IOT programs base on it.

We did that because in Linux, we have different drivers that will be used depending on which hardware are you running on, and some would do this behavior as default, so we decided that for consistency, we should have all drivers do the same, so the ones that didn't by default were changed so that the Pinmode and value gets reset.

Was this page helpful?
0 / 5 - 0 ratings