Skip to content

Commit

Permalink
rock64: introduce adaptor for PINE64-ROCK64
Browse files Browse the repository at this point in the history
  • Loading branch information
gen2thomas committed Jan 12, 2025
1 parent 4e9c832 commit 2b2a951
Show file tree
Hide file tree
Showing 7 changed files with 443 additions and 0 deletions.
84 changes: 84 additions & 0 deletions examples/rock64_direct_pin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//go:build example
// +build example

//
// Do not build by default.

package main

import (
"fmt"
"time"

"gobot.io/x/gobot/v2"
"gobot.io/x/gobot/v2/drivers/gpio"
"gobot.io/x/gobot/v2/platforms/adaptors"
"gobot.io/x/gobot/v2/platforms/pine64/rock64"
)

// Wiring
// PWR ROCK64: 1, P5_1 (+3.3V, VCC); 2, 4, P5_2 (+5V, VDD); 6, 9, 14, 20, P5_7, P5_8, P5_15, P5_16 (GND)
// GPIO ROCK64: second header P5+BUS pin 3 is input, pin 4 is normal output, pin 5 is inverted output
// Button: the input pin is wired with a button to GND, the internal pull up resistor is used
// LED's: the output pins are wired to the cathode of the LED, the anode is wired with a resistor (70-130Ohm for 20mA)
// to VCC
// Expected behavior: always one LED is on, the other in opposite state, if button is pressed for >2 seconds the state
// changes
func main() {
const (
inPinNum = "P5_3"
outPinNum = "P5_4"
outPinInvertedNum = "P5_5"
debounceTime = 2 * time.Second
)
// note: WithGpiosOpenDrain() is optional, if using WithGpiosOpenSource() the LED's will not light up
board := rock64.NewAdaptor(adaptors.WithGpiosActiveLow(outPinInvertedNum),
adaptors.WithGpiosOpenDrain(outPinNum, outPinInvertedNum),
adaptors.WithGpiosPullUp(inPinNum),
adaptors.WithGpioDebounce(inPinNum, debounceTime))

inPin := gpio.NewDirectPinDriver(board, inPinNum)
outPin := gpio.NewDirectPinDriver(board, outPinNum)
outPinInverted := gpio.NewDirectPinDriver(board, outPinInvertedNum)

work := func() {
level := byte(1)

gobot.Every(500*time.Millisecond, func() {
read, err := inPin.DigitalRead()
fmt.Printf("pin %s state is %d\n", inPinNum, read)
if err != nil {
fmt.Println(err)
if level == 1 {
level = 0
} else {
level = 1
}
} else {
level = byte(read)
}

err = outPin.DigitalWrite(level)
fmt.Printf("pin %s is now %d\n", outPinNum, level)
if err != nil {
fmt.Println(err)
}

err = outPinInverted.DigitalWrite(level)
fmt.Printf("pin %s is now not %d\n", outPinInvertedNum, level)
if err != nil {
fmt.Println(err)
}
})
}

robot := gobot.NewRobot("pinBot",
[]gobot.Connection{board},
[]gobot.Device{inPin, outPin, outPinInverted},
work,
)

if err := robot.Start(); err != nil {
panic(err)
}
}
81 changes: 81 additions & 0 deletions examples/rock64_yl40.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
//go:build example
// +build example

//
// Do not build by default.

package main

import (
"fmt"
"log"
"time"

"gobot.io/x/gobot/v2"
"gobot.io/x/gobot/v2/drivers/i2c"
"gobot.io/x/gobot/v2/platforms/pine64/rock64"
)

func main() {
// Wiring
// PWR ROCK64: 1, P5_1 (+3.3V, VCC), 6, 9, 14, 20, P5_7, P5_8, P5_15, P5_16 (GND)
// I2C0 ROCK64: 3 (SDA), 5 (SCL)
// I2C1 ROCK64: 27 (SDA), 28 (SCL)
// YL-40 module: wire AOUT --> AIN2 for this example
//
// Note: temperature measurement is often buggy, because sensor is not properly grounded
// fix it by soldering a small bridge to the adjacent ground pin of brightness sensor
board := rock64.NewAdaptor()
yl := i2c.NewYL40Driver(board, i2c.WithBus(1))

work := func() {
// the LED light is visible above ~1.7V
writeVal, _ := yl.AOUT()

gobot.Every(1000*time.Millisecond, func() {
if err := yl.Write(writeVal); err != nil {
fmt.Println(err)
} else {
log.Printf(" %.1f V written", writeVal)
writeVal = writeVal + 0.1
if writeVal > 3.3 {
writeVal = 0
}
}

if brightness, err := yl.ReadBrightness(); err != nil {
fmt.Println(err)
} else {
log.Printf("Brightness: %.0f [0..1000]", brightness)
}

if temperature, err := yl.ReadTemperature(); err != nil {
fmt.Println(err)
} else {
log.Printf("Temperature: %.1f °C", temperature)
}

if ain2, err := yl.ReadAIN2(); err != nil {
fmt.Println(err)
} else {
log.Printf("Read back AOUT: %.1f [0..3.3]", ain2)
}

if potiState, err := yl.ReadPotentiometer(); err != nil {
fmt.Println(err)
} else {
log.Printf("Resistor: %.0f %% [-100..+100]", potiState)
}
})
}

robot := gobot.NewRobot("yl40Bot",
[]gobot.Connection{board},
[]gobot.Device{yl},
work,
)

if err := robot.Start(); err != nil {
panic(err)
}
}
13 changes: 13 additions & 0 deletions platforms/pine64/rock64/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Copyright (c) 2025 The Hybrid Group

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
63 changes: 63 additions & 0 deletions platforms/pine64/rock64/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Pine ROCK64

The Pine ROCK64 is a single board SoC computer based on the Rockchip RK3328 arm64 processor. It has built-in GPIO and
I2C interfaces. SPI is most likely not usable, because access of SPI FLASH 128M memory chip use it.

For more info about the Pine ROCK64, go to [https://pine64.org/documentation/ROCK64/](https://pine64.org/documentation/ROCK64/).

## How to Install

Please refer to the main [README.md](https://github.com/hybridgroup/gobot/blob/release/README.md)

Tested OS:

* [armbian](https://www.armbian.com/rock64/) with Debian

## Configuration steps for the OS

### System access and configuration basics

```sh
ssh <user>@192.168.1.xxx
```

### Enabling hardware drivers

Not all drivers are enabled by default. You can have a look at the configuration file, to find out what is enabled at
your system:

```sh
cat /boot/armbianEnv.txt
```

```sh
sudo apt install armbian-config
sudo armbian-config
```

## How to Use

The pin numbering used by your Gobot program should match the way your board is labeled right on the board itself.

```go
r := rock64.NewAdaptor()
led := gpio.NewLedDriver(r, "7")
```

## How to Connect

### Compiling

Compile your Gobot program on your workstation like this:

```sh
GOARCH=arm64 GOOS=linux go build -o output/ examples/rock64_blink.go
```

Once you have compiled your code, you can upload your program and execute it on the board from your workstation
using the `scp` and `ssh` commands like this:

```sh
scp rock64_blink <user>@192.168.1.xxx:~
ssh -t <user>@192.168.1.xxx "./rock64_blink"
```
140 changes: 140 additions & 0 deletions platforms/pine64/rock64/adaptor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package rock64

import (
"fmt"
"sync"

multierror "github.com/hashicorp/go-multierror"

"gobot.io/x/gobot/v2"
"gobot.io/x/gobot/v2/platforms/adaptors"
"gobot.io/x/gobot/v2/system"
)

const (
defaultI2cBusNumber = 1

defaultSpiBusNumber = 0
defaultSpiChipNumber = 0
defaultSpiMode = 0
defaultSpiBitsNumber = 8
defaultSpiMaxSpeed = 500000
)

// Adaptor represents a Gobot Adaptor for the PINE64 ROCK64
type Adaptor struct {
name string
sys *system.Accesser // used for unit tests only
mutex *sync.Mutex
*adaptors.AnalogPinsAdaptor
*adaptors.DigitalPinsAdaptor
*adaptors.I2cBusAdaptor
*adaptors.SpiBusAdaptor
*adaptors.OneWireBusAdaptor
}

// NewAdaptor creates a ROCK64 Adaptor
//
// Optional parameters:
//
// adaptors.WithGpioSysfsAccess(): use legacy sysfs driver instead of default character device driver
// adaptors.WithSpiGpioAccess(sclk, ncs, sdo, sdi): use GPIO's instead of /dev/spidev#.#
// adaptors.WithGpiosActiveLow(pin's): invert the pin behavior
// adaptors.WithGpiosPullUp/Down(pin's): sets the internal pull resistor
//
// Optional parameters for PWM, see [adaptors.NewPWMPinsAdaptor]
func NewAdaptor(opts ...interface{}) *Adaptor {
sys := system.NewAccesser()
a := &Adaptor{
name: gobot.DefaultName("ROCK64"),
sys: sys,
mutex: &sync.Mutex{},
}

var digitalPinsOpts []adaptors.DigitalPinsOptionApplier
var spiBusOpts []adaptors.SpiBusOptionApplier
for _, opt := range opts {
switch o := opt.(type) {
case adaptors.DigitalPinsOptionApplier:
digitalPinsOpts = append(digitalPinsOpts, o)
case adaptors.SpiBusOptionApplier:
spiBusOpts = append(spiBusOpts, o)
default:
panic(fmt.Sprintf("'%s' can not be applied on adaptor '%s'", opt, a.name))
}
}

analogPinTranslator := adaptors.NewAnalogPinTranslator(sys, analogPinDefinitions)
digitalPinTranslator := adaptors.NewDigitalPinTranslator(sys, gpioPinDefinitions)
// Valid bus numbers are [0,1] which corresponds to /dev/i2c-0, /dev/i2c-1.
// We don't support "/dev/i2c-4 DesignWare HDMI".
i2cBusNumberValidator := adaptors.NewBusNumberValidator([]int{0, 1})
// Valid bus number is 0 which corresponds to /dev/spidev0.x
// x is the chip number <255
spiBusNumberValidator := adaptors.NewBusNumberValidator([]int{0})

a.AnalogPinsAdaptor = adaptors.NewAnalogPinsAdaptor(sys, analogPinTranslator.Translate)
a.DigitalPinsAdaptor = adaptors.NewDigitalPinsAdaptor(sys, digitalPinTranslator.Translate, digitalPinsOpts...)
a.I2cBusAdaptor = adaptors.NewI2cBusAdaptor(sys, i2cBusNumberValidator.Validate, defaultI2cBusNumber)
a.SpiBusAdaptor = adaptors.NewSpiBusAdaptor(sys, spiBusNumberValidator.Validate, defaultSpiBusNumber,
defaultSpiChipNumber, defaultSpiMode, defaultSpiBitsNumber, defaultSpiMaxSpeed, a.DigitalPinsAdaptor, spiBusOpts...)
a.OneWireBusAdaptor = adaptors.NewOneWireBusAdaptor(sys)

return a
}

// Name returns the name of the Adaptor
func (a *Adaptor) Name() string { return a.name }

// SetName sets the name of the Adaptor
func (a *Adaptor) SetName(n string) { a.name = n }

// Connect create new connection to board and pins.
func (a *Adaptor) Connect() error {
a.mutex.Lock()
defer a.mutex.Unlock()

if err := a.OneWireBusAdaptor.Connect(); err != nil {
return err
}

if err := a.SpiBusAdaptor.Connect(); err != nil {
return err
}

if err := a.I2cBusAdaptor.Connect(); err != nil {
return err
}

if err := a.AnalogPinsAdaptor.Connect(); err != nil {
return err
}

return a.DigitalPinsAdaptor.Connect()
}

// Finalize closes connection to board, pins and bus
func (a *Adaptor) Finalize() error {
a.mutex.Lock()
defer a.mutex.Unlock()

err := a.DigitalPinsAdaptor.Finalize()

if e := a.AnalogPinsAdaptor.Finalize(); e != nil {
err = multierror.Append(err, e)
}

if e := a.I2cBusAdaptor.Finalize(); e != nil {
err = multierror.Append(err, e)
}

if e := a.SpiBusAdaptor.Finalize(); e != nil {
err = multierror.Append(err, e)
}

if e := a.OneWireBusAdaptor.Finalize(); e != nil {
err = multierror.Append(err, e)
}

return err
}
7 changes: 7 additions & 0 deletions platforms/pine64/rock64/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/*
Package rock64 contains the Gobot adaptor for the PINE64 ROCK64.
For further information refer to the boards README:
https://github.com/hybridgroup/gobot/blob/release/platforms/pine64/rock64/README.md
*/
package rock64 // import "gobot.io/x/gobot/v2/platforms/rock64"
Loading

0 comments on commit 2b2a951

Please sign in to comment.