nrzled.NewSPI: also add padding in the front

Some SPI devices take a while to set up for transfer, and while doing
so, show the first bit they're about to send.

This causes the first LED to always interpret the first symbol as a
logical 1. Zapping out the whole strip will leave the first LED green,
and the first pixel will always be slightly green-ish.

Prevent this, by applying the same 3 bit padding we have at the end to
the front.

Signed-off-by: Florian Klink <flokli@flokli.de>
pull/48/head
Florian Klink 4 years ago
parent 0012149b5d
commit ead9d71cac

@ -81,10 +81,13 @@ func NewSPI(p spi.Port, opts *Opts) (*Dev, error) {
} }
// 4 symbol bytes per byte, 3/4 bytes per pixel. // 4 symbol bytes per byte, 3/4 bytes per pixel.
streamLen := 4 * (opts.Channels * opts.NumPixels) streamLen := 4 * (opts.Channels * opts.NumPixels)
// 3 bytes for latch. 24*400ns = 9600ns. In practice this could be skipped, // 3 bytes for latch. 24*400ns = 9600ns. In practice this could be skipped at
// as the overhead for SPI Tx() tear down and the next one is likely at least // the end as the overhead for SPI Tx() tear down and the next one is likely
// 10µs. // at least 10µs.
bufSize := streamLen + 3 // In the front, we definitely want it, as SPIs might otherwise be high for
// quite a while while setting themselves up, causing the first symbol to be
// interpreted as a logical 1.
bufSize := 3 + streamLen + 3
if l, ok := p.(conn.Limits); ok { if l, ok := p.(conn.Limits); ok {
if s := l.MaxTxSize(); s < bufSize { if s := l.MaxTxSize(); s < bufSize {
return nil, errors.New("spi port buffer is too short for the specified number of pixels") return nil, errors.New("spi port buffer is too short for the specified number of pixels")
@ -101,7 +104,7 @@ func NewSPI(p spi.Port, opts *Opts) (*Dev, error) {
numPixels: opts.NumPixels, numPixels: opts.NumPixels,
channels: opts.Channels, channels: opts.Channels,
b: gpiostream.BitStream{Freq: opts.Freq, Bits: buf, LSBF: false}, b: gpiostream.BitStream{Freq: opts.Freq, Bits: buf, LSBF: false},
rawBuf: buf[:streamLen], rawBuf: buf[3 : bufSize-3],
rect: image.Rect(0, 0, opts.NumPixels, 1), rect: image.Rect(0, 0, opts.NumPixels, 1),
}, nil }, nil
} }

@ -36,7 +36,7 @@ func TestSPI_Empty(t *testing.T) {
s := spitest.Playback{ s := spitest.Playback{
Playback: conntest.Playback{ Playback: conntest.Playback{
Count: 1, Count: 1,
Ops: []conntest.IO{{W: []byte{0x00, 0x00, 0x00}}}, Ops: []conntest.IO{{W: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
}, },
} }
d, err := NewSPI(spitest.NewRecordRaw(&buf), &o) d, err := NewSPI(spitest.NewRecordRaw(&buf), &o)
@ -105,6 +105,7 @@ var writeTests = []struct {
{0xFF, 0xFF, 0xFF, 0x00}, {0xFF, 0xFF, 0xFF, 0x00},
}), }),
want: []byte{ want: []byte{
/*NUL*/ 0x00, 0x00, 0x00,
/*FF*/ 0xEE, 0xEE, 0xEE, 0xEE /*FF*/, 0xEE, 0xEE, 0xEE, 0xEE /*FF*/, 0xEE, 0xEE, 0xEE, 0xEE, /*FF*/ 0xEE, 0xEE, 0xEE, 0xEE /*FF*/, 0xEE, 0xEE, 0xEE, 0xEE /*FF*/, 0xEE, 0xEE, 0xEE, 0xEE,
/*EOF*/ 0x00, 0x00, 0x00, /*EOF*/ 0x00, 0x00, 0x00,
}, },
@ -120,6 +121,7 @@ var writeTests = []struct {
{0xFE, 0xFE, 0xFE, 0x00}, {0xFE, 0xFE, 0xFE, 0x00},
}), }),
want: []byte{ want: []byte{
/*NUL*/ 0x00, 0x00, 0x00,
/*FE*/ 0xEE, 0xEE, 0xEE, 0xE8 /*FE*/, 0xEE, 0xEE, 0xEE, 0xE8 /*FE*/, 0xEE, 0xEE, 0xEE, 0xE8, /*FE*/ 0xEE, 0xEE, 0xEE, 0xE8 /*FE*/, 0xEE, 0xEE, 0xEE, 0xE8 /*FE*/, 0xEE, 0xEE, 0xEE, 0xE8,
/*EOF*/ 0x00, 0x00, 0x00, /*EOF*/ 0x00, 0x00, 0x00,
}, },
@ -135,6 +137,7 @@ var writeTests = []struct {
{0xF0, 0xF0, 0xF0, 0x00}, {0xF0, 0xF0, 0xF0, 0x00},
}), }),
want: []byte{ want: []byte{
/*NUL*/ 0x00, 0x00, 0x00,
/*F0*/ 0xEE, 0xEE, 0x88, 0x88 /*F0*/, 0xEE, 0xEE, 0x88, 0x88 /*F0*/, 0xEE, 0xEE, 0x88, 0x88, /*F0*/ 0xEE, 0xEE, 0x88, 0x88 /*F0*/, 0xEE, 0xEE, 0x88, 0x88 /*F0*/, 0xEE, 0xEE, 0x88, 0x88,
/*EOF*/ 0x00, 0x00, 0x00, /*EOF*/ 0x00, 0x00, 0x00,
}, },
@ -150,6 +153,7 @@ var writeTests = []struct {
{0x80, 0x80, 0x80, 0x00}, {0x80, 0x80, 0x80, 0x00},
}), }),
want: []byte{ want: []byte{
/*NUL*/ 0x00, 0x00, 0x00,
/*80*/ 0xE8, 0x88, 0x88, 0x88 /*80*/, 0xE8, 0x88, 0x88, 0x88 /*80*/, 0xE8, 0x88, 0x88, 0x88, /*80*/ 0xE8, 0x88, 0x88, 0x88 /*80*/, 0xE8, 0x88, 0x88, 0x88 /*80*/, 0xE8, 0x88, 0x88, 0x88,
/*EOF*/ 0x00, 0x00, 0x00, /*EOF*/ 0x00, 0x00, 0x00,
}, },
@ -165,6 +169,7 @@ var writeTests = []struct {
{0x80, 0xFF, 0x00, 0x00}, {0x80, 0xFF, 0x00, 0x00},
}), }),
want: []byte{ want: []byte{
/*NUL*/ 0x00, 0x00, 0x00,
/*FF*/ 0xEE, 0xEE, 0xEE, 0xEE /*80*/, 0xE8, 0x88, 0x88, 0x88 /*00*/, 0x88, 0x88, 0x88, 0x88, /*FF*/ 0xEE, 0xEE, 0xEE, 0xEE /*80*/, 0xE8, 0x88, 0x88, 0x88 /*00*/, 0x88, 0x88, 0x88, 0x88,
/*EOF*/ 0x00, 0x00, 0x00, /*EOF*/ 0x00, 0x00, 0x00,
}, },
@ -180,6 +185,7 @@ var writeTests = []struct {
{0x80, 0x00, 0x00, 0x00}, {0x80, 0x00, 0x00, 0x00},
}), }),
want: []byte{ want: []byte{
/*NUL*/ 0x00, 0x00, 0x00,
/*00*/ 0x88, 0x88, 0x88, 0x88 /*80*/, 0xE8, 0x88, 0x88, 0x88 /*00*/, 0x88, 0x88, 0x88, 0x88, /*00*/ 0x88, 0x88, 0x88, 0x88 /*80*/, 0xE8, 0x88, 0x88, 0x88 /*00*/, 0x88, 0x88, 0x88, 0x88,
/*EOF*/ 0x00, 0x00, 0x00, /*EOF*/ 0x00, 0x00, 0x00,
}, },
@ -195,6 +201,7 @@ var writeTests = []struct {
{0x00, 0x80, 0x00, 0x00}, {0x00, 0x80, 0x00, 0x00},
}), }),
want: []byte{ want: []byte{
/*NUL*/ 0x00, 0x00, 0x00,
/*80*/ 0xE8, 0x88, 0x88, 0x88 /*00*/, 0x88, 0x88, 0x88, 0x88 /*00*/, 0x88, 0x88, 0x88, 0x88, /*80*/ 0xE8, 0x88, 0x88, 0x88 /*00*/, 0x88, 0x88, 0x88, 0x88 /*00*/, 0x88, 0x88, 0x88, 0x88,
/*EOF*/ 0x00, 0x00, 0x00, /*EOF*/ 0x00, 0x00, 0x00,
}, },
@ -210,6 +217,7 @@ var writeTests = []struct {
{0x00, 0x00, 0x80, 0x00}, {0x00, 0x00, 0x80, 0x00},
}), }),
want: []byte{ want: []byte{
/*NUL*/ 0x00, 0x00, 0x00,
/*00*/ 0x88, 0x88, 0x88, 0x88 /*00*/, 0x88, 0x88, 0x88, 0x88 /*80*/, 0xE8, 0x88, 0x88, 0x88, /*00*/ 0x88, 0x88, 0x88, 0x88 /*00*/, 0x88, 0x88, 0x88, 0x88 /*80*/, 0xE8, 0x88, 0x88, 0x88,
/*EOF*/ 0x00, 0x00, 0x00, /*EOF*/ 0x00, 0x00, 0x00,
}, },
@ -236,6 +244,7 @@ var writeTests = []struct {
{0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
}), }),
want: []byte{ want: []byte{
/*NUL*/ 0x00, 0x00, 0x00,
/*FF*/ 0xEE, 0xEE, 0xEE, 0xEE /*FF*/, 0xEE, 0xEE, 0xEE, 0xEE /*FF*/, 0xEE, 0xEE, 0xEE, 0xEE, /*FF*/ 0xEE, 0xEE, 0xEE, 0xEE /*FF*/, 0xEE, 0xEE, 0xEE, 0xEE /*FF*/, 0xEE, 0xEE, 0xEE, 0xEE,
/*FE*/ 0xEE, 0xEE, 0xEE, 0xE8 /*FE*/, 0xEE, 0xEE, 0xEE, 0xE8 /*FE*/, 0xEE, 0xEE, 0xEE, 0xE8, /*FE*/ 0xEE, 0xEE, 0xEE, 0xE8 /*FE*/, 0xEE, 0xEE, 0xEE, 0xE8 /*FE*/, 0xEE, 0xEE, 0xEE, 0xE8,
/*F0*/ 0xEE, 0xEE, 0x88, 0x88 /*F0*/, 0xEE, 0xEE, 0x88, 0x88 /*F0*/, 0xEE, 0xEE, 0x88, 0x88, /*F0*/ 0xEE, 0xEE, 0x88, 0x88 /*F0*/, 0xEE, 0xEE, 0x88, 0x88 /*F0*/, 0xEE, 0xEE, 0x88, 0x88,
@ -302,14 +311,15 @@ func TestSPI_Long(t *testing.T) {
if n, err := d.Write(toRGB(colors)); n != len(colors)*3 || err != nil { if n, err := d.Write(toRGB(colors)); n != len(colors)*3 || err != nil {
t.Fatalf("%d %v", n, err) t.Fatalf("%d %v", n, err)
} }
expected := make([]byte, 12*o.NumPixels+3) expected := make([]byte, 3+12*o.NumPixels+3)
for i := 0; i < 12*o.NumPixels; i += 12 { // leave three bytes of padding
for i := 3; i < 12*o.NumPixels; i += 12 {
//Each channel should be 0x00 //Each channel should be 0x00
for j := 0; j < 12; j++ { for j := 0; j < 12; j++ {
expected[i+j] = 0x88 expected[i+j] = 0x88
} }
} }
trailer := expected[12*o.NumPixels:] trailer := expected[3+12*o.NumPixels:]
for i := range trailer { for i := range trailer {
trailer[i] = 0x00 trailer[i] = 0x00
} }
@ -350,11 +360,16 @@ var drawTests = []struct {
}(), }(),
want: func() []byte { want: func() []byte {
var b []byte var b []byte
//padding
for i := 0; i < 3; i++ {
b = append(b, 0x00)
}
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
b = append(b, 0xE8, 0x88, 0x88, 0x88) //0x80 b = append(b, 0xE8, 0x88, 0x88, 0x88) //0x80
b = append(b, 0x88, 0x88, 0x88, 0x88) //0x00 b = append(b, 0x88, 0x88, 0x88, 0x88) //0x00
b = append(b, 0xEE, 0xEE, 0xEE, 0xEE) //0xFF b = append(b, 0xEE, 0xEE, 0xEE, 0xEE) //0xFF
} }
//padding
for i := 0; i < 3; i++ { for i := 0; i < 3; i++ {
b = append(b, 0x00) b = append(b, 0x00)
} }
@ -427,6 +442,9 @@ func TestSPI_Halt(t *testing.T) {
Ops: []conntest.IO{ Ops: []conntest.IO{
{}, {},
{W: []byte{ {W: []byte{
//Begin of frame
0x00, 0x00, 0x00,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,

Loading…
Cancel
Save