Skip to content

Conversation

ysoldak
Copy link
Contributor

@ysoldak ysoldak commented Sep 21, 2025

This change proposes an approach to break dependency of the drivers from machine package.
See also #749 and #753

This approach uses build tags to ensure machine pins configured as outputs in drivers that used to do so and no-op in general pin case. Configuring machine pins as outputs transparently is important to not to break existing client code.
The wrapper does a type check and executes only on machine.Pin, passing any custom implementation through.
PinOutput interface is kept minimal, it has Set(bool) method only, dropping convenience methods High() and Low(). This expected to simplify custom implementations but requires many, yet trivial, changes in drivers -- a fair tradeoff.

All new drivers strongly advised not to use this legacy workaround and let pin modes be controlled by client code, either automatically by implementing checks in Get() and Set() methods or once before calling a driver constructor.
See updated DHT driver example for automatic pin mode handling.

A proof-of-concept non-TinyGo pin implementation is provided in rpio package to control pins on Raspberry Pi.
See also example of controlling Waveshare 1.44inch LCD HAT (ST7735 driver) on RPi in examples/rpio.
This also demonstrates automatic pin mode handling in Get() and Set() functions.

Several drivers were updated to use drivers.Pin[Output], for demonstration.

  • Buzzer driver stores pointer to Set() function to avoid performance penalty associated with interface lookups.
  • BMI160, ST7735 and SSD1306 drivers are the standard drivers with output pins, demonstrate use of legacy.PinOutput() wrapper to maintain old behavior.
  • DHT driver uses drivers.Pin interface that calls both Get() and Set() on a pin -- in this one we have to stop configuring for inputs and outputs and let client code to maintain pin modes, as we can't know in drivers code which of input modes shall be set: PinInput, PinInputPullup or PinInputPulldown. See note in the bottom of this PR description.
  • HCSR04 driver uses both input and output pins, we shall stop configuring pin modes for this driver, see DHT above and the note below. Alternatively, we could use legacy.PinOutput and implement legacy.PinInput.

Please note, none of examples for mentioned drivers, except "DHT" and "HCSR04", were changed, this demonstrates backwards compatibility and the ability to pass machine.Pin in changed drivers as before, maintaining functionality.
DHT and HCSR04 examples use new helper type tinygo.Pin that handles pin modes automatically. It's up to client code to use this implementation or make their own.


Note on automatic input mode setting.
At first (see the first commit in this PR), I've tried to implement fully automatic pin mode handling for machine.Pin, the only requirement was drivers have to use drivers.SafePinOutput(), etc functions. There is a major problem: we can't know for sure which input mode must be set automatically on Get() operation. Rather than guessing, I propose we let the client code control that. Thankfully, there are not many drivers that use a flavor of PinInput mode. And, in the drivers that do, they shall stop doing that, since, as discussed, there is no way to know which mode is correct in every case.

@ysoldak ysoldak marked this pull request as draft September 22, 2025 22:10
@ysoldak
Copy link
Contributor Author

ysoldak commented Sep 22, 2025

Converted to draft to give priority to #753
I'll take bits from this change (ex. rpio pin implementation and example) and cary them over as a follow ups for #753

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant