Skip to content

Commit 457e1e5

Browse files
committed
first commit: add HAL and uc8151 driver demo
1 parent 297ad41 commit 457e1e5

File tree

8 files changed

+248
-17
lines changed

8 files changed

+248
-17
lines changed

internal/legacy/pinconfig.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package legacy
2+
3+
import (
4+
"errors"
5+
6+
"tinygo.org/x/drivers/internal/pin"
7+
)
8+
9+
// The pingconfig group of files serve to abstract away
10+
// pin configuration calls on the machine.Pin type.
11+
// It was observed this way of developing drivers was
12+
// non-portable and unusable on "big" Go projects so
13+
// future projects should NOT configure pins in driver code.
14+
// Users must configure pins before passing them as arguments
15+
// to drivers.
16+
17+
// ConfigurePinOut is a legacy function used to configure pins as outputs.
18+
//
19+
// Deprecated: Do not configure pins in drivers.
20+
// This is a legacy feature and should only be used by drivers that
21+
// previously configured pins in initialization to avoid breaking users.
22+
func ConfigurePinOut(po pin.Output) {
23+
configurePinOut(po)
24+
}
25+
26+
// ConfigurePinInput is a legacy function used to configure pins as inputs.
27+
//
28+
// Deprecated: Do not configure pins in drivers.
29+
// This is a legacy feature and should only be used by drivers that
30+
// previously configured pins in initialization to avoid breaking users.
31+
func ConfigurePinInputPulldown(pi pin.Input) {
32+
configurePinInputPulldown(pi)
33+
}
34+
35+
// ConfigurePinInput is a legacy function used to configure pins as inputs.
36+
//
37+
// Deprecated: Do not configure pins in drivers.
38+
// This is a legacy feature and should only be used by drivers that
39+
// previously configured pins in initialization to avoid breaking users.
40+
func ConfigurePinInput(pi pin.Input) {
41+
configurePinInput(pi)
42+
}
43+
44+
// ConfigurePinInput is a legacy function used to configure pins as inputs.
45+
//
46+
// Deprecated: Do not configure pins in drivers.
47+
// This is a legacy feature and should only be used by drivers that
48+
// previously configured pins in initialization to avoid breaking users.
49+
func ConfigurePinInputPullup(pi pin.Input) {
50+
configurePinInputPullup(pi)
51+
}
52+
53+
// PinIsNoPin returns true if the argument is a machine.Pin type and is the machine.NoPin predeclared type.
54+
//
55+
// Deprecated: Drivers do not require pin knowledge from now on.
56+
func PinIsNoPin(pin any) bool {
57+
return pinIsNoPin(pin)
58+
}
59+
60+
var (
61+
ErrConfigBeforeInstantiated = errors.New("device must be instantiated with New before calling Configure method")
62+
)

internal/legacy/pinconfig_go.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//go:build !tinygo
2+
3+
package legacy
4+
5+
import "tinygo.org/x/drivers/internal/pin"
6+
7+
// This file compiles for non-tinygo builds
8+
// for use with "big" or "upstream" Go where
9+
// there is no machine package.
10+
11+
func configurePinOut(p pin.Output) {}
12+
func configurePinInput(p pin.Input) {}
13+
func configurePinInputPulldown(p pin.Input) {}
14+
func configurePinInputPullup(p pin.Input) {}
15+
func pinIsNoPin(a any) bool { return false }
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//go:build baremetal && fe310
2+
3+
package legacy
4+
5+
import "machine"
6+
7+
const (
8+
pulldown = machine.PinInput
9+
pullup = machine.PinInput
10+
)

internal/legacy/pinconfig_pulls.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//go:build baremetal && !fe310
2+
3+
package legacy
4+
5+
import "machine"
6+
7+
// If you are getting a build error here you then we missed adding
8+
// your CPU build tag to the list of CPUs that do not have pulldown/pullups.
9+
// Add it above and in pinhal_nopulls! You should also add a smoketest for it :)
10+
const (
11+
pulldown = machine.PinInputPulldown
12+
pullup = machine.PinInputPullup
13+
)
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//go:build baremetal
2+
3+
package legacy
4+
5+
import (
6+
"machine"
7+
8+
"tinygo.org/x/drivers/internal/pin"
9+
)
10+
11+
func configurePinOut(po pin.Output) {
12+
configurePin(po, machine.PinOutput)
13+
}
14+
15+
func configurePinInputPulldown(pi pin.Input) {
16+
configurePin(pi, pulldown) // some chips do not have pull down, in which case pulldown==machine.PinInput.
17+
}
18+
19+
func configurePinInput(pi pin.Input) {
20+
configurePin(pi, machine.PinInput)
21+
}
22+
23+
func configurePinInputPullup(pi pin.Input) {
24+
configurePin(pi, pullup) // some chips do not have pull up, in which case pullup==machine.PinInput.
25+
}
26+
27+
func pinIsNoPin(a any) bool {
28+
p, ok := a.(machine.Pin)
29+
return ok && p == machine.NoPin
30+
}
31+
32+
func configurePin(p any, mode machine.PinMode) {
33+
machinePin, ok := p.(machine.Pin)
34+
if ok {
35+
machinePin.Configure(machine.PinConfig{Mode: mode})
36+
}
37+
}

internal/pin/internalpin.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package pin
2+
3+
import "tinygo.org/x/drivers"
4+
5+
// This file contains interface-style Pin HAL definition.
6+
// It serves to eliminate machine.Pin from driver constructors
7+
// so that drivers can be used in "big" Go projects where
8+
// there is no machine package.
9+
10+
// Here to aid relevant documentation links of [drivers.PinOutput] and [drivers.PinInput].
11+
var _ drivers.PinOutput
12+
13+
// Output represents a pin hardware abstraction layer for a pin that can output a digital signal.
14+
//
15+
// This is an alternative to [drivers.PinOutput] abstraction which is a function type and has
16+
// not been standardized as of yet as a standard HAL in the drivers package,
17+
// [discussion ongoing here].
18+
//
19+
// [discussion ongoing here]: https://github.com/orgs/tinygo-org/discussions/5043
20+
type Output interface {
21+
Set(level bool)
22+
}
23+
24+
// Input represents a pin hardware abstraction layer.
25+
// See [Output] for more information on why this type exists separate to drivers.
26+
type Input interface {
27+
Get() (level bool)
28+
}

pin.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package drivers
2+
3+
// TinyGo Pin HAL (exported)
4+
//
5+
// Pins are represented as function types instead of interfaces because they are:
6+
// - Faster on MCUs
7+
// - Conceptually simpler than an interface
8+
// - Very likely easier to teach than interface:
9+
// - Cleaner at call sites (e.g., isBusy := d.isBusy() vs d.isBusy.Get()).
10+
// - Enable inline funcs at the usage site- less boilerplate than defining
11+
// an interface type + method (see example below).
12+
// - Less prone to “method creep”: the API surface stays small while
13+
// advanced behavior can be composed in user code.
14+
// Example: a pin that can act as both output and input without adding methods.
15+
//
16+
// var pinIsOutput bool
17+
// var po PinOutput = func(b bool) {
18+
// if !pinIsOutput {
19+
// pin.Configure(outputMode)
20+
// pinIsOutput = true
21+
// }
22+
// pin.Set(b)
23+
// }
24+
// var pi PinInput = func() bool {
25+
// if pinIsOutput {
26+
// pin.Configure(inputMode)
27+
// pinIsOutput = false
28+
// }
29+
// return pin.Get()
30+
// }
31+
//
32+
// See https://github.com/tinygo-org/drivers/pull/753 for detailed commentary.
33+
34+
// PinOutput is hardware abstraction for a pin which outputs a
35+
// digital signal (high or low level).
36+
//
37+
// // Code conversion demo: from machine.Pin to drivers.PinOutput
38+
// led := machine.LED
39+
// led.Configure(machine.PinConfig{Mode: machine.PinOutput})
40+
// var pin drivers.PinOutput = led.Set // Going from a machine.Pin to a drivers.PinOutput
41+
type PinOutput func(level bool)
42+
43+
// High sets the underlying pin's level to high. This is equivalent to calling PinOutput(true).
44+
func (setPin PinOutput) High() {
45+
setPin(true)
46+
}
47+
48+
// Low sets the underlying pin's level to low. This is equivalent to calling PinOutput(false).
49+
func (setPin PinOutput) Low() {
50+
setPin(false)
51+
}
52+
53+
// PinInput is hardware abstraction for a pin which receives a
54+
// digital signal and reads it (high or low level).
55+
//
56+
// // Code conversion demo: from machine.Pin to drivers.PinInput
57+
// input := machine.LED
58+
// input.Configure(machine.PinConfig{Mode: machine.PinInputPulldown}) // or use machine.PinInputPullup or machine.PinInput
59+
// var pin drivers.PinInput = input.Get // Going from a machine.Pin to a drivers.PinInput
60+
type PinInput func() (level bool)

uc8151/uc8151.go

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ package uc8151 // import "tinygo.org/x/drivers/uc8151"
88
import (
99
"errors"
1010
"image/color"
11-
"machine"
1211
"time"
1312

1413
"tinygo.org/x/drivers"
14+
"tinygo.org/x/drivers/internal/legacy"
15+
"tinygo.org/x/drivers/internal/pin"
1516
"tinygo.org/x/drivers/pixel"
1617
)
1718

@@ -31,10 +32,10 @@ type Config struct {
3132

3233
type Device struct {
3334
bus drivers.SPI
34-
cs machine.Pin
35-
dc machine.Pin
36-
rst machine.Pin
37-
busy machine.Pin
35+
cs drivers.PinOutput
36+
dc drivers.PinOutput
37+
rst drivers.PinOutput
38+
isBusy drivers.PinInput
3839
width int16
3940
height int16
4041
buffer []uint8
@@ -49,17 +50,22 @@ type Device struct {
4950
type Speed uint8
5051

5152
// New returns a new uc8151 driver. Pass in a fully configured SPI bus.
52-
func New(bus drivers.SPI, csPin, dcPin, rstPin, busyPin machine.Pin) Device {
53-
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
54-
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
55-
rstPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
56-
busyPin.Configure(machine.PinConfig{Mode: machine.PinInput})
53+
// Pins passed in must be configured beforehand.
54+
func New(bus drivers.SPI, csPin, dcPin, rstPin pin.Output, busyPin pin.Input) Device {
55+
// For backwards compatibility.
56+
// This driver used to configure pins,
57+
// so leave in to not break users.
58+
// May be removed in future so try not to depend on it!
59+
legacy.ConfigurePinOut(csPin)
60+
legacy.ConfigurePinOut(dcPin)
61+
legacy.ConfigurePinOut(rstPin)
62+
legacy.ConfigurePinInput(busyPin)
5763
return Device{
58-
bus: bus,
59-
cs: csPin,
60-
dc: dcPin,
61-
rst: rstPin,
62-
busy: busyPin,
64+
bus: bus,
65+
cs: csPin.Set,
66+
dc: dcPin.Set,
67+
rst: rstPin.Set,
68+
isBusy: busyPin.Get,
6369
}
6470
}
6571

@@ -313,14 +319,14 @@ func (d *Device) ClearDisplay() {
313319

314320
// WaitUntilIdle waits until the display is ready
315321
func (d *Device) WaitUntilIdle() {
316-
for !d.busy.Get() {
322+
for !d.isBusy() {
317323
time.Sleep(10 * time.Millisecond)
318324
}
319325
}
320326

321327
// IsBusy returns the busy status of the display
322328
func (d *Device) IsBusy() bool {
323-
return d.busy.Get()
329+
return d.isBusy()
324330
}
325331

326332
// ClearBuffer sets the buffer to 0xFF (white)

0 commit comments

Comments
 (0)