Skip to content

Commit

Permalink
Merge branch 'feature/pocket-beaglebone' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
deadprogram committed Dec 20, 2017
2 parents 658533c + 1dc8de6 commit 4068c02
Show file tree
Hide file tree
Showing 9 changed files with 344 additions and 112 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,8 @@ Gobot has a extensible system for connecting to hardware devices. The following

- [Arduino](http://www.arduino.cc/) <=> [Package](https://github.com/hybridgroup/gobot/tree/master/platforms/firmata)
- Audio <=> [Package](https://github.com/hybridgroup/gobot/tree/master/platforms/audio)
- [Beaglebone Black](http://beagleboard.org/Products/BeagleBone+Black/) <=> [Package](https://github.com/hybridgroup/gobot/tree/master/platforms/beaglebone)
- [Beaglebone Black](http://beagleboard.org/boards) <=> [Package](https://github.com/hybridgroup/gobot/tree/master/platforms/beaglebone)
- [Beaglebone PocketBeagle](http://beagleboard.org/pocket/) <=> [Package](https://github.com/hybridgroup/gobot/tree/master/platforms/beaglebone)
- [Bluetooth LE](https://www.bluetooth.com/what-is-bluetooth-technology/bluetooth-technology-basics/low-energy) <=> [Package](https://github.com/hybridgroup/gobot/tree/master/platforms/ble)
- [C.H.I.P](http://www.nextthing.co/pages/chip) <=> [Package](https://github.com/hybridgroup/gobot/tree/master/platforms/chip)
- [C.H.I.P Pro](https://docs.getchip.com/chip_pro.html) <=> [Package](https://github.com/hybridgroup/gobot/tree/master/platforms/chip)
Expand Down
76 changes: 72 additions & 4 deletions platforms/beaglebone/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@

The BeagleBone is an ARM based single board computer, with lots of GPIO, I2C, and analog interfaces built in.

The Gobot adaptor for the BeagleBone should support all of the various BeagleBone boards such as the BeagleBone Black, SeeedStudio BeagleBone Green, SeeedStudio BeagleBone Green Wireless, and others that use the latest Debian and standard "Cape Manager" interfaces.
The Gobot adaptor for the BeagleBone supports all of the various BeagleBone boards such as the BeagleBone Black, SeeedStudio BeagleBone Green, SeeedStudio BeagleBone Green Wireless, and others that use the latest Debian and standard "Cape Manager" interfaces.

For more info about the BeagleBone platform go to [http://beagleboard.org/getting-started](http://beagleboard.org/getting-started).

In addition, there is an separate Adaptor for the PocketBeagle, a USB-key-fob sized computer. The PocketBeagle has a different pin layout and somewhat different capabilities.

For more info about the PocketBeagle platform go to [http://beagleboard.org/pocket](http://beagleboard.org/pocket).


## How to Install

We recommend updating to the latest Debian Jessie OS when using the BeagleBone. The current Gobot only supports 4.x versions of the OS. If you need support for older versions of the OS, you will need to use Gobot v1.4.
We recommend updating to the latest Debian OS when using the BeagleBone. The current Gobot only supports 4.x versions of the OS. If you need support for older versions of the OS, you will need to use Gobot v1.4.

You would normally install Go and Gobot on your workstation. Once installed, cross compile your program on your workstation, transfer the final executable to your BeagleBone, and run the program on the BeagleBone itself as documented here.

Expand Down Expand Up @@ -54,6 +58,39 @@ func main() {
}
```

To use the PocketBeagle, use `beaglebone.NewPocketBeagleAdaptor()` like this:

```go
package main

import (
"time"

"gobot.io/x/gobot"
"gobot.io/x/gobot/drivers/gpio"
"gobot.io/x/gobot/platforms/beaglebone"
)

func main() {
beagleboneAdaptor := beaglebone.NewPocketBeagleAdaptor()
led := gpio.NewLedDriver(beagleboneAdaptor, "P1_2")

work := func() {
gobot.Every(1*time.Second, func() {
led.Toggle()
})
}

robot := gobot.NewRobot("pocketBeagleBot",
[]gobot.Connection{beagleboneAdaptor},
[]gobot.Device{led},
work,
)

robot.Start()
}
```

## How to Connect

### Compiling
Expand All @@ -67,12 +104,14 @@ $ GOARM=7 GOARCH=arm GOOS=linux go build examples/beaglebone_blink.go
Once you have compiled your code, you can you can upload your program and execute it on the BeagleBone from your workstation using the `scp` and `ssh` commands like this:

```bash
$ scp beaglebone_blink root@192.168.7.2:/home/root/
$ ssh -t root@192.168.7.2 "./beaglebone_blink"
$ scp beaglebone_blink debian@192.168.7.2:/home/debian/
$ ssh -t debian@192.168.7.2 "./beaglebone_blink"
```

In order to run the preceeding commands, you must be running the official Debian Linux through the usb->ethernet connection, or be connected to the board using WiFi.

You must also configure hardware settings as described below.

### Updating your board to the latest OS

We recommend updating your BeagleBone to the latest Debian OS. It is very easy to do this using the Etcher (https://etcher.io/) utility program.
Expand All @@ -92,3 +131,32 @@ Once you have created the SD card, boot your BeagleBone using the new image as f
These instructions come from the Beagleboard web site's "Getting Started" page located here:

http://beagleboard.org/getting-started

### Configure hardware settings

In order to enable the various hardware devices on your BeagleBone or PocketBeagle, you need to configure a special file named `/boot/uEnv.txt`.

This file controls all of the different hardware options used at startup time, so you can enable or disable features based on your specific needs. You only need to do this once, and then the settings will apply each time you start up your BeagleBone.

First connect to the BeagleBone using ssh:

```
ssh [email protected]
```

Once you are connected to the BeagleBone, edit the /boot/uEnv.txt file like this:

```
sudo nano /boot/uEnv.txt
```

To enable GPIO, PWM, I2C, and SPI, modify the `##Example v4.1.x` section to add a line to enable the cape manager:

```
##Example v4.1.x
cape_enable=bone_capemgr.enable_partno=cape-universaln,BB-ADC
```

Save the file, then reboot your BeagleBone.

You will now be able to run your Gobot programs to control the various hardware.
163 changes: 94 additions & 69 deletions platforms/beaglebone/beaglebone_adaptor.go
Original file line number Diff line number Diff line change
@@ -1,52 +1,75 @@
package beaglebone

import (
"bufio"
"errors"
"fmt"
"os"
"path/filepath"
"strconv"
"strings"
"sync"

multierror "github.com/hashicorp/go-multierror"
"gobot.io/x/gobot"
"gobot.io/x/gobot/drivers/i2c"
"gobot.io/x/gobot/drivers/spi"
"gobot.io/x/gobot/sysfs"
)

type pwmPinData struct {
channel int
path string
}

const pwmDefaultPeriod = 500000

// Adaptor is the gobot.Adaptor representation for the Beaglebone
// Adaptor is the gobot.Adaptor representation for the Beaglebone Black/Green
type Adaptor struct {
name string
digitalPins []*sysfs.DigitalPin
pwmPins map[string]*sysfs.PWMPin
i2cBuses map[int]i2c.I2cDevice
usrLed string
analogPath string
slots string
mutex *sync.Mutex
name string
digitalPins []*sysfs.DigitalPin
pwmPins map[string]*sysfs.PWMPin
i2cBuses map[int]i2c.I2cDevice
usrLed string
analogPath string
pinMap map[string]int
pwmPinMap map[string]pwmPinData
analogPinMap map[string]string
mutex *sync.Mutex
findPin func(pinPath string) (string, error)
spiDefaultBus int
spiBuses [2]spi.SPIDevice
spiDefaultMode int
spiDefaultMaxSpeed int64
}

// NewAdaptor returns a new Beaglebone Adaptor
// NewAdaptor returns a new Beaglebone Black/Green Adaptor
func NewAdaptor() *Adaptor {
b := &Adaptor{
name: gobot.DefaultName("Beaglebone"),
digitalPins: make([]*sysfs.DigitalPin, 120),
pwmPins: make(map[string]*sysfs.PWMPin),
i2cBuses: make(map[int]i2c.I2cDevice),
mutex: &sync.Mutex{},
name: gobot.DefaultName("BeagleboneBlack"),
digitalPins: make([]*sysfs.DigitalPin, 120),
pwmPins: make(map[string]*sysfs.PWMPin),
i2cBuses: make(map[int]i2c.I2cDevice),
mutex: &sync.Mutex{},
pinMap: bbbPinMap,
pwmPinMap: bbbPwmPinMap,
analogPinMap: bbbAnalogPinMap,
findPin: func(pinPath string) (string, error) {
files, err := filepath.Glob(pinPath)
return files[0], err
},
}

b.setSlots()
b.setPaths()
return b
}

func (b *Adaptor) setSlots() {
b.slots = "/sys/devices/platform/bone_capemgr/slots"
func (b *Adaptor) setPaths() {
b.usrLed = "/sys/class/leds/beaglebone:green:"
b.analogPath = "/sys/bus/iio/devices/iio:device0"

b.spiDefaultBus = 0
b.spiDefaultMode = 0
b.spiDefaultMaxSpeed = 500000
}

// Name returns the Adaptor name
Expand All @@ -57,13 +80,6 @@ func (b *Adaptor) SetName(n string) { b.name = n }

// Connect initializes the pwm and analog dts.
func (b *Adaptor) Connect() error {
b.mutex.Lock()
defer b.mutex.Unlock()

if err := ensureSlot(b.slots, "BB-ADC"); err != nil {
return err
}

return nil
}

Expand Down Expand Up @@ -93,6 +109,13 @@ func (b *Adaptor) Finalize() (err error) {
}
}
}
for _, bus := range b.spiBuses {
if bus != nil {
if e := bus.Close(); e != nil {
err = multierror.Append(err, e)
}
}
}
return
}

Expand Down Expand Up @@ -163,6 +186,10 @@ func (b *Adaptor) DigitalPin(pin string, dir string) (sysfsPin sysfs.DigitalPinn
}
if b.digitalPins[i] == nil {
b.digitalPins[i] = sysfs.NewDigitalPin(i)
if err = muxPin(pin, "gpio"); err != nil {
return
}

err := b.digitalPins[i].Export()
if err != nil {
return nil, err
Expand All @@ -186,9 +213,11 @@ func (b *Adaptor) PWMPin(pin string) (sysfsPin sysfs.PWMPinner, err error) {

if b.pwmPins[pin] == nil {
newPin := sysfs.NewPWMPin(pinInfo.channel)
newPin.Path = pinInfo.path
if err = muxPin(pin, "pwm"); err != nil {
return
}

if err = muxPWMPin(pin); err != nil {
if newPin.Path, err = b.findPin(pinInfo.path); err != nil {
return
}
if err = newPin.Export(); err != nil {
Expand All @@ -197,9 +226,6 @@ func (b *Adaptor) PWMPin(pin string) (sysfsPin sysfs.PWMPinner, err error) {
if err = newPin.SetPeriod(pwmDefaultPeriod); err != nil {
return
}
// if err = newPin.InvertPolarity(false); err != nil {
// return
// }
if err = newPin.Enable(true); err != nil {
return
}
Expand Down Expand Up @@ -254,9 +280,41 @@ func (b *Adaptor) GetDefaultBus() int {
return 2
}

// GetSpiConnection returns an spi connection to a device on a specified bus.
// Valid bus number is [0..1] which corresponds to /dev/spidev0.0 through /dev/spidev0.1.
func (b *Adaptor) GetSpiConnection(busNum, mode int, maxSpeed int64) (connection spi.Connection, err error) {
b.mutex.Lock()
defer b.mutex.Unlock()

if (busNum < 0) || (busNum > 1) {
return nil, fmt.Errorf("Bus number %d out of range", busNum)
}

if b.spiBuses[busNum] == nil {
b.spiBuses[busNum], err = spi.GetSpiBus(busNum, mode, maxSpeed)
}

return spi.NewConnection(b.spiBuses[busNum]), err
}

// GetSpiDefaultBus returns the default spi bus for this platform.
func (b *Adaptor) GetSpiDefaultBus() int {
return b.spiDefaultBus
}

// GetSpiDefaultMode returns the default spi mode for this platform.
func (b *Adaptor) GetSpiDefaultMode() int {
return b.spiDefaultMode
}

// GetSpiDefaultMaxSpeed returns the default spi bus for this platform.
func (b *Adaptor) GetSpiDefaultMaxSpeed() int64 {
return b.spiDefaultMaxSpeed
}

// translatePin converts digital pin name to pin position
func (b *Adaptor) translatePin(pin string) (value int, err error) {
if val, ok := pins[pin]; ok {
if val, ok := b.pinMap[pin]; ok {
value = val
} else {
err = errors.New("Not a valid pin")
Expand All @@ -265,7 +323,7 @@ func (b *Adaptor) translatePin(pin string) (value int, err error) {
}

func (b *Adaptor) translatePwmPin(pin string) (p pwmPinData, err error) {
if val, ok := pwmPins[pin]; ok {
if val, ok := b.pwmPinMap[pin]; ok {
p = val
} else {
err = errors.New("Not a valid PWM pin")
Expand All @@ -275,54 +333,21 @@ func (b *Adaptor) translatePwmPin(pin string) (p pwmPinData, err error) {

// translateAnalogPin converts analog pin name to pin position
func (b *Adaptor) translateAnalogPin(pin string) (value string, err error) {
if val, ok := analogPins[pin]; ok {
if val, ok := b.analogPinMap[pin]; ok {
value = val
} else {
err = errors.New("Not a valid analog pin")
}
return
}

func ensureSlot(slots, item string) (err error) {
fi, err := sysfs.OpenFile(slots, os.O_RDWR|os.O_APPEND, 0666)
defer fi.Close()
if err != nil {
return
}

// ensure the slot is not already written into the capemanager
// (from: https://github.com/mrmorphic/hwio/blob/master/module_bb_pwm.go#L190)
scanner := bufio.NewScanner(fi)
for scanner.Scan() {
line := scanner.Text()
if strings.Index(line, item) > 0 {
return
}
}

_, err = fi.WriteString(item)
if err != nil {
return err
}
fi.Sync()

scanner = bufio.NewScanner(fi)
for scanner.Scan() {
line := scanner.Text()
if strings.Index(line, item) > 0 {
return
}
}
return
}

func muxPWMPin(pin string) error {
func muxPin(pin, cmd string) error {
path := fmt.Sprintf("/sys/devices/platform/ocp/ocp:%s_pinmux/state", pin)
fi, e := sysfs.OpenFile(path, os.O_WRONLY, 0666)
defer fi.Close()
if e != nil {
return e
}
_, e = fi.WriteString("pwm")
_, e = fi.WriteString(cmd)
return e
}
Loading

0 comments on commit 4068c02

Please sign in to comment.