From 2e6bd46354a851f46de6efd5b587182c703819d4 Mon Sep 17 00:00:00 2001 From: Gavin Cabbage Date: Sat, 29 Aug 2015 00:42:44 -0400 Subject: [PATCH 01/19] i2c: added ReadBytes to I2CBus --- host/generic/i2cbus.go | 22 ++++++++++++++++++++++ i2c.go | 2 ++ 2 files changed, 24 insertions(+) diff --git a/host/generic/i2cbus.go b/host/generic/i2cbus.go index dc8e74c..45c5870 100644 --- a/host/generic/i2cbus.go +++ b/host/generic/i2cbus.go @@ -101,6 +101,28 @@ func (b *i2cBus) ReadByte(addr byte) (byte, error) { return bytes[0], nil } +func (b *i2cBus) ReadBytes(addr byte, num int) ([]byte, error) { + b.mu.Lock() + defer b.mu.Unlock() + + if err := b.init(); err != nil { + return []byte{0}, err + } + + if err := b.setAddress(addr); err != nil { + return []byte{0}, err + } + + bytes := make([]byte, num) + n, _ := b.file.Read(bytes) + + if n != num { + return []byte{0}, fmt.Errorf("i2c: Unexpected number (%v) of bytes read", n) + } + + return bytes, nil +} + func (b *i2cBus) WriteByte(addr, value byte) error { b.mu.Lock() defer b.mu.Unlock() diff --git a/i2c.go b/i2c.go index 8bdb876..d9922ed 100644 --- a/i2c.go +++ b/i2c.go @@ -4,6 +4,8 @@ package embd // I2CBus interface is used to interact with the I2C bus. type I2CBus interface { + // ReadByte reads a byte from the given address. + ReadBytes(addr byte, num int) (value []byte, err error) // ReadByte reads a byte from the given address. ReadByte(addr byte) (value byte, err error) // WriteByte writes a byte to the given address. From afa49bb2bc5488863b3b97944eb51c602ac6398d Mon Sep 17 00:00:00 2001 From: Gavin Cabbage Date: Sat, 29 Aug 2015 00:53:34 -0400 Subject: [PATCH 02/19] build: fixed broken tests --- controller/hd44780/hd44780_test.go | 1 + i2c.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/controller/hd44780/hd44780_test.go b/controller/hd44780/hd44780_test.go index b05dddc..40b3e2a 100644 --- a/controller/hd44780/hd44780_test.go +++ b/controller/hd44780/hd44780_test.go @@ -131,6 +131,7 @@ type mockI2CBus struct { closed bool } +func (bus *mockI2CBus) ReadBytes(addr byte, num int) ([]byte, error) { return []byte{0x00}, nil } func (bus *mockI2CBus) ReadByte(addr byte) (byte, error) { return 0x00, nil } func (bus *mockI2CBus) WriteBytes(addr byte, value []byte) error { return nil } func (bus *mockI2CBus) ReadFromReg(addr, reg byte, value []byte) error { return nil } diff --git a/i2c.go b/i2c.go index d9922ed..41244ea 100644 --- a/i2c.go +++ b/i2c.go @@ -6,7 +6,7 @@ package embd type I2CBus interface { // ReadByte reads a byte from the given address. ReadBytes(addr byte, num int) (value []byte, err error) - // ReadByte reads a byte from the given address. + // ReadByte reads a slice of bytes from the given address. ReadByte(addr byte) (value byte, err error) // WriteByte writes a byte to the given address. WriteByte(addr, value byte) error From db5c9abb2a12eca86ba44f2d1690a62ffe476d7f Mon Sep 17 00:00:00 2001 From: Gavin Cabbage Date: Sat, 29 Aug 2015 00:57:25 -0400 Subject: [PATCH 03/19] ran gofmt --- controller/hd44780/hd44780_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controller/hd44780/hd44780_test.go b/controller/hd44780/hd44780_test.go index 40b3e2a..eee375d 100644 --- a/controller/hd44780/hd44780_test.go +++ b/controller/hd44780/hd44780_test.go @@ -131,7 +131,7 @@ type mockI2CBus struct { closed bool } -func (bus *mockI2CBus) ReadBytes(addr byte, num int) ([]byte, error) { return []byte{0x00}, nil } +func (bus *mockI2CBus) ReadBytes(addr byte, num int) ([]byte, error) { return []byte{0x00}, nil } func (bus *mockI2CBus) ReadByte(addr byte) (byte, error) { return 0x00, nil } func (bus *mockI2CBus) WriteBytes(addr byte, value []byte) error { return nil } func (bus *mockI2CBus) ReadFromReg(addr, reg byte, value []byte) error { return nil } From 48c26358bdbce029d3e614635bd435d9dbd439c9 Mon Sep 17 00:00:00 2001 From: Gavin Cabbage Date: Sun, 30 Aug 2015 09:48:43 -0400 Subject: [PATCH 04/19] doc: fixed mixed up comments --- i2c.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/i2c.go b/i2c.go index 41244ea..6a5d1ec 100644 --- a/i2c.go +++ b/i2c.go @@ -5,9 +5,9 @@ package embd // I2CBus interface is used to interact with the I2C bus. type I2CBus interface { // ReadByte reads a byte from the given address. - ReadBytes(addr byte, num int) (value []byte, err error) - // ReadByte reads a slice of bytes from the given address. ReadByte(addr byte) (value byte, err error) + // ReadBytes reads a slice of bytes from the given address. + ReadBytes(addr byte, num int) (value []byte, err error) // WriteByte writes a byte to the given address. WriteByte(addr, value byte) error // WriteBytes writes a slice bytes to the given address. From 9d8285ca0169f361264fd951cb137227b06989d9 Mon Sep 17 00:00:00 2001 From: Gavin Cabbage Date: Sat, 10 Oct 2015 23:23:40 -0400 Subject: [PATCH 05/19] changed ReadBytes to get file size from stat --- controller/hd44780/hd44780_test.go | 2 +- host/generic/i2cbus.go | 12 +++++++++--- i2c.go | 2 ++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/controller/hd44780/hd44780_test.go b/controller/hd44780/hd44780_test.go index eee375d..9542bf7 100644 --- a/controller/hd44780/hd44780_test.go +++ b/controller/hd44780/hd44780_test.go @@ -131,7 +131,7 @@ type mockI2CBus struct { closed bool } -func (bus *mockI2CBus) ReadBytes(addr byte, num int) ([]byte, error) { return []byte{0x00}, nil } +func (bus *mockI2CBus) ReadBytes(addr byte) ([]byte, error) { return []byte{0x00}, nil } func (bus *mockI2CBus) ReadByte(addr byte) (byte, error) { return 0x00, nil } func (bus *mockI2CBus) WriteBytes(addr byte, value []byte) error { return nil } func (bus *mockI2CBus) ReadFromReg(addr, reg byte, value []byte) error { return nil } diff --git a/host/generic/i2cbus.go b/host/generic/i2cbus.go index 45c5870..63b6eb1 100644 --- a/host/generic/i2cbus.go +++ b/host/generic/i2cbus.go @@ -101,7 +101,7 @@ func (b *i2cBus) ReadByte(addr byte) (byte, error) { return bytes[0], nil } -func (b *i2cBus) ReadBytes(addr byte, num int) ([]byte, error) { +func (b *i2cBus) ReadBytes(addr byte) ([]byte, error) { b.mu.Lock() defer b.mu.Unlock() @@ -113,10 +113,16 @@ func (b *i2cBus) ReadBytes(addr byte, num int) ([]byte, error) { return []byte{0}, err } - bytes := make([]byte, num) + info, err := b.file.Stat() + if err != nil { + return []byte{0}, err + } + + size := int(info.Size()) + bytes := make([]byte, size) n, _ := b.file.Read(bytes) - if n != num { + if n != size { return []byte{0}, fmt.Errorf("i2c: Unexpected number (%v) of bytes read", n) } diff --git a/i2c.go b/i2c.go index 6a5d1ec..f0c79da 100644 --- a/i2c.go +++ b/i2c.go @@ -4,6 +4,8 @@ package embd // I2CBus interface is used to interact with the I2C bus. type I2CBus interface { + // ReadBytes reads a slice of bytes from the given address. + ReadBytes(addr byte) (value []byte, err error) // ReadByte reads a byte from the given address. ReadByte(addr byte) (value byte, err error) // ReadBytes reads a slice of bytes from the given address. From b296368a0557615cbc3ba19bd21965d364d44dba Mon Sep 17 00:00:00 2001 From: Gavin Cabbage Date: Sat, 10 Oct 2015 23:58:24 -0400 Subject: [PATCH 06/19] removing failed Stat use --- controller/hd44780/hd44780_test.go | 2 +- host/generic/i2cbus.go | 12 +++--------- i2c.go | 2 -- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/controller/hd44780/hd44780_test.go b/controller/hd44780/hd44780_test.go index 9542bf7..eee375d 100644 --- a/controller/hd44780/hd44780_test.go +++ b/controller/hd44780/hd44780_test.go @@ -131,7 +131,7 @@ type mockI2CBus struct { closed bool } -func (bus *mockI2CBus) ReadBytes(addr byte) ([]byte, error) { return []byte{0x00}, nil } +func (bus *mockI2CBus) ReadBytes(addr byte, num int) ([]byte, error) { return []byte{0x00}, nil } func (bus *mockI2CBus) ReadByte(addr byte) (byte, error) { return 0x00, nil } func (bus *mockI2CBus) WriteBytes(addr byte, value []byte) error { return nil } func (bus *mockI2CBus) ReadFromReg(addr, reg byte, value []byte) error { return nil } diff --git a/host/generic/i2cbus.go b/host/generic/i2cbus.go index 63b6eb1..45c5870 100644 --- a/host/generic/i2cbus.go +++ b/host/generic/i2cbus.go @@ -101,7 +101,7 @@ func (b *i2cBus) ReadByte(addr byte) (byte, error) { return bytes[0], nil } -func (b *i2cBus) ReadBytes(addr byte) ([]byte, error) { +func (b *i2cBus) ReadBytes(addr byte, num int) ([]byte, error) { b.mu.Lock() defer b.mu.Unlock() @@ -113,16 +113,10 @@ func (b *i2cBus) ReadBytes(addr byte) ([]byte, error) { return []byte{0}, err } - info, err := b.file.Stat() - if err != nil { - return []byte{0}, err - } - - size := int(info.Size()) - bytes := make([]byte, size) + bytes := make([]byte, num) n, _ := b.file.Read(bytes) - if n != size { + if n != num { return []byte{0}, fmt.Errorf("i2c: Unexpected number (%v) of bytes read", n) } diff --git a/i2c.go b/i2c.go index f0c79da..6a5d1ec 100644 --- a/i2c.go +++ b/i2c.go @@ -4,8 +4,6 @@ package embd // I2CBus interface is used to interact with the I2C bus. type I2CBus interface { - // ReadBytes reads a slice of bytes from the given address. - ReadBytes(addr byte) (value []byte, err error) // ReadByte reads a byte from the given address. ReadByte(addr byte) (value byte, err error) // ReadBytes reads a slice of bytes from the given address. From c1886eb5bf22bf655793ce7c50491175de95923f Mon Sep 17 00:00:00 2001 From: ssk Date: Tue, 3 Nov 2015 19:24:27 +0530 Subject: [PATCH 07/19] Fixed SPIController issue with missing fields --- host/generic/spibus.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/host/generic/spibus.go b/host/generic/spibus.go index f682daa..e2f7513 100644 --- a/host/generic/spibus.go +++ b/host/generic/spibus.go @@ -36,6 +36,8 @@ type spiIOCTransfer struct { speedHz uint32 delayus uint16 bitsPerWord uint8 + csChange uint8 + pad uint32 } type spiBus struct { From 1b48067d77c31a74d6ce2d5b1f9734a03487f9ec Mon Sep 17 00:00:00 2001 From: Wu Jiang Date: Tue, 22 Dec 2015 17:05:28 -0500 Subject: [PATCH 08/19] Println doesn't accept formatting. It looks like this is caused by confusion between `fmt.Println` and `fmt.Printf`. --- samples/spi.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/samples/spi.go b/samples/spi.go index 298acc4..20d606c 100644 --- a/samples/spi.go +++ b/samples/spi.go @@ -24,25 +24,25 @@ func main() { panic(err) } - fmt.Println("received data is: %v", dataBuf) + fmt.Println("received data is:", dataBuf) dataReceived, err := spiBus.ReceiveData(3) if err != nil { panic(err) } - fmt.Println("received data is: %v", dataReceived) + fmt.Println("received data is:", dataReceived) dataByte := byte(1) receivedByte, err := spiBus.TransferAndReceiveByte(dataByte) if err != nil { panic(err) } - fmt.Println("received byte is: %v", receivedByte) + fmt.Println("received byte is:", receivedByte) receivedByte, err = spiBus.ReceiveByte() if err != nil { panic(err) } - fmt.Println("received byte is: %v", receivedByte) + fmt.Println("received byte is:", receivedByte) } From 60218147312c0f5550bfca018a579639cae41b51 Mon Sep 17 00:00:00 2001 From: gotang Date: Sat, 20 Aug 2016 14:10:49 +0800 Subject: [PATCH 09/19] fix fatal error: concurrent map read and map write --- host/generic/interrupt.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/host/generic/interrupt.go b/host/generic/interrupt.go index 4052283..7f9b766 100644 --- a/host/generic/interrupt.go +++ b/host/generic/interrupt.go @@ -61,11 +61,13 @@ func initEpollListener() *epollListener { if err != nil { panic(fmt.Sprintf("EpollWait error: %v", err)) } + listener.mu.Lock() for i := 0; i < n; i++ { if irq, ok := listener.interruptablePins[int(epollEvents[i].Fd)]; ok { irq.Signal() } } + listener.mu.Unlock() } }() return listener From d9dd4b51a95dc57aa8b740b402806de957706b13 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Fri, 26 Aug 2016 23:00:39 -0700 Subject: [PATCH 10/19] add minimal support for NextThing CHIP --- detect.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/detect.go b/detect.go index a92ff4e..93f4500 100644 --- a/detect.go +++ b/detect.go @@ -31,6 +31,9 @@ const ( // HostRadxa represents the Radxa board. HostRadxa = "Radxa" + + // HostCHIP represents the NextThing C.H.I.P. + HostCHIP = "CHIP" ) func execOutput(name string, arg ...string) (output string, err error) { @@ -92,7 +95,7 @@ func cpuInfo() (model, hardware string, revision int, err error) { } revision = int(rev) case strings.HasPrefix(fields[0], "Hardware"): - hardware = fields[1] + hardware = strings.TrimSpace(fields[1]) case strings.HasPrefix(fields[0], "model name"): model = fields[1] } @@ -108,7 +111,9 @@ func DetectHost() (host Host, rev int, err error) { } if major < 3 || (major == 3 && minor < 8) { - return HostNull, 0, fmt.Errorf("embd: linux kernel versions lower than 3.8 are not supported. you have %v.%v.%v", major, minor, patch) + return HostNull, 0, fmt.Errorf( + "embd: linux kernel versions lower than 3.8 are not supported, "+ + "you have %v.%v.%v", major, minor, patch) } model, hardware, rev, err := cpuInfo() @@ -121,6 +126,13 @@ func DetectHost() (host Host, rev int, err error) { return HostBBB, rev, nil case strings.Contains(hardware, "BCM2708") || strings.Contains(hardware, "BCM2709"): return HostRPi, rev, nil + case hardware == "Allwinner sun4i/sun5i Families": + if major < 4 || (major == 4 && minor < 4) { + return HostNull, 0, fmt.Errorf( + "embd: linux kernel version 4.4+ required, you have %v.%v", + major, minor) + } + return HostCHIP, rev, nil default: return HostNull, 0, fmt.Errorf(`embd: your host "%v:%v" is not supported at this moment. request support at https://github.com/kidoman/embd/issues`, host, model) } From 938a071c1ad1f5a4eb5a0cfa06cf8ab3831aecac Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Fri, 26 Aug 2016 23:02:11 -0700 Subject: [PATCH 11/19] add minimal support for NextThing CHIP, part 2 --- host/chip/chip.go | 68 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 host/chip/chip.go diff --git a/host/chip/chip.go b/host/chip/chip.go new file mode 100644 index 0000000..e7b541a --- /dev/null +++ b/host/chip/chip.go @@ -0,0 +1,68 @@ +// Copyright 2016 by Thorsten von Eicken + +// Package chip provides NextThing C.H.I.P. support. +// References: +// http://docs.getchip.com/chip.html#chip-hardware +// http://www.chip-community.org/index.php/Hardware_Information +// +// The following features are supported on Linux kernel 4.4+ +// GPIO (digital (rw)) +// I²C +// SPI +// Could add LED support by following https://bbs.nextthing.co/t/pwr-and-stat-leds/748/5 + +package chip + +import ( + "github.com/kidoman/embd" + "github.com/kidoman/embd/host/generic" +) + +var spiDeviceMinor = byte(0) + +var chipPins = embd.PinMap{ + &embd.PinDesc{"XIO-P0", []string{"1016", "0", "gpio0"}, embd.CapDigital, 1016, 0}, + &embd.PinDesc{"XIO-P6", []string{"1022", "6", "gpio6"}, embd.CapDigital, 1022, 0}, + /* + &embd.PinDesc{ID: "P1_3", Aliases: []string{"0", "GPIO_0", "SDA", "I2C0_SDA"}, Caps: embd.CapDigital | embd.CapI2C, DigitalLogical: 0}, + &embd.PinDesc{ID: "P1_5", Aliases: []string{"1", "GPIO_1", "SCL", "I2C0_SCL"}, Caps: embd.CapDigital | embd.CapI2C, DigitalLogical: 1}, + &embd.PinDesc{ID: "P1_7", Aliases: []string{"4", "GPIO_4", "GPCLK0"}, Caps: embd.CapDigital, DigitalLogical: 4}, + &embd.PinDesc{ID: "P1_8", Aliases: []string{"14", "GPIO_14", "TXD", "UART0_TXD"}, Caps: embd.CapDigital | embd.CapUART, DigitalLogical: 14}, + &embd.PinDesc{ID: "P1_10", Aliases: []string{"15", "GPIO_15", "RXD", "UART0_RXD"}, Caps: embd.CapDigital | embd.CapUART, DigitalLogical: 15}, + &embd.PinDesc{ID: "P1_11", Aliases: []string{"17", "GPIO_17"}, Caps: embd.CapDigital, DigitalLogical: 17}, + &embd.PinDesc{ID: "P1_12", Aliases: []string{"18", "GPIO_18", "PCM_CLK"}, Caps: embd.CapDigital, DigitalLogical: 18}, + &embd.PinDesc{ID: "P1_13", Aliases: []string{"21", "GPIO_21"}, Caps: embd.CapDigital, DigitalLogical: 21}, + &embd.PinDesc{ID: "P1_15", Aliases: []string{"22", "GPIO_22"}, Caps: embd.CapDigital, DigitalLogical: 22}, + &embd.PinDesc{ID: "P1_16", Aliases: []string{"23", "GPIO_23"}, Caps: embd.CapDigital, DigitalLogical: 23}, + &embd.PinDesc{ID: "P1_18", Aliases: []string{"24", "GPIO_24"}, Caps: embd.CapDigital, DigitalLogical: 24}, + &embd.PinDesc{ID: "P1_19", Aliases: []string{"10", "GPIO_10", "MOSI", "SPI0_MOSI"}, Caps: embd.CapDigital | embd.CapSPI, DigitalLogical: 10}, + &embd.PinDesc{ID: "P1_21", Aliases: []string{"9", "GPIO_9", "MISO", "SPI0_MISO"}, Caps: embd.CapDigital | embd.CapSPI, DigitalLogical: 9}, + &embd.PinDesc{ID: "P1_22", Aliases: []string{"25", "GPIO_25"}, Caps: embd.CapDigital, DigitalLogical: 25}, + &embd.PinDesc{ID: "P1_23", Aliases: []string{"11", "GPIO_11", "SCLK", "SPI0_SCLK"}, Caps: embd.CapDigital | embd.CapSPI, DigitalLogical: 11}, + &embd.PinDesc{ID: "P1_24", Aliases: []string{"8", "GPIO_8", "CE0", "SPI0_CE0_N"}, Caps: embd.CapDigital | embd.CapSPI, DigitalLogical: 8}, + &embd.PinDesc{ID: "P1_26", Aliases: []string{"7", "GPIO_7", "CE1", "SPI0_CE1_N"}, Caps: embd.CapDigital | embd.CapSPI, DigitalLogical: 7}, + */ +} + +var ledMap = embd.LEDMap{ + "led0": []string{"0", "led0", "LED0"}, +} + +func init() { + embd.Register(embd.HostCHIP, func(rev int) *embd.Descriptor { + return &embd.Descriptor{ + GPIODriver: func() embd.GPIODriver { + return embd.NewGPIODriver(chipPins, generic.NewDigitalPin, nil, nil) + }, + I2CDriver: func() embd.I2CDriver { + return embd.NewI2CDriver(generic.NewI2CBus) + }, + LEDDriver: func() embd.LEDDriver { + return embd.NewLEDDriver(ledMap, generic.NewLED) + }, + SPIDriver: func() embd.SPIDriver { + return embd.NewSPIDriver(spiDeviceMinor, generic.NewSPIBus, nil) + }, + } + }) +} From 091d6f558821db718702f1dd9636637d2c429d6f Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Fri, 26 Aug 2016 23:02:41 -0700 Subject: [PATCH 12/19] gpio: don't fail if pin is already exported --- host/generic/digitalpin.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/host/generic/digitalpin.go b/host/generic/digitalpin.go index 80a81ea..525eeb4 100644 --- a/host/generic/digitalpin.go +++ b/host/generic/digitalpin.go @@ -10,6 +10,7 @@ import ( "os" "path" "strconv" + "syscall" "time" "github.com/kidoman/embd" @@ -69,6 +70,9 @@ func (p *digitalPin) export() error { } defer exporter.Close() _, err = exporter.WriteString(strconv.Itoa(p.n)) + if e, ok := err.(*os.PathError); ok && e.Err == syscall.EBUSY { + return nil // EBUSY -> the pin has already been exported + } return err } From e16818f0aac35d121688fdd049ad19cc5eeaa85b Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Sat, 27 Aug 2016 00:35:14 -0700 Subject: [PATCH 13/19] add support for NextThing CHIP, part 3 --- host/chip/chip.go | 85 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 58 insertions(+), 27 deletions(-) diff --git a/host/chip/chip.go b/host/chip/chip.go index e7b541a..c6bf7cc 100644 --- a/host/chip/chip.go +++ b/host/chip/chip.go @@ -21,31 +21,62 @@ import ( var spiDeviceMinor = byte(0) var chipPins = embd.PinMap{ - &embd.PinDesc{"XIO-P0", []string{"1016", "0", "gpio0"}, embd.CapDigital, 1016, 0}, - &embd.PinDesc{"XIO-P6", []string{"1022", "6", "gpio6"}, embd.CapDigital, 1022, 0}, - /* - &embd.PinDesc{ID: "P1_3", Aliases: []string{"0", "GPIO_0", "SDA", "I2C0_SDA"}, Caps: embd.CapDigital | embd.CapI2C, DigitalLogical: 0}, - &embd.PinDesc{ID: "P1_5", Aliases: []string{"1", "GPIO_1", "SCL", "I2C0_SCL"}, Caps: embd.CapDigital | embd.CapI2C, DigitalLogical: 1}, - &embd.PinDesc{ID: "P1_7", Aliases: []string{"4", "GPIO_4", "GPCLK0"}, Caps: embd.CapDigital, DigitalLogical: 4}, - &embd.PinDesc{ID: "P1_8", Aliases: []string{"14", "GPIO_14", "TXD", "UART0_TXD"}, Caps: embd.CapDigital | embd.CapUART, DigitalLogical: 14}, - &embd.PinDesc{ID: "P1_10", Aliases: []string{"15", "GPIO_15", "RXD", "UART0_RXD"}, Caps: embd.CapDigital | embd.CapUART, DigitalLogical: 15}, - &embd.PinDesc{ID: "P1_11", Aliases: []string{"17", "GPIO_17"}, Caps: embd.CapDigital, DigitalLogical: 17}, - &embd.PinDesc{ID: "P1_12", Aliases: []string{"18", "GPIO_18", "PCM_CLK"}, Caps: embd.CapDigital, DigitalLogical: 18}, - &embd.PinDesc{ID: "P1_13", Aliases: []string{"21", "GPIO_21"}, Caps: embd.CapDigital, DigitalLogical: 21}, - &embd.PinDesc{ID: "P1_15", Aliases: []string{"22", "GPIO_22"}, Caps: embd.CapDigital, DigitalLogical: 22}, - &embd.PinDesc{ID: "P1_16", Aliases: []string{"23", "GPIO_23"}, Caps: embd.CapDigital, DigitalLogical: 23}, - &embd.PinDesc{ID: "P1_18", Aliases: []string{"24", "GPIO_24"}, Caps: embd.CapDigital, DigitalLogical: 24}, - &embd.PinDesc{ID: "P1_19", Aliases: []string{"10", "GPIO_10", "MOSI", "SPI0_MOSI"}, Caps: embd.CapDigital | embd.CapSPI, DigitalLogical: 10}, - &embd.PinDesc{ID: "P1_21", Aliases: []string{"9", "GPIO_9", "MISO", "SPI0_MISO"}, Caps: embd.CapDigital | embd.CapSPI, DigitalLogical: 9}, - &embd.PinDesc{ID: "P1_22", Aliases: []string{"25", "GPIO_25"}, Caps: embd.CapDigital, DigitalLogical: 25}, - &embd.PinDesc{ID: "P1_23", Aliases: []string{"11", "GPIO_11", "SCLK", "SPI0_SCLK"}, Caps: embd.CapDigital | embd.CapSPI, DigitalLogical: 11}, - &embd.PinDesc{ID: "P1_24", Aliases: []string{"8", "GPIO_8", "CE0", "SPI0_CE0_N"}, Caps: embd.CapDigital | embd.CapSPI, DigitalLogical: 8}, - &embd.PinDesc{ID: "P1_26", Aliases: []string{"7", "GPIO_7", "CE1", "SPI0_CE1_N"}, Caps: embd.CapDigital | embd.CapSPI, DigitalLogical: 7}, - */ -} + // official GPIO pins (U14 connector) using the pcf8574a + &embd.PinDesc{"XIO-P0", []string{"1016", "0", "U14-13", "gpio0"}, embd.CapDigital, 1016, 0}, + &embd.PinDesc{"XIO-P1", []string{"1017", "1", "U14-14", "gpio1"}, embd.CapDigital, 1017, 0}, + &embd.PinDesc{"XIO-P2", []string{"1018", "2", "U14-15", "gpio2"}, embd.CapDigital, 1018, 0}, + &embd.PinDesc{"XIO-P3", []string{"1019", "3", "U14-16", "gpio3"}, embd.CapDigital, 1019, 0}, + &embd.PinDesc{"XIO-P4", []string{"1020", "4", "U14-17", "gpio4"}, embd.CapDigital, 1020, 0}, + &embd.PinDesc{"XIO-P5", []string{"1021", "5", "U14-18", "gpio5"}, embd.CapDigital, 1021, 0}, + &embd.PinDesc{"XIO-P6", []string{"1022", "6", "U14-19", "gpio6"}, embd.CapDigital, 1022, 0}, + &embd.PinDesc{"XIO-P7", []string{"1023", "7", "U14-20", "gpio7"}, embd.CapDigital, 1023, 0}, -var ledMap = embd.LEDMap{ - "led0": []string{"0", "led0", "LED0"}, + // pins usable on the U13 connector + &embd.PinDesc{"TWI1-SDA", []string{"48", "U13-9", "I2C0_SDA"}, embd.CapDigital | embd.CapI2C, 48, 0}, + &embd.PinDesc{"TWI1-SCK", []string{"47", "U13-11", "I2C0_SCK"}, embd.CapDigital | embd.CapI2C, 47, 0}, + &embd.PinDesc{"PWM0", []string{"34", "U13-18"}, embd.CapDigital | embd.CapPWM, 34, 0}, + &embd.PinDesc{"LCD-D2", []string{"98", "U13-17"}, embd.CapDigital, 98, 0}, + &embd.PinDesc{"LCD-D3", []string{"99", "U13-20"}, embd.CapDigital, 99, 0}, + &embd.PinDesc{"LCD-D4", []string{"100", "U13-19"}, embd.CapDigital, 100, 0}, + &embd.PinDesc{"LCD-D5", []string{"101", "U13-22"}, embd.CapDigital, 101, 0}, + &embd.PinDesc{"LCD-D6", []string{"102", "U13-21"}, embd.CapDigital, 102, 0}, + &embd.PinDesc{"LCD-D7", []string{"103", "U13-24"}, embd.CapDigital, 103, 0}, + &embd.PinDesc{"LCD-D10", []string{"106", "U13-23"}, embd.CapDigital, 106, 0}, + &embd.PinDesc{"LCD-D11", []string{"107", "U13-26"}, embd.CapDigital, 107, 0}, + &embd.PinDesc{"LCD-D12", []string{"108", "U13-25"}, embd.CapDigital, 108, 0}, + &embd.PinDesc{"LCD-D13", []string{"109", "U13-28"}, embd.CapDigital, 109, 0}, + &embd.PinDesc{"LCD-D14", []string{"110", "U13-27"}, embd.CapDigital, 110, 0}, + &embd.PinDesc{"LCD-D15", []string{"111", "U13-30"}, embd.CapDigital, 111, 0}, + &embd.PinDesc{"LCD-D18", []string{"114", "U13-29"}, embd.CapDigital, 114, 0}, + &embd.PinDesc{"LCD-D19", []string{"115", "U13-32"}, embd.CapDigital, 115, 0}, + &embd.PinDesc{"LCD-D20", []string{"116", "U13-31"}, embd.CapDigital, 116, 0}, + &embd.PinDesc{"LCD-D21", []string{"117", "U13-34"}, embd.CapDigital, 117, 0}, + &embd.PinDesc{"LCD-D22", []string{"118", "U13-33"}, embd.CapDigital, 118, 0}, + &embd.PinDesc{"LCD-D23", []string{"119", "U13-36"}, embd.CapDigital, 119, 0}, + &embd.PinDesc{"LCD-CLK", []string{"120", "U13-35"}, embd.CapDigital, 120, 0}, + &embd.PinDesc{"LCD-VSYNC", []string{"123", "U13-37"}, embd.CapDigital, 123, 0}, + &embd.PinDesc{"LCD-HSYNC", []string{"122", "U13-38"}, embd.CapDigital, 122, 0}, + &embd.PinDesc{"LCD-DE", []string{"121", "U13-40"}, embd.CapDigital, 121, 0}, + + // pins usable on the U14 connector + &embd.PinDesc{"UART1-TX", []string{"195", "U14-3", "EINT3"}, embd.CapDigital | embd.CapUART, 195, 0}, + &embd.PinDesc{"UART1-RX", []string{"196", "U14-5", "EINT4"}, embd.CapDigital | embd.CapUART, 196, 0}, + &embd.PinDesc{"AP-EINT1", []string{"193", "U14-23", "EINT1"}, embd.CapDigital, 193, 0}, + &embd.PinDesc{"AP-EINT3", []string{"35", "U14-24", "EINT3"}, embd.CapDigital, 35, 0}, + &embd.PinDesc{"TWI2-SDA", []string{"50", "U14-25", "I2C2_SDA"}, embd.CapDigital | embd.CapI2C, 50, 0}, + &embd.PinDesc{"TWI2-SCK", []string{"49", "U14-26", "I2C2_SCK"}, embd.CapDigital | embd.CapI2C, 49, 0}, + &embd.PinDesc{"CSIPCK", []string{"128", "U14-27", "SPI2_SCO", "SPI2_CS0"}, embd.CapDigital | embd.CapSPI, 128, 0}, + &embd.PinDesc{"CSICK", []string{"129", "U14-28", "SPI2_CLK"}, embd.CapDigital | embd.CapSPI, 129, 0}, + &embd.PinDesc{"CSIHSYNC", []string{"130", "U14-29", "SPI2_MOSI"}, embd.CapDigital | embd.CapSPI, 130, 0}, + &embd.PinDesc{"CSIVSYNC", []string{"131", "U14-30", "SPI2_MISO"}, embd.CapDigital | embd.CapSPI, 131, 0}, + &embd.PinDesc{"CSID0", []string{"132", "U14-31"}, embd.CapDigital, 132, 0}, + &embd.PinDesc{"CSID1", []string{"133", "U14-32"}, embd.CapDigital, 133, 0}, + &embd.PinDesc{"CSID2", []string{"134", "U14-33"}, embd.CapDigital, 134, 0}, + &embd.PinDesc{"CSID3", []string{"135", "U14-34"}, embd.CapDigital, 135, 0}, + &embd.PinDesc{"CSID4", []string{"136", "U14-35"}, embd.CapDigital, 136, 0}, + &embd.PinDesc{"CSID5", []string{"137", "U14-36"}, embd.CapDigital, 137, 0}, + &embd.PinDesc{"CSID6", []string{"138", "U14-37", "UART1_TX"}, embd.CapDigital | embd.CapUART, 138, 0}, + &embd.PinDesc{"CSID7", []string{"139", "U14-38", "UART1_RX"}, embd.CapDigital | embd.CapUART, 139, 0}, } func init() { @@ -57,9 +88,9 @@ func init() { I2CDriver: func() embd.I2CDriver { return embd.NewI2CDriver(generic.NewI2CBus) }, - LEDDriver: func() embd.LEDDriver { - return embd.NewLEDDriver(ledMap, generic.NewLED) - }, + //LEDDriver: func() embd.LEDDriver { + // return embd.NewLEDDriver(ledMap, generic.NewLED) + //}, SPIDriver: func() embd.SPIDriver { return embd.NewSPIDriver(spiDeviceMinor, generic.NewSPIBus, nil) }, From 56cb934dbfbea57124e395deebcb3b0f5aadd84b Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Mon, 5 Sep 2016 23:11:12 -0700 Subject: [PATCH 14/19] Update README for CHIP support by TvE --- README.md | 64 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index f37b5b5..94a954a 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,22 @@ -# embd [![Build Status](https://travis-ci.org/kidoman/embd.svg?branch=master)](https://travis-ci.org/kidoman/embd) [![GoDoc](http://godoc.org/github.com/kidoman/embd?status.png)](http://godoc.org/github.com/kidoman/embd) +# embd [![Build Status](https://travis-ci.org/tve/embd.svg?branch=master)](https://travis-ci.org/tve/embd) [![GoDoc](http://godoc.org/github.com/tve/embd?status.png)](http://godoc.org/github.com/tve/embd) **embd** is a hardware abstraction layer (HAL) for embedded systems. -It allows you to start your hardware hack on easily available hobby boards (like the Raspberry Pi, BeagleBone Black, etc.) by giving you staight forward access to the board's capabilities as well as a plethora of **sensors** (like accelerometers, gyroscopes, thermometers, etc.) and **controllers** (PWM generators, digital-to-analog convertors) for which we have written drivers. And when things get serious, you dont have to throw away the code. You carry forward the effort onto more custom designed boards where the HAL abstraction of EMBD will save you precious time. +**The github.com/tve/embd fork** attempts to continue the work started by +@kidoman and adds support for NextThing's C.H.I.P. -Development supported and sponsored by [**SoStronk**](https://www.sostronk.com) and [**ThoughtWorks**](http://www.thoughtworks.com/) +It allows you to start your hardware hack on easily available hobby boards +(like the Raspberry Pi, BeagleBone Black, C.H.I.P., etc.) by giving you staight +forward access to the board's capabilities as well as a plethora of +**sensors** (like accelerometers, gyroscopes, thermometers, etc.) and +**controllers** (PWM generators, digital-to-analog convertors) for +which we have written drivers. And when things get serious, you dont +have to throw away the code. You carry forward the effort onto more +custom designed boards where the HAL abstraction of EMBD will save you +precious time. + +Original development supported and sponsored by [**SoStronk**](https://www.sostronk.com) and +[**ThoughtWorks**](http://www.thoughtworks.com/). Also, you might be interested in: [Why Golang?](https://github.com/kidoman/embd/wiki/Why-Go) @@ -12,7 +24,8 @@ Also, you might be interested in: [Why Golang?](https://github.com/kidoman/embd/ ## Getting Started -After installing Go* and setting up your [GOPATH](http://golang.org/doc/code.html#GOPATH), create your first .go file. We'll call it ```simpleblinker.go```. +After installing Go* and setting up your [GOPATH](http://golang.org/doc/code.html#GOPATH), +create your first .go file. We'll call it ```simpleblinker.go```. ```go package main @@ -32,9 +45,9 @@ func main() { } ``` -Then install the EMBD package (go1.2 and greater is required): +Then install the EMBD package (go1.6 or greater is required): - $ go get github.com/kidoman/embd + $ go get github.com/tve/embd Build the binary*: @@ -54,11 +67,11 @@ Then run the program with ```sudo```*: *** Notes** -* Please install the cross compilers. Mac users: ```brew install go --cross-compile-common```. [goxc](https://github.com/laher/goxc) can be a big help as well * We are instructing the ```go``` compiler to create a binary which will run on the RaspberryPi processor * Assuming your RaspberryPi has an IP address of ```192.168.2.2```. Substitute as necessary * ```sudo``` (root) permission is required as we are controlling the hardware by writing to special files -* This sample program is optimized for brevity and does not clean up after itself. Click here to see the [full version](https://github.com/kidoman/embd/blob/master/samples/fullblinker.go) +* This sample program is optimized for brevity and does not clean up after itself. Click here to + see the [full version](https://github.com/kidoman/embd/blob/master/samples/fullblinker.go) ## Getting Help @@ -68,6 +81,7 @@ Join the [mailing list](https://groups.google.com/forum/#!forum/go-embd) * [RaspberryPi](http://www.raspberrypi.org/) (including [A+](http://www.raspberrypi.org/products/model-a-plus/) and [B+](http://www.raspberrypi.org/products/model-b-plus/)) * [RaspberryPi 2](http://www.raspberrypi.org/) +* [NextThing C.H.I.P](https://www.nextthing.co/pages/chip) * [BeagleBone Black](http://beagleboard.org/Products/BeagleBone%20Black) * [Intel Edison](http://www.intel.com/content/www/us/en/do-it-yourself/galileo-maker-quark-board.html) **coming soon** * [Radxa](http://radxa.com/) **coming soon** @@ -202,6 +216,40 @@ heading, err := mag.Heading() The above two examples depend on **I2C** and therefore will work without change on almost all platforms. +## Using embd on CHIP + +The CHIP drivers support gpio, I2C, SPI, and pin interrupts. Not supported are PWM or LED. +The names of the pins on chip have multiple aliases. The official CHIP pin names are supported, +for example XIO-P1 or LCD-D2 and the pin number are also supported, such as U14-14 (same as XIO-P1) +or U13-17. Some of the alternate function names are also supported, like "SPI2_MOSI", and the +linux 4.4 kernel gpio pin numbers as well, e.g., 1017 for XIO-P1. Finally, the official GPIO pins +(XIO-P0 thru XIO-P7) can be addressed as gpio0-gpio7. + +A simple demo to blink an LED connected with a small resistor between XIO-P6 and 3.3V is + +``` +package main +import ( + "time" + "github.com/kidoman/embd" + _ "github.com/kidoman/embd/host/chip" +) + +func main() { + embd.InitGPIO() + defer embd.CloseGPIO() + + embd.SetDirection("gpio6", embd.Out) + on := 0 + for { + embd.DigitalWrite("gpio6", on) + on = 1 - on + time.Sleep(250 * time.Millisecond) + } +} +``` +Run it as root: `sudo ./blinky` + ## Protocols Supported * **Digital GPIO** [Documentation](http://godoc.org/github.com/kidoman/embd#DigitalPin) From 6cfa481f30ea3425d5480d4e0d016b75d908d0b4 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Mon, 5 Sep 2016 23:13:14 -0700 Subject: [PATCH 15/19] Support SPI minor devices >255 (PR #33) --- host/bbb/bbb.go | 2 +- host/chip/chip.go | 2 +- host/generic/i2cbus.go | 2 +- host/generic/spibus.go | 4 ++-- host/rpi/rpi.go | 2 +- spidriver.go | 6 +++--- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/host/bbb/bbb.go b/host/bbb/bbb.go index f909627..1f42d7d 100644 --- a/host/bbb/bbb.go +++ b/host/bbb/bbb.go @@ -95,7 +95,7 @@ var ledMap = embd.LEDMap{ "beaglebone:green:usr3": []string{"3", "USR3", "usr3"}, } -var spiDeviceMinor byte = 1 +var spiDeviceMinor int = 1 func ensureFeatureEnabled(id string) error { glog.V(3).Infof("bbb: enabling feature %v", id) diff --git a/host/chip/chip.go b/host/chip/chip.go index c6bf7cc..277b72f 100644 --- a/host/chip/chip.go +++ b/host/chip/chip.go @@ -18,7 +18,7 @@ import ( "github.com/kidoman/embd/host/generic" ) -var spiDeviceMinor = byte(0) +var spiDeviceMinor = 32766 var chipPins = embd.PinMap{ // official GPIO pins (U14 connector) using the pcf8574a diff --git a/host/generic/i2cbus.go b/host/generic/i2cbus.go index 45c5870..fbe6f55 100644 --- a/host/generic/i2cbus.go +++ b/host/generic/i2cbus.go @@ -245,7 +245,7 @@ func (b *i2cBus) WriteToReg(addr, reg byte, value []byte) error { message.addr = uint16(addr) message.flags = 0 message.len = uint16(len(outbuf)) - message.buf = uintptr(unsafe.Pointer(&hdrp.Data)) + message.buf = uintptr(unsafe.Pointer(hdrp.Data)) var packets i2c_rdwr_ioctl_data diff --git a/host/generic/spibus.go b/host/generic/spibus.go index ef29c02..a33576f 100644 --- a/host/generic/spibus.go +++ b/host/generic/spibus.go @@ -43,7 +43,7 @@ type spiIOCTransfer struct { type spiBus struct { file *os.File - spiDevMinor byte + spiDevMinor int channel byte mode byte @@ -63,7 +63,7 @@ func spiIOCMessageN(n uint32) uint32 { return (spiIOCMessage0 + (n * spiIOCIncrementor)) } -func NewSPIBus(spiDevMinor, mode, channel byte, speed, bpw, delay int, i func() error) embd.SPIBus { +func NewSPIBus(spiDevMinor int, mode, channel byte, speed, bpw, delay int, i func() error) embd.SPIBus { return &spiBus{ spiDevMinor: spiDevMinor, mode: mode, diff --git a/host/rpi/rpi.go b/host/rpi/rpi.go index 0a82a4b..9279ca8 100644 --- a/host/rpi/rpi.go +++ b/host/rpi/rpi.go @@ -13,7 +13,7 @@ import ( "github.com/kidoman/embd/host/generic" ) -var spiDeviceMinor = byte(0) +var spiDeviceMinor = 0 var rev1Pins = embd.PinMap{ &embd.PinDesc{ID: "P1_3", Aliases: []string{"0", "GPIO_0", "SDA", "I2C0_SDA"}, Caps: embd.CapDigital | embd.CapI2C, DigitalLogical: 0}, diff --git a/spidriver.go b/spidriver.go index cecc19d..a145155 100644 --- a/spidriver.go +++ b/spidriver.go @@ -2,10 +2,10 @@ package embd import "sync" -type spiBusFactory func(byte, byte, byte, int, int, int, func() error) SPIBus +type spiBusFactory func(int, byte, byte, int, int, int, func() error) SPIBus type spiDriver struct { - spiDevMinor byte + spiDevMinor int initializer func() error busMap map[byte]SPIBus @@ -16,7 +16,7 @@ type spiDriver struct { // NewSPIDriver returns a SPIDriver interface which allows control // over the SPI bus. -func NewSPIDriver(spiDevMinor byte, sbf spiBusFactory, i func() error) SPIDriver { +func NewSPIDriver(spiDevMinor int, sbf spiBusFactory, i func() error) SPIDriver { return &spiDriver{ spiDevMinor: spiDevMinor, sbf: sbf, From 997876e74b6b82d668d37e0003ad2f9758161ea1 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Mon, 5 Sep 2016 23:14:12 -0700 Subject: [PATCH 16/19] Initial support for rfm69 radio --- controller/doc.go | 2 + radio/doc.go | 1 + radio/rfm69/README.md | 8 ++ radio/rfm69/registers.go | 68 +++++++++++ radio/rfm69/rfm69.go | 257 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 336 insertions(+) create mode 100644 controller/doc.go create mode 100644 radio/doc.go create mode 100644 radio/rfm69/README.md create mode 100644 radio/rfm69/registers.go create mode 100644 radio/rfm69/rfm69.go diff --git a/controller/doc.go b/controller/doc.go new file mode 100644 index 0000000..01256a5 --- /dev/null +++ b/controller/doc.go @@ -0,0 +1,2 @@ +// Package controller is a container for the various device controllers supported by EMBD. +package controller diff --git a/radio/doc.go b/radio/doc.go new file mode 100644 index 0000000..3e2bdf6 --- /dev/null +++ b/radio/doc.go @@ -0,0 +1 @@ +package radio diff --git a/radio/rfm69/README.md b/radio/rfm69/README.md new file mode 100644 index 0000000..9dcd402 --- /dev/null +++ b/radio/rfm69/README.md @@ -0,0 +1,8 @@ +RFM69 Driver Info +================= + + + +Interesting links +----------------- +- Info about listen mode with low duty cycle: https://lowpowerlab.com/forum/low-power-techniques/ultra-low-power-listening-mode-for-battery-nodes/ diff --git a/radio/rfm69/registers.go b/radio/rfm69/registers.go new file mode 100644 index 0000000..0e2b2e3 --- /dev/null +++ b/radio/rfm69/registers.go @@ -0,0 +1,68 @@ +// Copyright 2016 by Thorsten von Eicken + +package rfm69 + +const ( + REG_FIFO = 0x00 + REG_OPMODE = 0x01 + REG_FRFMSB = 0x07 + REG_PALEVEL = 0x11 + REG_LNAVALUE = 0x18 + REG_AFCMSB = 0x1F + REG_AFCLSB = 0x20 + REG_FEIMSB = 0x21 + REG_FEILSB = 0x22 + REG_RSSIVALUE = 0x24 + REG_IRQFLAGS1 = 0x27 + REG_IRQFLAGS2 = 0x28 + REG_SYNCVALUE1 = 0x2F + REG_SYNCVALUE2 = 0x30 + REG_NODEADDR = 0x39 + REG_BCASTADDR = 0x3A + REG_FIFOTHRESH = 0x3C + REG_PKTCONFIG2 = 0x3D + REG_AESKEYMSB = 0x3E + + MODE_SLEEP = 0 << 2 + MODE_STANDBY = 1 << 2 + MODE_TRANSMIT = 3 << 2 + MODE_RECEIVE = 4 << 2 + + START_TX = 0xC2 + STOP_TX = 0x42 + + RCCALSTART = 0x80 + IRQ1_MODEREADY = 1 << 7 + IRQ1_RXREADY = 1 << 6 + IRQ1_SYNADDRMATCH = 1 << 0 + + IRQ2_FIFONOTEMPTY = 1 << 6 + IRQ2_PACKETSENT = 1 << 3 + IRQ2_PAYLOADREADY = 1 << 2 +) + +// register values to initialize the chip, this array has pairs of +var configRegs = []byte{ + // POR value is better for first rf_sleep 0x01, 0x00, // OpMode = sleep + 0x02, 0x00, // DataModul = packet mode, fsk + 0x03, 0x02, // BitRateMsb, data rate = 49,261 khz + 0x04, 0x8A, // BitRateLsb, divider = 32 MHz / 650 + 0x05, 0x02, // FdevMsb = 45 KHz + 0x06, 0xE1, // FdevLsb = 45 KHz + 0x0B, 0x20, // Low M + 0x19, 0x4A, // RxBw 100 KHz + 0x1A, 0x42, // AfcBw 125 KHz + 0x1E, 0x0C, // AfcAutoclearOn, AfcAutoOn + //0x25, 0x40, //0x80, // DioMapping1 = SyncAddress (Rx) + 0x26, 0x07, // disable clkout + 0x29, 0xA0, // RssiThresh -80 dB + 0x2D, 0x05, // PreambleSize = 5 + 0x2E, 0x88, // SyncConfig = sync on, sync size = 2 + 0x2F, 0x2D, // SyncValue1 = 0x2D + 0x37, 0xD0, // PacketConfig1 = fixed, white, no filtering + 0x38, 0x42, // PayloadLength = 0, unlimited + 0x3C, 0x8F, // FifoTresh, not empty, level 15 + 0x3D, 0x12, // 0x10, // PacketConfig2, interpkt = 1, autorxrestart off + 0x6F, 0x20, // TestDagc ... + 0x71, 0x02, // RegTestAfc +} diff --git a/radio/rfm69/rfm69.go b/radio/rfm69/rfm69.go new file mode 100644 index 0000000..ec2d638 --- /dev/null +++ b/radio/rfm69/rfm69.go @@ -0,0 +1,257 @@ +// Copyright 2016 by Thorsten von Eicken + +// The RFM69 package interfaces with a HopeRF RFM69 radio connected to an SPI bus. In addition, +// an interrupt capable GPIO pin may be used to avoid having to poll the radio. +package rfm69 + +import ( + "fmt" + "log" + + "github.com/kidoman/embd" +) + +// rfm69 represents a HopeRF RFM69 radio +type rfm69 struct { + // configuration + spi embd.SPIBus // bus where the radio is connected + intrPin embd.InterruptPin // interrupt pin for RX and TX interrupts + id byte // my RF ID/address + group byte // RF address of group + freq int // center frequency + parity byte // ??? + // state + mode byte // current operation mode + // info about current RX packet + rxInfo *RxInfo +} + +type Packet struct { + Length uint8 // number of message bytes plus 1 for the address byte + Address uint8 // destination address + Message []byte +} + +type RxInfo struct { + rssi int // rssi value for current packet + lna int // low noise amp gain for current packet + fei int // frequency error for current packet + afc int // frequency correction applied for current packet +} + +// New creates a connection to an rfm69 radio connected to the provided SPI bus and interrupt pin. +// the bufCount determines how many transmit buffers are allocated to allow for the queueing of +// transmit packets. +// For the RFM69 the SPI bus must be set to 10Mhz and mode 0. +func New(bus embd.SPIBus, intr embd.InterruptPin, id, group byte, freq int) *rfm69 { + // bit 7 = b7^b5^b3^b1; bit 6 = b6^b4^b2^b0 + parity := group ^ (group << 4) + parity = (parity ^ (parity << 2)) & 0xc0 + return &rfm69{spi: bus, intrPin: intr, id: id, group: group, freq: freq, parity: parity, + mode: 255} +} + +func (rf *rfm69) writeReg(addr, data byte) error { + buf := []byte{addr | 0x80, data} + return rf.spi.TransferAndReceiveData(buf) +} + +func (rf *rfm69) readReg(addr byte) (byte, error) { + buf := []byte{addr & 0x7f, 0} + err := rf.spi.TransferAndReceiveData(buf) + return buf[1], err +} + +func (rf *rfm69) Init() error { + // try to establish communication with the rfm69 + sync := func(pattern byte) error { + n := 10 + for { + rf.writeReg(REG_SYNCVALUE1, pattern) + v, err := rf.readReg(REG_SYNCVALUE1) + if err != nil { + return err + } + if v == pattern { + return nil + } + if n == 0 { + return fmt.Errorf("Cannot sync with rfm69 chip") + } + n-- + } + } + if err := sync(0xaa); err != nil { + return err + } + if err := sync(0x55); err != nil { + return err + } + + // write the configuration into the registers + for i := 0; i < len(configRegs)-1; i += 2 { + if err := rf.writeReg(configRegs[i], configRegs[i+1]); err != nil { + return err + } + } + + rf.setFrequency(rf.freq) + rf.writeReg(REG_SYNCVALUE2, rf.group) + + if gpio, ok := rf.intrPin.(embd.DigitalPin); ok { + log.Printf("Set intr direction") + gpio.SetDirection(embd.In) + } + if err := rf.intrPin.Watch(embd.EdgeRising, rf.intrHandler); err != nil { + return err + } + + return nil +} + +func (rf *rfm69) setFrequency(freq int) { + // accept any frequency scale as input, including KHz and MHz + // multiply by 10 until freq >= 100 MHz + for freq > 0 && freq < 100000000 { + freq = freq * 10 + } + + // Frequency steps are in units of (32,000,000 >> 19) = 61.03515625 Hz + // use multiples of 64 to avoid multi-precision arithmetic, i.e. 3906.25 Hz + // due to this, the lower 6 bits of the calculated factor will always be 0 + // this is still 4 ppm, i.e. well below the radio's 32 MHz crystal accuracy + // 868.0 MHz = 0xD90000, 868.3 MHz = 0xD91300, 915.0 MHz = 0xE4C000 + frf := (freq << 2) / (32000000 >> 11) + rf.writeReg(REG_FRFMSB, byte(frf>>10)) + rf.writeReg(REG_FRFMSB+1, byte(frf>>2)) + rf.writeReg(REG_FRFMSB+2, byte(frf<<6)) +} + +func (rf *rfm69) setMode(mode byte) error { + reg, err := rf.readReg(REG_OPMODE) + if err != nil { + return err + } + reg = (reg & 0xE3) | mode + err = rf.writeReg(REG_OPMODE, reg) + if err != nil { + return err + } + for { + val, err := rf.readReg(REG_IRQFLAGS1) + if err != nil { + rf.mode = 255 + return err + } + if val&IRQ1_MODEREADY != 0 { + rf.mode = mode + return nil + } + } +} + +func (rf *rfm69) Send(header byte, message []byte) error { + if len(message) > 62 { + return fmt.Errorf("message too long") + } + rf.setMode(MODE_SLEEP) + + buf := make([]byte, len(message)+4) + buf[0] = REG_FIFO | 0x80 + buf[1] = byte(len(message) + 2) + buf[2] = (header & 0x3f) | rf.parity + buf[3] = (header & 0xC0) | rf.id + copy(buf[4:], message) + err := rf.spi.TransferAndReceiveData(buf) + if err != nil { + return err + } + rf.setMode(MODE_TRANSMIT) + for { + val, err := rf.readReg(REG_IRQFLAGS2) + if err != nil { + return err + } + if val&IRQ2_PACKETSENT != 0 { + break + } + } + rf.setMode(MODE_STANDBY) + return nil +} + +func (rf *rfm69) readInfo() *RxInfo { + // collect rxinfo, start with rssi + rxInfo := &RxInfo{} + rssi, _ := rf.readReg(REG_RSSIVALUE) + rxInfo.rssi = 0 - int(rssi)/2 + // low noise amp gain + lna, _ := rf.readReg(REG_LNAVALUE) + rxInfo.lna = int((lna >> 3) & 0x7) + // auto freq correction applied, caution: signed value + buf := []byte{REG_AFCMSB, 0, 0} + rf.spi.TransferAndReceiveData(buf) + rxInfo.afc = int(int8(buf[1]))<<8 | int(buf[2]) + // freq error detected, caution: signed value + buf = []byte{REG_FEIMSB, 0, 0} + rf.spi.TransferAndReceiveData(buf) + rxInfo.fei = int(int8(buf[1]))<<8 | int(buf[2]) + return rxInfo +} + +func (rf *rfm69) Receive() (header byte, message []byte, info *RxInfo, err error) { + // if we're not in receive mode, then switch, this also flushes the FIFO + if rf.mode != MODE_RECEIVE { + rf.setMode(MODE_RECEIVE) + return + } + + // if we don't have rxinfo check whether we have RX_READY, which means that we've + // started receiving a packet so we can collect info + if rf.rxInfo == nil { + irq1, err := rf.readReg(REG_IRQFLAGS1) + if err != nil { + return 0, nil, nil, err + } + if irq1&IRQ1_RXREADY != 0 { + rf.rxInfo = rf.readInfo() + } + } + + // see whether we have a full packet + irq2, err := rf.readReg(REG_IRQFLAGS2) + if err != nil { + return 0, nil, nil, err + } + if irq2&IRQ2_PAYLOADREADY == 0 { + return + } + i2 := rf.readInfo() + if rf.rxInfo != nil && i2 != nil && + (rf.rxInfo.rssi != i2.rssi || rf.rxInfo.lna != i2.lna || + rf.rxInfo.afc != i2.afc || rf.rxInfo.fei != i2.fei) { + fmt.Printf("\nrxInfo mismatch: %+v vs %+v\n", *rf.rxInfo, *i2) + } + // got packet, read it by fetching the entire FIFO, should be faster than first + // looking at the length + buf := make([]byte, 67) + buf[0] = REG_FIFO + err = rf.spi.TransferAndReceiveData(buf) + if err != nil { + return 0, nil, nil, err + } + // return the packet + info = rf.rxInfo + rf.rxInfo = nil + l := buf[1] + if l > 66 { + l = 66 // or error? + } + header = buf[2] + message = buf[3 : 2+l] + return +} + +func (rf *rfm69) intrHandler(pin embd.DigitalPin) { + log.Printf("Interrupt called!") +} From b6706df9a8525e587eb72be1a833cc59c512611b Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Tue, 6 Sep 2016 21:07:08 -0700 Subject: [PATCH 17/19] make fork ready for merge-back --- README.md | 39 +-------------------------------------- host/chip/README.md | 34 ++++++++++++++++++++++++++++++++++ host/chip/chip.go | 2 +- radio/rfm69/registers.go | 2 +- radio/rfm69/rfm69.go | 2 +- 5 files changed, 38 insertions(+), 41 deletions(-) create mode 100644 host/chip/README.md diff --git a/README.md b/README.md index 94a954a..a7396b8 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,7 @@ -# embd [![Build Status](https://travis-ci.org/tve/embd.svg?branch=master)](https://travis-ci.org/tve/embd) [![GoDoc](http://godoc.org/github.com/tve/embd?status.png)](http://godoc.org/github.com/tve/embd) +# embd [![Build Status](https://travis-ci.org/kidoman/embd.svg?branch=master)](https://travis-ci.org/kidoman/embd) [![GoDoc](http://godoc.org/github.com/kidoman/embd?status.png)](http://godoc.org/github.com/kidoman/embd) **embd** is a hardware abstraction layer (HAL) for embedded systems. -**The github.com/tve/embd fork** attempts to continue the work started by -@kidoman and adds support for NextThing's C.H.I.P. - It allows you to start your hardware hack on easily available hobby boards (like the Raspberry Pi, BeagleBone Black, C.H.I.P., etc.) by giving you staight forward access to the board's capabilities as well as a plethora of @@ -216,40 +213,6 @@ heading, err := mag.Heading() The above two examples depend on **I2C** and therefore will work without change on almost all platforms. -## Using embd on CHIP - -The CHIP drivers support gpio, I2C, SPI, and pin interrupts. Not supported are PWM or LED. -The names of the pins on chip have multiple aliases. The official CHIP pin names are supported, -for example XIO-P1 or LCD-D2 and the pin number are also supported, such as U14-14 (same as XIO-P1) -or U13-17. Some of the alternate function names are also supported, like "SPI2_MOSI", and the -linux 4.4 kernel gpio pin numbers as well, e.g., 1017 for XIO-P1. Finally, the official GPIO pins -(XIO-P0 thru XIO-P7) can be addressed as gpio0-gpio7. - -A simple demo to blink an LED connected with a small resistor between XIO-P6 and 3.3V is - -``` -package main -import ( - "time" - "github.com/kidoman/embd" - _ "github.com/kidoman/embd/host/chip" -) - -func main() { - embd.InitGPIO() - defer embd.CloseGPIO() - - embd.SetDirection("gpio6", embd.Out) - on := 0 - for { - embd.DigitalWrite("gpio6", on) - on = 1 - on - time.Sleep(250 * time.Millisecond) - } -} -``` -Run it as root: `sudo ./blinky` - ## Protocols Supported * **Digital GPIO** [Documentation](http://godoc.org/github.com/kidoman/embd#DigitalPin) diff --git a/host/chip/README.md b/host/chip/README.md new file mode 100644 index 0000000..51fd49e --- /dev/null +++ b/host/chip/README.md @@ -0,0 +1,34 @@ +# Using embd on CHIP + +The CHIP drivers support gpio, I2C, SPI, and pin interrupts. Not supported are PWM or LED. +The names of the pins on chip have multiple aliases. The official CHIP pin names are supported, +for example XIO-P1 or LCD-D2 and the pin number are also supported, such as U14-14 (same as XIO-P1) +or U13-17. Some of the alternate function names are also supported, like "SPI2_MOSI", and the +linux 4.4 kernel gpio pin numbers as well, e.g., 1017 for XIO-P1. Finally, the official GPIO pins +(XIO-P0 thru XIO-P7) can be addressed as gpio0-gpio7. + +A simple demo to blink an LED connected with a small resistor between XIO-P6 and 3.3V is + +``` +package main +import ( + "time" + "github.com/kidoman/embd" + _ "github.com/kidoman/embd/host/chip" +) + +func main() { + embd.InitGPIO() + defer embd.CloseGPIO() + + embd.SetDirection("gpio6", embd.Out) + on := 0 + for { + embd.DigitalWrite("gpio6", on) + on = 1 - on + time.Sleep(250 * time.Millisecond) + } +} +``` +Run it as root: `sudo ./blinky` + diff --git a/host/chip/chip.go b/host/chip/chip.go index 277b72f..d849df4 100644 --- a/host/chip/chip.go +++ b/host/chip/chip.go @@ -1,4 +1,4 @@ -// Copyright 2016 by Thorsten von Eicken +// Copyright 2016 by Thorsten von Eicken, see LICENSE file // Package chip provides NextThing C.H.I.P. support. // References: diff --git a/radio/rfm69/registers.go b/radio/rfm69/registers.go index 0e2b2e3..94e2a73 100644 --- a/radio/rfm69/registers.go +++ b/radio/rfm69/registers.go @@ -1,4 +1,4 @@ -// Copyright 2016 by Thorsten von Eicken +// Copyright 2016 by Thorsten von Eicken, see LICENSE file package rfm69 diff --git a/radio/rfm69/rfm69.go b/radio/rfm69/rfm69.go index ec2d638..15029b6 100644 --- a/radio/rfm69/rfm69.go +++ b/radio/rfm69/rfm69.go @@ -1,4 +1,4 @@ -// Copyright 2016 by Thorsten von Eicken +// Copyright 2016 by Thorsten von Eicken, see LICENSE file // The RFM69 package interfaces with a HopeRF RFM69 radio connected to an SPI bus. In addition, // an interrupt capable GPIO pin may be used to avoid having to poll the radio. From 789e3f82b2ca9146700c87a08a48e0f8499b86e8 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Tue, 6 Sep 2016 21:12:17 -0700 Subject: [PATCH 18/19] make fork ready for merge-back, try #2 --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a7396b8..1bc5e08 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ **embd** is a hardware abstraction layer (HAL) for embedded systems. It allows you to start your hardware hack on easily available hobby boards -(like the Raspberry Pi, BeagleBone Black, C.H.I.P., etc.) by giving you staight -forward access to the board's capabilities as well as a plethora of +(like the Raspberry Pi, BeagleBone Black, C.H.I.P., etc.) by giving you +straight-forward access to the board's capabilities as well as a plethora of **sensors** (like accelerometers, gyroscopes, thermometers, etc.) and **controllers** (PWM generators, digital-to-analog convertors) for which we have written drivers. And when things get serious, you dont @@ -12,7 +12,7 @@ have to throw away the code. You carry forward the effort onto more custom designed boards where the HAL abstraction of EMBD will save you precious time. -Original development supported and sponsored by [**SoStronk**](https://www.sostronk.com) and +Development supported and sponsored by [**SoStronk**](https://www.sostronk.com) and [**ThoughtWorks**](http://www.thoughtworks.com/). Also, you might be interested in: [Why Golang?](https://github.com/kidoman/embd/wiki/Why-Go) From e19d72b27bf87a65287313b1eee5285383e73106 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Tue, 6 Sep 2016 21:13:16 -0700 Subject: [PATCH 19/19] make fork ready for merge-back, try #3 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1bc5e08..932be11 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ func main() { Then install the EMBD package (go1.6 or greater is required): - $ go get github.com/tve/embd + $ go get github.com/kidoman/embd Build the binary*: