add: humidity (WIP)
This commit is contained in:
		
							
								
								
									
										7
									
								
								vendor/periph.io/x/periph/host/bcm283x/bcm283x_arm.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								vendor/periph.io/x/periph/host/bcm283x/bcm283x_arm.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
// Copyright 2016 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.
 | 
			
		||||
 | 
			
		||||
package bcm283x
 | 
			
		||||
 | 
			
		||||
const isArm = true
 | 
			
		||||
							
								
								
									
										9
									
								
								vendor/periph.io/x/periph/host/bcm283x/bcm283x_arm64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								vendor/periph.io/x/periph/host/bcm283x/bcm283x_arm64.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
// Copyright 2016 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.
 | 
			
		||||
 | 
			
		||||
// +build arm64
 | 
			
		||||
 | 
			
		||||
package bcm283x
 | 
			
		||||
 | 
			
		||||
const isArm = true
 | 
			
		||||
							
								
								
									
										9
									
								
								vendor/periph.io/x/periph/host/bcm283x/bcm283x_other.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								vendor/periph.io/x/periph/host/bcm283x/bcm283x_other.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
// Copyright 2016 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.
 | 
			
		||||
 | 
			
		||||
// +build !arm,!arm64
 | 
			
		||||
 | 
			
		||||
package bcm283x
 | 
			
		||||
 | 
			
		||||
const isArm = false
 | 
			
		||||
							
								
								
									
										330
									
								
								vendor/periph.io/x/periph/host/bcm283x/clock.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										330
									
								
								vendor/periph.io/x/periph/host/bcm283x/clock.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,330 @@
 | 
			
		||||
// Copyright 2017 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.
 | 
			
		||||
 | 
			
		||||
package bcm283x
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"periph.io/x/periph/conn/physic"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// errClockRegister is returned in a situation where the clock memory is not
 | 
			
		||||
// working as expected. It is mocked in tests.
 | 
			
		||||
var errClockRegister = errors.New("can't write to clock divisor CPU register")
 | 
			
		||||
 | 
			
		||||
// Clock sources frequency in hertz.
 | 
			
		||||
const (
 | 
			
		||||
	clk19dot2MHz = 19200 * physic.KiloHertz
 | 
			
		||||
	clk500MHz    = 500 * physic.MegaHertz
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// 31:24 password
 | 
			
		||||
	clockPasswdCtl clockCtl = 0x5A << 24 // PASSWD
 | 
			
		||||
	// 23:11 reserved
 | 
			
		||||
	clockMashMask clockCtl = 3 << 9 // MASH
 | 
			
		||||
	clockMash0    clockCtl = 0 << 9 // src_freq / divI  (ignores divF)
 | 
			
		||||
	clockMash1    clockCtl = 1 << 9
 | 
			
		||||
	clockMash2    clockCtl = 2 << 9
 | 
			
		||||
	clockMash3    clockCtl = 3 << 9 // will cause higher spread
 | 
			
		||||
	clockFlip     clockCtl = 1 << 8 // FLIP
 | 
			
		||||
	clockBusy     clockCtl = 1 << 7 // BUSY
 | 
			
		||||
	// 6 reserved
 | 
			
		||||
	clockKill          clockCtl = 1 << 5   // KILL
 | 
			
		||||
	clockEnable        clockCtl = 1 << 4   // ENAB
 | 
			
		||||
	clockSrcMask       clockCtl = 0xF << 0 // SRC
 | 
			
		||||
	clockSrcGND        clockCtl = 0        // 0Hz
 | 
			
		||||
	clockSrc19dot2MHz  clockCtl = 1        // 19.2MHz
 | 
			
		||||
	clockSrcTestDebug0 clockCtl = 2        // 0Hz
 | 
			
		||||
	clockSrcTestDebug1 clockCtl = 3        // 0Hz
 | 
			
		||||
	clockSrcPLLA       clockCtl = 4        // 0Hz
 | 
			
		||||
	clockSrcPLLC       clockCtl = 5        // 1000MHz (changes with overclock settings)
 | 
			
		||||
	clockSrcPLLD       clockCtl = 6        // 500MHz
 | 
			
		||||
	clockSrcHDMI       clockCtl = 7        // 216MHz; may be disabled
 | 
			
		||||
	// 8-15 == GND.
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// clockCtl controls the clock properties.
 | 
			
		||||
//
 | 
			
		||||
// It must not be changed while busy is set or a glitch may occur.
 | 
			
		||||
//
 | 
			
		||||
// Page 107
 | 
			
		||||
type clockCtl uint32
 | 
			
		||||
 | 
			
		||||
func (c clockCtl) String() string {
 | 
			
		||||
	var out []string
 | 
			
		||||
	if c&0xFF000000 == clockPasswdCtl {
 | 
			
		||||
		c &^= 0xFF000000
 | 
			
		||||
		out = append(out, "PWD")
 | 
			
		||||
	}
 | 
			
		||||
	switch c & clockMashMask {
 | 
			
		||||
	case clockMash1:
 | 
			
		||||
		out = append(out, "Mash1")
 | 
			
		||||
	case clockMash2:
 | 
			
		||||
		out = append(out, "Mash2")
 | 
			
		||||
	case clockMash3:
 | 
			
		||||
		out = append(out, "Mash3")
 | 
			
		||||
	default:
 | 
			
		||||
	}
 | 
			
		||||
	c &^= clockMashMask
 | 
			
		||||
	if c&clockFlip != 0 {
 | 
			
		||||
		out = append(out, "Flip")
 | 
			
		||||
		c &^= clockFlip
 | 
			
		||||
	}
 | 
			
		||||
	if c&clockBusy != 0 {
 | 
			
		||||
		out = append(out, "Busy")
 | 
			
		||||
		c &^= clockBusy
 | 
			
		||||
	}
 | 
			
		||||
	if c&clockKill != 0 {
 | 
			
		||||
		out = append(out, "Kill")
 | 
			
		||||
		c &^= clockKill
 | 
			
		||||
	}
 | 
			
		||||
	if c&clockEnable != 0 {
 | 
			
		||||
		out = append(out, "Enable")
 | 
			
		||||
		c &^= clockEnable
 | 
			
		||||
	}
 | 
			
		||||
	switch x := c & clockSrcMask; x {
 | 
			
		||||
	case clockSrcGND:
 | 
			
		||||
		out = append(out, "GND(0Hz)")
 | 
			
		||||
	case clockSrc19dot2MHz:
 | 
			
		||||
		out = append(out, "19.2MHz")
 | 
			
		||||
	case clockSrcTestDebug0:
 | 
			
		||||
		out = append(out, "Debug0(0Hz)")
 | 
			
		||||
	case clockSrcTestDebug1:
 | 
			
		||||
		out = append(out, "Debug1(0Hz)")
 | 
			
		||||
	case clockSrcPLLA:
 | 
			
		||||
		out = append(out, "PLLA(0Hz)")
 | 
			
		||||
	case clockSrcPLLC:
 | 
			
		||||
		out = append(out, "PLLD(1000MHz)")
 | 
			
		||||
	case clockSrcPLLD:
 | 
			
		||||
		out = append(out, "PLLD(500MHz)")
 | 
			
		||||
	case clockSrcHDMI:
 | 
			
		||||
		out = append(out, "HDMI(216MHz)")
 | 
			
		||||
	default:
 | 
			
		||||
		out = append(out, fmt.Sprintf("GND(%d)", x))
 | 
			
		||||
	}
 | 
			
		||||
	c &^= clockSrcMask
 | 
			
		||||
	if c != 0 {
 | 
			
		||||
		out = append(out, fmt.Sprintf("clockCtl(0x%0x)", uint32(c)))
 | 
			
		||||
	}
 | 
			
		||||
	return strings.Join(out, "|")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// 31:24 password
 | 
			
		||||
	clockPasswdDiv clockDiv = 0x5A << 24 // PASSWD
 | 
			
		||||
	// Integer part of the divisor
 | 
			
		||||
	clockDiviShift          = 12
 | 
			
		||||
	clockDiviMax            = (1 << 12) - 1
 | 
			
		||||
	clockDiviMask  clockDiv = clockDiviMax << clockDiviShift // DIVI
 | 
			
		||||
	// Fractional part of the divisor
 | 
			
		||||
	clockDivfMask clockDiv = (1 << 12) - 1 // DIVF
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// clockDiv is a 12.12 fixed point value.
 | 
			
		||||
//
 | 
			
		||||
// The fractional part generates a significant amount of noise so it is
 | 
			
		||||
// preferable to not use it.
 | 
			
		||||
//
 | 
			
		||||
// Page 108
 | 
			
		||||
type clockDiv uint32
 | 
			
		||||
 | 
			
		||||
func (c clockDiv) String() string {
 | 
			
		||||
	i := (c & clockDiviMask) >> clockDiviShift
 | 
			
		||||
	c &^= clockDiviMask
 | 
			
		||||
	if c == 0 {
 | 
			
		||||
		return fmt.Sprintf("%d.0", i)
 | 
			
		||||
	}
 | 
			
		||||
	return fmt.Sprintf("%d.(%d/%d)", i, c, clockDiviMax)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// clock is a pair of clockCtl / clockDiv.
 | 
			
		||||
//
 | 
			
		||||
// It can be set to one of the sources: clockSrc19dot2MHz(19.2MHz) and
 | 
			
		||||
// clockSrcPLLD(500Mhz), then divided to a value to get the resulting clock.
 | 
			
		||||
// Per spec the resulting frequency should be under 25Mhz.
 | 
			
		||||
type clock struct {
 | 
			
		||||
	ctl clockCtl
 | 
			
		||||
	div clockDiv
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// findDivisorExact finds the clock divisor and wait cycles to reduce src to
 | 
			
		||||
// desired hz.
 | 
			
		||||
//
 | 
			
		||||
// The clock divisor is capped to clockDiviMax.
 | 
			
		||||
//
 | 
			
		||||
// Returns clock divisor, wait cycles. Returns 0, 0 if no exact match is found.
 | 
			
		||||
// Favorizes high clock divisor value over high clock wait cycles. This means
 | 
			
		||||
// that the function is slower than it could be, but results in more stable
 | 
			
		||||
// clock.
 | 
			
		||||
func findDivisorExact(src, desired physic.Frequency, maxWaitCycles uint32) (uint32, uint32) {
 | 
			
		||||
	if src < desired || src%desired != 0 || src/physic.Frequency(maxWaitCycles*clockDiviMax) > desired {
 | 
			
		||||
		// Can't attain without oversampling (too low) or desired frequency is
 | 
			
		||||
		// higher than the source (too high) or is not a multiple.
 | 
			
		||||
		return 0, 0
 | 
			
		||||
	}
 | 
			
		||||
	factor := uint32(src / desired)
 | 
			
		||||
	// TODO(maruel): Only iterate over valid divisors to save a bit more
 | 
			
		||||
	// calculations. Since it's is only doing 32 loops, this is not a big deal.
 | 
			
		||||
	for wait := uint32(1); wait <= maxWaitCycles; wait++ {
 | 
			
		||||
		if rest := factor % wait; rest != 0 {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		clk := factor / wait
 | 
			
		||||
		if clk == 0 {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		if clk <= clockDiviMax {
 | 
			
		||||
			return clk, wait
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return 0, 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// findDivisorOversampled tries to find the lowest allowed oversampling to make
 | 
			
		||||
// desiredHz a multiple of srcHz.
 | 
			
		||||
//
 | 
			
		||||
// Allowed oversampling depends on the desiredHz. Cap oversampling because
 | 
			
		||||
// oversampling at 10x in the 1Mhz range becomes unreasonable in term of
 | 
			
		||||
// memory usage.
 | 
			
		||||
func findDivisorOversampled(src, desired physic.Frequency, maxWaitCycles uint32) (uint32, uint32, physic.Frequency) {
 | 
			
		||||
	//log.Printf("findDivisorOversampled(%s, %s, %d)", src, desired, maxWaitCycles)
 | 
			
		||||
	// There are 2 reasons:
 | 
			
		||||
	// - desired is so low it is not possible to lower src to this frequency
 | 
			
		||||
	// - not a multiple, there's a need for a prime number
 | 
			
		||||
	// TODO(maruel): Rewrite without a loop, this is not needed. Leverage primes
 | 
			
		||||
	// to reduce the number of iterations.
 | 
			
		||||
	for multiple := physic.Frequency(2); ; multiple++ {
 | 
			
		||||
		n := multiple * desired
 | 
			
		||||
		if n > 100*physic.KiloHertz && multiple > 10 {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		if clk, wait := findDivisorExact(src, n, maxWaitCycles); clk != 0 {
 | 
			
		||||
			return clk, wait, n
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return 0, 0, 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// calcSource choose the best source to get the exact desired clock.
 | 
			
		||||
//
 | 
			
		||||
// It calculates the clock source, the clock divisor and the wait cycles, if
 | 
			
		||||
// applicable. Wait cycles is 'div minus 1'.
 | 
			
		||||
func calcSource(f physic.Frequency, maxWaitCycles uint32) (clockCtl, uint32, uint32, physic.Frequency, error) {
 | 
			
		||||
	if f < physic.Hertz {
 | 
			
		||||
		return 0, 0, 0, 0, fmt.Errorf("bcm283x-clock: desired frequency %s must be >1hz", f)
 | 
			
		||||
	}
 | 
			
		||||
	if f > 125*physic.MegaHertz {
 | 
			
		||||
		return 0, 0, 0, 0, fmt.Errorf("bcm283x-clock: desired frequency %s is too high", f)
 | 
			
		||||
	}
 | 
			
		||||
	// http://elinux.org/BCM2835_datasheet_errata states that clockSrc19dot2MHz
 | 
			
		||||
	// is the cleanest clock source so try it first.
 | 
			
		||||
	div, wait := findDivisorExact(clk19dot2MHz, f, maxWaitCycles)
 | 
			
		||||
	if div != 0 {
 | 
			
		||||
		return clockSrc19dot2MHz, div, wait, f, nil
 | 
			
		||||
	}
 | 
			
		||||
	// Try 500Mhz.
 | 
			
		||||
	div, wait = findDivisorExact(clk500MHz, f, maxWaitCycles)
 | 
			
		||||
	if div != 0 {
 | 
			
		||||
		return clockSrcPLLD, div, wait, f, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Try with up to 10x oversampling. This is generally useful for lower
 | 
			
		||||
	// frequencies, below 10kHz. Prefer the one with less oversampling. Only for
 | 
			
		||||
	// non-aliased matches.
 | 
			
		||||
	div19, wait19, f19 := findDivisorOversampled(clk19dot2MHz, f, maxWaitCycles)
 | 
			
		||||
	div500, wait500, f500 := findDivisorOversampled(clk500MHz, f, maxWaitCycles)
 | 
			
		||||
	if div19 != 0 && (div500 == 0 || f19 < f500) {
 | 
			
		||||
		return clockSrc19dot2MHz, div19, wait19, f19, nil
 | 
			
		||||
	}
 | 
			
		||||
	if div500 != 0 {
 | 
			
		||||
		return clockSrcPLLD, div500, wait500, f500, nil
 | 
			
		||||
	}
 | 
			
		||||
	return 0, 0, 0, 0, errors.New("failed to find a good clock")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// set changes the clock frequency to the desired value or the closest one
 | 
			
		||||
// otherwise.
 | 
			
		||||
//
 | 
			
		||||
// f=0 means disabled.
 | 
			
		||||
//
 | 
			
		||||
// maxWaitCycles is the maximum oversampling via an additional wait cycles that
 | 
			
		||||
// can further divide the clock. Use 1 if no additional wait cycle is
 | 
			
		||||
// available. It is expected to be dmaWaitcyclesMax+1.
 | 
			
		||||
//
 | 
			
		||||
// Returns the actual clock used and divisor.
 | 
			
		||||
func (c *clock) set(f physic.Frequency, maxWaitCycles uint32) (physic.Frequency, uint32, error) {
 | 
			
		||||
	if f == 0 {
 | 
			
		||||
		c.ctl = clockPasswdCtl | clockKill
 | 
			
		||||
		for c.ctl&clockBusy != 0 {
 | 
			
		||||
		}
 | 
			
		||||
		return 0, 0, nil
 | 
			
		||||
	}
 | 
			
		||||
	ctl, div, div2, actual, err := calcSource(f, maxWaitCycles)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, 0, err
 | 
			
		||||
	}
 | 
			
		||||
	return actual, div2, c.setRaw(ctl, div)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// setRaw sets the clock speed with the clock source and the divisor.
 | 
			
		||||
func (c *clock) setRaw(ctl clockCtl, div uint32) error {
 | 
			
		||||
	if div < 1 || div > clockDiviMax {
 | 
			
		||||
		return errors.New("invalid clock divisor")
 | 
			
		||||
	}
 | 
			
		||||
	if ctl != clockSrc19dot2MHz && ctl != clockSrcPLLD {
 | 
			
		||||
		return errors.New("invalid clock control")
 | 
			
		||||
	}
 | 
			
		||||
	// Stop the clock.
 | 
			
		||||
	// TODO(maruel): Do not stop the clock if the current clock rate is the one
 | 
			
		||||
	// desired.
 | 
			
		||||
	for c.ctl&clockBusy != 0 {
 | 
			
		||||
		c.ctl = clockPasswdCtl | clockKill
 | 
			
		||||
	}
 | 
			
		||||
	d := clockDiv(div << clockDiviShift)
 | 
			
		||||
	c.div = clockPasswdDiv | d
 | 
			
		||||
	Nanospin(10 * time.Nanosecond)
 | 
			
		||||
	// Page 107
 | 
			
		||||
	c.ctl = clockPasswdCtl | ctl
 | 
			
		||||
	Nanospin(10 * time.Nanosecond)
 | 
			
		||||
	c.ctl = clockPasswdCtl | ctl | clockEnable
 | 
			
		||||
	if c.div != d {
 | 
			
		||||
		// This error is mocked out in tests, so the code path of set() callers can
 | 
			
		||||
		// follow on.
 | 
			
		||||
		return errClockRegister
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *clock) String() string {
 | 
			
		||||
	return fmt.Sprintf("%s / %s", c.ctl, c.div)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// clockMap is the memory mapped clock registers.
 | 
			
		||||
//
 | 
			
		||||
// The clock #1 must not be touched since it is being used by the ethernet
 | 
			
		||||
// controller.
 | 
			
		||||
//
 | 
			
		||||
// Page 107 for gp0~gp2.
 | 
			
		||||
// https://scribd.com/doc/127599939/BCM2835-Audio-clocks for PCM/PWM.
 | 
			
		||||
type clockMap struct {
 | 
			
		||||
	reserved0 [0x70 / 4]uint32          //
 | 
			
		||||
	gp0       clock                     // CM_GP0CTL+CM_GP0DIV; 0x70-0x74 (125MHz max)
 | 
			
		||||
	gp1ctl    uint32                    // CM_GP1CTL+CM_GP1DIV; 0x78-0x7A must not use (used by ethernet)
 | 
			
		||||
	gp1div    uint32                    // CM_GP1CTL+CM_GP1DIV; 0x78-0x7A must not use (used by ethernet)
 | 
			
		||||
	gp2       clock                     // CM_GP2CTL+CM_GP2DIV; 0x80-0x84 (125MHz max)
 | 
			
		||||
	reserved1 [(0x98 - 0x88) / 4]uint32 // 0x88-0x94
 | 
			
		||||
	pcm       clock                     // CM_PCMCTL+CM_PCMDIV 0x98-0x9C
 | 
			
		||||
	pwm       clock                     // CM_PWMCTL+CM_PWMDIV 0xA0-0xA4
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *clockMap) GoString() string {
 | 
			
		||||
	return fmt.Sprintf(
 | 
			
		||||
		"{\n  gp0: %s,\n  gp1: %s,\n  gp2: %s,\n  pcm: %sw,\n  pwm: %s,\n}",
 | 
			
		||||
		&c.gp0, &clock{clockCtl(c.gp1ctl), clockDiv(c.gp1div)}, &c.gp2, &c.pcm, &c.pwm)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1224
									
								
								vendor/periph.io/x/periph/host/bcm283x/dma.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1224
									
								
								vendor/periph.io/x/periph/host/bcm283x/dma.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										42
									
								
								vendor/periph.io/x/periph/host/bcm283x/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								vendor/periph.io/x/periph/host/bcm283x/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
			
		||||
// Copyright 2016 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.
 | 
			
		||||
 | 
			
		||||
// Package bcm283x exposes the BCM283x GPIO functionality.
 | 
			
		||||
//
 | 
			
		||||
// This driver implements memory-mapped GPIO pin manipulation and leverages
 | 
			
		||||
// sysfs-gpio for edge detection.
 | 
			
		||||
//
 | 
			
		||||
// If you are looking for the actual implementation, open doc.go for further
 | 
			
		||||
// implementation details.
 | 
			
		||||
//
 | 
			
		||||
// GPIOs
 | 
			
		||||
//
 | 
			
		||||
// Aliases for GPCLK0, GPCLK1, GPCLK2 are created for corresponding CLKn pins.
 | 
			
		||||
// Same for PWM0_OUT and PWM1_OUT, which point respectively to PWM0 and PWM1.
 | 
			
		||||
//
 | 
			
		||||
// Datasheet
 | 
			
		||||
//
 | 
			
		||||
// https://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf
 | 
			
		||||
//
 | 
			
		||||
// Its crowd-sourced errata: http://elinux.org/BCM2835_datasheet_errata
 | 
			
		||||
//
 | 
			
		||||
// BCM2836:
 | 
			
		||||
// https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf
 | 
			
		||||
//
 | 
			
		||||
// Another doc about PCM and PWM:
 | 
			
		||||
// https://scribd.com/doc/127599939/BCM2835-Audio-clocks
 | 
			
		||||
//
 | 
			
		||||
// GPIO pad control:
 | 
			
		||||
// https://scribd.com/doc/101830961/GPIO-Pads-Control2
 | 
			
		||||
package bcm283x
 | 
			
		||||
 | 
			
		||||
// Other implementations details
 | 
			
		||||
//
 | 
			
		||||
// mainline:
 | 
			
		||||
// https://github.com/torvalds/linux/blob/master/drivers/dma/bcm2835-dma.c
 | 
			
		||||
// https://github.com/torvalds/linux/blob/master/drivers/gpio
 | 
			
		||||
//
 | 
			
		||||
// Raspbian kernel:
 | 
			
		||||
// https://github.com/raspberrypi/linux/blob/rpi-4.11.y/drivers/dma
 | 
			
		||||
// https://github.com/raspberrypi/linux/blob/rpi-4.11.y/drivers/gpio
 | 
			
		||||
							
								
								
									
										1361
									
								
								vendor/periph.io/x/periph/host/bcm283x/gpio.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1361
									
								
								vendor/periph.io/x/periph/host/bcm283x/gpio.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										234
									
								
								vendor/periph.io/x/periph/host/bcm283x/pcm.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										234
									
								
								vendor/periph.io/x/periph/host/bcm283x/pcm.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,234 @@
 | 
			
		||||
// Copyright 2017 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.
 | 
			
		||||
 | 
			
		||||
// pcm means I2S.
 | 
			
		||||
 | 
			
		||||
package bcm283x
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"periph.io/x/periph/conn/physic"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type pcmCS uint32
 | 
			
		||||
 | 
			
		||||
// Pages 126-129
 | 
			
		||||
const (
 | 
			
		||||
	// 31:26 reserved
 | 
			
		||||
	pcmStandby      pcmCS = 1 << 25 // STBY Allow at least 4 PCM clock cycles to take effect
 | 
			
		||||
	pcmSync         pcmCS = 1 << 24 // SYNC Two PCM clocks have occurred since last write
 | 
			
		||||
	pcmRXSignExtend pcmCS = 1 << 23 // RXSEX Sign extend RXZ data
 | 
			
		||||
	pcmRXFull       pcmCS = 1 << 22 // RXF RX FIFO is full
 | 
			
		||||
	pcmTXEmpty      pcmCS = 1 << 21 // TXE TX FIFO is empty
 | 
			
		||||
	pcmRXData       pcmCS = 1 << 20 // RXD RX FIFO contains data
 | 
			
		||||
	pcmTXData       pcmCS = 1 << 19 // TXD TX FIFO ready to accept data
 | 
			
		||||
	pcmRXR          pcmCS = 1 << 18 // RXR RX FIFO needs reading
 | 
			
		||||
	pcmTXW          pcmCS = 1 << 17 // TXW TX FIFO needs writing
 | 
			
		||||
	pcmRXErr        pcmCS = 1 << 16 // RXERR RX FIFO error
 | 
			
		||||
	pcmTXErr        pcmCS = 1 << 15 // TXERR TX FIFO error
 | 
			
		||||
	pcmRXSync       pcmCS = 1 << 14 // RXSYNC RX FIFO is out of sync
 | 
			
		||||
	pcmTXSync       pcmCS = 1 << 13 // TXSYNC TX FIFO is out of sync
 | 
			
		||||
	// 12:10 reserved
 | 
			
		||||
	pcmDMAEnable pcmCS = 1 << 9 // DMAEN Generate TX&RX DMA DREQ
 | 
			
		||||
	// 8:7 RXTHR controls when pcmRXR is set
 | 
			
		||||
	pcmRXThresholdOne  pcmCS = 0 << 7 // One sample in RX FIFO
 | 
			
		||||
	pcmRXThreshold1    pcmCS = 1 << 7 // RX FIFO is at least (?) full
 | 
			
		||||
	pcmRXThreshold2    pcmCS = 2 << 7 // ?
 | 
			
		||||
	pcmRXThresholdFull pcmCS = 3 << 7 // RX is full
 | 
			
		||||
	// 6:5 TXTHR controls when pcmTXW is set
 | 
			
		||||
	pcmTXThresholdEmpty    pcmCS = 0 << 5 // TX FIFO is empty
 | 
			
		||||
	pcmTXThresholdNotFull1 pcmCS = 1 << 5 // At least one sample can be put
 | 
			
		||||
	pcmTXThresholdNotFull2 pcmCS = 2 << 5 // At least one sample can be put
 | 
			
		||||
	pcmTXThresholdOne      pcmCS = 3 << 5 // One sample can be put
 | 
			
		||||
	pcmRXClear             pcmCS = 1 << 4 // RXCLR Clear RX FIFO; takes 2 PCM clock to take effect
 | 
			
		||||
	pcmTXClear             pcmCS = 1 << 3 // TXCLR Clear TX FIFO; takes 2 PCM clock to take effect
 | 
			
		||||
	pcmTXEnable            pcmCS = 1 << 2 // TXON Enable TX
 | 
			
		||||
	pcmRXEnable            pcmCS = 1 << 1 // RXON Enable FX
 | 
			
		||||
	pcmEnable              pcmCS = 1 << 0 // EN Enable the PCM
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type pcmMode uint32
 | 
			
		||||
 | 
			
		||||
// Page 129-131
 | 
			
		||||
const (
 | 
			
		||||
	// 31:29 reserved
 | 
			
		||||
	pcmClockDisable     pcmMode = 1 << 28                     // CLK_DIS Cleanly disable the PCM clock
 | 
			
		||||
	pcmDecimation32     pcmMode = 1 << 27                     // PDMN; 0 is factor 16, 1 is factor 32
 | 
			
		||||
	pcmRXPDMFilter      pcmMode = 1 << 26                     // PDME Enable input CIC filter on PDM input
 | 
			
		||||
	pcmRXMerge          pcmMode = 1 << 25                     // FRXP Merge both channels as single FIFO entry
 | 
			
		||||
	pcmTXMerge          pcmMode = 1 << 24                     // FTXP Merge both channels as singe FIFO entry
 | 
			
		||||
	pcmClockSlave       pcmMode = 1 << 23                     // CLKM PCM CLK is input
 | 
			
		||||
	pcmClockInverted    pcmMode = 1 << 22                     // CLKI Inverse clock signal
 | 
			
		||||
	pcmFSSlave          pcmMode = 1 << 21                     // FSM PCM FS is input
 | 
			
		||||
	pcmFSInverted       pcmMode = 1 << 20                     // FSI Invese FS signal
 | 
			
		||||
	pcmFrameLengthShift         = 10                          //
 | 
			
		||||
	pcmFrameLenghtMask  pcmMode = 0x3F << pcmFrameLengthShift // FLEN Frame length + 1
 | 
			
		||||
	pcmFSLenghtMask     pcmMode = 0x3F << 0                   // FSLEN FS pulse clock width
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type pcmRX uint32
 | 
			
		||||
 | 
			
		||||
// Page 131-132
 | 
			
		||||
const (
 | 
			
		||||
	pcmRX1Width     pcmRX = 1 << 31 // CH1WEX Legacy
 | 
			
		||||
	pcmRX1Enable    pcmRX = 1 << 30 // CH1EN
 | 
			
		||||
	pcmRX1PosShift        = 20
 | 
			
		||||
	pcmRX1PosMask   pcmRX = 0x3F << pcmRX1PosShift // CH1POS Clock delay
 | 
			
		||||
	pcmRX1Channel16 pcmRX = 8 << 16                // CH1WID (Arbitrary width between 8 and 16 is supported)
 | 
			
		||||
	pcmRX2Width     pcmRX = 1 << 15                // CH2WEX Legacy
 | 
			
		||||
	pcmRX2Enable    pcmRX = 1 << 14                // CH2EN
 | 
			
		||||
	pcmRX2PosShift        = 4
 | 
			
		||||
	pcmRX2PosMask   pcmRX = 0x3F << pcmRX2PosShift // CH2POS Clock delay
 | 
			
		||||
	pcmRX2Channel16 pcmRX = 8 << 0                 // CH2WID (Arbitrary width between 8 and 16 is supported)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type pcmTX uint32
 | 
			
		||||
 | 
			
		||||
// Page 133-134
 | 
			
		||||
const (
 | 
			
		||||
	pcmTX1Width     pcmTX = 1 << 31 // CH1WX Legacy
 | 
			
		||||
	pcmTX1Enable    pcmTX = 1 << 30 // CH1EN Enable channel 1
 | 
			
		||||
	pcmTX1PosShift        = 20
 | 
			
		||||
	pcmTX1PosMask   pcmTX = 0x3F << pcmTX1PosShift // CH1POS Clock delay
 | 
			
		||||
	pcmTX1Channel16 pcmTX = 8 << 16                // CH1WID (Arbitrary width between 8 and 16 is supported)
 | 
			
		||||
	pcmTX2Width     pcmTX = 1 << 15                // CH2WEX Legacy
 | 
			
		||||
	pcmTX2Enable    pcmTX = 1 << 14                // CH2EN
 | 
			
		||||
	pcmTX2PosShift        = 4
 | 
			
		||||
	pcmTX2PosMask   pcmTX = 0x3F << pcmTX2PosShift // CH2POS Clock delay
 | 
			
		||||
	pcmTX2Channel16 pcmTX = 8 << 0                 // CH2WID (Arbitrary width between 8 and 16 is supported)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type pcmDreq uint32
 | 
			
		||||
 | 
			
		||||
// Page 134-135
 | 
			
		||||
const (
 | 
			
		||||
	// 31 reserved
 | 
			
		||||
	pcmDreqTXPanicShift         = 24
 | 
			
		||||
	pcmDreqTXPanicMask  pcmDreq = 0x7F << pcmDreqTXPanicShift // TX_PANIC Panic level
 | 
			
		||||
	// 23 reserved
 | 
			
		||||
	pcmDreqRXPanicShift         = 16
 | 
			
		||||
	pcmDreqRXPanicMask  pcmDreq = 0x7F << pcmDreqRXPanicShift // RX_PANIC Panic level
 | 
			
		||||
	// 15 reserved
 | 
			
		||||
	pcmDreqTXLevelShift         = 8
 | 
			
		||||
	pcmDreqTXLevelMask  pcmDreq = 0x7F << pcmDreqTXPanicShift // TX Request Level
 | 
			
		||||
	// 7 reserved
 | 
			
		||||
	pcmDreqRXLevelShift         = 0
 | 
			
		||||
	pcmDreqRXLevelMask  pcmDreq = 0x7F << pcmDreqRXPanicShift // RX Request Level
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type pcmInterrupt uint32
 | 
			
		||||
 | 
			
		||||
// Page 135
 | 
			
		||||
const (
 | 
			
		||||
	// 31:4 reserved
 | 
			
		||||
	pcmIntRXErr    pcmInterrupt = 1 << 3 // RXERR RX error interrupt enable
 | 
			
		||||
	pcmIntTXErr    pcmInterrupt = 1 << 2 // TXERR TX error interrupt enable
 | 
			
		||||
	pcmIntRXEnable pcmInterrupt = 1 << 1 // RXR RX Read interrupt enable
 | 
			
		||||
	pcmIntTXEnable pcmInterrupt = 1 << 0 // TXW TX Write interrupt enable
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type pcmIntStatus uint32
 | 
			
		||||
 | 
			
		||||
// Page 135-136
 | 
			
		||||
const (
 | 
			
		||||
	// 31:4 reserved
 | 
			
		||||
	pcmIntStatRXErr    pcmIntStatus = 1 << 3 // RXERR RX error occurred / clear
 | 
			
		||||
	pcmIntStatTXErr    pcmIntStatus = 1 << 2 // TXERR TX error occurred / clear
 | 
			
		||||
	pcmIntStatRXEnable pcmIntStatus = 1 << 1 // RXR RX Read interrupt occurred / clear
 | 
			
		||||
	pcmIntStatTXEnable pcmIntStatus = 1 << 0 // TXW TX Write interrupt occurred / clear
 | 
			
		||||
	pcmIntStatusClear  pcmIntStatus = 0xF
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// pcmGray puts it into a special data/strobe mode that is under 'best effort'
 | 
			
		||||
// contract.
 | 
			
		||||
type pcmGray uint32
 | 
			
		||||
 | 
			
		||||
// Page 136-137
 | 
			
		||||
const (
 | 
			
		||||
	// 31:22 reserved
 | 
			
		||||
	pcmGrayRXFIFOLevelShift         = 16
 | 
			
		||||
	pcmGrayRXFIFOLevelMask  pcmGray = 0x3F << pcmGrayRXFIFOLevelShift // RXFIFOLEVEL How many words in RXFIFO
 | 
			
		||||
	pcmGrayFlushShift               = 10
 | 
			
		||||
	pcmGrayFlushMask                = 0x3F << pcmGrayFlushShift // FLUSHED How many bits were valid when flush occurred
 | 
			
		||||
	pcmGrayRXLevelShift             = 4
 | 
			
		||||
	pcmGrayRXLevelMask      pcmGray = 0x3F << pcmGrayRXLevelShift // RXLEVEL How many GRAY coded bits received
 | 
			
		||||
	pcmGrayFlush            pcmGray = 1 << 2                      // FLUSH
 | 
			
		||||
	pcmGrayClear            pcmGray = 1 << 1                      // CLR
 | 
			
		||||
	pcmGrayEnable           pcmGray = 1 << 0                      // EN
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Page 119
 | 
			
		||||
type pcmMap struct {
 | 
			
		||||
	cs     pcmCS        // CS_A Control Status
 | 
			
		||||
	fifo   uint32       // FIFO_A FIFO register
 | 
			
		||||
	mode   pcmMode      // MODE_A Operation mode
 | 
			
		||||
	rxc    pcmRX        // RXC_A RX control
 | 
			
		||||
	txc    pcmTX        // TXC_A TX control
 | 
			
		||||
	dreq   pcmDreq      // DREQ_A DMA control
 | 
			
		||||
	inten  pcmInterrupt // INTEN_A Interrupt enable
 | 
			
		||||
	intstc pcmIntStatus // INTSTC_A Interrupt status
 | 
			
		||||
	gray   pcmGray      // GRAY Gray mode input processing
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *pcmMap) GoString() string {
 | 
			
		||||
	return fmt.Sprintf(
 | 
			
		||||
		"{\n  cs:     0x%x,\n  mode:   0x%x,\n  rxc:    0x%x,\n  txc:    0x%x,\n  dreq:   0x%x,\n  inten:  0x%x,\n  intstc: 0x%x,\n  gray:   0x%x,\n}",
 | 
			
		||||
		p.cs, p.mode, p.rxc, p.txc, p.dreq, p.inten, p.intstc, p.gray)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *pcmMap) reset() {
 | 
			
		||||
	p.cs = 0
 | 
			
		||||
	// In theory need to wait the equivalent of 2 PCM clocks.
 | 
			
		||||
	// TODO(maruel): Use pcmSync busy loop to synchronize.
 | 
			
		||||
	Nanospin(time.Microsecond)
 | 
			
		||||
	// Hard reset
 | 
			
		||||
	p.fifo = 0
 | 
			
		||||
	p.mode = 0
 | 
			
		||||
	p.rxc = 0
 | 
			
		||||
	p.txc = 0
 | 
			
		||||
	p.dreq = 0
 | 
			
		||||
	p.inten = 0
 | 
			
		||||
	p.intstc = pcmIntStatusClear
 | 
			
		||||
	p.gray = 0
 | 
			
		||||
 | 
			
		||||
	// Clear pcmStandby / pcm
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// set initializes 8 bits stream via DMA with no delay and no FS.
 | 
			
		||||
func (p *pcmMap) set() {
 | 
			
		||||
	p.cs |= pcmEnable
 | 
			
		||||
	p.txc = pcmTX1Width | pcmTX1Channel16 | pcmTX1Enable // 32bit TX
 | 
			
		||||
	p.mode = (32 - 1) << pcmFrameLengthShift
 | 
			
		||||
	p.cs |= pcmTXClear | pcmRXClear
 | 
			
		||||
	// In theory need to wait the equivalent of 2 PCM clocks.
 | 
			
		||||
	// TODO(maruel): Use pcmSync busy loop to synchronize.
 | 
			
		||||
	Nanospin(time.Microsecond)
 | 
			
		||||
	p.dreq = 0x10<<pcmDreqTXPanicShift | 0x30<<pcmDreqTXLevelShift
 | 
			
		||||
	p.cs |= pcmDMAEnable
 | 
			
		||||
	//  pcmTXThresholdOne ?
 | 
			
		||||
	p.cs |= pcmTXEnable
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// setPCMClockSource sets the PCM clock.
 | 
			
		||||
//
 | 
			
		||||
// It may select an higher frequency than the one requested.
 | 
			
		||||
//
 | 
			
		||||
// Other potentially good clock sources are PWM, SPI and UART.
 | 
			
		||||
func setPCMClockSource(f physic.Frequency) (physic.Frequency, uint32, error) {
 | 
			
		||||
	if drvDMA.pcmMemory == nil {
 | 
			
		||||
		return 0, 0, errors.New("subsystem PCM not initialized")
 | 
			
		||||
	}
 | 
			
		||||
	if drvDMA.clockMemory == nil {
 | 
			
		||||
		return 0, 0, errors.New("subsystem Clock not initialized")
 | 
			
		||||
	}
 | 
			
		||||
	actual, divs, err := drvDMA.clockMemory.pcm.set(f, 1)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		drvDMA.pcmMemory.cs = 0
 | 
			
		||||
	}
 | 
			
		||||
	// Convert divisor into wait cycles.
 | 
			
		||||
	return actual, divs, err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										272
									
								
								vendor/periph.io/x/periph/host/bcm283x/pwm.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										272
									
								
								vendor/periph.io/x/periph/host/bcm283x/pwm.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,272 @@
 | 
			
		||||
// Copyright 2017 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.
 | 
			
		||||
 | 
			
		||||
package bcm283x
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"periph.io/x/periph/conn/physic"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// PWENi is used to enable/disable the corresponding channel. Setting this bit
 | 
			
		||||
// to 1 enables the channel and transmitter state machine. All registers and
 | 
			
		||||
// FIFO is writable without setting this bit.
 | 
			
		||||
//
 | 
			
		||||
// MODEi bit is used to determine mode of operation. Setting this bit to 0
 | 
			
		||||
// enables PWM mode. In this mode data stored in either PWM_DATi or FIFO is
 | 
			
		||||
// transmitted by pulse width modulation within the range defined by PWM_RNGi.
 | 
			
		||||
// When this mode is used MSENi defines whether to use PWM algorithm. Setting
 | 
			
		||||
// MODEi to 1 enables serial mode, in which data stored in either PWM_DATi or
 | 
			
		||||
// FIFO is transmitted serially within the range defined by PWM_RNGi. Data is
 | 
			
		||||
// transmitted MSB first and truncated or zeropadded depending on PWM_RNGi.
 | 
			
		||||
// Default mode is PWM.
 | 
			
		||||
//
 | 
			
		||||
// RPTLi is used to enable/disable repeating of the last data available in the
 | 
			
		||||
// FIFO just before it empties. When this bit is 1 and FIFO is used, the last
 | 
			
		||||
// available data in the FIFO is repeatedly sent. This may be useful in PWM
 | 
			
		||||
// mode to avoid duty cycle gaps. If the FIFO is not used this bit does not
 | 
			
		||||
// have any effect. Default operation is do-notrepeat.
 | 
			
		||||
//
 | 
			
		||||
// SBITi defines the state of the output when no transmission takes place. It
 | 
			
		||||
// also defines the zero polarity for the zero padding in serialiser mode. This
 | 
			
		||||
// bit is padded between two consecutive transfers as well as tail of the data
 | 
			
		||||
// when PWM_RNGi is larger than bit depth of data being transferred. this bit
 | 
			
		||||
// is zero by default.
 | 
			
		||||
//
 | 
			
		||||
// POLAi is used to configure the polarity of the output bit. When set to high
 | 
			
		||||
// the final output is inverted. Default operation is no inversion.
 | 
			
		||||
//
 | 
			
		||||
// USEFi bit is used to enable/disable FIFO transfer. When this bit is high
 | 
			
		||||
// data stored in the FIFO is used for transmission. When it is low, data
 | 
			
		||||
// written to PWM_DATi is transferred. This bit is 0 as default.
 | 
			
		||||
//
 | 
			
		||||
// CLRF is used to clear the FIFO. Writing a 1 to this bit clears the FIFO.
 | 
			
		||||
// Writing 0 has no effect. This is a single shot operation and reading the bit
 | 
			
		||||
// always returns 0.
 | 
			
		||||
//
 | 
			
		||||
// MSENi is used to determine whether to use PWM algorithm or simple M/S ratio
 | 
			
		||||
// transmission. When this bit is high M/S transmission is used. This bit is
 | 
			
		||||
// zero as default. When MODEi is 1, this configuration bit has no effect.
 | 
			
		||||
//
 | 
			
		||||
// See page 139-140 for the description of the PWM and M/S ratio algorithms.
 | 
			
		||||
const (
 | 
			
		||||
	// 31:16 reserved
 | 
			
		||||
	pwm2MS pwmControl = 1 << 15 // MSEN2; 0: PWM algorithm is used; 1: M/S transmission is used
 | 
			
		||||
	// 14 reserved
 | 
			
		||||
	pwm2UseFIFO        pwmControl = 1 << 13 // USEF2; 0: Data register is transmitted; 1: Fifo is used for transmission
 | 
			
		||||
	pwm2Polarity       pwmControl = 1 << 12 // POLA2; 0: 0=low 1=high; 1: 1=low 0=high
 | 
			
		||||
	pwm2SilenceHigh    pwmControl = 1 << 11 // SBIT2; Defines the state of the output when no transmission takes place
 | 
			
		||||
	pwm2RepeatLastData pwmControl = 1 << 10 // RPTL2; 0: Transmission interrupts when FIFO is empty; 1: Last data in FIFO is transmitted repetedly until FIFO is not empty
 | 
			
		||||
	pwm2Serialiser     pwmControl = 1 << 9  // MODE2; 0: PWM mode; 1: Serialiser mode
 | 
			
		||||
	pwm2Enable         pwmControl = 1 << 8  // PWEN2; Enable channel 2
 | 
			
		||||
	pwm2Mask           pwmControl = pwm2MS | pwm2UseFIFO | pwm2Polarity | pwm2SilenceHigh | pwm2RepeatLastData | pwm2Serialiser | pwm2Enable
 | 
			
		||||
	pwm1MS             pwmControl = 1 << 7 // MSEN1; 0: PWM algorithm is used; 1: M/S transmission is used
 | 
			
		||||
	pwmClearFIFO       pwmControl = 1 << 6 // CLRF1; Clear the fifo
 | 
			
		||||
	pwm1UseFIFO        pwmControl = 1 << 5 // USEF1; 0: Data register is transmitted; 1: Fifo is used for transmission
 | 
			
		||||
	pwm1Polarity       pwmControl = 1 << 4 // POLA1; 0: 0=low 1=high; 1: 1=low 0=high
 | 
			
		||||
	pwm1SilenceHigh    pwmControl = 1 << 3 // SBIT1; Defines the state of the output when no transmission takes place
 | 
			
		||||
	pwm1RepeatLastData pwmControl = 1 << 2 // RPTL1; 0: Transmission interrupts when FIFO is empty; 1: Last data in FIFO is transmitted repetedly until FIFO is not empty
 | 
			
		||||
	pwm1Serialiser     pwmControl = 1 << 1 // MODE1; 0: PWM mode; 1: Serialiser mode
 | 
			
		||||
	pwm1Enable         pwmControl = 1 << 0 // PWEN1; Enable channel 1
 | 
			
		||||
	pwm1Mask           pwmControl = pwm1MS | pwm1UseFIFO | pwm1Polarity | pwm1SilenceHigh | pwm1RepeatLastData | pwm1Serialiser | pwm1Enable
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Pages 141-143.
 | 
			
		||||
type pwmControl uint32
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// 31:13 reserved
 | 
			
		||||
	// STAi bit indicates the current state of the channel which is useful for
 | 
			
		||||
	// debugging purposes. The bit set means the channel is currently
 | 
			
		||||
	// transmitting data.
 | 
			
		||||
	pwmSta4 pwmStatus = 1 << 12 // STA4
 | 
			
		||||
	pwmSta3 pwmStatus = 1 << 11 // STA3
 | 
			
		||||
	pwmSta2 pwmStatus = 1 << 10 // STA2
 | 
			
		||||
	pwmSta1 pwmStatus = 1 << 9  // STA1
 | 
			
		||||
	// BERR sets to high when an error has occurred while writing to registers
 | 
			
		||||
	// via APB. This may happen if the bus tries to write successively to same
 | 
			
		||||
	// set of registers faster than the synchroniser block can cope with.
 | 
			
		||||
	// Multiple switching may occur and contaminate the data during
 | 
			
		||||
	// synchronisation. Software should clear this bit by writing 1. Writing 0
 | 
			
		||||
	// to this bit has no effect.
 | 
			
		||||
	pwmBusErr pwmStatus = 1 << 8 // BERR Bus Error flag
 | 
			
		||||
	// GAPOi. bit indicates that there has been a gap between transmission of two
 | 
			
		||||
	// consecutive data from FIFO. This may happen when FIFO gets empty after
 | 
			
		||||
	// state machine has sent a word and waits for the next. If control bit RPTLi
 | 
			
		||||
	// is set to high this event will not occur. Software must clear this bit by
 | 
			
		||||
	// writing 1. Writing 0 to this bit has no effect.
 | 
			
		||||
	pwmGapo4 pwmStatus = 1 << 7 // GAPO4 Channel 4 Gap Occurred flag
 | 
			
		||||
	pwmGapo3 pwmStatus = 1 << 6 // GAPO3 Channel 3 Gap Occurred flag
 | 
			
		||||
	pwmGapo2 pwmStatus = 1 << 5 // GAPO2 Channel 2 Gap Occurred flag
 | 
			
		||||
	pwmGapo1 pwmStatus = 1 << 4 // GAPO1 Channel 1 Gap Occurred flag
 | 
			
		||||
	// RERR1 bit sets to high when a read when empty error occurs. Software must
 | 
			
		||||
	// clear this bit by writing 1. Writing 0 to this bit has no effect.
 | 
			
		||||
	pwmRerr1 pwmStatus = 1 << 3 // RERR1
 | 
			
		||||
	// WERR1 bit sets to high when a write when full error occurs. Software must
 | 
			
		||||
	// clear this bit by writing 1. Writing 0 to this bit has no effect.
 | 
			
		||||
	pwmWerr1 pwmStatus = 1 << 2 // WERR1
 | 
			
		||||
	// EMPT1 bit indicates the empty status of the FIFO. If this bit is high FIFO
 | 
			
		||||
	// is empty.
 | 
			
		||||
	pwmEmpt1 pwmStatus = 1 << 1 // EMPT1
 | 
			
		||||
	// FULL1 bit indicates the full status of the FIFO. If this bit is high FIFO
 | 
			
		||||
	// is full.
 | 
			
		||||
	pwmFull1      pwmStatus = 1 << 0 // FULL1
 | 
			
		||||
	pwmStatusMask           = pwmSta4 | pwmSta3 | pwmSta2 | pwmSta1 | pwmBusErr | pwmGapo4 | pwmGapo3 | pwmGapo2 | pwmGapo1 | pwmRerr1 | pwmWerr1 | pwmEmpt1 | pwmFull1
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Pages 144-145.
 | 
			
		||||
type pwmStatus uint32
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	pwmDMAEnable pwmDMACfg = 1 << 31 // ENAB
 | 
			
		||||
	// 30:16 reserved
 | 
			
		||||
	pwmPanicShift           = 16
 | 
			
		||||
	pwmPanicMask  pwmDMACfg = 0xFF << pwmPanicShift // PANIC Default is 7
 | 
			
		||||
	pwmDreqMask   pwmDMACfg = 0xFF                  // DREQ Default is 7
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Page 145.
 | 
			
		||||
type pwmDMACfg uint32
 | 
			
		||||
 | 
			
		||||
// pwmMap is the block to control the PWM generator.
 | 
			
		||||
//
 | 
			
		||||
// Note that pins are named PWM0 and PWM1 but the mapping uses channel numbers
 | 
			
		||||
// 1 and 2.
 | 
			
		||||
//   - PWM0: GPIO12, GPIO18, GPIO40, GPIO52.
 | 
			
		||||
//   - PWM1: GPIO13, GPIO19, GPIO41, GPIO45, GPIO53.
 | 
			
		||||
//
 | 
			
		||||
// Each channel works independently. They can either output a bitstream or a
 | 
			
		||||
// serialised version of up to eight 32 bits words.
 | 
			
		||||
//
 | 
			
		||||
// The default base PWM frequency is 100Mhz.
 | 
			
		||||
//
 | 
			
		||||
// Description at page 138-139.
 | 
			
		||||
//
 | 
			
		||||
// Page 140-141.
 | 
			
		||||
type pwmMap struct {
 | 
			
		||||
	ctl    pwmControl // CTL
 | 
			
		||||
	status pwmStatus  // STA
 | 
			
		||||
	dmaCfg pwmDMACfg  // DMAC
 | 
			
		||||
	// This register is used to define the range for the corresponding channel.
 | 
			
		||||
	// In PWM mode evenly distributed pulses are sent within a period of length
 | 
			
		||||
	// defined by this register. In serial mode serialised data is transmitted
 | 
			
		||||
	// within the same period. If the value in PWM_RNGi is less than 32, only the
 | 
			
		||||
	// first PWM_RNGi bits are sent resulting in a truncation. If it is larger
 | 
			
		||||
	// than 32 excess zero bits are padded at the end of data. Default value for
 | 
			
		||||
	// this register is 32.
 | 
			
		||||
	dummy1 uint32 // Padding
 | 
			
		||||
	rng1   uint32 // RNG1
 | 
			
		||||
	// This register stores the 32 bit data to be sent by the PWM Controller when
 | 
			
		||||
	// USEFi is 0. In PWM mode data is sent by pulse width modulation: the value
 | 
			
		||||
	// of this register defines the number of pulses which is sent within the
 | 
			
		||||
	// period defined by PWM_RNGi. In serialiser mode data stored in this
 | 
			
		||||
	// register is serialised and transmitted.
 | 
			
		||||
	dat1 uint32 // DAT1
 | 
			
		||||
	// This register is the FIFO input for the all channels. Data written to this
 | 
			
		||||
	// address is stored in channel FIFO and if USEFi is enabled for the channel
 | 
			
		||||
	// i it is used as data to be sent. This register is write only, and reading
 | 
			
		||||
	// this register will always return bus default return value, pwm0.
 | 
			
		||||
	// When more than one channel is enabled for FIFO usage, the data written
 | 
			
		||||
	// into the FIFO is shared between these channels in turn. For example if the
 | 
			
		||||
	// word series A B C D E F G H I .. is written to FIFO and two channels are
 | 
			
		||||
	// active and configured to use FIFO then channel 1 will transmit words A C E
 | 
			
		||||
	// G I .. and channel 2 will transmit words B D F H .. .  Note that
 | 
			
		||||
	// requesting data from the FIFO is in locked-step manner and therefore
 | 
			
		||||
	// requires tight coupling of state machines of the channels. If any of the
 | 
			
		||||
	// channel range (period) value is different than the others this will cause
 | 
			
		||||
	// the channels with small range values to wait between words hence resulting
 | 
			
		||||
	// in gaps between words. To avoid that, each channel sharing the FIFO should
 | 
			
		||||
	// be configured to use the same range value. Also note that RPTLi are not
 | 
			
		||||
	// meaningful when the FIFO is shared between channels as there is no defined
 | 
			
		||||
	// channel to own the last data in the FIFO. Therefore sharing channels must
 | 
			
		||||
	// have their RPTLi set to zero.
 | 
			
		||||
	//
 | 
			
		||||
	// If the set of channels to share the FIFO has been modified after a
 | 
			
		||||
	// configuration change, FIFO should be cleared before writing new data.
 | 
			
		||||
	fifo   uint32 // FIF1
 | 
			
		||||
	dummy2 uint32 // Padding
 | 
			
		||||
	rng2   uint32 // RNG2 Equivalent of rng1 for channel 2
 | 
			
		||||
	dat2   uint32 // DAT2 Equivalent of dat1 for channel 2
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// reset stops the PWM.
 | 
			
		||||
func (p *pwmMap) reset() {
 | 
			
		||||
	p.dmaCfg = 0
 | 
			
		||||
	p.ctl |= pwmClearFIFO
 | 
			
		||||
	p.ctl &^= pwm1Enable | pwm2Enable
 | 
			
		||||
	Nanospin(100 * time.Microsecond) // Cargo cult copied. Probably not necessary.
 | 
			
		||||
	p.status = pwmBusErr | pwmGapo1 | pwmGapo2 | pwmGapo3 | pwmGapo4 | pwmRerr1 | pwmWerr1
 | 
			
		||||
	Nanospin(100 * time.Microsecond)
 | 
			
		||||
	// Use the full 32 bits of DATi.
 | 
			
		||||
	p.rng1 = 32
 | 
			
		||||
	p.rng2 = 32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// setPWMClockSource sets the PWM clock for use by the DMA controller for
 | 
			
		||||
// pacing.
 | 
			
		||||
//
 | 
			
		||||
// It may select an higher frequency than the one requested.
 | 
			
		||||
//
 | 
			
		||||
// Other potentially good clock sources are PCM, SPI and UART.
 | 
			
		||||
func setPWMClockSource() (physic.Frequency, error) {
 | 
			
		||||
	if drvDMA.pwmMemory == nil {
 | 
			
		||||
		return 0, errors.New("subsystem PWM not initialized")
 | 
			
		||||
	}
 | 
			
		||||
	if drvDMA.clockMemory == nil {
 | 
			
		||||
		return 0, errors.New("subsystem Clock not initialized")
 | 
			
		||||
	}
 | 
			
		||||
	if drvDMA.pwmDMACh != nil {
 | 
			
		||||
		// Already initialized
 | 
			
		||||
		return drvDMA.pwmDMAFreq, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// divs * div must fit in rng1 registor.
 | 
			
		||||
	div := uint32(drvDMA.pwmBaseFreq / drvDMA.pwmDMAFreq)
 | 
			
		||||
	actual, divs, err := drvDMA.clockMemory.pwm.set(drvDMA.pwmBaseFreq, div)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if e := actual / physic.Frequency(divs*div); drvDMA.pwmDMAFreq != e {
 | 
			
		||||
		return 0, fmt.Errorf("Unexpected DMA frequency %s != %s (%d/%d/%d)", drvDMA.pwmDMAFreq, e, actual, divs, div)
 | 
			
		||||
	}
 | 
			
		||||
	// It acts as a clock multiplier, since this amount of data is sent per
 | 
			
		||||
	// clock tick.
 | 
			
		||||
	drvDMA.pwmMemory.rng1 = divs * div
 | 
			
		||||
	Nanospin(10 * time.Microsecond)
 | 
			
		||||
	// Periph data (?)
 | 
			
		||||
 | 
			
		||||
	// Use low priority.
 | 
			
		||||
	drvDMA.pwmMemory.dmaCfg = pwmDMAEnable | pwmDMACfg(15<<pwmPanicShift|15)
 | 
			
		||||
	Nanospin(10 * time.Microsecond)
 | 
			
		||||
	drvDMA.pwmMemory.ctl |= pwmClearFIFO
 | 
			
		||||
	Nanospin(10 * time.Microsecond)
 | 
			
		||||
	old := drvDMA.pwmMemory.ctl
 | 
			
		||||
	drvDMA.pwmMemory.ctl = (old & ^pwmControl(0xff)) | pwm1UseFIFO | pwm1Enable
 | 
			
		||||
 | 
			
		||||
	// Start DMA
 | 
			
		||||
	if drvDMA.pwmDMACh, drvDMA.pwmDMABuf, err = dmaWritePWMFIFO(); err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return drvDMA.pwmDMAFreq, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func resetPWMClockSource() error {
 | 
			
		||||
	if drvDMA.pwmDMACh != nil {
 | 
			
		||||
		drvDMA.pwmDMACh.reset()
 | 
			
		||||
		drvDMA.pwmDMACh = nil
 | 
			
		||||
	}
 | 
			
		||||
	if drvDMA.pwmDMABuf != nil {
 | 
			
		||||
		if err := drvDMA.pwmDMABuf.Close(); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		drvDMA.pwmDMABuf = nil
 | 
			
		||||
	}
 | 
			
		||||
	_, _, err := drvDMA.clockMemory.pwm.set(0, 0)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										134
									
								
								vendor/periph.io/x/periph/host/bcm283x/streams.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								vendor/periph.io/x/periph/host/bcm283x/streams.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,134 @@
 | 
			
		||||
// Copyright 2017 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.
 | 
			
		||||
 | 
			
		||||
package bcm283x
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"periph.io/x/periph/conn/gpio/gpiostream"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// uint32ToBitLSBF packs a bit offset found on slice `d` (that is actually
 | 
			
		||||
// uint32) back into a densely packed Bits stream.
 | 
			
		||||
func uint32ToBitLSBF(w []byte, d []uint8, bit uint8, skip int) {
 | 
			
		||||
	// Little endian.
 | 
			
		||||
	x := bit / 8
 | 
			
		||||
	d = d[x:]
 | 
			
		||||
	bit -= 8 * x
 | 
			
		||||
	mask := uint8(1) << bit
 | 
			
		||||
	for i := range w {
 | 
			
		||||
		w[i] = ((d[0]&mask)>>bit<<0 |
 | 
			
		||||
			(d[skip*1]&mask)>>bit<<1 |
 | 
			
		||||
			(d[skip*2]&mask)>>bit<<2 |
 | 
			
		||||
			(d[skip*3]&mask)>>bit<<3 |
 | 
			
		||||
			(d[skip*4]&mask)>>bit<<4 |
 | 
			
		||||
			(d[skip*5]&mask)>>bit<<5 |
 | 
			
		||||
			(d[skip*6]&mask)>>bit<<6 |
 | 
			
		||||
			(d[skip*7]&mask)>>bit<<7)
 | 
			
		||||
		d = d[skip*8:]
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getBit(b byte, index int, msb bool) byte {
 | 
			
		||||
	var shift uint
 | 
			
		||||
	if msb {
 | 
			
		||||
		shift = uint(7 - index)
 | 
			
		||||
	} else {
 | 
			
		||||
		shift = uint(index)
 | 
			
		||||
	}
 | 
			
		||||
	return (b >> shift) & 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func raster32Bits(s gpiostream.Stream, skip int, clear, set []uint32, mask uint32) error {
 | 
			
		||||
	var msb bool
 | 
			
		||||
	var bits []byte
 | 
			
		||||
	switch b := s.(type) {
 | 
			
		||||
	case *gpiostream.BitStream:
 | 
			
		||||
		msb = !b.LSBF
 | 
			
		||||
		bits = b.Bits
 | 
			
		||||
	default:
 | 
			
		||||
		return fmt.Errorf("Unsupported type %T", b)
 | 
			
		||||
	}
 | 
			
		||||
	m := len(clear) / 8
 | 
			
		||||
	if n := len(bits); n < m {
 | 
			
		||||
		m = n
 | 
			
		||||
	}
 | 
			
		||||
	index := 0
 | 
			
		||||
	for i := 0; i < m; i++ {
 | 
			
		||||
		for j := 0; j < 8; j++ {
 | 
			
		||||
			if getBit(bits[i], j, msb) != 0 {
 | 
			
		||||
				for k := 0; k < skip; k++ {
 | 
			
		||||
					set[index] |= mask
 | 
			
		||||
					index++
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				for k := 0; k < skip; k++ {
 | 
			
		||||
					clear[index] |= mask
 | 
			
		||||
					index++
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// raster32 rasters the stream into a uint32 stream with the specified masks to
 | 
			
		||||
// put in the correctly slice when the bit is set and when it is clear.
 | 
			
		||||
//
 | 
			
		||||
// `s` must be one of the types in this package.
 | 
			
		||||
func raster32(s gpiostream.Stream, skip int, clear, set []uint32, mask uint32) error {
 | 
			
		||||
	if mask == 0 {
 | 
			
		||||
		return errors.New("bcm283x: mask is 0")
 | 
			
		||||
	}
 | 
			
		||||
	if len(clear) == 0 {
 | 
			
		||||
		return errors.New("bcm283x: clear buffer is empty")
 | 
			
		||||
	}
 | 
			
		||||
	if len(set) == 0 {
 | 
			
		||||
		return errors.New("bcm283x: set buffer is empty")
 | 
			
		||||
	}
 | 
			
		||||
	if len(clear) != len(set) {
 | 
			
		||||
		return errors.New("bcm283x: clear and set buffers have different length")
 | 
			
		||||
	}
 | 
			
		||||
	switch x := s.(type) {
 | 
			
		||||
	case *gpiostream.BitStream:
 | 
			
		||||
		// TODO
 | 
			
		||||
		return raster32Bits(x, skip, clear, set, mask)
 | 
			
		||||
	case *gpiostream.EdgeStream:
 | 
			
		||||
		return errors.New("bcm283x: EdgeStream is not supported yet")
 | 
			
		||||
	case *gpiostream.Program:
 | 
			
		||||
		return errors.New("bcm283x: Program is not supported yet")
 | 
			
		||||
	default:
 | 
			
		||||
		return errors.New("bcm283x: unknown stream type")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PCM/PWM DMA buf is encoded as little-endian and MSB first.
 | 
			
		||||
func copyStreamToDMABuf(w gpiostream.Stream, dst []uint32) error {
 | 
			
		||||
	switch v := w.(type) {
 | 
			
		||||
	case *gpiostream.BitStream:
 | 
			
		||||
		if v.LSBF {
 | 
			
		||||
			return errors.New("TODO(simokawa): handle BitStream.LSBF")
 | 
			
		||||
		}
 | 
			
		||||
		// This is big-endian and MSB first.
 | 
			
		||||
		i := 0
 | 
			
		||||
		for ; i < len(v.Bits)/4; i++ {
 | 
			
		||||
			dst[i] = binary.BigEndian.Uint32(v.Bits[i*4:])
 | 
			
		||||
		}
 | 
			
		||||
		last := uint32(0)
 | 
			
		||||
		if mod := len(v.Bits) % 4; mod > 0 {
 | 
			
		||||
			for j := 0; j < mod; j++ {
 | 
			
		||||
				last |= (uint32(v.Bits[i*4+j])) << uint32(8*(3-j))
 | 
			
		||||
			}
 | 
			
		||||
			dst[i] = last
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	case *gpiostream.EdgeStream:
 | 
			
		||||
		return errors.New("TODO(simokawa): handle EdgeStream")
 | 
			
		||||
	default:
 | 
			
		||||
		return errors.New("Unsupported Stream type")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										60
									
								
								vendor/periph.io/x/periph/host/bcm283x/timer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								vendor/periph.io/x/periph/host/bcm283x/timer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,60 @@
 | 
			
		||||
// Copyright 2017 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.
 | 
			
		||||
 | 
			
		||||
package bcm283x
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"periph.io/x/periph/host/cpu"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ReadTime returns the time on a monotonic 1Mhz clock (1µs resolution).
 | 
			
		||||
//
 | 
			
		||||
// It only works if bcm283x-dma successfully loaded. Otherwise it returns 0.
 | 
			
		||||
func ReadTime() time.Duration {
 | 
			
		||||
	if drvDMA.timerMemory == nil {
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
	return (time.Duration(drvDMA.timerMemory.high)<<32 | time.Duration(drvDMA.timerMemory.low)) * time.Microsecond
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Nanospin spins the CPU without calling into the kernel code if possible.
 | 
			
		||||
func Nanospin(t time.Duration) {
 | 
			
		||||
	start := ReadTime()
 | 
			
		||||
	if start == 0 {
 | 
			
		||||
		// Use the slow generic version.
 | 
			
		||||
		cpu.Nanospin(t)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	// TODO(maruel): Optimize code path for sub-1µs duration.
 | 
			
		||||
	for ReadTime()-start < t {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// 31:4 reserved
 | 
			
		||||
	timerM3 = 1 << 3 // M3
 | 
			
		||||
	timerM2 = 1 << 2 // M2
 | 
			
		||||
	timerM1 = 1 << 1 // M1
 | 
			
		||||
	timerM0 = 1 << 0 // M0
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Page 173
 | 
			
		||||
type timerCtl uint32
 | 
			
		||||
 | 
			
		||||
// timerMap represents the registers to access the 1Mhz timer.
 | 
			
		||||
//
 | 
			
		||||
// Page 172
 | 
			
		||||
type timerMap struct {
 | 
			
		||||
	ctl  timerCtl // CS
 | 
			
		||||
	low  uint32   // CLO
 | 
			
		||||
	high uint32   // CHI
 | 
			
		||||
	c0   uint32   // 0
 | 
			
		||||
	c1   uint32   // C1
 | 
			
		||||
	c2   uint32   // C2
 | 
			
		||||
	c3   uint32   // C3
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user