APA102 individually addressable LEDs #982
Replies: 33 comments
-
Posted at 2016-01-23 by @allObjects Since they are clocked and not timed, higher switch frequencies can be applied... adafruit sells them under the term DotStar LEDs https://www.adafruit.com/products/2241. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-23 by DrAzzy I got a whole page written up from them ready to submit to the docs. Click "Commit" Anyway - the pingpong ball light project lives: |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-24 by @MaBecker Maybe you want to check this video as well APA102 RGB Pixel Addressable LED, Julian Ilett is doing great stuff ! Or check this site digging-into-the-apa102-serial-led-protocol on HACKADAY |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-24 by DrAzzy
|
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-24 by @MaBecker NICE ! Question: shouldn't setTimeout("animate()",100); be outside of function animate() {} ? |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-24 by DrAzzy animate() sets the timer to call itself again for the next frame ;-) |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-25 by DrAzzy On an ESP8266:
The table needs to be adjusted a bit more still, I think. The "twinkle" effect is a slow drift of the LED color around the set point - in this way, a bunch of LEDs that are set to the "same" color won't all look identical, and their colors relative to eachother will subtly shift over time, giving a more organic effect. The diffusers look great now - I'm using a single halved pingpong ball for each, with the halves inside eachother (with the help of a bit of glue). |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-25 by @gfwilliams Looks nice! I guess it doesn't actually add much to the cost vs. a WS2812B if you're using LEDs on a PCB. I guess the LED strings with wires will still have a slight premium though. What's the power-on state? I know I bought a bunch of APA104s (WS2812B clones) and the power on state was full blue, which really sucked for pretty much everything - the under counter lights in my kitchen have this annoying 100ms blue flash when turned on now! By the way, you can change:
to:
|
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-26 by DrAzzy
Added web control, selectable twinkle modes, and pulse/fade. Takes URLs like this:
New gtab that seems to do a better job of linearizing the light output vs brightness and smooths dimming at low brightness, and another level of global dimming use to take advantage of this. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-28 by DrAzzy Anyone have any thoughts on improving performance of flip() and dotwinkle()? I realize they're inefficient, but I'm not sure I know what the right approach is towards making them more efficient. I'm discovering that if I want even 10 LEDs in the string, the frame rate is going to be terrible.... it's about 70ms per flip() and 50ms per dotwinkle() |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-28 by @gfwilliams I'm not 100% sure what it's doing, but I'd say lookup tables are the way to go. Also allocating a new Uint16Array each time around the loop isn't great - it'd be faster as a normal array. Even something like:
would help, as it's not having to parse a whole bunch of stuff each time around the loop. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-29 by DrAzzy I've reworked these.... but it's still slow.
flip() is taking about 16ms. doTwinkle() (with animode=0) is taking 30-45ms (depending on animation modes - mo=1 is the worst, mo=2 is only a little better) with 5 LEDs. That means 3ms + 6~9ms per pixel, which is too slow for a string of 10-12 pixels... Changing from this.blah (with the longer variable names) only saved a few milliseconds per run. I'm sort of wondering what it is that I'm doing that's taking the time. Would reworking it to use map() in dotwinkle() be faster? Er, can I even do that? Maybe I can't... |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-01-29 by @gfwilliams Well, at the moment you have a bunch of commented out code in the FOR loop. Just removing that would help a lot (or you could turn on minification?). Also, What happens with If so, make
to:
|
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-02-02 by DrAzzy I'm already minifying. The point of the Math.max() is to ensure that if bch > 0, the result is >0 - basically, so that if a channel is supposed to be on, but very dim, and the bitshift would make it 0 (off), we instead set it to minimum brightness (1). changing to incrementing a variable only shaved off about 1ms. I was playing around with commenting out lines though. flip() is now down to 18ms or so, but with mode=1 (twinkle), dotwinkle() takes like 45ms.... There are three lines that will save 11ms if I comment them out (ofc, they're critical lines!). These times are with just 5 LEDs, too...
On the Pico, times are 16ms and 38ms - so the pico is only a little faster than the ESP8266. It looks like the costly operation may be accessing array members? |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-02-02 by @gfwilliams Are all those arrays typed arrays? Accessing those should be quite quick, but accessing large, normal arrays is slow. Mind you, your arrays really aren't that large. It also helps if all the variables you're accessing are defined in the function itself, but it looks like you're doing that. Actually even finding a variable based on name is a bit slow, and for an array access you're finding at least 2 variables. So something like Compiled code is also potentially an option? |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-02-03 by @allObjects What about... For execution, the code is loaded into the RAM - and therefore it is modifiable - is it?. With some JIT compiler mind, the interpreter could after first lookup of a (long enough) variable (or function) referencing name override that name with a prefixed pointer. The prefix is some reserved byte(s) value which is telling the interpreter on subsequent interpretation that the lookup already happened. (May be there is no such special byte(s) left to make the interpreter recognize). Caveat: the delete of a variable becomes a bit tricky... and would thus not be allowed anymore. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-02-03 by @gfwilliams One issue is that there isn't any kind of JIT in Espruino - it just runs the source code directly. I had wondered about trying to tokenise it and pull out the variable names, but that is quite a big undertaking. My worry is that if you have some kind of cache, you have to make sure it's in the right state. I'm struggling to think, but I could imagine that halfway through a function you might be able to call another function which changed which variable something like Perhaps I'm wrong about that though - if so then life could be a lot easier. I like your variable name suggestion @drazzy - that could be very easy to add a special-case for, and it would be very easy for users to take advantage of. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-02-03 by DrAzzy Yeah - there's sort of this knee-jerk reaction in my brain "oh that's evil, special cases for certain variable names", but the more I think about it, the more sense I think it makes here. The fact that the minifier is already transmuting local variables into lowercase single letter variables with letters near the start of the alphabet means that people will take advantage of this without even knowing it, assuming they send the code from the right side of the IDE so it gets minified. And we already have to minify the code if we care about it running fast. But if you're hand optimizing code, it's the same thing - single-letter variable names are what we should be using anyway. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-02-03 by @allObjects I did not study the variable handling close enough, but I expect a memory area where actually the metadata about the variable is kept - last but not least for garbage collection and the like - and that part stays put (has fixed address) - I expect or hope... I know: in science and technology, only fools hope :). But anyway... The pointer overwriting the variable name in the source I was thinking of would point to the location of the meta data and not the location where the actual value is. Since I do not know how the space of the variable metadata is organized (where The linked-list concept makes me just now think that the meta data may be a 'memory address in-line' header of the actual variable data, and all is a linked list with explicit (pointers) or with implicit (length) linking for the lookup. Separation of the variable meta data from the actual value data make a partial JIT possible... (That's what I did in my OO VMs in order to have resolved references... that are fast, random - array like - accessible). There are usually not infinite places for a 'contiguous, growing/shrinking' memory space... and the separation asks just for one more... In addition, one more pointer has to be hosted per variable which points from the meta data to the value data. Furthermore, more discrete items in memory waste more bytes since they do not all align with the memory block boundaries... which confirms the truth that speed costs space. For some defined data types - such as int, boolean, float (and natively implemented objects of known fixed lengths), the meta data can also include the values and there is no need for pointing into the 'wild' (dynamically) managed memory space. While writing this post, I conclude that Espruino does not separate variables' meta-data form variable data, and going for a separation is a major concept change: a new Theory of Operation. @drazzy's idea is NOT THAT knee-jerk: remember Rockwell's 6502... a processor breath life into Commodore's PET and Apple I and on is still very a-live, and what did this thing do - more precisely - what where the architects of it thinking? Let's treat the first 256 memory locations / (single bit addresses) be handled differently: let's treat them as general registers! A brilliant hybrid choice for a time when (memory and processing) resources weren't commodities yet... and about the same I feel with Espruino. And I used the Wang Computers which used a similar approach: Variable names would always start with an uppercase and be followed by a digit 0 thru 9. Ending with a $ denoted one of the two only available data types: Strings. The other data type was a number (of course - last but not least it was 'a computer' - Wang 2200 T, starting out from a Wang 370 desk calculator). Wang 2200 T was a TTL implementation with 18 bit word format and 7483 based ALU and memory was blankets of blankets of RAM chip 'cards'. Usually, i like pure, consistent implementations, but with what is at stake and can be achieved 'here' with very limited resources asks for a bit more flexibility, creativity,... (going for that single letter variable thing, may mess a bit with the minifiers..., but after all it could be quite a boost. It could though start a 'war of claims': who owns which variable... because they are global and exist only once! |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-02-04 by @gfwilliams
It'd be worth looking at http://www.espruino.com/Performance and http://www.espruino.com/Internals... Espruino has the concept of a 'name' and an actual value. So something like I think we might be getting sidetracked from APA102s though. The single-char cache might work, but I'm wary that there may be some nasty edge cases - it'd be a case of trying it when I have some time, and seeing if it broke any of the language tests. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-02-04 by @allObjects
Was thinking that too... but did not want to start separate thread (yet).
Yes, but they are 'stuck' with one another in 'block contiguous' memory. As soon as they can be / are separated, a JIT as sketched in previous posts can be achieved. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-02-17 by DrAzzy
Latest version of code. I can put animations on the eeprom like this, and play them back with leds.setAnimation(), and I can load and save the static (well static including twinkle/pulse data) frame data as well with leds,save() and leds.load().
with that, try: leds.setAnimate(1,2432,4); leds.setAnimate(1,2560,10); Upcoming is a way to track which index slots are occupied, same with animations. My big problem now is just finding ways to make the animation data.... Well, that and performance - with ten pixels, I get about 8FPS, which is pretty shit. I'll probably redo it when we get the cheap Espruino - use that to handle the updates, and use compiled JS to juice the execution speed, and communicate over serial with an ESP8266 running Espruino to handle the web interface. Hell, it could just send javascript commands down serial, and use the Espruino's serial console! That'd be neat, and if it got me more than 10 LEDs that would be awesome ;-) |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-02-18 by DrAzzy
Alternate modes for animations - this lets me get ~30 fps with animode =5 (where the background is totally replaced) or 18fps with animode=3 (where the background and current twinkle state is used, but all other calculations are stopped. I just wish I could do the twinkle calculations faster. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-02-18 by @gfwilliams For the twinkle, can you just use a table of intensities that you cycle through over time? Maybe just multiply 'mult' by the value that's in it? I'm not quite sure what the twinkle effect is (I haven't tried the code) but if it could be replaced by a table, it'd probably speed things up a lot. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-02-18 by DrAzzy The "twinkle" effect sets the contents of leds.t, a signed int8 array.... I don't see how it could be done with a table though: There are two twinkle modes (so far) - the basic random twinkle - each channel of each LED has a chance (from 1/16 to 16/16, depending on high nybble of the mode for that channel of that LED in leds.tm) to change by 1 (plus or minus) within the range set by leds.ta and leds.ti. At high chances of change, and lowish brightness, you can get an effect reminiscent of flickering candle flames. At higher brightnesses and/or lower chances of change, the changes are less visible, but you can have all of the LEDs, or groups of the LEDs set to the same color, but with twinkle on, so they're not each exactly the same color - which is a key goal. The other mode is simple fade back and forth of the twinkle brightness between the minimum and maximum brightnesses. All of these are per channel not per LED. |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-05-20 by user64869 i want to know if those APA102 led code can work with Arduino or not . thanks |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-05-20 by @gfwilliams With Arduino, or Espruino? If you're asking about Arduino this is the wrong place I'm afraid... |
Beta Was this translation helpful? Give feedback.
-
Posted at 2016-05-20 by DrAzzy APA-102 can be used with both Arduino and Espruino - anything that can do SPI should be able to drive them. As Gordon noted, this is the Espruino forum, so if you're looking for Arduino information, you're in the wrong place. Arduino is programmed in compiled C, Espruino is programmed in interpreted javascript - the code is totally different. The thing you linked to - I'm not sure how that link was relevant. It looks like they just assemble APA102 LEDs into strips... ? |
Beta Was this translation helpful? Give feedback.
-
Posted at 2018-06-07 by DrAzzy I just noticed the E.mapInPlace() function. Would using this be expected to improve performance where I was looping over the array? What version of Espruino was that added with? |
Beta Was this translation helpful? Give feedback.
-
Posted at 2018-06-07 by @gfwilliams
In a lot of cases, yes. You can also use it with a lookup table which will be really fast.
1v77 by the look of it :) |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Posted at 2016-01-22 by DrAzzy
Has anyone else written any code for these bad boys?
If you haven't heard the news - the APA102 is like a WS2812B on steroids.
They use data and clock lines, not just data, so the timing isn't critical (and you control them with normal SPI, albeit in a weird mode). They have 4 bytes per pixel. 3 1's, 5 bit global brightness, then 8 bits per color. The per-color brightness is PWM'ed at 20khz, while the global brightness is PWMed separately at ~600hz. So yeah - these are like WS2812B's, only you can do dim colors better (0/255 to 1/255 to 2/255 is a very visible change in brightness - you need more than 255 steps to smoothly dim all the way down to nothing), or you can use them in fast-moving things without getting the dashed-tracers that you get from WS2812B's or things PWMed at low frequencies.
I've got these working on the bench (ie, controlling them by hand) and will be writing usable code to control them, but I wanted to check that I wasn't going to reinvent the wheel.
If nobody else has, I'll write up what I did to control them and submit to the docs.
Beta Was this translation helpful? Give feedback.
All reactions