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> Matt Aimonetti <mattaimonetti@gmail.com>
Max Ekman <max@looplab.se> Max Ekman <max@looplab.se>
Matias Insaurralde <matias@insaurral.de> Matias Insaurralde <matias@insaurral.de>
Seán C McCord <ulexus@gmail.com> <scm@cycoresys.com>
Stephan Sperber <sperberstephan@googlemail.com> Stephan Sperber <sperberstephan@googlemail.com>
Thorsten von Eicken <tve@voneicken.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 { if mode&spi.LSBFirst == spi.LSBFirst {
return nil, errors.New("bitbang-spi: LSBFirst mode not supported") 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() s.spiConn.mu.Lock()
defer s.spiConn.mu.Unlock() defer s.spiConn.mu.Unlock()
s.spiConn.freqDev = f 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.mode = mode
s.spiConn.bits = bits 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 return &s.spiConn, nil
} }
@ -132,12 +143,14 @@ type spiConn struct {
csn gpio.PinOut // CS csn gpio.PinOut // CS
// Mutable. // Mutable.
mu sync.Mutex mu sync.Mutex
freqPort physic.Frequency freqPort physic.Frequency
freqDev physic.Frequency freqDev physic.Frequency
mode spi.Mode clockIdle gpio.Level
bits int readAfterClockPulse bool
halfCycle time.Duration mode spi.Mode
bits int
halfCycle time.Duration
} }
func (s *spiConn) String() string { func (s *spiConn) String() string {
@ -150,46 +163,6 @@ func (s *spiConn) Duplex() conn.Duplex {
return conn.Full 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. // Tx implements spi.Conn.
// //
// BUG(maruel): Implement mode (HalfDuplex and LSBFirst remain to be done). // 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() 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) return fmt.Errorf("bitbang-spi: failed to assert clock: %v", err)
} }
s.sleepHalfCycle() s.sleepHalfCycle()
if s.readAfterClockPulse() { if s.readAfterClockPulse {
if err = s.clockOff(); err != nil { if err = s.sck.Out(s.clockIdle); err != nil {
return fmt.Errorf("bitbang-spi: failed to unassert clock: %v", err) return fmt.Errorf("bitbang-spi: failed to idle clock: %v", err)
} }
s.sleepHalfCycle() s.sleepHalfCycle()
} }
@ -231,9 +204,9 @@ func (s *spiConn) Tx(w, r []byte) (err error) {
} }
} }
if !s.readAfterClockPulse() { if !s.readAfterClockPulse {
if err = s.clockOff(); err != nil { if err = s.sck.Out(s.clockIdle); err != nil {
return fmt.Errorf("bitbang-spi: failed to unassert clock: %v", err) return fmt.Errorf("bitbang-spi: failed to idle clock: %v", err)
} }
} }
} }
@ -284,5 +257,27 @@ func (s *spiConn) sleepHalfCycle() {
cpu.Nanospin(s.halfCycle) 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 _ spi.PortCloser = &SPI{}
var _ fmt.Stringer = &SPI{} var _ fmt.Stringer = &SPI{}

Loading…
Cancel
Save