tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/apa102/apa102.go (about) 1 // Package apa102 implements a driver for the APA102 SPI LED. 2 // 3 // Datasheet: https://cdn-shop.adafruit.com/product-files/2343/APA102C.pdf 4 package apa102 // import "tinygo.org/x/drivers/apa102" 5 6 import ( 7 "image/color" 8 "machine" 9 10 "tinygo.org/x/drivers" 11 ) 12 13 const ( 14 // BGR aka "Blue Green Red" is the current APA102 LED color order. 15 BGR = iota 16 17 // BRG aka "Blue Red Green" is the typical APA102 color order from 2015-2017. 18 BRG 19 20 // GRB aka "Green Red Blue" is the typical APA102 color order from pre-2015. 21 GRB 22 ) 23 24 var startFrame = []byte{0x00, 0x00, 0x00, 0x00} 25 26 // Device wraps APA102 SPI LEDs. 27 type Device struct { 28 bus drivers.SPI 29 Order int 30 buf [4]byte 31 } 32 33 // New returns a new APA102 driver. Pass in a fully configured SPI bus. 34 func New(b drivers.SPI) *Device { 35 return &Device{bus: b, Order: BGR} 36 } 37 38 // NewSoftwareSPI returns a new APA102 driver that will use a software based 39 // implementation of the SPI protocol. 40 func NewSoftwareSPI(sckPin, sdoPin machine.Pin, delay uint32) *Device { 41 return New(&bbSPI{SCK: sckPin, SDO: sdoPin, Delay: delay}) 42 } 43 44 // WriteColors writes the given RGBA color slice out using the APA102 protocol. 45 // The A value (Alpha channel) is used for brightness, set to 0xff (255) for maximum. 46 func (d *Device) WriteColors(cs []color.RGBA) (n int, err error) { 47 d.startFrame() 48 49 // write data 50 for _, c := range cs { 51 // brightness is scaled to 5 bit value 52 d.buf[0] = 0xe0 | (c.A >> 3) 53 54 // set the colors 55 switch d.Order { 56 case BRG: 57 d.buf[1] = c.B 58 d.buf[2] = c.R 59 d.buf[3] = c.G 60 case GRB: 61 d.buf[1] = c.G 62 d.buf[2] = c.R 63 d.buf[3] = c.B 64 case BGR: 65 d.buf[1] = c.B 66 d.buf[2] = c.G 67 d.buf[3] = c.R 68 } 69 d.bus.Tx(d.buf[:], nil) 70 } 71 72 d.endFrame(len(cs)) 73 74 return len(cs), nil 75 } 76 77 // Write the raw bytes using the APA102 protocol. 78 func (d *Device) Write(buf []byte) (n int, err error) { 79 d.startFrame() 80 d.bus.Tx(buf, nil) 81 d.endFrame(len(buf) / 4) 82 83 return len(buf), nil 84 } 85 86 // startFrame sends the start bytes for a strand of LEDs. 87 func (d *Device) startFrame() { 88 d.bus.Tx(startFrame, nil) 89 } 90 91 // endFrame sends the end frame marker with one extra bit per LED so 92 // long strands of LEDs receive the necessary termination for updates. 93 // See https://cpldcpu.wordpress.com/2014/11/30/understanding-the-apa102-superled/ 94 func (d *Device) endFrame(count int) { 95 for i := 0; i < count/16; i++ { 96 d.bus.Transfer(0xff) 97 } 98 }