The strip has 2 grounds, 2 5v, and a data pin (green wire). I have a 5v going from the strip to the power supply and a ground going from the strip to the power supply. I also have a 5v going to the VIN on the spark core and a ground going to the ground on spark core. The data wire is plugged into D0. I hope that’s not confusing… lol.
I tried running one pixel, but defining 120 pixels in the code… and it looks like (#1 I’m blind from staring at the damn neopixel) and #2noInterrupts(); and interrupts(); don’t do as much as I would have liked…
Switched those out for __disable_irq(); and __enable_irq(); and it’s glitch free. Thanks @jagor for mentioning those! I need to readjust the timing a little now, but just making those changes works well.
I powered the pixel from Vin and 3.3 and 3.3* and all are flicker free now.
From the datasheet, the Din on the pixels should be 3.5V if powering from 5V, but apparently YMMV and it you might get lucky! Your desk looks insanely glowie! So is it not glitching just with those changes?
Regarding the flashing blue… that can happen if you block the main loop too much. If using rainbow(); with 120 pixels, it takes about 3.6ms to send all pixel data, so you can’t set rainbow to anything less than rainbow(5); I’d say which is 5 milliseconds. If you set rainbow to anything higher than rainbow(50) I’ve noticed it block the main loop.
It is! I need to extend this so we can turn on/off rainbow mode, turn the entire led strip a color, blink a section of the lights while continuing normal operations on the other lights, etc. I think we should start at making a few spark functions for various things, like: toggleRainbow( 'true' || 'false' ) and so forth.
It's WAYY smoother with __disable_irq(); and __enabled_irq();
It was designed to make christmas lights, which are 10 groups of 4 LEDs (circles) connected in series.
Also it is not in usual Arduino library style of C++ class, as I was doing as much as possible to shrink it to fit Atmega8 8K of flash (for 25-pixel rabbit toy). Now I’m too lazy to make it back a set of classes. Hope example helps.
It has some patterns built-in.
You will have one “real” strip (whole in example), which does all the transmission work.
You can have partial strip (circles, half arrays in example), which is just strip mapped to the part of another strip, so it is easier to apply different patterns to different parts of the strip.
It also allows to have Meta-strips (cl - consists of whole circles, clh - half-circles, cl2 - odd/even circles, cl3 - each 3rd circle in example ). Meta-strip consists of several strips, each of which becomes it’s pixel and so can be controlled as a single LED. Fun starts when colour you set is not plain RGB colour, but animated colour. Like you can have rainbow animation on meta-strip, but instead of setting sub-strip to a single colour from rainbow it will set it to running pixel animation of that colour (rainbowRun in example application).
Check out example application.cpp
Have fun and let me know if you have any questions.
Timing is really nice now for larger strips. I just tried driving the arduino’s max number of 500 pixels (arduino runs out of ram at that point), and the Spark Core is banging them all out in ~15ms without deviating on the last pulse by more than 5ns! Of course I have the color fixed for this test, but if you change the bit pattern, the timing changes by design. All timing of the high and low portions of the HIGH/LOW bit patterns are measuring within 8ns and under of spec, and the spec has a +/-150ns tolerance so I’d say that’s pretty damn good for C code and a little ASM for delays. https://github.com/technobly/SparkCore-NeoPixel
I tried and succeeded to use the SPI to create the WS2812 data stream. When SPI clock divider is set to 8, the SPI frequency is 9MHz, so a bit period is 111nS. So sending 3 bits set to 1 in a row creates a 0.33µS pulse, and sending 6 bits set to 1 creates a 0.66µS pulse; this is well within the tolerance for the WS2812. This works well and with very little code, see below.
However, the approach suffers from the same problem as all others: spark system IRQs interrupt the execution of show() for more than 50uS now and then, which resets the WS2812 chips in mid-transmission and leads to ugly glitches in the color pattern. This can be fixed using __disable_irq(), but in turn this blocks other tasks within the spark core firmware for quite long chunks of time.
So what’s the point of using SPI then? The spark chip can use DMA to send SPI data streams without any CPU load, at full speed. So if we can manage to set up DMA, and an IRQ to re-fill the output buffer from RGB data, this would be the most elegant solution for the WS2812 driving problem. So take the following code as a proof-of-concept that SPI can be used to generate WS2812 timing easily, and a starting point for a DMA based, non IRQ blocking WS2812 driver.
Anyone out there who already got experience with the spark core’s DMA?
Here’s the minimal code based on SPI (complete working WS2812 driver, connect LED data to pin A5):
#define NUMLEDS 240
#define NUMDATABYTES (NUMLEDS*3)
byte msg[NUMDATABYTES];
void begin()
{
SPI.begin();
SPI.setClockDivider(SPI_CLOCK_DIV8); // System clock is 72MHz, we need 9MHz for SPI
SPI.setBitOrder(MSBFIRST); // MSB first for easier scope reading :-)
SPI.transfer(0); // make sure SPI line starts low (Note: SPI line remains at level of last sent bit, fortunately)
// initialize the buffer
for (int i=0; i<NUMDATABYTES; i++) {
msg[i] = 0;
}
}
void show()
{
// Note: on the spark core, system IRQs might happen which exceed 50uS
// causing WS2812 chips to reset in midst of data stream.
// Thus, until we can send via DMA, we need to disable IRQs while sending
__disable_irq();
for (int i=0; i<NUMDATABYTES; i++) {
byte b = msg[i];
for (int j=0; j<8; j++) {
SPI.transfer(b & 0x80 ? 0x7E : 0x70); // 0x7E = 6 bits high = WS2812 HI, 0x70 = 3 bits high = WS2812 LO
b = b << 1;
}
}
__enable_irq();
}
void setRGB(int aLEDNumber, byte aRed, byte aGreen, byte aBlue)
{
int i = aLEDNumber*3;
// order in message is G-R-B for each LED
msg[i] = aGreen;
msg[i+1] = aRed;
msg[i+2] = aBlue;
}
I’ve been experimenting with different kinds of ways to output stable waveform (not on Spark, but on AVR Xmega mostly).
The problem with SPI is that if it is done with pure DMA it will require to pre-process all the data and it will take 8 times more (byte per bit). You can do this after DMA has finished each transaction, but this will take CPU during transmission then.
First thing I used to deal with this is to add attiny13, which will convert SPI to WS2811 waveform just by knowing delays required. This works fine if you have stable 800KHz SPI output, but adds more HW and FW (just ~50 lines of asm, but still thing to flash IC with).
Another option was DMA+SPI + 1G97 + capacitor for delay, which is lower cost and no additional FW. Adds a little of analog circuitry though, so I decided to go digital-only way.
It was DMA + PWM + AWeX and some preprocessing (but it does not add more memory requirements - just bits rearrangement) + OR IC on each channel to be able to output to 16 LED strips in parallel. Though unlike Cortex-M3 it does not have separate memory bus for each DMA and CPU, so it was not possible to do something while DMA is working or you can brake things, but DMA allows to get exact timings on lots of parallel channels.
For Spark it should be possible to port OctoWS2811, as it was written for Teensy. It uses Cortex-M4, not M3, so I’m not sure how big differences will be. From what I see it does not have separate bus for DMA, so may have the same problems I had on Xmega. But it can be worth to try it anyway.
SPI - Serial Peripheral Interface. Synchronous data transfer interface with clock, 2 data lines and chip select per slave device. DMA - Direct Memory Access (in this case - the way to transfer data between memory and peripherals without using CPU) AWeX - Advanced Waveform Extension (basically extended PWM on Xmega)
Very cool @luz! I just checked the timing on my scope and it’s about 330ns high and 660ns high as you say, but the off time is about 2us and that makes the period out of spec from 1.2us +/- 600ns. That said, it seems to work ok for me with some WS2812’s. Nice color cycle too
Have you been finding the __disable_irq(); to cause issues with your bg tasks? So far I haven’t seen any, but I might not be testing the right thing.
I know that the off time is much longer than the specs say, but from my understanding of a bit stream decoder as the one in the WS2812 I’d guess the low time specs are just minimums. You can’t go faster, but you can go muuuch slower. The circuit probably just triggers on the rising edge, then samples the state about 0.5µS later. How long the signal remains low does not matter, except that it might not be low for longer than 50µS, because then the chip resets.
So far, I haven’t found __disable_irq() causing issues to bg tasks. In particular, the cloud API works fine. However, my spark core crashes about once every 2 hours (as others have reported in other threads) - maybe the IRQ blocking contributes to this, hard to know.