rp-rs / rp-hal

A Rust Embedded-HAL for the rp series microcontrollers
https://crates.io/crates/rp2040-hal
Apache License 2.0
1.45k stars 234 forks source link

Add open-drain output implementation #552

Closed bartweber closed 1 year ago

bartweber commented 1 year ago

For convenience, please add an open-drain output implementation. I experimented with the implementation InOutPin used in the example rp2040-hal/examples/dht11.rs for communication with the 1-wire protocol (i.c.w. a DS18B20), but it seems to be unreliable. (Or more accurately: not working at all.)

As stated in the example, it is not possible to drive the pin low before changing the pin mode to output to emulate the open-drain output low state.

// In theory, we should set the pin to low first, to make sure we never actively // pull it up. But if we try it on the input pin, we get Err(Gpio(InvalidPinType)).

It seems to me this cannot be solved by a custom DynPin implementation (as is done in the example) and should be solved in the rp2040-hal itself. Hence this ticket.

In another hals - e.g. https://github.com/stm32-rs/stm32f3xx-hal - this pin mode is implemented. I would suggest a method like into_open_drain_output() as used in:

let mut one_wire_pin = pins.gpio0.into_open_drain_output();

To sum up the requirements (please correct me if I am wrong):

ithinuel commented 1 year ago

The main reason for not implementing this so far is that the hardware does not support it. It has to be emulated with controling OE.

The difference with the st hal (and lots of other silicon) is that they do have support for it in hardware (see stm32f3xx reference manual page 228/1141 – 11.3 GPIO Functional description).

bartweber commented 1 year ago

Ai, I should have RTFM first. Somehow I got the idea that all modern micro-controllers have no other option than to emulate the open-drain output. (I'm a software developer for many years but a beginner/hobbyist in embedded programming and electronics.)

In this case I might be better of with an I2C to 1-wire bridge (like the DS2482). No any hassle with the 1-wire protocol. (One disadvantage of this option is though, there no lib written in Rust yet for this device.)

jannic commented 1 year ago

Well, that's an opportunity to write a driver for the weekly driver initiative :-)

Seriously: @ithinuel correctly explained why there is no open-drain output implementation. But that doesn't mean that the rp2040 is unable to speak the 1-wire protocol. If the emulated InOutPin doesn't work, we should find out why.

anall commented 1 year ago

I actually considered adding support for open drain/open collector [by fiddling OE] when doing the conversion to the type-based GPIO, but didn't want the added complexity when the original code didn't support it.

I don't think it would be that hard to add.

jannic commented 1 year ago

I probably wouldn't call it open drain/open collector. It works similar, but electrically, it's something different. I'm not knowledgeable enough about electrical circuits to tell if it actually makes a difference, so I'd just be cautious and give it some neutral name. That's why I just called it InOutPin in the dht11 example. And yes, it shouldn't be hard to add. Hardest thing would be to find a good API (ie. as flexible as possible without becoming difficult to use).