I'm trying to bitbang a WS2812B LED in blue using Arduino C++. The WS2812B protocol requires precise delays in nanoseconds, but the delayMicroseconds function can't achieve this—my oscilloscope shows a minimum delay of about 1 µs, which is too long for the first transition.
I found asm volatile("nop");, but it doesn't help me reach the 450 ns required. Is there a way to achieve this in Arduino C++, or do I need to use assembly code?
I tested a sketch to measure four NOP instructions with my oscilloscope, but the results are inconsistent. When I add another NOP or remove one, the timing changes randomly.
Any suggestions on how to achieve more reliable timing?
I tried not to use digitalWrite to reduce overhead, but with no luke.
It's easily done. In my case, I've a .cpp file containing an interrupt routine that does a number of things; one of them is writing to a string of WS2812D pixels. The timing is accurate to the WS2812D spec that I have, and rock-stable, as observed with an oscilloscope.
As Bill notes in his contributions to that thread, there are things that can happen when the compiler optimizes your code; he points out how to avoid that.
DigitalWrite is a non-starter. Too slow by a longshot.
DigitalWriteFast is faster, but requires a constant for the pin number to achieve the best speed; that must be specified at compile time, so you can't make the pin # a variable that you pass in to the routine, for example.
Since I was locked in to a particular Arduino, and wasn't concerned about making the pin number adjustable, I decided to just use direct port access, such as
` PORTB |= 0b00100000; //start high portion of bit