From 70f3a511cc89715e5d9e7fe2c007c99041285aa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20G=C3=BCthner?= Date: Fri, 23 Jul 2021 12:12:51 +0200 Subject: [PATCH 1/3] APA102: Allow to specify SPI Mode --- apa102/apa102.go | 8 ++++++-- apa102/apa102_test.go | 28 ++++++++++++++-------------- apa102/example_test.go | 5 +++-- rainbowhat/rainbowhat.go | 3 ++- 4 files changed, 25 insertions(+), 19 deletions(-) diff --git a/apa102/apa102.go b/apa102/apa102.go index b68b8e7..d07ad78 100644 --- a/apa102/apa102.go +++ b/apa102/apa102.go @@ -92,8 +92,12 @@ type Opts struct { // As per APA102-C spec, the chip's max refresh rate is 400hz. // https://en.wikipedia.org/wiki/Flicker_fusion_threshold is a recommended // reading. -func New(p spi.Port, o *Opts) (*Dev, error) { - c, err := p.Connect(20*physic.MegaHertz, spi.Mode3, 8) +// +// Most devices can use spi.Mode3, but the raspberry pi 3 secondary SPI +// for example does not support this Mode. You may need to use spi.Mode0 +// in this and similar cases. +func New(p spi.Port, o *Opts, spiMode spi.Mode) (*Dev, error) { + c, err := p.Connect(20*physic.MegaHertz, spiMode, 8) if err != nil { return nil, err } diff --git a/apa102/apa102_test.go b/apa102/apa102_test.go index 9697127..90915e1 100644 --- a/apa102/apa102_test.go +++ b/apa102/apa102_test.go @@ -333,7 +333,7 @@ func TestDevEmpty(t *testing.T) { buf := bytes.Buffer{} o := DefaultOpts o.NumPixels = 0 - d, _ := New(spitest.NewRecordRaw(&buf), &o) + d, _ := New(spitest.NewRecordRaw(&buf), &o, spi.Mode3) if n, err := d.Write([]byte{}); n != 0 || err != nil { t.Fatalf("%d %v", n, err) } @@ -346,7 +346,7 @@ func TestDevEmpty(t *testing.T) { } func TestConnectFail(t *testing.T) { - if d, err := New(&configFail{}, &DefaultOpts); d != nil || err == nil { + if d, err := New(&configFail{}, &DefaultOpts, spi.Mode3); d != nil || err == nil { t.Fatal("Connect() call have failed") } } @@ -355,7 +355,7 @@ func TestDevLen(t *testing.T) { buf := bytes.Buffer{} o := DefaultOpts o.NumPixels = 1 - d, _ := New(spitest.NewRecordRaw(&buf), &o) + d, _ := New(spitest.NewRecordRaw(&buf), &o, spi.Mode3) if n, err := d.Write([]byte{0}); n != 0 || err == nil { t.Fatalf("%d %v", n, err) } @@ -555,7 +555,7 @@ func TestWrites(t *testing.T) { for _, tt := range writeTests { buf := bytes.Buffer{} tt.opts.NumPixels = len(tt.pixels) / 3 - d, _ := New(spitest.NewRecordRaw(&buf), &tt.opts) + d, _ := New(spitest.NewRecordRaw(&buf), &tt.opts, spi.Mode3) n, err := d.Write(tt.pixels) if err != nil { t.Fatal(err) @@ -580,7 +580,7 @@ func TestDevLong(t *testing.T) { colors := make([]color.NRGBA, 256) o := DefaultOpts o.NumPixels = len(colors) - d, _ := New(spitest.NewRecordRaw(&buf), &o) + d, _ := New(spitest.NewRecordRaw(&buf), &o, spi.Mode3) if n, err := d.Write(ToRGB(colors)); n != len(colors)*3 || err != nil { t.Fatalf("%d %v", n, err) } @@ -601,7 +601,7 @@ func TestDevWrite_Long(t *testing.T) { buf := bytes.Buffer{} o := DefaultOpts o.NumPixels = 1 - d, _ := New(spitest.NewRecordRaw(&buf), &o) + d, _ := New(spitest.NewRecordRaw(&buf), &o, spi.Mode3) if n, err := d.Write([]byte{0, 0, 0, 1, 1, 1}); n != 0 || err == nil { t.Fatal(n, err) } @@ -769,7 +769,7 @@ var drawTests = []struct { func TestDraws(t *testing.T) { for _, tt := range drawTests { buf := bytes.Buffer{} - d, _ := New(spitest.NewRecordRaw(&buf), &tt.opts) + d, _ := New(spitest.NewRecordRaw(&buf), &tt.opts, spi.Mode3) if err := d.Draw(d.Bounds(), tt.img, image.Point{}); err != nil { t.Fatalf("%s: %v", tt.name, err) } @@ -874,7 +874,7 @@ var offsetDrawTests = []struct { func TestOffsetDraws(t *testing.T) { for _, tt := range offsetDrawTests { buf := bytes.Buffer{} - d, _ := New(spitest.NewRecordRaw(&buf), &tt.opts) + d, _ := New(spitest.NewRecordRaw(&buf), &tt.opts, spi.Mode3) if err := d.Draw(tt.offset, tt.img, tt.point); err != nil { t.Fatalf("%s: %v", tt.name, err) } @@ -895,7 +895,7 @@ func TestHalt(t *testing.T) { o := DefaultOpts o.NumPixels = 4 o.Temperature = 5000 - d, _ := New(&s, &o) + d, _ := New(&s, &o, spi.Mode3) if err := d.Halt(); err != nil { t.Fatal(err) } @@ -925,7 +925,7 @@ func benchmarkWrite(b *testing.B, o Opts, length int, f genColor) { } o.NumPixels = length b.ReportAllocs() - d, _ := New(spitest.NewRecordRaw(ioutil.Discard), &o) + d, _ := New(spitest.NewRecordRaw(ioutil.Discard), &o, spi.Mode3) _, _ = d.Write(pixels[:]) b.ResetTimer() for i := 0; i < b.N; i++ { @@ -983,7 +983,7 @@ func BenchmarkWriteColorfulVariation(b *testing.B) { o.NumPixels = len(pixels) / 3 o.Intensity = 250 o.Temperature = 5000 - d, _ := New(spitest.NewRecordRaw(ioutil.Discard), &o) + d, _ := New(spitest.NewRecordRaw(ioutil.Discard), &o, spi.Mode3) _, _ = d.Write(pixels[:]) b.ResetTimer() for i := 0; i < b.N; i++ { @@ -1003,7 +1003,7 @@ func benchmarkDraw(b *testing.B, o Opts, img draw.Image, f genColor) { } o.NumPixels = img.Bounds().Max.X b.ReportAllocs() - d, _ := New(spitest.NewRecordRaw(ioutil.Discard), &o) + d, _ := New(spitest.NewRecordRaw(ioutil.Discard), &o, spi.Mode3) r := d.Bounds() p := image.Point{} if err := d.Draw(r, img, p); err != nil { @@ -1062,7 +1062,7 @@ func BenchmarkDrawSlowpath(b *testing.B) { o := DefaultOpts o.NumPixels = img.Bounds().Max.X b.ReportAllocs() - d, _ := New(spitest.NewRecordRaw(ioutil.Discard), &o) + d, _ := New(spitest.NewRecordRaw(ioutil.Discard), &o, spi.Mode3) r := d.Bounds() p := image.Point{} if err := d.Draw(r, img, p); err != nil { @@ -1078,7 +1078,7 @@ func BenchmarkDrawSlowpath(b *testing.B) { func BenchmarkHalt(b *testing.B) { b.ReportAllocs() - d, _ := New(spitest.NewRecordRaw(ioutil.Discard), &DefaultOpts) + d, _ := New(spitest.NewRecordRaw(ioutil.Discard), &DefaultOpts, spi.Mode3) b.ResetTimer() for i := 0; i < b.N; i++ { if err := d.Halt(); err != nil { diff --git a/apa102/example_test.go b/apa102/example_test.go index f37061c..b0e5709 100644 --- a/apa102/example_test.go +++ b/apa102/example_test.go @@ -9,6 +9,7 @@ import ( "image/color" "log" + "periph.io/x/conn/v3/spi" "periph.io/x/conn/v3/spi/spireg" "periph.io/x/devices/v3/apa102" "periph.io/x/host/v3" @@ -33,7 +34,7 @@ func Example() { o.NumPixels = 300 o.Intensity = 127 o.Temperature = 3500 - dev, err := apa102.New(p, &o) + dev, err := apa102.New(p, &o, spi.Mode0) if err != nil { log.Fatalf("failed to open: %v", err) } @@ -61,7 +62,7 @@ func ExampleToRGB() { o := apa102.PassThruOpts o.NumPixels = 2 - dev, err := apa102.New(p, &o) + dev, err := apa102.New(p, &o, spi.Mode3) if err != nil { log.Fatalf("failed to open: %v", err) } diff --git a/rainbowhat/rainbowhat.go b/rainbowhat/rainbowhat.go index 0853aeb..e7d6816 100644 --- a/rainbowhat/rainbowhat.go +++ b/rainbowhat/rainbowhat.go @@ -7,6 +7,7 @@ package rainbowhat import ( "periph.io/x/conn/v3/gpio" "periph.io/x/conn/v3/i2c/i2creg" + "periph.io/x/conn/v3/spi" "periph.io/x/conn/v3/spi/spireg" "periph.io/x/devices/v3/apa102" "periph.io/x/devices/v3/bmxx80" @@ -53,7 +54,7 @@ func NewRainbowHat(ao *apa102.Opts) (*Dev, error) { opts := *ao opts.NumPixels = 7 - ledstrip, err := apa102.New(spiPort, &opts) + ledstrip, err := apa102.New(spiPort, &opts, spi.Mode3) if err != nil { return nil, err } From c768f7de3c9fe0d198842c13822db1b8900027e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20G=C3=BCthner?= Date: Fri, 23 Jul 2021 13:46:51 +0200 Subject: [PATCH 2/3] update go.mod --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index b64427e..2b2c857 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ // Use of this source code is governed under the Apache License, Version 2.0 // that can be found in the LICENSE file. -module periph.io/x/devices/v3 +module github.com/GermanBionicSystems/devices go 1.13 From 20c235b4ec20a852fd1a1f37d6c5245f0b96492c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20G=C3=BCthner?= Date: Tue, 10 Aug 2021 12:44:36 +0200 Subject: [PATCH 3/3] apa102: make spimode part of the Opts --- apa102/apa102.go | 24 ++++++++++++++---------- apa102/apa102_test.go | 28 ++++++++++++++-------------- apa102/example_test.go | 5 ++--- go.mod | 2 +- rainbowhat/rainbowhat.go | 3 +-- 5 files changed, 32 insertions(+), 30 deletions(-) diff --git a/apa102/apa102.go b/apa102/apa102.go index d07ad78..859d6c9 100644 --- a/apa102/apa102.go +++ b/apa102/apa102.go @@ -36,10 +36,11 @@ const NeutralTemp uint16 = 6500 // DefaultOpts is the recommended default options. var DefaultOpts = Opts{ - NumPixels: 150, // 150 LEDs is a common strip length. - Intensity: 255, // Full blinding power. - Temperature: 5000, // More pleasing white balance than NeutralTemp. - DisableGlobalPWM: false, // Use full 13 bits range. + NumPixels: 150, // 150 LEDs is a common strip length. + Intensity: 255, // Full blinding power. + Temperature: 5000, // More pleasing white balance than NeutralTemp. + DisableGlobalPWM: false, // Use full 13 bits range. + SpiMode: spi.Mode3, // SPI Mode3 works on most devices. } // PassThruOpts makes the driver draw RGB pixels exactly as specified. @@ -51,6 +52,7 @@ var PassThruOpts = Opts{ Intensity: 255, Temperature: NeutralTemp, DisableGlobalPWM: true, + SpiMode: spi.Mode3, } // Opts defines the options for the device. @@ -81,6 +83,12 @@ type Opts struct { // to 8 bits, this also disables the dynamic perceptual mapping of intensity // since there is not enough bits of resolution to do it effectively. DisableGlobalPWM bool + // SpiMode sets the clock polarity and phase as one of the 4 possible SPI Modes. + // + // Most devices can use spi.Mode3, but the Raspberry Pi 3 secondary SPI port + // for example does not support this Mode. You may need to use spi.Mode0 + // in this and similar cases. + SpiMode spi.Mode } // New returns a strip that communicates over SPI to APA102 LEDs. @@ -92,12 +100,8 @@ type Opts struct { // As per APA102-C spec, the chip's max refresh rate is 400hz. // https://en.wikipedia.org/wiki/Flicker_fusion_threshold is a recommended // reading. -// -// Most devices can use spi.Mode3, but the raspberry pi 3 secondary SPI -// for example does not support this Mode. You may need to use spi.Mode0 -// in this and similar cases. -func New(p spi.Port, o *Opts, spiMode spi.Mode) (*Dev, error) { - c, err := p.Connect(20*physic.MegaHertz, spiMode, 8) +func New(p spi.Port, o *Opts) (*Dev, error) { + c, err := p.Connect(20*physic.MegaHertz, o.SpiMode, 8) if err != nil { return nil, err } diff --git a/apa102/apa102_test.go b/apa102/apa102_test.go index 90915e1..9697127 100644 --- a/apa102/apa102_test.go +++ b/apa102/apa102_test.go @@ -333,7 +333,7 @@ func TestDevEmpty(t *testing.T) { buf := bytes.Buffer{} o := DefaultOpts o.NumPixels = 0 - d, _ := New(spitest.NewRecordRaw(&buf), &o, spi.Mode3) + d, _ := New(spitest.NewRecordRaw(&buf), &o) if n, err := d.Write([]byte{}); n != 0 || err != nil { t.Fatalf("%d %v", n, err) } @@ -346,7 +346,7 @@ func TestDevEmpty(t *testing.T) { } func TestConnectFail(t *testing.T) { - if d, err := New(&configFail{}, &DefaultOpts, spi.Mode3); d != nil || err == nil { + if d, err := New(&configFail{}, &DefaultOpts); d != nil || err == nil { t.Fatal("Connect() call have failed") } } @@ -355,7 +355,7 @@ func TestDevLen(t *testing.T) { buf := bytes.Buffer{} o := DefaultOpts o.NumPixels = 1 - d, _ := New(spitest.NewRecordRaw(&buf), &o, spi.Mode3) + d, _ := New(spitest.NewRecordRaw(&buf), &o) if n, err := d.Write([]byte{0}); n != 0 || err == nil { t.Fatalf("%d %v", n, err) } @@ -555,7 +555,7 @@ func TestWrites(t *testing.T) { for _, tt := range writeTests { buf := bytes.Buffer{} tt.opts.NumPixels = len(tt.pixels) / 3 - d, _ := New(spitest.NewRecordRaw(&buf), &tt.opts, spi.Mode3) + d, _ := New(spitest.NewRecordRaw(&buf), &tt.opts) n, err := d.Write(tt.pixels) if err != nil { t.Fatal(err) @@ -580,7 +580,7 @@ func TestDevLong(t *testing.T) { colors := make([]color.NRGBA, 256) o := DefaultOpts o.NumPixels = len(colors) - d, _ := New(spitest.NewRecordRaw(&buf), &o, spi.Mode3) + d, _ := New(spitest.NewRecordRaw(&buf), &o) if n, err := d.Write(ToRGB(colors)); n != len(colors)*3 || err != nil { t.Fatalf("%d %v", n, err) } @@ -601,7 +601,7 @@ func TestDevWrite_Long(t *testing.T) { buf := bytes.Buffer{} o := DefaultOpts o.NumPixels = 1 - d, _ := New(spitest.NewRecordRaw(&buf), &o, spi.Mode3) + d, _ := New(spitest.NewRecordRaw(&buf), &o) if n, err := d.Write([]byte{0, 0, 0, 1, 1, 1}); n != 0 || err == nil { t.Fatal(n, err) } @@ -769,7 +769,7 @@ var drawTests = []struct { func TestDraws(t *testing.T) { for _, tt := range drawTests { buf := bytes.Buffer{} - d, _ := New(spitest.NewRecordRaw(&buf), &tt.opts, spi.Mode3) + d, _ := New(spitest.NewRecordRaw(&buf), &tt.opts) if err := d.Draw(d.Bounds(), tt.img, image.Point{}); err != nil { t.Fatalf("%s: %v", tt.name, err) } @@ -874,7 +874,7 @@ var offsetDrawTests = []struct { func TestOffsetDraws(t *testing.T) { for _, tt := range offsetDrawTests { buf := bytes.Buffer{} - d, _ := New(spitest.NewRecordRaw(&buf), &tt.opts, spi.Mode3) + d, _ := New(spitest.NewRecordRaw(&buf), &tt.opts) if err := d.Draw(tt.offset, tt.img, tt.point); err != nil { t.Fatalf("%s: %v", tt.name, err) } @@ -895,7 +895,7 @@ func TestHalt(t *testing.T) { o := DefaultOpts o.NumPixels = 4 o.Temperature = 5000 - d, _ := New(&s, &o, spi.Mode3) + d, _ := New(&s, &o) if err := d.Halt(); err != nil { t.Fatal(err) } @@ -925,7 +925,7 @@ func benchmarkWrite(b *testing.B, o Opts, length int, f genColor) { } o.NumPixels = length b.ReportAllocs() - d, _ := New(spitest.NewRecordRaw(ioutil.Discard), &o, spi.Mode3) + d, _ := New(spitest.NewRecordRaw(ioutil.Discard), &o) _, _ = d.Write(pixels[:]) b.ResetTimer() for i := 0; i < b.N; i++ { @@ -983,7 +983,7 @@ func BenchmarkWriteColorfulVariation(b *testing.B) { o.NumPixels = len(pixels) / 3 o.Intensity = 250 o.Temperature = 5000 - d, _ := New(spitest.NewRecordRaw(ioutil.Discard), &o, spi.Mode3) + d, _ := New(spitest.NewRecordRaw(ioutil.Discard), &o) _, _ = d.Write(pixels[:]) b.ResetTimer() for i := 0; i < b.N; i++ { @@ -1003,7 +1003,7 @@ func benchmarkDraw(b *testing.B, o Opts, img draw.Image, f genColor) { } o.NumPixels = img.Bounds().Max.X b.ReportAllocs() - d, _ := New(spitest.NewRecordRaw(ioutil.Discard), &o, spi.Mode3) + d, _ := New(spitest.NewRecordRaw(ioutil.Discard), &o) r := d.Bounds() p := image.Point{} if err := d.Draw(r, img, p); err != nil { @@ -1062,7 +1062,7 @@ func BenchmarkDrawSlowpath(b *testing.B) { o := DefaultOpts o.NumPixels = img.Bounds().Max.X b.ReportAllocs() - d, _ := New(spitest.NewRecordRaw(ioutil.Discard), &o, spi.Mode3) + d, _ := New(spitest.NewRecordRaw(ioutil.Discard), &o) r := d.Bounds() p := image.Point{} if err := d.Draw(r, img, p); err != nil { @@ -1078,7 +1078,7 @@ func BenchmarkDrawSlowpath(b *testing.B) { func BenchmarkHalt(b *testing.B) { b.ReportAllocs() - d, _ := New(spitest.NewRecordRaw(ioutil.Discard), &DefaultOpts, spi.Mode3) + d, _ := New(spitest.NewRecordRaw(ioutil.Discard), &DefaultOpts) b.ResetTimer() for i := 0; i < b.N; i++ { if err := d.Halt(); err != nil { diff --git a/apa102/example_test.go b/apa102/example_test.go index b0e5709..f37061c 100644 --- a/apa102/example_test.go +++ b/apa102/example_test.go @@ -9,7 +9,6 @@ import ( "image/color" "log" - "periph.io/x/conn/v3/spi" "periph.io/x/conn/v3/spi/spireg" "periph.io/x/devices/v3/apa102" "periph.io/x/host/v3" @@ -34,7 +33,7 @@ func Example() { o.NumPixels = 300 o.Intensity = 127 o.Temperature = 3500 - dev, err := apa102.New(p, &o, spi.Mode0) + dev, err := apa102.New(p, &o) if err != nil { log.Fatalf("failed to open: %v", err) } @@ -62,7 +61,7 @@ func ExampleToRGB() { o := apa102.PassThruOpts o.NumPixels = 2 - dev, err := apa102.New(p, &o, spi.Mode3) + dev, err := apa102.New(p, &o) if err != nil { log.Fatalf("failed to open: %v", err) } diff --git a/go.mod b/go.mod index 2b2c857..b64427e 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ // Use of this source code is governed under the Apache License, Version 2.0 // that can be found in the LICENSE file. -module github.com/GermanBionicSystems/devices +module periph.io/x/devices/v3 go 1.13 diff --git a/rainbowhat/rainbowhat.go b/rainbowhat/rainbowhat.go index e7d6816..0853aeb 100644 --- a/rainbowhat/rainbowhat.go +++ b/rainbowhat/rainbowhat.go @@ -7,7 +7,6 @@ package rainbowhat import ( "periph.io/x/conn/v3/gpio" "periph.io/x/conn/v3/i2c/i2creg" - "periph.io/x/conn/v3/spi" "periph.io/x/conn/v3/spi/spireg" "periph.io/x/devices/v3/apa102" "periph.io/x/devices/v3/bmxx80" @@ -54,7 +53,7 @@ func NewRainbowHat(ao *apa102.Opts) (*Dev, error) { opts := *ao opts.NumPixels = 7 - ledstrip, err := apa102.New(spiPort, &opts, spi.Mode3) + ledstrip, err := apa102.New(spiPort, &opts) if err != nil { return nil, err }