Skip to content

Commit 91539d9

Browse files
aykevldeadprogram
authored andcommitted
apa102: avoid creating garbage
Avoid creating unnecessary garbage in the following ways: * Use the Transfer method instead of the Tx method for single byte transfers. * Use a statically allocated buffer for the fixed start-of-frame sequence. Running this for a few minutes did not cause the garbage collector to run. Previously, it would run every second or so in a persistence-of-vision application.
1 parent c3f3af5 commit 91539d9

File tree

2 files changed

+20
-15
lines changed

2 files changed

+20
-15
lines changed

apa102/apa102.go

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ const (
1919
GRB
2020
)
2121

22+
var startFrame = []byte{0x00, 0x00, 0x00, 0x00}
23+
2224
// Device wraps APA102 SPI LEDs.
2325
type Device struct {
2426
bus SPI
@@ -30,6 +32,7 @@ type Device struct {
3032
// SPI from the TinyGo "machine" package implements this already.
3133
type SPI interface {
3234
Tx(w, r []byte) error
35+
Transfer(b byte) (byte, error)
3336
}
3437

3538
// New returns a new APA102 driver. Pass in a fully configured SPI bus.
@@ -51,22 +54,22 @@ func (d Device) WriteColors(cs []color.RGBA) (n int, err error) {
5154
// write data
5255
for _, c := range cs {
5356
// brightness is scaled to 5 bit value
54-
d.bus.Tx([]byte{0xe0 | (c.A >> 3)}, nil)
57+
d.bus.Transfer(0xe0 | (c.A >> 3))
5558

5659
// set the colors
5760
switch d.Order {
5861
case BRG:
59-
d.bus.Tx([]byte{c.B}, nil)
60-
d.bus.Tx([]byte{c.R}, nil)
61-
d.bus.Tx([]byte{c.G}, nil)
62+
d.bus.Transfer(c.B)
63+
d.bus.Transfer(c.R)
64+
d.bus.Transfer(c.G)
6265
case GRB:
63-
d.bus.Tx([]byte{c.G}, nil)
64-
d.bus.Tx([]byte{c.R}, nil)
65-
d.bus.Tx([]byte{c.B}, nil)
66+
d.bus.Transfer(c.G)
67+
d.bus.Transfer(c.R)
68+
d.bus.Transfer(c.B)
6669
case BGR:
67-
d.bus.Tx([]byte{c.B}, nil)
68-
d.bus.Tx([]byte{c.G}, nil)
69-
d.bus.Tx([]byte{c.R}, nil)
70+
d.bus.Transfer(c.B)
71+
d.bus.Transfer(c.G)
72+
d.bus.Transfer(c.R)
7073
}
7174
}
7275

@@ -86,14 +89,14 @@ func (d Device) Write(buf []byte) (n int, err error) {
8689

8790
// startFrame sends the start bytes for a strand of LEDs.
8891
func (d Device) startFrame() {
89-
d.bus.Tx([]byte{0x00, 0x00, 0x00, 0x00}, nil)
92+
d.bus.Tx(startFrame, nil)
9093
}
9194

9295
// endFrame sends the end frame marker with one extra bit per LED so
9396
// long strands of LEDs receive the necessary termination for updates.
9497
// See https://cpldcpu.wordpress.com/2014/11/30/understanding-the-apa102-superled/
9598
func (d Device) endFrame(count int) {
9699
for i := 0; i < count/16; i++ {
97-
d.bus.Tx([]byte{0xff}, nil)
100+
d.bus.Transfer(0xff)
98101
}
99102
}

apa102/softspi.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@ func (s *bbSPI) delay() {
4141
}
4242
}
4343

44-
// Transfer is used to send a single byte.
45-
func (s *bbSPI) Transfer(b byte) {
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) {
4647
for i := uint8(0); i < 8; i++ {
4748

4849
// half clock cycle high to start
@@ -63,6 +64,7 @@ func (s *bbSPI) Transfer(b byte) {
6364

6465
// for actual SPI would try to read the MISO value here
6566
s.delay()
66-
6767
}
68+
69+
return 0, nil
6870
}

0 commit comments

Comments
 (0)