diff --git a/ws2812/ws2812-asm_cortexm.go b/ws2812/ws2812-asm_cortexm.go index 0cdece1..a13e7fa 100644 --- a/ws2812/ws2812-asm_cortexm.go +++ b/ws2812/ws2812-asm_cortexm.go @@ -1320,6 +1320,465 @@ void ws2812_writeByte168(char c, uint32_t *portSet, uint32_t *portClear, uint32_ [maskClear]"r"(maskClear), [portClear]"m"(*portClear)); } + +__attribute__((always_inline)) +void ws2812_writeByte200(char c, uint32_t *portSet, uint32_t *portClear, uint32_t maskSet, uint32_t maskClear) { + // Timings: + // T0H: 70 - 72 cycles or 350.0ns - 360.0ns + // T1H: 210 - 212 cycles or 1050.0ns - 1060.0ns + // TLD: 230 - cycles or 1150.0ns - + uint32_t value = (uint32_t)c << 24; + char i = 8; + __asm__ __volatile__( + "1: @ send_bit\n" + "\t str %[maskSet], %[portSet] @ [2] T0H and T0L start here\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t lsls %[value], #1 @ [1]\n" + "\t bcs.n 2f @ [1/3] skip_store\n" + "\t str %[maskClear], %[portClear] @ [2] T0H -> T0L transition\n" + "\t2: @ skip_store\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t str %[maskClear], %[portClear] @ [2] T1H -> T1L transition\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t nop\n" + "\t subs %[i], #1 @ [1]\n" + "\t beq.n 3f @ [1/3] end\n" + "\t b 1b @ [1/3] send_bit\n" + "\t3: @ end\n" + : [value]"+r"(value), + [i]"+r"(i) + : [maskSet]"r"(maskSet), + [portSet]"m"(*portSet), + [maskClear]"r"(maskClear), + [portClear]"m"(*portClear)); +} */ import "C" @@ -1382,3 +1841,13 @@ func (d Device) writeByte168(c byte) { interrupt.Restore(mask) } + +func (d Device) writeByte200(c byte) { + portSet, maskSet := d.Pin.PortMaskSet() + portClear, maskClear := d.Pin.PortMaskClear() + + mask := interrupt.Disable() + C.ws2812_writeByte200(C.char(c), (*C.uint32_t)(unsafe.Pointer(portSet)), (*C.uint32_t)(unsafe.Pointer(portClear)), C.uint32_t(maskSet), C.uint32_t(maskClear)) + + interrupt.Restore(mask) +} diff --git a/ws2812/ws2812.go b/ws2812/ws2812.go index a0e0791..d5860f6 100644 --- a/ws2812/ws2812.go +++ b/ws2812/ws2812.go @@ -1,7 +1,7 @@ // Package ws2812 implements a driver for WS2812 and SK6812 RGB LED strips. package ws2812 // import "tinygo.org/x/drivers/ws2812" -//go:generate go run gen-ws2812.go -arch=cortexm 16 48 64 120 125 168 +//go:generate go run gen-ws2812.go -arch=cortexm 16 48 64 120 125 168 200 //go:generate go run gen-ws2812.go -arch=tinygoriscv 160 320 import ( diff --git a/ws2812/ws2812_cortexm.go b/ws2812/ws2812_cortexm.go index dafdb49..b818a67 100644 --- a/ws2812/ws2812_cortexm.go +++ b/ws2812/ws2812_cortexm.go @@ -28,12 +28,15 @@ func (d Device) WriteByte(c byte) error { case 120_000_000: // 120MHz d.writeByte120(c) return nil - case 125_000_000: // 125 MHz e.g. rp2040 + case 125_000_000: // 125 MHz e.g. rp2040 originally d.writeByte125(c) return nil case 168_000_000: // 168MHz, e.g. stm32f405 d.writeByte168(c) return nil + case 200_000_000: // 200MHz, e.g. rp2040 starting with TinyGo v0.37 + d.writeByte200(c) + return nil default: return errUnknownClockSpeed }