The reason is due to the special high-timing-specific nature of the data sent to the pixels. NeoPixels, or WS2812/WS2811, use a single wire protocol that encodes bits as pulses, the time width of the pulses determine whether each bit is a binary 1 or 0. The following is a screenshot from the WS2812 datasheet.
(note: neither of these are over-all disadvantages! In fact, they exist to make your code safer, and makes coding easier)
Interpreted code means that you write your code in C#, but instead of directly being compiled to ARM assembly code (and subsequently, machine code), it is first compiled to "bytecode", and the processor runs an interpreter to read the bytecode, instead of directly executing machine code. The advantage of this is that the code is safer, you can detect errors like overflows, bad memory access, and check object type info. The disadvantage is that it is much slower than directly executing machine code.
(note: from Wikipedia: "Managed code is a term coined by Microsoft to identify computer program source code that requires and will only execute under the management of a Common Language Runtime virtual machine (resulting in bytecode).")
(note: microcontrollers do not normally run interpreted code until you put a interpreter on it, the Netduino is a STM32 microcontroller with a C# CLR interpreter, the BASIC Stamp is a PIC microcontroller with a BASIC interpreter. Arduino is an AVR microcontroller and it does NOT use an interpreter.)
using System; using System.Threading; using Microsoft.SPOT; using Microsoft.SPOT.Hardware; using SecretLabs.NETMF.Hardware; using SecretLabs.NETMF.Hardware.Netduino; namespace Blinky { public class Program { public static void Main() { bool pinState = false; OutputPort x = new OutputPort(Pins.GPIO_PIN_D0, pinState); while (true) { pinState = !pinState; x.Write(pinState); } } } }
The other problem is the garbage collector, which runs "once in a while". The garbage collector basically prevents memory leaks when you don't explicitly free memory you don't need anymore. But if it runs while we are pulsing signals to the WS2812, it might extend a pulse and violate the timing requirements. This problem can be solved by making sure that interrupts are disabled when we communicate with the WS2812.
Fortunately, .NET Micro Framework and the Netduino firmware are open source. This means it is possible to write native code functions into the firmware, and call these functions from the managed code.
(note: calling functions between managed and unmanaged code is referred to as interop, you might have come across this term if you tried to use DLLs in C# before)
Our goal is to write a function in C or C++ that will toggle a pin with strict uninterruptable timing, in order to communicate to WS2812 NeoPixels. This function will then be compiled as a part of Netduino's firmware, and we will update the Netduino with this new modified firmware. After that, we should be able to call our new function from within the C# code.