bitbang/spi cleanup (#268)

- precalculate clock idle polarity and remove clockOn()/clockOff()
 - check for higher (unknown) modes and reject them
 - move internal functions down, to be grouped together
- idle clock on Connect
pull/1/head
Seán C. McCord 8 years ago committed by M-A
parent d2f71ca23c
commit 34b6d1d3d2

@ -33,5 +33,6 @@ Marc-Antoine Ruel <maruel@chromium.org> <maruel@gmail.com>
Matt Aimonetti <mattaimonetti@gmail.com>
Max Ekman <max@looplab.se>
Matias Insaurralde <matias@insaurral.de>
Seán C McCord <ulexus@gmail.com> <scm@cycoresys.com>
Stephan Sperber <sperberstephan@googlemail.com>
Thorsten von Eicken <tve@voneicken.com>

@ -76,6 +76,9 @@ func (s *SPI) Connect(f physic.Frequency, mode spi.Mode, bits int) (spi.Conn, er
if mode&spi.LSBFirst == spi.LSBFirst {
return nil, errors.New("bitbang-spi: LSBFirst mode not supported")
}
if mode >= 0x20 {
return nil, fmt.Errorf("bitbang-spi: unhandled mode %d(%s)", mode, mode.String())
}
s.spiConn.mu.Lock()
defer s.spiConn.mu.Unlock()
s.spiConn.freqDev = f
@ -84,6 +87,14 @@ func (s *SPI) Connect(f physic.Frequency, mode spi.Mode, bits int) (spi.Conn, er
}
s.spiConn.mode = mode
s.spiConn.bits = bits
s.spiConn.readAfterClockPulse = mode&spi.Mode1 == spi.Mode1
// Set clock idle polarity, ensuring an idle clock to start
s.spiConn.clockIdle = gpio.Level(mode&spi.Mode2 == spi.Mode2)
if err := s.spiConn.sck.Out(s.spiConn.clockIdle); err != nil {
return nil, fmt.Errorf("bitbang-spi: failed to idle clock: %v", err)
}
return &s.spiConn, nil
}
@ -132,12 +143,14 @@ type spiConn struct {
csn gpio.PinOut // CS
// Mutable.
mu sync.Mutex
freqPort physic.Frequency
freqDev physic.Frequency
mode spi.Mode
bits int
halfCycle time.Duration
mu sync.Mutex
freqPort physic.Frequency
freqDev physic.Frequency
clockIdle gpio.Level
readAfterClockPulse bool
mode spi.Mode
bits int
halfCycle time.Duration
}
func (s *spiConn) String() string {
@ -150,46 +163,6 @@ func (s *spiConn) Duplex() conn.Duplex {
return conn.Full
}
func (s *spiConn) clockOn() error {
if s.mode&spi.Mode2 == spi.Mode2 {
return s.sck.Out(gpio.Low)
}
return s.sck.Out(gpio.High)
}
func (s *spiConn) clockOff() error {
if s.mode&spi.Mode2 == spi.Mode2 {
return s.sck.Out(gpio.High)
}
return s.sck.Out(gpio.Low)
}
func (s *spiConn) readAfterClockPulse() bool {
return s.mode&spi.Mode1 == spi.Mode1
}
func (s *spiConn) assertCS() error {
if s.csn == nil || s.mode&spi.NoCS == spi.NoCS {
return nil
}
if err := s.csn.Out(gpio.Low); err != nil {
return err
}
s.sleepHalfCycle()
return nil
}
func (s *spiConn) unassertCS() error {
if s.csn == nil || s.mode&spi.NoCS == spi.NoCS {
return nil
}
if err := s.csn.Out(gpio.High); err != nil {
return err
}
s.sleepHalfCycle()
return nil
}
// Tx implements spi.Conn.
//
// BUG(maruel): Implement mode (HalfDuplex and LSBFirst remain to be done).
@ -213,14 +186,14 @@ func (s *spiConn) Tx(w, r []byte) (err error) {
}
s.sleepHalfCycle()
if err = s.clockOn(); err != nil {
if err = s.sck.Out(!s.clockIdle); err != nil {
return fmt.Errorf("bitbang-spi: failed to assert clock: %v", err)
}
s.sleepHalfCycle()
if s.readAfterClockPulse() {
if err = s.clockOff(); err != nil {
return fmt.Errorf("bitbang-spi: failed to unassert clock: %v", err)
if s.readAfterClockPulse {
if err = s.sck.Out(s.clockIdle); err != nil {
return fmt.Errorf("bitbang-spi: failed to idle clock: %v", err)
}
s.sleepHalfCycle()
}
@ -231,9 +204,9 @@ func (s *spiConn) Tx(w, r []byte) (err error) {
}
}
if !s.readAfterClockPulse() {
if err = s.clockOff(); err != nil {
return fmt.Errorf("bitbang-spi: failed to unassert clock: %v", err)
if !s.readAfterClockPulse {
if err = s.sck.Out(s.clockIdle); err != nil {
return fmt.Errorf("bitbang-spi: failed to idle clock: %v", err)
}
}
}
@ -284,5 +257,27 @@ func (s *spiConn) sleepHalfCycle() {
cpu.Nanospin(s.halfCycle)
}
func (s *spiConn) assertCS() error {
if s.csn == nil || s.mode&spi.NoCS == spi.NoCS {
return nil
}
if err := s.csn.Out(gpio.Low); err != nil {
return err
}
s.sleepHalfCycle()
return nil
}
func (s *spiConn) unassertCS() error {
if s.csn == nil || s.mode&spi.NoCS == spi.NoCS {
return nil
}
if err := s.csn.Out(gpio.High); err != nil {
return err
}
s.sleepHalfCycle()
return nil
}
var _ spi.PortCloser = &SPI{}
var _ fmt.Stringer = &SPI{}

Loading…
Cancel
Save