mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-10 18:03:41 +00:00
ws2812: add nrf52 support, update timings for m0 and avr
This commit adds support for the nrf52, which is a Cortex-M4 running at 64MHz. While implementing this, I discovered that the timings for AVR/16MHz and Cortex-M0 at 16MHz weren't quite right. They do work, but were slightly out of spec. So I fixed this as well.
This commit is contained in:
committed by
Ron Evans
parent
1475a63798
commit
4ff437e5d4
@@ -14,6 +14,12 @@ func (d Device) WriteByte(c byte) error {
|
|||||||
portSet, maskSet := d.Pin.PortMaskSet()
|
portSet, maskSet := d.Pin.PortMaskSet()
|
||||||
portClear, maskClear := d.Pin.PortMaskClear()
|
portClear, maskClear := d.Pin.PortMaskClear()
|
||||||
|
|
||||||
|
// See:
|
||||||
|
// https://wp.josh.com/2014/05/13/ws2812-neopixels-are-not-so-finicky-once-you-get-to-know-them/
|
||||||
|
// T0H: 4 cycles or 250ns
|
||||||
|
// T0L: 14 cycles or 875ns -> together 18 cycles or 1125ns
|
||||||
|
// T1H: 9 cycles or 562ns
|
||||||
|
// T1L: 8 cycles or 500ns -> together 17 cycles or 1062ns
|
||||||
avr.AsmFull(`
|
avr.AsmFull(`
|
||||||
send_bit:
|
send_bit:
|
||||||
st {portSet}, {maskSet} ; [2] set output high
|
st {portSet}, {maskSet} ; [2] set output high
|
||||||
@@ -21,13 +27,14 @@ func (d Device) WriteByte(c byte) error {
|
|||||||
brcs skip_store ; [1/2] branch if this bit is high (long pulse)
|
brcs skip_store ; [1/2] branch if this bit is high (long pulse)
|
||||||
st {portClear}, {maskClear} ; [2] set output low (short pulse)
|
st {portClear}, {maskClear} ; [2] set output low (short pulse)
|
||||||
skip_store:
|
skip_store:
|
||||||
nop ; [6] wait before changing the output again
|
nop ; [4] wait before changing the output again
|
||||||
nop
|
|
||||||
nop
|
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
st {portClear}, {maskClear} ; [2] set output low (end of pulse)
|
st {portClear}, {maskClear} ; [2] set output low (end of pulse)
|
||||||
|
nop ; [3]
|
||||||
|
nop
|
||||||
|
nop
|
||||||
subi {i}, 1 ; [1] subtract one (for the loop)
|
subi {i}, 1 ; [1] subtract one (for the loop)
|
||||||
brne send_bit ; [1/2] send the next bit, if not at the end of the loop
|
brne send_bit ; [1/2] send the next bit, if not at the end of the loop
|
||||||
`, map[string]interface{}{
|
`, map[string]interface{}{
|
||||||
|
|||||||
+15
-9
@@ -15,23 +15,29 @@ func (d Device) WriteByte(c byte) error {
|
|||||||
portSet, maskSet := d.Pin.PortMaskSet()
|
portSet, maskSet := d.Pin.PortMaskSet()
|
||||||
portClear, maskClear := d.Pin.PortMaskClear()
|
portClear, maskClear := d.Pin.PortMaskClear()
|
||||||
|
|
||||||
|
// See:
|
||||||
|
// https://wp.josh.com/2014/05/13/ws2812-neopixels-are-not-so-finicky-once-you-get-to-know-them/
|
||||||
|
// T0H: 4 cycles or 250ns
|
||||||
|
// T0L: 14 cycles or 875ns -> together 18 cycles or 1125ns
|
||||||
|
// T1H: 10 cycles or 625ns
|
||||||
|
// T1H: 8 cycles or 500ns -> together 18 cycles or 1125ns
|
||||||
value := uint32(c) << 24
|
value := uint32(c) << 24
|
||||||
arm.AsmFull(`
|
arm.AsmFull(`
|
||||||
send_bit:
|
send_bit:
|
||||||
str {maskSet}, {portSet}
|
str {maskSet}, {portSet} @ [2] T0H and T0L start here
|
||||||
lsls {value}, #1
|
lsls {value}, #1 @ [1]
|
||||||
bcs.n skip_store
|
bcs.n skip_store @ [1/3]
|
||||||
str {maskClear}, {portClear}
|
str {maskClear}, {portClear} @ [2] T0H -> T0L transition
|
||||||
skip_store:
|
skip_store:
|
||||||
|
nop @ [4]
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
|
str {maskClear}, {portClear} @ [2] T1H -> T1L transition
|
||||||
|
nop @ [2]
|
||||||
nop
|
nop
|
||||||
nop
|
subs {i}, #1 @ [1]
|
||||||
nop
|
bne.n send_bit @ [1/3]
|
||||||
str {maskClear}, {portClear}
|
|
||||||
subs {i}, #1
|
|
||||||
bne.n send_bit
|
|
||||||
`, map[string]interface{}{
|
`, map[string]interface{}{
|
||||||
"value": value,
|
"value": value,
|
||||||
"i": 8,
|
"i": 8,
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
// +build nrf52
|
||||||
|
|
||||||
|
package ws2812
|
||||||
|
|
||||||
|
// This file implements the WS2812 protocol for 64MHz Cortex-M4
|
||||||
|
// microcontrollers.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device/arm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Send a single byte using the WS2812 protocol.
|
||||||
|
func (d Device) WriteByte(c byte) error {
|
||||||
|
// For the Cortex-M4 at 64MHz
|
||||||
|
portSet, maskSet := d.Pin.PortMaskSet()
|
||||||
|
portClear, maskClear := d.Pin.PortMaskClear()
|
||||||
|
|
||||||
|
// See:
|
||||||
|
// https://wp.josh.com/2014/05/13/ws2812-neopixels-are-not-so-finicky-once-you-get-to-know-them/
|
||||||
|
// T0H: 14-16 cycles or 218.75ns - 250.00ns
|
||||||
|
// T0L: 54-56 cycles or 843.75ns - 875.00ns
|
||||||
|
// +: 68-72 cycles or 1062.50ns - 1125.00ns
|
||||||
|
// T1H: 36-38 cycles or 562.50ns - 593.75ns
|
||||||
|
// T1L: 30-32 cycles or 468.75ns - 500.0ns
|
||||||
|
// +: 66-70 cycles or 1031.25ns - 1093.75ns
|
||||||
|
// A branch is treated here as 1-3 cycles, because apparently it might get
|
||||||
|
// speculated. This is more of a guess than hard fact, because the only docs
|
||||||
|
// by ARM that state this are now considered superseded (by what?).
|
||||||
|
value := uint32(c) << 24
|
||||||
|
arm.AsmFull(`
|
||||||
|
send_bit:
|
||||||
|
str {maskSet}, {portSet} @ [2] T0H and T0L start here
|
||||||
|
lsls {value}, #1 @ [1]
|
||||||
|
nop @ [10]
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
bcs.n skip_store @ [1-3]
|
||||||
|
str {maskClear}, {portClear} @ [2] T0H -> T0L transition
|
||||||
|
skip_store:
|
||||||
|
nop @ [22]
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
str {maskClear}, {portClear} @ [2] T1H -> T1L transition
|
||||||
|
nop @ [26]
|
||||||
|
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 send_bit @ [1-3]
|
||||||
|
`, map[string]interface{}{
|
||||||
|
"value": value,
|
||||||
|
"i": 8,
|
||||||
|
"maskSet": maskSet,
|
||||||
|
"portSet": portSet,
|
||||||
|
"maskClear": maskClear,
|
||||||
|
"portClear": portClear,
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user