Skip to content

Commit 65f8299

Browse files
aykevldeadprogram
authored andcommitted
ws2812: add support for ESP8266
This patch adds support for the ESP8266 chip by adding support for 80MHz operation. This should also work when the ESP32 is changed to 80MHz, but I didn't test it (as there is not currently a way to do that). Verified on a NodeMCU dev board with an ESP8266.
1 parent a689aef commit 65f8299

File tree

1 file changed

+117
-1
lines changed

1 file changed

+117
-1
lines changed

ws2812/ws2812_xtensa.go

Lines changed: 117 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ func (d Device) WriteByte(c byte) error {
1616
portClear, maskClear := d.Pin.PortMaskClear()
1717

1818
switch machine.CPUFrequency() {
19-
case 160e6:
19+
case 160e6: // 160MHz
2020
// See:
2121
// https://wp.josh.com/2014/05/13/ws2812-neopixels-are-not-so-finicky-once-you-get-to-know-them/
2222
// Because I do not know the exact instruction timings, I'm going to
@@ -224,6 +224,122 @@ func (d Device) WriteByte(c byte) error {
224224
"portClear": uintptr(unsafe.Pointer(portClear)),
225225
})
226226
return nil
227+
case 80e6: // 80MHz
228+
// See docs for 160MHz.
229+
// T0H: 21 cycles or 262.5ns
230+
// T0L: 67 cycles or 837.5ns
231+
// +: 88 cycles or 1100.0ns
232+
// T1H: 47 cycles or 587.5ns
233+
// T1L: 39 cycles or 487.5ns
234+
// +: 86 cycles or 1075.0ns
235+
device.AsmFull(`
236+
1: // send_bit
237+
s32i {maskSet}, {portSet}, 0 // [1] T0H and T1H start here
238+
nop // [18]
239+
nop
240+
nop
241+
nop
242+
nop
243+
nop
244+
nop
245+
nop
246+
nop
247+
nop
248+
nop
249+
nop
250+
nop
251+
nop
252+
nop
253+
nop
254+
nop
255+
nop
256+
slli {value}, {value}, 1 // [1] shift {value} to the left by 1
257+
bbsi {value}, 8, 2f // [1] branch to skip_store if bit 8 is set
258+
s32i {maskClear}, {portClear}, 0 // [1] T0H -> T0L transition
259+
2: // skip_store
260+
nop // [27]
261+
nop
262+
nop
263+
nop
264+
nop
265+
nop
266+
nop
267+
nop
268+
nop
269+
nop
270+
nop
271+
nop
272+
nop
273+
nop
274+
nop
275+
nop
276+
nop
277+
nop
278+
nop
279+
nop
280+
nop
281+
nop
282+
nop
283+
nop
284+
nop
285+
nop
286+
nop
287+
s32i {maskClear}, {portClear}, 0 // [1] T1H -> T1L transition
288+
nop // [36]
289+
nop
290+
nop
291+
nop
292+
nop
293+
nop
294+
nop
295+
nop
296+
nop
297+
nop
298+
nop
299+
nop
300+
nop
301+
nop
302+
nop
303+
nop
304+
nop
305+
nop
306+
nop
307+
nop
308+
nop
309+
nop
310+
nop
311+
nop
312+
nop
313+
nop
314+
nop
315+
nop
316+
nop
317+
nop
318+
nop
319+
nop
320+
nop
321+
nop
322+
nop
323+
nop
324+
addi {i}, {i}, -1 // [1]
325+
bnez {i}, 1b // [1] send_bit, T1H and T1L end here
326+
327+
// Restore original values after modifying them in the inline
328+
// assembly. Not doing that would result in undefined behavior as
329+
// the compiler doesn't know we're modifying these values.
330+
movi.n {i}, 8
331+
slli {value}, {value}, 8
332+
`, map[string]interface{}{
333+
// Note: casting pointers to uintptr here because of what might be
334+
// an Xtensa backend bug with inline assembly.
335+
"value": uint32(c),
336+
"i": 8,
337+
"maskSet": maskSet,
338+
"portSet": uintptr(unsafe.Pointer(portSet)),
339+
"maskClear": maskClear,
340+
"portClear": uintptr(unsafe.Pointer(portClear)),
341+
})
342+
return nil
227343
default:
228344
return errUnknownClockSpeed
229345
}

0 commit comments

Comments
 (0)