Compare commits

...

3 Commits

Author SHA1 Message Date
Yurii Soldak b990fc887f rpio: basic impl of Pins and SPI interfaces for Raspberry Pi 2025-12-23 13:42:48 +01:00
Yurii Soldak 2a42fa7cbb st7735: remove dependency on the machine package 2025-12-22 08:59:05 +00:00
deadprogram 5d96a56603 build: use the latest TinyGo release container instead of the dev container for builds.
Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-12-17 10:28:24 +00:00
7 changed files with 190 additions and 22 deletions
+7 -6
View File
@@ -11,13 +11,12 @@ on:
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: ghcr.io/tinygo-org/tinygo-dev:latest container:
image: ghcr.io/tinygo-org/tinygo:latest
options: --user root
steps: steps:
- name: Work around CVE-2022-24765
# We're not on a multi-user machine, so this is safe.
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v6
- name: TinyGo version check - name: TinyGo version check
run: tinygo version run: tinygo version
- name: Enforce Go Formatted Code - name: Enforce Go Formatted Code
@@ -25,4 +24,6 @@ jobs:
- name: Run unit tests - name: Run unit tests
run: make unit-test run: make unit-test
- name: Run build and smoke tests - name: Run build and smoke tests
run: make smoke-test run: |
go env -w GOFLAGS=-buildvcs=false
make smoke-test
+91
View File
@@ -0,0 +1,91 @@
package main
// Example program for the ST7735 display (Waveshare 1.44" LCD HAT) using the rpio driver on a Raspberry Pi.
// Build command:
// GOOS=linux GOARCH=arm64 go build -o rpio-example ./examples/rpio/
import (
"fmt"
"image/color"
"time"
go_rpio "github.com/stianeikeland/go-rpio/v4"
"tinygo.org/x/drivers"
"tinygo.org/x/drivers/rpio"
"tinygo.org/x/drivers/st7735"
)
var (
black = color.RGBA{0, 0, 0, 255}
colors = [...]color.RGBA{
{255, 0, 0, 255}, // red
{0, 255, 0, 255}, // green
{0, 0, 255, 255}, // blue
{255, 255, 0, 255}, // yellow
}
)
func main() {
if err := go_rpio.Open(); err != nil {
fmt.Println("Error opening GPIO:", err)
return
}
defer go_rpio.Close()
// Initialize SPI and pins
spi := rpio.NewSPI()
resetPin := rpio.NewPin(27)
dcPin := rpio.NewPin(25)
csPin := rpio.NewPin(8)
blPin := rpio.NewPin(24)
rotatePin := rpio.NewPin(20) // middle button on the HAT
rotatePin.Pin.PullUp() // enable pull-up resistor, our wrapper sets only input mode automatically
// Initialize display
device := st7735.New(spi, resetPin, dcPin, csPin, blPin)
device.Configure(st7735.Config{
Width: 128,
Height: 128,
Model: st7735.GREENTAB,
RowOffset: 3,
ColumnOffset: 2,
})
device.InvertColors(false)
device.EnableBacklight(true)
device.IsBGR(true) // no effect w/o rotation!
device.SetRotation(st7735.NO_ROTATION)
width, height := device.Size()
// Clear display
device.FillScreen(black)
// Draw rectangles in a loop, clockwise rotation of colors
pos := 0
for {
device.FillRectangle(0, 0, width/2, height/2, colors[(pos+0)%len(colors)]) // top left
device.FillRectangle(0, height/2, width/2, height/2, colors[(pos+1)%len(colors)]) // bottom left
device.FillRectangle(width/2, height/2, width/2, height/2, colors[(pos+2)%len(colors)]) // bottom right
device.FillRectangle(width/2, 0, width/2, height/2, colors[(pos+3)%len(colors)]) // top right
device.FillRectangle(0, 0, 10, 10, black) // rotation marker
pos++
timeout := time.Now().Add(1 * time.Second)
for time.Now().Before(timeout) {
// check button pressed
if !rotatePin.Get() {
currentRotation := device.Rotation()
newRotation := (currentRotation + 1) % 4
device.SetRotation(drivers.Rotation(newRotation))
// wait for button release
for !rotatePin.Get() {
time.Sleep(10 * time.Millisecond)
}
break
}
time.Sleep(50 * time.Millisecond)
}
}
}
+1
View File
@@ -12,6 +12,7 @@ require (
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/orsinium-labs/tinymath v1.1.0 github.com/orsinium-labs/tinymath v1.1.0
github.com/soypat/natiu-mqtt v0.5.1 github.com/soypat/natiu-mqtt v0.5.1
github.com/stianeikeland/go-rpio/v4 v4.6.0
golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d
golang.org/x/net v0.33.0 golang.org/x/net v0.33.0
tinygo.org/x/tinyfont v0.3.0 tinygo.org/x/tinyfont v0.3.0
+2
View File
@@ -17,6 +17,8 @@ github.com/orsinium-labs/tinymath v1.1.0 h1:KomdsyLHB7vE3f1nRAJF2dyf1m/gnM2HxfTe
github.com/orsinium-labs/tinymath v1.1.0/go.mod h1:WPXX6ei3KSXG7JfA03a+ekCYaY9SWN4I+JRl2p6ck+A= github.com/orsinium-labs/tinymath v1.1.0/go.mod h1:WPXX6ei3KSXG7JfA03a+ekCYaY9SWN4I+JRl2p6ck+A=
github.com/soypat/natiu-mqtt v0.5.1 h1:rwaDmlvjzD2+3MCOjMZc4QEkDkNwDzbct2TJbpz+TPc= github.com/soypat/natiu-mqtt v0.5.1 h1:rwaDmlvjzD2+3MCOjMZc4QEkDkNwDzbct2TJbpz+TPc=
github.com/soypat/natiu-mqtt v0.5.1/go.mod h1:xEta+cwop9izVCW7xOx2W+ct9PRMqr0gNVkvBPnQTc4= github.com/soypat/natiu-mqtt v0.5.1/go.mod h1:xEta+cwop9izVCW7xOx2W+ct9PRMqr0gNVkvBPnQTc4=
github.com/stianeikeland/go-rpio/v4 v4.6.0 h1:eAJgtw3jTtvn/CqwbC82ntcS+dtzUTgo5qlZKe677EY=
github.com/stianeikeland/go-rpio/v4 v4.6.0/go.mod h1:A3GvHxC1Om5zaId+HqB3HKqx4K/AqeckxB7qRjxMK7o=
github.com/valyala/fastjson v1.6.3/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= github.com/valyala/fastjson v1.6.3/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d h1:0olWaB5pg3+oychR51GUVCEsGkeCU/2JxjBgIo4f3M0= golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d h1:0olWaB5pg3+oychR51GUVCEsGkeCU/2JxjBgIo4f3M0=
golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
+37
View File
@@ -0,0 +1,37 @@
// Implements internal.pin.[Input,Output] interfaces for the Raspberry Pi GPIO pins.
// Depends on the go-rpio library.
// Configures pin modes automatically when Get or Set methods are called.
package rpio // import "tinygo.org/x/drivers/rpio"
import go_rpio "github.com/stianeikeland/go-rpio/v4"
type Pin struct {
modeSet bool
Mode go_rpio.Mode
Pin go_rpio.Pin
}
func NewPin(pinNumber int) *Pin {
return &Pin{Pin: go_rpio.Pin(pinNumber)}
}
func (p *Pin) Get() bool {
if !p.modeSet || p.Mode != go_rpio.Input {
p.Pin.Input()
p.Mode = go_rpio.Input
}
return p.Pin.Read() == go_rpio.High
}
func (p *Pin) Set(high bool) {
if !p.modeSet || p.Mode != go_rpio.Output {
p.Pin.Output()
p.Mode = go_rpio.Output
}
state := go_rpio.Low
if high {
state = go_rpio.High
}
p.Pin.Write(state)
}
+33
View File
@@ -0,0 +1,33 @@
// Implemenmts drivers.SPI interface for the Raspberry Pi.
// Depends on the go-rpio library.
package rpio // import "tinygo.org/x/drivers/rpio"
import go_rpio "github.com/stianeikeland/go-rpio/v4"
type SPI struct {
}
func NewSPI() (s *SPI) {
if err := go_rpio.SpiBegin(go_rpio.Spi0); err != nil {
panic(err)
}
go_rpio.SpiSpeed(25_000_000) // 25 MHz
go_rpio.SpiChipSelect(0)
return &SPI{}
}
func (s *SPI) Tx(w, r []byte) error {
data := make([]byte, len(w))
copy(data, w)
go_rpio.SpiExchange(data)
copy(r, data)
return nil
}
func (s *SPI) Transfer(b byte) (byte, error) {
w := []byte{b}
r := make([]byte, len(w))
err := s.Tx(w, r)
return r[0], err
}
+19 -16
View File
@@ -5,12 +5,13 @@ package st7735 // import "tinygo.org/x/drivers/st7735"
import ( import (
"image/color" "image/color"
"machine"
"time" "time"
"errors" "errors"
"tinygo.org/x/drivers" "tinygo.org/x/drivers"
"tinygo.org/x/drivers/internal/legacy"
"tinygo.org/x/drivers/internal/pin"
"tinygo.org/x/drivers/pixel" "tinygo.org/x/drivers/pixel"
) )
@@ -39,10 +40,10 @@ type Device = DeviceOf[pixel.RGB565BE]
// formats. // formats.
type DeviceOf[T Color] struct { type DeviceOf[T Color] struct {
bus drivers.SPI bus drivers.SPI
dcPin machine.Pin dcPin pin.OutputFunc
resetPin machine.Pin resetPin pin.OutputFunc
csPin machine.Pin csPin pin.OutputFunc
blPin machine.Pin blPin pin.OutputFunc
width int16 width int16
height int16 height int16
columnOffset int16 columnOffset int16
@@ -65,23 +66,25 @@ type Config struct {
} }
// New creates a new ST7735 connection. The SPI wire must already be configured. // New creates a new ST7735 connection. The SPI wire must already be configured.
func New(bus drivers.SPI, resetPin, dcPin, csPin, blPin machine.Pin) Device { func New(bus drivers.SPI, resetPin, dcPin, csPin, blPin pin.Output) Device {
return NewOf[pixel.RGB565BE](bus, resetPin, dcPin, csPin, blPin) return NewOf[pixel.RGB565BE](bus, resetPin, dcPin, csPin, blPin)
} }
// NewOf creates a new ST7735 connection with a particular pixel format. The SPI // NewOf creates a new ST7735 connection with a particular pixel format. The SPI
// wire must already be configured. // wire must already be configured.
func NewOf[T Color](bus drivers.SPI, resetPin, dcPin, csPin, blPin machine.Pin) DeviceOf[T] { func NewOf[T Color](bus drivers.SPI, resetPin, dcPin, csPin, blPin pin.Output) DeviceOf[T] {
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput}) // IMPORTANT: pin configuration should really be done outside of this driver,
resetPin.Configure(machine.PinConfig{Mode: machine.PinOutput}) // but for backwards compatibility with existing code, we do it here.
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput}) legacy.ConfigurePinOut(dcPin)
blPin.Configure(machine.PinConfig{Mode: machine.PinOutput}) legacy.ConfigurePinOut(resetPin)
legacy.ConfigurePinOut(csPin)
legacy.ConfigurePinOut(blPin)
return DeviceOf[T]{ return DeviceOf[T]{
bus: bus, bus: bus,
dcPin: dcPin, dcPin: dcPin.Set,
resetPin: resetPin, resetPin: resetPin.Set,
csPin: csPin, csPin: csPin.Set,
blPin: blPin, blPin: blPin.Set,
} }
} }
@@ -423,7 +426,7 @@ func (d *DeviceOf[T]) Data(data uint8) {
// Tx sends data to the display // Tx sends data to the display
func (d *DeviceOf[T]) Tx(data []byte, isCommand bool) { func (d *DeviceOf[T]) Tx(data []byte, isCommand bool) {
d.dcPin.Set(!isCommand) d.dcPin(!isCommand)
d.bus.Tx(data, nil) d.bus.Tx(data, nil)
} }