tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/apa102/softspi.go (about)

     1  package apa102
     2  
     3  import "machine"
     4  
     5  // bbSPI is a dumb bit-bang implementation of SPI protocol that is hardcoded
     6  // to mode 0 and ignores trying to receive data. Just enough for the APA102.
     7  // Note: making this unexported for now because it is probable not suitable
     8  // most purposes other than the APA102 package. It might be desirable to make
     9  // this more generic and include it in the TinyGo "machine" package instead.
    10  type bbSPI struct {
    11  	SCK   machine.Pin
    12  	SDO   machine.Pin
    13  	Delay uint32
    14  }
    15  
    16  // Configure sets up the SCK and SDO pins as outputs and sets them low
    17  func (s *bbSPI) Configure() {
    18  	s.SCK.Configure(machine.PinConfig{Mode: machine.PinOutput})
    19  	s.SDO.Configure(machine.PinConfig{Mode: machine.PinOutput})
    20  	s.SCK.Low()
    21  	s.SDO.Low()
    22  	if s.Delay == 0 {
    23  		s.Delay = 1
    24  	}
    25  }
    26  
    27  // Tx matches signature of machine.SPI.Tx() and is used to send multiple bytes.
    28  // The r slice is ignored and no error will ever be returned.
    29  func (s *bbSPI) Tx(w []byte, r []byte) error {
    30  	s.Configure()
    31  	for _, b := range w {
    32  		s.Transfer(b)
    33  	}
    34  	return nil
    35  }
    36  
    37  // delay represents a quarter of the clock cycle
    38  func (s *bbSPI) delay() {
    39  	for i := uint32(0); i < s.Delay; {
    40  		i++
    41  	}
    42  }
    43  
    44  // Transfer matches signature of machine.SPI.Transfer() and is used to send a
    45  // single byte. The received data is ignored and no error will ever be returned.
    46  func (s *bbSPI) Transfer(b byte) (byte, error) {
    47  	for i := uint8(0); i < 8; i++ {
    48  
    49  		// half clock cycle high to start
    50  		s.SCK.High()
    51  		s.delay()
    52  
    53  		// write the value to SDO (MSB first)
    54  		if b&(1<<(7-i)) == 0 {
    55  			s.SDO.Low()
    56  		} else {
    57  			s.SDO.High()
    58  		}
    59  		s.delay()
    60  
    61  		// half clock cycle low
    62  		s.SCK.Low()
    63  		s.delay()
    64  
    65  		// for actual SPI would try to read the SDI value here
    66  		s.delay()
    67  	}
    68  
    69  	return 0, nil
    70  }