From f822da51feb9dc5a425a3db0f0d63b601a7e2352 Mon Sep 17 00:00:00 2001 From: Jonathan Basseri Date: Wed, 4 Dec 2019 00:38:38 -0800 Subject: [PATCH] Add support for Cortex-M4 120MHz This adjusts the timing for 120MHz as seen on atsamd51 boards. The timing was kept as close as possible to the Cortex-M4 64MHz logic in ws2812_m4_64m.go. Tested: This works on ItsyBitsy-M4 --- ws2812/ws2812_m4_120m.go | 173 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 ws2812/ws2812_m4_120m.go diff --git a/ws2812/ws2812_m4_120m.go b/ws2812/ws2812_m4_120m.go new file mode 100644 index 0000000..84bf500 --- /dev/null +++ b/ws2812/ws2812_m4_120m.go @@ -0,0 +1,173 @@ +// +build atsamd51 + +package ws2812 + +// This file implements the WS2812 protocol for 120MHz Cortex-M4 +// microcontrollers. +// Note: This implementation does not work with tinygo 0.9.0 or older. + +import ( + "device/arm" +) + +// Send a single byte using the WS2812 protocol. +func (d Device) WriteByte(c byte) error { + // For the Cortex-M4 at 120MHz + 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: 32-34 cycles or 266.67ns - 283.33ns + // T0L: 101-103 cycles or 841.67ns - 858.33ns + // +: 133-137 cycles or 1108.33ns - 1141.67ns + // T1H: 73-75 cycles or 608.33ns - 625.00ns + // T1L: 58-60 cycles or 483.33ns - 500.00ns + // +: 131-135 cycles or 1091.67ns - 1125.00ns + // 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 @ [28] + 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 + bcs.n skip_store @ [1-3] + str {maskClear}, {portClear} @ [2] T0H -> T0L transition + skip_store: + nop @ [41] + 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 + str {maskClear}, {portClear} @ [2] T1H -> T1L transition + nop @ [54] + 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 send_bit @ [1-3] + `, map[string]interface{}{ + "value": value, + "i": 8, + "maskSet": maskSet, + "portSet": portSet, + "maskClear": maskClear, + "portClear": portClear, + }) + return nil +}