ws2812: improve timings to be compatible with the WS2811

The WS2811 has a slightly slower data rate, but it is close enough that
a single library can support both LEDs at the same time. In my testing,
this package was already compatible with WS2811 LEDs before this change
when running at 4-5V, but when the voltage dropped to 3V or so the LEDs
started misbehaving. With these improved timings, the LEDs remained of
the correct color even at very low voltages (although blue was starting
to fade due to lack of voltage - that's not a software/protocol issue).
This commit is contained in:
Ayke van Laethem
2021-09-16 17:41:26 +02:00
committed by Ron Evans
parent cad03a7d4e
commit 7a2b1b8c90
2 changed files with 334 additions and 15 deletions
+310 -12
View File
@@ -16,18 +16,26 @@ func (d Device) writeByte16(c byte) {
portClear, maskClear := d.Pin.PortMaskClear()
// Timings:
// T0H: 4 - 6 cycles or 250.0ns - 375.0ns
// T1H: 9 - 11 cycles or 562.5ns - 687.5ns
// TLD: 8 - cycles or 500.0ns -
// T0H: 6 - 8 cycles or 375.0ns - 500.0ns
// T1H: 17 - 19 cycles or 1062.5ns - 1187.5ns
// TLD: 19 - cycles or 1187.5ns -
mask := interrupt.Disable()
value := uint32(c) << 24
device.AsmFull(`
1: @ send_bit
str {maskSet}, {portSet} @ [2] T0H and T0L start here
nop
nop
lsls {value}, #1 @ [1]
bcs.n 2f @ [1/3] skip_store
str {maskClear}, {portClear} @ [2] T0H -> T0L transition
2: @ skip_store
nop
nop
nop
nop
nop
nop
nop
nop
nop
@@ -38,6 +46,17 @@ func (d Device) writeByte16(c byte) {
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
subs {i}, #1 @ [1]
bne.n 1b @ [1/3] send_bit
`, map[string]interface{}{
@@ -56,9 +75,9 @@ func (d Device) writeByte48(c byte) {
portClear, maskClear := d.Pin.PortMaskClear()
// Timings:
// T0H: 10 - 12 cycles or 208.3ns - 250.0ns
// T1H: 27 - 29 cycles or 562.5ns - 604.2ns
// TLD: 22 - cycles or 458.3ns -
// T0H: 17 - 19 cycles or 354.2ns - 395.8ns
// T1H: 51 - 53 cycles or 1062.5ns - 1104.2ns
// TLD: 56 - cycles or 1166.7ns -
mask := interrupt.Disable()
value := uint32(c) << 24
device.AsmFull(`
@@ -70,10 +89,34 @@ func (d Device) writeByte48(c byte) {
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
lsls {value}, #1 @ [1]
bcs.n 2f @ [1/3] skip_store
str {maskClear}, {portClear} @ [2] T0H -> T0L transition
2: @ skip_store
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
@@ -110,6 +153,40 @@ func (d Device) writeByte48(c byte) {
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
subs {i}, #1 @ [1]
bne.n 1b @ [1/3] send_bit
`, map[string]interface{}{
@@ -128,9 +205,9 @@ func (d Device) writeByte64(c byte) {
portClear, maskClear := d.Pin.PortMaskClear()
// Timings:
// T0H: 13 - 15 cycles or 203.1ns - 234.4ns
// T1H: 36 - 38 cycles or 562.5ns - 593.8ns
// TLD: 29 - cycles or 453.1ns -
// T0H: 23 - 25 cycles or 359.4ns - 390.6ns
// T1H: 68 - 70 cycles or 1062.5ns - 1093.8ns
// TLD: 74 - cycles or 1156.2ns -
mask := interrupt.Disable()
value := uint32(c) << 24
device.AsmFull(`
@@ -145,10 +222,42 @@ func (d Device) writeByte64(c byte) {
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
lsls {value}, #1 @ [1]
bcs.n 2f @ [1/3] skip_store
str {maskClear}, {portClear} @ [2] T0H -> T0L transition
2: @ skip_store
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
@@ -198,6 +307,51 @@ func (d Device) writeByte64(c byte) {
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
subs {i}, #1 @ [1]
bne.n 1b @ [1/3] send_bit
`, map[string]interface{}{
@@ -216,9 +370,9 @@ func (d Device) writeByte120(c byte) {
portClear, maskClear := d.Pin.PortMaskClear()
// Timings:
// T0H: 24 - 26 cycles or 200.0ns - 216.7ns
// T1H: 66 - 68 cycles or 550.0ns - 566.7ns
// TLD: 54 - cycles or 450.0ns -
// T0H: 42 - 44 cycles or 350.0ns - 366.7ns
// T1H: 126 - 128 cycles or 1050.0ns - 1066.7ns
// TLD: 138 - cycles or 1150.0ns -
mask := interrupt.Disable()
value := uint32(c) << 24
device.AsmFull(`
@@ -244,10 +398,70 @@ func (d Device) writeByte120(c byte) {
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
lsls {value}, #1 @ [1]
bcs.n 2f @ [1/3] skip_store
str {maskClear}, {portClear} @ [2] T0H -> T0L transition
2: @ skip_store
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
@@ -341,6 +555,90 @@ func (d Device) writeByte120(c byte) {
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
subs {i}, #1 @ [1]
bne.n 1b @ [1/3] send_bit
`, map[string]interface{}{