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 }