Upgrade dependencies

This commit is contained in:
2020-09-07 18:41:44 +02:00
parent 738c2f5a82
commit de6f39bddc
329 changed files with 50010 additions and 109914 deletions

View File

@@ -1,3 +1,7 @@
# Copyright 2020 The Periph Authors. All rights reserved.
# Use of this source code is governed under the Apache License, Version 2.0
# that can be found in the LICENSE file.
# See https://github.com/periph/gohci
version: 1
workers:

View File

@@ -2,52 +2,41 @@
# Use of this source code is governed under the Apache License, Version 2.0
# that can be found in the LICENSE file.
os: linux
dist: bionic
language: go
sudo: false
dist: xenial
go_import_path: periph.io/x/periph
matrix:
jobs:
include:
- go: 1.12.x
env: GO111MODULE=on
- go: 1.14.x
cache:
directories:
# go1.10+ 'go test' cache on linux (macOS and Windows are # different).
- $HOME/.cache/go-build
# go1.11+ with GO111MODULE=on
- $GOPATH/pkg/mod
# Cache tools sources. Manually verified that both misspell and ineffassign
# only depend on the stdlib.
- $GOPATH/src/github\.com
# For shadow.
- $GOPATH/src/golang\.org
# Dear future me: if you touch this line, don't forget to update the
# conditions below!
- go: 1.7.6
before_script:
- echo $TRAVIS_GO_VERSION
- go get -t -v periph.io/x/periph/...
- if [[ $TRAVIS_GO_VERSION != 1.7.6 ]]; then go get -u -v github.com/client9/misspell/cmd/misspell github.com/gordonklaus/ineffassign golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow; fi
script:
# Checks run on latest version.
- if [[ $TRAVIS_GO_VERSION != 1.7.6 ]]; then echo 'Check Code is well formatted'; ! gofmt -s -d . | read; fi
- if [[ $TRAVIS_GO_VERSION != 1.7.6 ]]; then echo 'Looking for external dependencies:'; go list -f '{{join .Imports "\n"}}' periph.io/x/periph/... | sort | uniq | grep -v ^periph.io/x/periph | xargs go list -f '{{if not .Standard}}- {{.ImportPath}}{{end}}'; fi
- if [[ $TRAVIS_GO_VERSION != 1.7.6 ]]; then echo 'Erroring on external dependencies:'; ! go list -f '{{join .Imports "\n"}}' periph.io/x/periph/... | sort | uniq | grep -v ^periph.io/x/periph | xargs go list -f '{{if not .Standard}}Remove {{.ImportPath}}{{end}}' | grep -q Remove; fi
- if [[ $TRAVIS_GO_VERSION != 1.7.6 ]]; then echo 'Erroring on /host depending on /devices:'; ! go list -f '{{.ImportPath}} depends on {{join .Imports ", "}}' periph.io/x/periph/host/... | sort | uniq | grep periph.io/x/periph/devices; fi
- if [[ $TRAVIS_GO_VERSION != 1.7.6 ]]; then echo 'Erroring on /conn depending on /devices:'; ! go list -f '{{.ImportPath}} depends on {{join .Imports ", "}}' periph.io/x/periph/conn/... | sort | uniq | grep periph.io/x/periph/devices; fi
- if [[ $TRAVIS_GO_VERSION != 1.7.6 ]]; then echo 'Erroring on /conn depending on /host:'; ! go list -f '{{.ImportPath}} depends on {{join .Imports ", "}}' periph.io/x/periph/conn/... | sort | uniq | grep periph.io/x/periph/host; fi
- if [[ $TRAVIS_GO_VERSION != 1.7.6 ]]; then echo 'Erroring on misspelling'; ! misspell . | grep a; fi
- if [[ $TRAVIS_GO_VERSION != 1.7.6 ]]; then ineffassign .; fi
- if [[ $TRAVIS_GO_VERSION != 1.7.6 ]]; then ! go vet -vettool=$(which shadow) ./... |& grep -v '"err"' | grep -e '^[^#]'; fi
- if [[ $TRAVIS_GO_VERSION != 1.7.6 ]]; then bash -c 'set -e; echo "" > coverage.txt; for d in $(go list ./...); do go test -covermode=count -coverprofile=p.out $d; if [ -f p.out ]; then cat p.out >> coverage.txt; rm p.out; fi; done'; fi
- if [[ $TRAVIS_GO_VERSION != 1.7.6 ]]; then go test -race ./...; fi
# Checks run on older version.
- if [[ $TRAVIS_GO_VERSION == 1.7.6 ]]; then go test ./...; fi
- if [[ $TRAVIS_GO_VERSION == 1.7.6 ]]; then if find . -path ./.git -prune -o -type f -executable -print | grep -e . ; then echo 'Do not commit executables'; false; fi; fi
after_success:
- if [[ $TRAVIS_GO_VERSION != 1.7.6 ]]; then bash <(curl -s https://codecov.io/bash); fi
- $GOPATH/pkg/mod
# Cache tools sources.
#- $GOPATH/src/golang\.org
before_script:
- echo $TRAVIS_GO_VERSION
- go get -t -v periph.io/x/periph/...
- >
go get -u -v
golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow
script:
- >
echo 'Looking for external dependencies:';
go list -f '{{join .Imports "\n"}}' periph.io/x/periph/... | sort | uniq | grep -v ^periph.io/x/periph | xargs go list -f '{{if not .Standard}}- {{.ImportPath}}{{end}}'
- >
echo 'Erroring on external dependencies:';
! go list -f '{{join .Imports "\n"}}' periph.io/x/periph/... | sort | uniq | grep -v ^periph.io/x/periph | xargs go list -f '{{if not .Standard}}Remove {{.ImportPath}}{{end}}' | grep -q Remove
- >
echo 'Erroring on /host depending on /devices:';
! go list -f '{{.ImportPath}} depends on {{join .Imports ", "}}' periph.io/x/periph/host/... | sort | uniq | grep periph.io/x/periph/devices
- >
echo 'Erroring on /conn depending on /devices:';
! go list -f '{{.ImportPath}} depends on {{join .Imports ", "}}' periph.io/x/periph/conn/... | sort | uniq | grep periph.io/x/periph/devices
- >
echo 'Erroring on /conn depending on /host:';
! go list -f '{{.ImportPath}} depends on {{join .Imports ", "}}' periph.io/x/periph/conn/... | sort | uniq | grep periph.io/x/periph/host
- >
echo 'Erroring on shadowed variables:';
! go vet -vettool=$(which shadow) ./... |& grep -v '"err"' | grep -e '^[^#]'

20
vendor/periph.io/x/periph/codecov.yml generated vendored Normal file
View File

@@ -0,0 +1,20 @@
# Copyright 2020 The Periph Authors. All rights reserved.
# Use of this source code is governed under the Apache License, Version 2.0
# that can be found in the LICENSE file.
# https://docs.codecov.io/docs/codecovyml-reference
# and
# https://docs.codecov.io/docs/coverage-configuration
coverage:
precision: 1
range: "40...80"
round: nearest
status:
patch:
default:
target: 60%
threshold: 10%
project:
default:
target: 60%
threshold: 10%

View File

@@ -1,3 +0,0 @@
// Code generated by "stringer -type Duplex"; DO NOT EDIT
package conn

View File

@@ -1923,12 +1923,10 @@ func dtoi(d decimal, scale int) (int64, bool) {
switch {
case d.exp+scale < 0:
u = (u + powerOf10[mag]/2) / powerOf10[mag]
break
case mag == 0:
if u > maxInt64 {
return 0, true
}
break
default:
check := u * powerOf10[mag]
if check/powerOf10[mag] != u || check > maxInt64 {
@@ -2020,7 +2018,6 @@ func atod(s string) (decimal, int, error) {
return decimal{}, 0, &parseError{errNotANumber}
}
end = i
break
}
}

View File

@@ -43,7 +43,7 @@ func All() map[string][][]pin.Pin {
func Position(p pin.Pin) (string, int) {
mu.Lock()
defer mu.Unlock()
pos, _ := byPin[realPin(p).Name()]
pos := byPin[realPin(p).Name()]
return pos.name, pos.number
}

View File

@@ -994,7 +994,7 @@ func (d *driverGPIO) After() []string {
// for the exact processor model detected.
func (d *driverGPIO) Init() (bool, error) {
if !Present() {
return false, errors.New("Allwinner CPU not detected")
return false, errors.New("no Allwinner CPU detected")
}
// Mark the right pins as available even if the memory map fails so they can

View File

@@ -478,7 +478,7 @@ func (d *driverGPIOPL) After() []string {
func (d *driverGPIOPL) Init() (bool, error) {
// BUG(maruel): H3 supports group PL too.
if !IsA64() {
return false, errors.New("A64 CPU not detected")
return false, errors.New("no A64 CPU detected")
}
// Mark the right pins as available even if the memory map fails so they can

View File

@@ -10,9 +10,31 @@
// The way it works under the hood is that the bcm283x has two registers, one
// to set a bit and one to clear a bit.
//
// So two DMA controllers are used, one writing a "clear bit" stream and one
// for the "set bit" stream. This requires two independent 32 bits wide streams
// per period for write but only one for read.
// Each pin using PWM will get its own DMA channel. Each channel writes a
// stream of "set bit" followed by "clear bit".
//
// <--------------- PWM period --------------->
// <-- Duty cycle -->
// High __________________ ______
// | | |
// | | |
// | | |
// Low | |__________________________|
// **************************************************
// ^each * is a DMA cycle
//
// For each DMA cycle, a control block (size 32 bytes) sets or clears the bit.
// Control blocks are chained together, with the last one looping back to the
// first. The number of control blocks is:
// # control block = frequency of the DMA channel / requested PWM frequency
//
// Important: those control blocks are allocated in the video memory. On a
// Raspberry Pi, this can configured, with a default at 64 MB.
// For each PWM signal, the memory usage is:
// size = 32 * frequency of the DMA channel / requested PWM frequency
// Example, for 1 Hz:
// size = 32 * 200 000 / 1 = 6400000, so around 6MB
//
//
// References
//
@@ -412,6 +434,11 @@ type controlBlock struct {
reserved [2]uint32 // 0x18+0x1C
}
const (
controlBlockSize = 32
uint32Size = 4
)
// initBlock initializes a controlBlock for any valid DMA operation.
//
// l is in bytes, not in words.
@@ -494,16 +521,16 @@ func (c *controlBlock) GoString() string {
//
// Page 39.
type dmaChannel struct {
cs dmaStatus // 0x00 CS
cbAddr uint32 // 0x04 CONNBLK_AD *controlBlock in physical address space; rounded to 32 bytes
transferInfo dmaTransferInfo // 0x08 TI (RO) Copyied by DMA on start from cbAddr
srcAddr uint32 // 0x0C SOURCE_AD (RO) Copyied by DMA on start from cbAddr
dstAddr uint32 // 0x10 DEST_AD (RO) Copyied by DMA on start from cbAddr
txLen dmaTransferLen // 0x14 TXFR_LEN (RO) Copyied by DMA on start from cbAddr
stride dmaStride // 0x18 STRIDE (RO) Copyied by DMA on start from cbAddr
nextCB uint32 // 0x1C NEXTCONBK Only safe to edit when DMA is paused
debug dmaDebug // 0x20 DEBUG
reserved [(0x100 - 0x24) / 4]uint32 // 0x24
cs dmaStatus // 0x00 CS
cbAddr uint32 // 0x04 CONNBLK_AD *controlBlock in physical address space; rounded to 32 bytes
transferInfo dmaTransferInfo // 0x08 TI (RO) Copyied by DMA on start from cbAddr
srcAddr uint32 // 0x0C SOURCE_AD (RO) Copyied by DMA on start from cbAddr
dstAddr uint32 // 0x10 DEST_AD (RO) Copyied by DMA on start from cbAddr
txLen dmaTransferLen // 0x14 TXFR_LEN (RO) Copyied by DMA on start from cbAddr
stride dmaStride // 0x18 STRIDE (RO) Copyied by DMA on start from cbAddr
nextCB uint32 // 0x1C NEXTCONBK Only safe to edit when DMA is paused
debug dmaDebug // 0x20 DEBUG
reserved [(0x100 - 0x24) / uint32Size]uint32 // 0x24
}
func (d *dmaChannel) isAvailable() bool {
@@ -713,17 +740,17 @@ func dmaWritePWMFIFO() (*dmaChannel, *videocore.Mem, error) {
if drvDMA.dmaMemory == nil {
return nil, nil, errors.New("bcm283x-dma is not initialized; try running as root?")
}
cb, buf, err := allocateCB(32 + 4) // CB + data
cb, buf, err := allocateCB(controlBlockSize + uint32Size) // CB + data
if err != nil {
return nil, nil, err
}
u := buf.Uint32()
offsetBytes := uint32(32)
u[offsetBytes/4] = 0x0
offsetBytes := uint32(controlBlockSize)
u[offsetBytes/uint32Size] = 0x0
physBuf := uint32(buf.PhysAddr())
physBit := physBuf + offsetBytes
dest := drvDMA.pwmBaseAddr + 0x18 // PWM FIFO
if err := cb[0].initBlock(physBit, dest, 4, false, true, false, false, dmaPWM); err != nil {
if err := cb[0].initBlock(physBit, dest, uint32Size, false, true, false, false, dmaPWM); err != nil {
_ = buf.Close()
return nil, nil, err
}
@@ -743,35 +770,45 @@ func startPWMbyDMA(p *Pin, rng, data uint32) (*dmaChannel, *videocore.Mem, error
if drvDMA.dmaMemory == nil {
return nil, nil, errors.New("bcm283x-dma is not initialized; try running as root?")
}
cb, buf, err := allocateCB(2*32 + 4) // 2 CBs + mask
cb, buf, err := allocateCB(int(rng)*controlBlockSize + uint32Size) // rng CBs + mask
if err != nil {
return nil, nil, err
}
u := buf.Uint32()
cbBytes := uint32(32)
offsetBytes := cbBytes * 2
u[offsetBytes/4] = uint32(1) << uint(p.number&31)
offsetBytes := controlBlockSize * rng
u[offsetBytes/uint32Size] = uint32(1) << uint(p.number&31)
physBuf := uint32(buf.PhysAddr())
physBit := physBuf + offsetBytes
dest := [2]uint32{
drvGPIO.gpioBaseAddr + 0x28 + 4*uint32(p.number/32), // clear
drvGPIO.gpioBaseAddr + 0x1C + 4*uint32(p.number/32), // set
drvGPIO.gpioBaseAddr + 0x28 + uint32Size*uint32(p.number/32), // clear
drvGPIO.gpioBaseAddr + 0x1C + uint32Size*uint32(p.number/32), // set
}
// High
if err := cb[0].initBlock(physBit, dest[1], data*4, false, true, false, false, dmaPWM); err != nil {
_ = buf.Close()
return nil, nil, err
ptr := physBuf
for i := uint32(0); i < data; i++ {
if err := cb[i].initBlock(physBit, dest[1], uint32Size, false, true, false, false, dmaPWM); err != nil {
_ = buf.Close()
return nil, nil, err
}
ptr += controlBlockSize
cb[i].nextCB = ptr
}
cb[0].nextCB = physBuf + cbBytes
// Low
if err := cb[1].initBlock(physBit, dest[0], (rng-data)*4, false, true, false, false, dmaPWM); err != nil {
_ = buf.Close()
return nil, nil, err
for i := data; i < rng; i++ {
if err := cb[i].initBlock(physBit, dest[0], uint32Size, false, true, false, false, dmaPWM); err != nil {
_ = buf.Close()
return nil, nil, err
}
ptr += controlBlockSize
cb[i].nextCB = ptr
}
cb[1].nextCB = physBuf // Loop back to cb[0]
cb[rng].nextCB = physBuf // Loop back to cb[0]
var blacklist []int
if data*4 >= 1<<16 || (rng-data)*4 >= 1<<16 {
if rng*uint32Size >= 1<<16 {
// Don't use lite channels.
blacklist = []int{7, 8, 9, 10, 11, 12, 13, 14, 15}
}
@@ -816,25 +853,25 @@ func dmaReadStream(p *Pin, b *gpiostream.BitStream) error {
// hand one could read 32 contiguous pins simultaneously at no cost.
// TODO(simokawa): Implement a function to get number of bits for all type of
// Stream
l := len(b.Bits) * 8 * 4 * int(skip)
l := len(b.Bits) * 8 * uint32Size * int(skip)
// TODO(simokawa): Allocate multiple pages and CBs for huge buffer.
buf, err := drvDMA.dmaBufAllocator((l + 0xFFF) &^ 0xFFF)
if err != nil {
return err
}
defer buf.Close()
cb, pCB, err := allocateCB(4)
cb, pCB, err := allocateCB(uint32Size)
if err != nil {
return err
}
defer pCB.Close()
reg := drvGPIO.gpioBaseAddr + 0x34 + 4*uint32(p.number/32) // GPIO Pin Level 0
reg := drvGPIO.gpioBaseAddr + 0x34 + uint32Size*uint32(p.number/32) // GPIO Pin Level 0
if err := cb[0].initBlock(reg, uint32(buf.PhysAddr()), uint32(l), true, false, false, true, dmaPWM); err != nil {
return err
}
err = runIO(pCB, l <= maxLite)
uint32ToBitLSBF(b.Bits, buf.Bytes(), uint8(p.number&31), skip*4)
uint32ToBitLSBF(b.Bits, buf.Bytes(), uint8(p.number&31), skip*uint32Size)
return err
}
@@ -886,7 +923,7 @@ func dmaWriteStreamEdges(p *Pin, w gpiostream.Stream) error {
stride += uint32(skip)
}
// 32 bytes for each CB and 4 bytes for the mask.
bufBytes := count*32 + 4
bufBytes := count*controlBlockSize + uint32Size
cb, buf, err := allocateCB((bufBytes + 0xFFF) &^ 0xFFF)
if err != nil {
return err
@@ -896,8 +933,8 @@ func dmaWriteStreamEdges(p *Pin, w gpiostream.Stream) error {
// Setup the single mask buffer of 4Kb.
mask := uint32(1) << uint(p.number&31)
u := buf.Uint32()
offset := (len(buf.Bytes()) - 4)
u[offset/4] = mask
offset := (len(buf.Bytes()) - uint32Size)
u[offset/uint32Size] = mask
physBit := uint32(buf.PhysAddr()) + uint32(offset)
// Other constants during the loop.
@@ -905,8 +942,8 @@ func dmaWriteStreamEdges(p *Pin, w gpiostream.Stream) error {
// Use PWM's rng1 instead for this.
//waits := divs - 1
dest := [2]uint32{
drvGPIO.gpioBaseAddr + 0x28 + 4*uint32(p.number/32), // clear
drvGPIO.gpioBaseAddr + 0x1C + 4*uint32(p.number/32), // set
drvGPIO.gpioBaseAddr + 0x28 + uint32Size*uint32(p.number/32), // clear
drvGPIO.gpioBaseAddr + 0x1C + uint32Size*uint32(p.number/32), // set
}
// Render the controlBlock's to trigger the bit trigger for either Set or
@@ -916,19 +953,18 @@ func dmaWriteStreamEdges(p *Pin, w gpiostream.Stream) error {
stride = uint32(skip)
for i := 1; i < l; i++ {
if v := getBit(bits[i/8], i%8, msb); v != last || stride == maxLite {
if err := cb[index].initBlock(physBit, dest[last], stride*4, false, true, false, false, dmaPWM); err != nil {
if err := cb[index].initBlock(physBit, dest[last], stride*uint32Size, false, true, false, false, dmaPWM); err != nil {
return err
}
// Hardcoded len(controlBlock) == 32. It is not necessary to use
// physToUncachedPhys() here.
cb[index].nextCB = uint32(buf.PhysAddr()) + uint32(32*(index+1))
// It is not necessary to use physToUncachedPhys() here.
cb[index].nextCB = uint32(buf.PhysAddr()) + controlBlockSize*uint32(index+1)
index++
stride = 0
last = v
}
stride += uint32(skip)
}
if err := cb[index].initBlock(physBit, dest[last], stride*4, false, true, false, false, dmaPWM); err != nil {
if err := cb[index].initBlock(physBit, dest[last], stride*uint32Size, false, true, false, false, dmaPWM); err != nil {
return err
}
@@ -953,7 +989,7 @@ func dmaWriteStreamDualChannel(p *Pin, w gpiostream.Stream) error {
return err
}
// Calculates the number of needed bytes.
l := int(int64(w.Duration())*int64(w.Frequency())/int64(physic.Hertz)) * skip * 4
l := int(int64(w.Duration())*int64(w.Frequency())/int64(physic.Hertz)) * skip * uint32Size
bufLen := (l + 0xFFF) &^ 0xFFF
bufSet, err := drvDMA.dmaBufAllocator(bufLen)
if err != nil {
@@ -984,11 +1020,11 @@ func dmaWriteStreamDualChannel(p *Pin, w gpiostream.Stream) error {
return err
}
regSet := drvGPIO.gpioBaseAddr + 0x1C + 4*uint32(p.number/32)
regSet := drvGPIO.gpioBaseAddr + 0x1C + uint32Size*uint32(p.number/32)
if err := cb[0].initBlock(uint32(bufSet.PhysAddr()), regSet, uint32(l), false, true, true, false, dmaPWM); err != nil {
return err
}
regClear := drvGPIO.gpioBaseAddr + 0x28 + 4*uint32(p.number/32)
regClear := drvGPIO.gpioBaseAddr + 0x28 + uint32Size*uint32(p.number/32)
if err := cb[1].initBlock(uint32(bufClear.PhysAddr()), regClear, uint32(l), false, true, true, false, dmaPWM); err != nil {
return err
}
@@ -1008,8 +1044,8 @@ func dmaWriteStreamDualChannel(p *Pin, w gpiostream.Stream) error {
defer chClear.reset()
// Two channel need to be synchronized but there is not such a mechanism.
chSet.startIO(uint32(pCB.PhysAddr())) // cb[0]
chClear.startIO(uint32(pCB.PhysAddr()) + 32) // cb[1]
chSet.startIO(uint32(pCB.PhysAddr())) // cb[0]
chClear.startIO(uint32(pCB.PhysAddr()) + controlBlockSize) // cb[1]
err1 := chSet.wait()
err2 := chClear.wait()
@@ -1050,8 +1086,8 @@ func smokeTest() error {
return errors.New("unexpected hardware: DMA enable is not fully set")
}
const size = 4096 * 4 // 16kb
const holeSize = 1 // Minimum DMA alignment
const size = 4096 * uint32Size // 16kb
const holeSize = 1 // Minimum DMA alignment
alloc := func(s int) (pmem.Mem, error) {
return videocore.Alloc(s)

View File

@@ -80,8 +80,11 @@ var (
// Present returns true if running on a Broadcom bcm283x based CPU.
func Present() bool {
if isArm {
hardware, ok := distro.CPUInfo()["Hardware"]
return ok && strings.HasPrefix(hardware, "BCM")
for _, line := range distro.DTCompatible() {
if strings.HasPrefix(line, "brcm,bcm") {
return true
}
}
}
return false
}
@@ -402,25 +405,53 @@ func (p *Pin) In(pull gpio.Pull, edge gpio.Edge) error {
// Changing pull resistor requires a specific dance as described at
// https://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf
// page 101.
// However, BCM2711 uses a simpler way of setting pull resistors, reference at
// https://github.com/raspberrypi/documentation/blob/master/hardware/raspberrypi/bcm2711/rpi_DATA_2711_1p0.pdf
// page 84 and 95 ~ 98.
// Set Pull
switch pull {
case gpio.PullDown:
drvGPIO.gpioMemory.pullEnable = 1
case gpio.PullUp:
drvGPIO.gpioMemory.pullEnable = 2
case gpio.Float:
// If we are running on a newer chip such as BCM2711, set Pull directly.
if !drvGPIO.useLegacyPull {
// GPIO_PUP_PDN_CNTRL_REG0 for GPIO0-15
// GPIO_PUP_PDN_CNTRL_REG1 for GPIO16-31
// GPIO_PUP_PDN_CNTRL_REG2 for GPIO32-47
// GPIO_PUP_PDN_CNTRL_REG3 for GPIO48-57
offset := p.number / 16
// Check page 94.
// Resistor Select for GPIOXX
// 00 = No resistor is selected
// 01 = Pull up resistor is selected
// 10 = Pull down resistor is selected
// 11 = Reserved
var pullState uint32
switch pull {
case gpio.PullDown:
pullState = 2
case gpio.PullUp:
pullState = 1
case gpio.Float:
pullState = 0
}
drvGPIO.gpioMemory.pullRegister[offset] = pullState << uint((p.number%16)<<1)
} else {
// Set Pull
switch pull {
case gpio.PullDown:
drvGPIO.gpioMemory.pullEnable = 1
case gpio.PullUp:
drvGPIO.gpioMemory.pullEnable = 2
case gpio.Float:
drvGPIO.gpioMemory.pullEnable = 0
}
// Datasheet states caller needs to sleep 150 cycles.
sleep150cycles()
offset := p.number / 32
drvGPIO.gpioMemory.pullEnableClock[offset] = 1 << uint(p.number%32)
sleep150cycles()
drvGPIO.gpioMemory.pullEnable = 0
drvGPIO.gpioMemory.pullEnableClock[offset] = 0
}
// Datasheet states caller needs to sleep 150 cycles.
sleep150cycles()
offset := p.number / 32
drvGPIO.gpioMemory.pullEnableClock[offset] = 1 << uint(p.number%32)
sleep150cycles()
drvGPIO.gpioMemory.pullEnable = 0
drvGPIO.gpioMemory.pullEnableClock[offset] = 0
}
if edge != gpio.NoEdge {
if p.sysfsPin == nil {
@@ -475,10 +506,27 @@ func (p *Pin) WaitForEdge(timeout time.Duration) bool {
// Pull implements gpio.PinIn.
//
// bcm283x doesn't support querying the pull resistor of any GPIO pin.
// bcm2711/bcm2838 support querying the pull resistor of all GPIO pins. Prior
// to it, bcm283x doesn't support querying the pull resistor of any GPIO pin.
func (p *Pin) Pull() gpio.Pull {
// TODO(maruel): The best that could be added is to cache the last set value
// and return it.
// sysfs does not have the capability to read pull resistor.
if drvGPIO.gpioMemory != nil {
if drvGPIO.useLegacyPull {
// TODO(maruel): The best that could be added is to cache the last set value
// and return it.
return gpio.PullNoChange
}
offset := p.number / 16
pullState := (drvGPIO.gpioMemory.pullRegister[offset] >> uint((p.number%16)<<1)) % 4
switch pullState {
case 0:
return gpio.Float
case 1:
return gpio.PullUp
case 2:
return gpio.PullDown
}
}
return gpio.PullNoChange
}
@@ -976,6 +1024,9 @@ type function uint8
// Mapping as
// https://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf
// pages 90-91.
// And
// https://github.com/raspberrypi/documentation/blob/master/hardware/raspberrypi/bcm2711/rpi_DATA_2711_1p0.pdf
// pages 83-84.
type gpioMap struct {
// 0x00 RW GPIO Function Select 0 (GPIO0-9)
// 0x04 RW GPIO Function Select 1 (GPIO10-19)
@@ -1043,7 +1094,18 @@ type gpioMap struct {
pullEnableClock [2]uint32 // GPPUDCLK0-GPPUDCLK1
// 0xA0 - Reserved
dummy uint32
// padding
dummy11 [3]uint32
// 0xB0 - Test (byte)
test uint32
// padding
dummy12 [12]uint32
// New in BCM2711
// 0xE4 RW GPIO Pull-up / Pull-down Register 0 (GPIO0-15)
// 0xE8 RW GPIO Pull-up / Pull-down Register 1 (GPIO16-31)
// 0xEC RW GPIO Pull-up / Pull-down Register 2 (GPIO32-47)
// 0xF0 RW GPIO Pull-up / Pull-down Register 3 (GPIO48-57)
pullRegister [4]uint32 // GPIO_PUP_PDN_CNTRL_REG0-GPIO_PUP_PDN_CNTRL_REG3
}
// pad defines the settings for a GPIO pad group.
@@ -1188,6 +1250,9 @@ type driverGPIO struct {
gpioMemory *gpioMap
// gpioBaseAddr is needed for DMA transfers.
gpioBaseAddr uint32
// useLegacyPull is set when the old slow pull resistor setup method before
// bcm2711 must be used.
useLegacyPull bool
}
func (d *driverGPIO) Close() {
@@ -1213,14 +1278,31 @@ func (d *driverGPIO) Init() (bool, error) {
if !Present() {
return false, errors.New("bcm283x CPU not detected")
}
model := distro.CPUInfo()["model name"]
if strings.Contains(model, "ARMv6") {
// It's kind of messy, some report bcm283x while others show bcm27xx.
// Let's play safe here.
dTCompatible := strings.Join(distro.DTCompatible(), " ")
// Reference: https://www.raspberrypi.org/documentation/hardware/raspberrypi/peripheral_addresses.md
if strings.Contains(dTCompatible, "bcm2708") ||
strings.Contains(dTCompatible, "bcm2835") {
// RPi0/1.
d.baseAddr = 0x20000000
d.dramBus = 0x40000000
} else {
d.useLegacyPull = true
} else if strings.Contains(dTCompatible, "bcm2709") ||
strings.Contains(dTCompatible, "bcm2836") ||
strings.Contains(dTCompatible, "bcm2710") ||
strings.Contains(dTCompatible, "bcm2837") {
// RPi2+
d.baseAddr = 0x3F000000
d.dramBus = 0xC0000000
d.useLegacyPull = true
} else {
// RPi4B+
d.baseAddr = 0xFE000000
d.dramBus = 0xC0000000
// BCM2711 (and perhaps future versions?) uses a simpler way to
// setup internal pull resistors.
d.useLegacyPull = false
}
// Page 6.
// Virtual addresses in kernel mode will range between 0xC0000000 and

View File

@@ -162,7 +162,7 @@ func (d *driver) String() string {
}
func (d *driver) Prerequisites() []string {
return []string{"am335x"}
return []string{"am335x", "sysfs-gpio"}
}
func (d *driver) After() []string {

View File

@@ -57,7 +57,7 @@ func (d *driver) String() string {
}
func (d *driver) Prerequisites() []string {
return []string{"am335x"}
return []string{"am335x", "sysfs-gpio"}
}
func (d *driver) After() []string {

View File

@@ -4,6 +4,11 @@
package distro
import (
"encoding/binary"
"io/ioutil"
)
// DTModel returns platform model info from the Linux device tree (/proc/device-tree/model), and
// returns "unknown" on non-linux systems or if the file is missing.
func DTModel() string {
@@ -35,11 +40,29 @@ func DTCompatible() []string {
return dtCompatible
}
// DTRevision returns the device revision (e.g. a02082 for the Raspberry Pi 3)
// from the Linux device tree, or 0 if the file is missing or malformed.
func DTRevision() uint32 {
mu.Lock()
defer mu.Unlock()
if dtRevisionRead {
return dtRevision
}
dtRevisionRead = true
if b, _ := ioutil.ReadFile("/proc/device-tree/system/linux,revision"); len(b) >= 4 {
dtRevision = binary.BigEndian.Uint32(b[:4])
}
return dtRevision
}
//
var (
dtModel string // cached /proc/device-tree/model
dtCompatible []string // cached /proc/device-tree/compatible
dtModel string // cached /proc/device-tree/model
dtCompatible []string // cached /proc/device-tree/compatible
dtRevision uint32 // cached /proc/device-tree/system/linux,revision
dtRevisionRead bool
)
func makeDTModelLinux() string {

View File

@@ -124,7 +124,7 @@ func (d *driver) After() []string {
func (d *driver) Init() (bool, error) {
if !Present() {
return false, errors.New("Hardkernel ODROID-C0/C1/C1+ board not detected")
return false, errors.New("board Hardkernel ODROID-C0/C1/C1+ not detected")
}
J2_3 = sysfsPin(74)
J2_5 = sysfsPin(75)

View File

@@ -10,7 +10,6 @@ import (
"errors"
"fmt"
"os"
"strconv"
"periph.io/x/periph"
"periph.io/x/periph/conn/gpio"
@@ -785,7 +784,7 @@ func (d *driver) After() []string {
func (d *driver) Init() (bool, error) {
if !Present() {
return false, errors.New("Raspberry Pi board not detected")
return false, errors.New("board Raspberry Pi not detected")
}
// Setup headers based on board revision.
@@ -794,13 +793,12 @@ func (d *driver) Init() (bool, error) {
// whenever it comes out.
// Revision codes from: http://elinux.org/RPi_HardwareHistory
f := features{}
rev := distro.CPUInfo()["Revision"]
if v, err := strconv.ParseUint(rev, 16, 32); err == nil {
if err := f.init(uint32(v)); err != nil {
return true, err
}
} else {
return true, fmt.Errorf("rpi: failed to read cpu_info: %v", err)
rev := distro.DTRevision()
if rev == 0 {
return true, fmt.Errorf("rpi: failed to obtain revision")
}
if err := f.init(rev); err != nil {
return true, err
}
return true, f.registerHeaders()

View File

@@ -127,8 +127,12 @@ func (e *eventsListener) init() error {
return err
}
e.r, e.w, err = os.Pipe()
if err != nil {
e.mu.Unlock()
return err
}
// Only need epollIN. epollPRI has no effect on pipes.
if err := e.addFdInner(e.r.Fd(), epollET|epollIN); err != nil {
if err = e.addFdInner(e.r.Fd(), epollET|epollIN); err != nil {
// This object will not be reusable at this point.
e.mu.Unlock()
return err