cpldcpu/light_ws2812

Random biterrors on Arduino M0 Pro (with Arduino Ethernet Shield 2)

Closed this issue · 1 comments

olemr commented

Thank you so much for your code!
I took the Cortex code from your project and C++ified it. (inspired by your Adruino code)
Connected a 4m strip with 240 LEDs (Luxorparts WS2812B NeoStrip compatible) @4.5V, no level converter.

I control the LEDs through a TCP connection using the DhcpChatServer (found in the Andruino examples).
I don't know if the Ethernet Shield is significant or not, but when I clocked the LEDs with all 0s, 3-4 random LEDs would turn on with random color and intensity. Same when clocking out RGB(1,1,1)

Reading your readme, made me focus on the NVM read cache and NVM wait-states @48MHz@3.3V.
Turning the cache off had no effect. Never figured out how to run the CPU @24MHz with 0 wait-states.

On a whim, I added __disable_irq(); & __enable_irq(); in ws2812_sendarray() and viola!
Rock steady @48MHz 1-wait-state & cache enabled.

Up to you to decide if this should be incorporated into the code or just make an entry in the ReadMe.
The current comment about max clock and wait-state restriction seem not to apply when disabling interrupts during the bit/banging.

Cheers

Edit: just hit me that interrupts did not need to be disabled during the whole clocking cycle.
josh.com states:

The only tight timing parameter for NeoPixel signaling is the maximum width of a 0-bit pulse

So I tested out the code below and it worked fine. Did not find out how to just do it for a 0, but interrupts are now allowed inside the clocking loop:

	asm volatile(
			"		lsl %[dat],#24				\n\t"
			"		movs %[ctr],#8				\n\t"
			"ilop%=:							\n\t"
--->			"cpsid i                            \n\t"
			"		lsl %[dat], #1				\n\t"
			"		str %[maskhi], [%[set]]		\n\t"
#if (w1&1)
			ws2812_DEL1
#endif
#if (w1&2)
			ws2812_DEL2
#endif
#if (w1&4)
			ws2812_DEL4
#endif
#if (w1&8)
			ws2812_DEL8
#endif
#if (w1&16)
			ws2812_DEL16
#endif
			"		bcs one%=					\n\t"
			"		str %[masklo], [%[clr]]		\n\t"
			"one%=:								\n\t"
--->			"cpsie i                            \n\t"
#if (w2&1)
			ws2812_DEL1
.
.

Thanks for sharing! Indeed, it seems like you did all the right things to achieve cycle exact timing - reduce memory latency and disable interrupts.