diff --git a/examples/beaglebone_blink_usr_led.go b/examples/beaglebone_blink_usr_led.go index 34479e4b..3774fc0c 100644 --- a/examples/beaglebone_blink_usr_led.go +++ b/examples/beaglebone_blink_usr_led.go @@ -10,7 +10,7 @@ import ( func main() { beagleboneAdaptor := beaglebone.NewAdaptor() - led := gpio.NewLedDriver(beagleboneAdaptor, "usr0") + led := gpio.NewLedDriver(beagleboneAdaptor, "usr1") work := func() { gobot.Every(1*time.Second, func() { diff --git a/platforms/beaglebone/README.md b/platforms/beaglebone/README.md index bee82a81..8cc6dcca 100644 --- a/platforms/beaglebone/README.md +++ b/platforms/beaglebone/README.md @@ -5,31 +5,11 @@ The BeagleBone is an ARM based single board computer, with many different GPIO i For more info about the BeagleBone platform click [here](http://beagleboard.org/Products/BeagleBone+Black). ## How to Install + ``` go get -d -u github.com/hybridgroup/gobot/... && go install github.com/hybridgroup/gobot/platforms/beaglebone ``` -## Cross compiling for the Beaglebone Black -You must first configure your Go environment for arm linux cross compiling - -```bash -$ cd $GOROOT/src -$ GOOS=linux GOARCH=arm ./make.bash --no-clean -``` - -Then compile your Gobot program with - -```bash -$ GOARM=7 GOARCH=arm GOOS=linux go build examples/beaglebone_blink.go -``` - -If you are running the official Angstrom or Debian linux through the usb->ethernet connection, you can simply upload your program and execute it with - -```bash -$ scp beaglebone_blink root@192.168.7.2:/home/root/ -$ ssh -t root@192.168.7.2 "./beaglebone_blink" -``` - ## How to Use ```go @@ -62,3 +42,40 @@ func main() { robot.Start() } ``` + +## How to Connect + +### Compiling + +Simply compile your Gobot program like this: + +```bash +$ GOARCH=arm GOOS=linux go build examples/beaglebone_blink.go +``` + +If you are running the official Debian Linux through the usb->ethernet connection, or are connected to the board using WiFi, you can simply upload your program and execute it with the `scp` command like this: + +```bash +$ scp beaglebone_blink root@192.168.7.2:/home/root/ +$ ssh -t root@192.168.7.2 "./beaglebone_blink" +``` + +### 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. + +First, download the latest BeagleBone OS from http://beagleboard.org/latest-images + +Now, use Etcher to create an SD card with the OS image you have downloaded. + +Once you have created the SD card, boot your BeagleBone using the new image as follows: + +- Insert SD card into your (powered-down) board, hold down the USER/BOOT button (if using Black) and apply power, either by the USB cable or 5V adapter. + +- If all you want to do it boot once from the SD card, it should now be booting. + +- If using BeagleBone Black and desire to write the image to your on-board eMMC, you'll need to follow the instructions at http://elinux.org/Beagleboard:BeagleBoneBlack_Debian#Flashing_eMMC. When the flashing is complete, all 4 USRx LEDs will be steady on or off. The latest Debian flasher images automatically power down the board upon completion. This can take up to 45 minutes. Power-down your board, remove the SD card and apply power again to be complete. + +These instructions come from the Beagleboard web site's "Getting Started" page located here: + +http://beagleboard.org/getting-started diff --git a/platforms/beaglebone/beaglebone_adaptor.go b/platforms/beaglebone/beaglebone_adaptor.go index a5fce0dc..c510d859 100644 --- a/platforms/beaglebone/beaglebone_adaptor.go +++ b/platforms/beaglebone/beaglebone_adaptor.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "os" + "os/exec" "path/filepath" "strconv" "strings" @@ -14,113 +15,22 @@ import ( "github.com/hybridgroup/gobot/sysfs" ) -var slots = "/sys/devices/bone_capemgr.*" -var ocp = "/sys/devices/ocp.*" -var usrLed = "/sys/devices/ocp.3/gpio-leds.8/leds/beaglebone:green:" - var glob = func(pattern string) (matches []string, err error) { return filepath.Glob(pattern) } -var pins = map[string]int{ - "P8_3": 38, - "P8_4": 39, - "P8_5": 34, - "P8_6": 35, - "P8_7": 66, - "P8_8": 67, - "P8_9": 69, - "P8_10": 68, - "P8_11": 45, - "P8_12": 44, - "P8_13": 23, - "P8_14": 26, - "P8_15": 47, - "P8_16": 46, - "P8_17": 27, - "P8_18": 65, - "P8_19": 22, - "P8_20": 63, - "P8_21": 62, - "P8_22": 37, - "P8_23": 36, - "P8_24": 33, - "P8_25": 32, - "P8_26": 61, - "P8_27": 86, - "P8_28": 88, - "P8_29": 87, - "P8_30": 89, - "P8_31": 10, - "P8_32": 11, - "P8_33": 9, - "P8_34": 81, - "P8_35": 8, - "P8_36": 80, - "P8_37": 78, - "P8_38": 79, - "P8_39": 76, - "P8_40": 77, - "P8_41": 74, - "P8_42": 75, - "P8_43": 72, - "P8_44": 73, - "P8_45": 70, - "P8_46": 71, - "P9_11": 30, - "P9_12": 60, - "P9_13": 31, - "P9_14": 50, - "P9_15": 48, - "P9_16": 51, - "P9_17": 5, - "P9_18": 4, - "P9_19": 13, - "P9_20": 12, - "P9_21": 3, - "P9_22": 2, - "P9_23": 49, - "P9_24": 15, - "P9_25": 117, - "P9_26": 14, - "P9_27": 115, - "P9_28": 113, - "P9_29": 111, - "P9_30": 112, - "P9_31": 110, -} - -var pwmPins = map[string]string{ - "P9_14": "P9_14", - "P9_21": "P9_21", - "P9_22": "P9_22", - "P9_29": "P9_29", - "P9_42": "P9_42", - "P8_13": "P8_13", - "P8_34": "P8_34", - "P8_45": "P8_45", - "P8_46": "P8_46", -} - -var analogPins = map[string]string{ - "P9_39": "AIN0", - "P9_40": "AIN1", - "P9_37": "AIN2", - "P9_38": "AIN3", - "P9_33": "AIN4", - "P9_36": "AIN5", - "P9_35": "AIN6", -} - // Adaptor is the gobot.Adaptor representation for the Beaglebone type Adaptor struct { - name string - digitalPins []sysfs.DigitalPin - pwmPins map[string]*pwmPin - i2cDevice sysfs.I2cDevice - ocp string - helper string - slots string + name string + kernel string + digitalPins []sysfs.DigitalPin + pwmPins map[string]*pwmPin + i2cDevice sysfs.I2cDevice + usrLed string + ocp string + analogPath string + analogPinMap map[string]string + slots string } // NewAdaptor returns a new Beaglebone Adaptor @@ -131,12 +41,27 @@ func NewAdaptor() *Adaptor { pwmPins: make(map[string]*pwmPin), } + b.setSlots() + return b +} + +func (b *Adaptor) setSlots() { + ocp := "/sys/devices/ocp.*" + slots := "/sys/devices/bone_capemgr.*" + + b.kernel = getKernel() + if b.kernel[:1] == "4" { + ocp = "/sys/devices/platform/ocp/ocp*" + slots = "/sys/devices/platform/bone_capemgr" + } + + b.usrLed = "/sys/class/leds/beaglebone:green:" + g, _ := glob(ocp) b.ocp = g[0] + g, _ = glob(slots) b.slots = fmt.Sprintf("%v/slots", g[0]) - - return b } // Name returns the Adaptor name @@ -145,22 +70,37 @@ func (b *Adaptor) Name() string { return b.name } // SetName sets the Adaptor name func (b *Adaptor) SetName(n string) { b.name = n } +// Kernel returns the Linux kernel version for the BeagleBone +func (b *Adaptor) Kernel() string { return b.kernel } + // Connect initializes the pwm and analog dts. func (b *Adaptor) Connect() error { - if err := ensureSlot(b.slots, "cape-bone-iio"); err != nil { - return err + // enable analog + if b.kernel[:1] == "4" { + if err := ensureSlot(b.slots, "BB-ADC"); err != nil { + return err + } + + b.analogPath = "/sys/bus/iio/devices/iio:device0" + b.analogPinMap = analogPins44 + } else { + if err := ensureSlot(b.slots, "cape-bone-iio"); err != nil { + return err + } + + g, err := glob(fmt.Sprintf("%v/helper.*", b.ocp)) + if err != nil { + return err + } + b.analogPath = g[0] + b.analogPinMap = analogPins3 } + // enable pwm if err := ensureSlot(b.slots, "am33xx_pwm"); err != nil { return err } - g, err := glob(fmt.Sprintf("%v/helper.*", b.ocp)) - if err != nil { - return err - } - b.helper = g[0] - return nil } @@ -217,7 +157,7 @@ func (b *Adaptor) DigitalRead(pin string) (val int, err error) { // valid usr pin values are usr0, usr1, usr2 and usr3 func (b *Adaptor) DigitalWrite(pin string, val byte) (err error) { if strings.Contains(pin, "usr") { - fi, err := sysfs.OpenFile(usrLed+pin+"/brightness", os.O_WRONLY|os.O_APPEND, 0666) + fi, err := sysfs.OpenFile(b.usrLed+pin+"/brightness", os.O_WRONLY|os.O_APPEND, 0666) defer fi.Close() if err != nil { return err @@ -238,7 +178,7 @@ func (b *Adaptor) AnalogRead(pin string) (val int, err error) { if err != nil { return } - fi, err := sysfs.OpenFile(fmt.Sprintf("%v/%v", b.helper, analogPin), os.O_RDONLY, 0644) + fi, err := sysfs.OpenFile(fmt.Sprintf("%v/%v", b.analogPath, analogPin), os.O_RDONLY, 0644) defer fi.Close() if err != nil { @@ -306,7 +246,7 @@ func (b *Adaptor) translatePwmPin(pin string) (value string, err error) { // translateAnalogPin converts analog pin name to pin position func (b *Adaptor) translateAnalogPin(pin string) (value string, err error) { - for key, value := range analogPins { + for key, value := range b.analogPinMap { if key == pin { return value, nil } @@ -396,3 +336,9 @@ func ensureSlot(slots, item string) (err error) { } return } + +func getKernel() string { + result, _ := exec.Command("uname", "-r").Output() + + return strings.TrimSpace(string(result)) +} diff --git a/platforms/beaglebone/beaglebone_adaptor_test.go b/platforms/beaglebone/beaglebone_adaptor_test.go index 55199129..84d96de7 100644 --- a/platforms/beaglebone/beaglebone_adaptor_test.go +++ b/platforms/beaglebone/beaglebone_adaptor_test.go @@ -42,7 +42,7 @@ func (n *NullReadWriteCloser) Read(b []byte) (int, error) { return len(b), nil } -var closeErr error = nil +var closeErr error func (n *NullReadWriteCloser) Close() error { return closeErr @@ -54,16 +54,15 @@ func TestBeagleboneAdaptor(t *testing.T) { } fs := sysfs.NewMockFilesystem([]string{ "/dev/i2c-1", - "/sys/devices/bone_capemgr.4", - "/sys/devices/ocp.3", - "/sys/devices/ocp.3/gpio-leds.8/leds/beaglebone:green:usr1/brightness", - "/sys/devices/ocp.3/helper.5", - "/sys/devices/ocp.3/helper.5/AIN1", - "/sys/devices/ocp.3/pwm_test_P9_14.5", - "/sys/devices/ocp.3/pwm_test_P9_14.5/run", - "/sys/devices/ocp.3/pwm_test_P9_14.5/period", - "/sys/devices/ocp.3/pwm_test_P9_14.5/polarity", - "/sys/devices/ocp.3/pwm_test_P9_14.5/duty", + "/sys/devices/platform/bone_capemgr", + "/sys/devices/platform/ocp/ocp4", + "/sys/class/leds/beaglebone:green:usr1/brightness", + "/sys/bus/iio/devices/iio:device0/in_voltage1_raw", + "/sys/devices/platform/ocp/ocp4/pwm_test_P9_14.5", + "/sys/devices/platform/ocp/ocp4/pwm_test_P9_14.5/run", + "/sys/devices/platform/ocp/ocp4/pwm_test_P9_14.5/period", + "/sys/devices/platform/ocp/ocp4/pwm_test_P9_14.5/polarity", + "/sys/devices/platform/ocp/ocp4/pwm_test_P9_14.5/duty", "/sys/class/gpio/export", "/sys/class/gpio/unexport", "/sys/class/gpio/gpio60/value", @@ -74,12 +73,13 @@ func TestBeagleboneAdaptor(t *testing.T) { sysfs.SetFilesystem(fs) a := NewAdaptor() - a.slots = "/sys/devices/bone_capemgr.4" - a.ocp = "/sys/devices/ocp.3" + a.slots = "/sys/devices/platform/bone_capemgr" + a.ocp = "/sys/devices/platform/ocp/ocp4" + a.kernel = "4.4" a.Connect() - a.helper = "/sys/devices/ocp.3/helper.5" + a.analogPath = "/sys/bus/iio/devices/iio:device0" // PWM glob = func(pattern string) (matches []string, err error) { @@ -91,39 +91,39 @@ func TestBeagleboneAdaptor(t *testing.T) { a.PwmWrite("P9_14", 175) gobottest.Assert( t, - fs.Files["/sys/devices/ocp.3/pwm_test_P9_14.5/period"].Contents, + fs.Files["/sys/devices/platform/ocp/ocp4/pwm_test_P9_14.5/period"].Contents, "500000", ) gobottest.Assert( t, - fs.Files["/sys/devices/ocp.3/pwm_test_P9_14.5/duty"].Contents, + fs.Files["/sys/devices/platform/ocp/ocp4/pwm_test_P9_14.5/duty"].Contents, "343137", ) a.ServoWrite("P9_14", 100) gobottest.Assert( t, - fs.Files["/sys/devices/ocp.3/pwm_test_P9_14.5/period"].Contents, + fs.Files["/sys/devices/platform/ocp/ocp4/pwm_test_P9_14.5/period"].Contents, "16666666", ) gobottest.Assert( t, - fs.Files["/sys/devices/ocp.3/pwm_test_P9_14.5/duty"].Contents, + fs.Files["/sys/devices/platform/ocp/ocp4/pwm_test_P9_14.5/duty"].Contents, "1898148", ) // Analog - fs.Files["/sys/devices/ocp.3/helper.5/AIN1"].Contents = "567\n" + fs.Files["/sys/bus/iio/devices/iio:device0/in_voltage1_raw"].Contents = "567\n" i, _ := a.AnalogRead("P9_40") gobottest.Assert(t, i, 567) - i, err := a.AnalogRead("P9_99") + _, err := a.AnalogRead("P9_99") gobottest.Assert(t, err, errors.New("Not a valid pin")) // DigitalIO a.DigitalWrite("usr1", 1) gobottest.Assert(t, - fs.Files["/sys/devices/ocp.3/gpio-leds.8/leds/beaglebone:green:usr1/brightness"].Contents, + fs.Files["/sys/class/leds/beaglebone:green:usr1/brightness"].Contents, "1", ) diff --git a/platforms/beaglebone/beaglebone_pins.go b/platforms/beaglebone/beaglebone_pins.go new file mode 100644 index 00000000..693af349 --- /dev/null +++ b/platforms/beaglebone/beaglebone_pins.go @@ -0,0 +1,101 @@ +package beaglebone + +var pins = map[string]int{ + "P8_3": 38, + "P8_4": 39, + "P8_5": 34, + "P8_6": 35, + "P8_7": 66, + "P8_8": 67, + "P8_9": 69, + "P8_10": 68, + "P8_11": 45, + "P8_12": 44, + "P8_13": 23, + "P8_14": 26, + "P8_15": 47, + "P8_16": 46, + "P8_17": 27, + "P8_18": 65, + "P8_19": 22, + "P8_20": 63, + "P8_21": 62, + "P8_22": 37, + "P8_23": 36, + "P8_24": 33, + "P8_25": 32, + "P8_26": 61, + "P8_27": 86, + "P8_28": 88, + "P8_29": 87, + "P8_30": 89, + "P8_31": 10, + "P8_32": 11, + "P8_33": 9, + "P8_34": 81, + "P8_35": 8, + "P8_36": 80, + "P8_37": 78, + "P8_38": 79, + "P8_39": 76, + "P8_40": 77, + "P8_41": 74, + "P8_42": 75, + "P8_43": 72, + "P8_44": 73, + "P8_45": 70, + "P8_46": 71, + "P9_11": 30, + "P9_12": 60, + "P9_13": 31, + "P9_14": 50, + "P9_15": 48, + "P9_16": 51, + "P9_17": 5, + "P9_18": 4, + "P9_19": 13, + "P9_20": 12, + "P9_21": 3, + "P9_22": 2, + "P9_23": 49, + "P9_24": 15, + "P9_25": 117, + "P9_26": 14, + "P9_27": 115, + "P9_28": 113, + "P9_29": 111, + "P9_30": 112, + "P9_31": 110, +} + +var pwmPins = map[string]string{ + "P9_14": "P9_14", + "P9_21": "P9_21", + "P9_22": "P9_22", + "P9_29": "P9_29", + "P9_42": "P9_42", + "P8_13": "P8_13", + "P8_34": "P8_34", + "P8_45": "P8_45", + "P8_46": "P8_46", +} + +var analogPins3 = map[string]string{ + "P9_39": "AIN0", + "P9_40": "AIN1", + "P9_37": "AIN2", + "P9_38": "AIN3", + "P9_33": "AIN4", + "P9_36": "AIN5", + "P9_35": "AIN6", +} + +var analogPins44 = map[string]string{ + "P9_39": "in_voltage0_raw", + "P9_40": "in_voltage1_raw", + "P9_37": "in_voltage2_raw", + "P9_38": "in_voltage3_raw", + "P9_33": "in_voltage4_raw", + "P9_36": "in_voltage5_raw", + "P9_35": "in_voltage6_raw", +}