@@ -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