You do not have permission to delete messages in this group
Copy link
Report message
Show original message
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to toasted-circu...@googlegroups.com
Hi Andrew and Lightuino group
First of all a Merry Christmas and a happy new year! In the seasons
spirit, I come bearing gifts. Well, one, little, gift: I made some additions to the
Lightuino library which I hope you will like. However I am also in need
of some help, more about that later.
For my wordclock project I want to have an animated matrix that blends
from one image to the next. The idea is pretty simple. I'm alternating
between 2 video buffers in a PWM like fashion. First 100% of the cycles
are image 1, halfway 50% image 1 and 50% image 2, and ending up at 100%
image 2.
In order to do this I made a few modifications to the Lightuino library:
- I wanted to run the matrix using the timer2 interrupt, but because the
timer function is also used for the software PWM of the sinks, I moved
the timer2 code to the class LightuinoTimer2. I added that the
pre-multiplier is chosen based on the requested run frequency. This
results in a broader range of frequencies, while using maximal resolution.
- I updated the LightuinoPwm class to use the LightuinoTimer2. I must
admit I haven't tested this, but it compiles, and the setup is very
similar to that in the LightuinoAnimatedMatrix class. What could
possibly go wrong? :-)
- I modified the LightuinoSourceDriver to use the DigitalPin library by
by William Greiman, which implements much faster digital in and out
functions. For the LightuinoAnimatedMatrix class I only use the
src.shift function, so I think this cannot be further optimized for speed.
- I added the LightuinoAnimatedMatrix class, which holds 2 image
buffers. While one is being shown, the other can be edited. After
editing, you can directly switch to the next image, or blend the next
image in. Compared to the LightuinoMatrix class, it exposes the
following new functions
- startAutoLoop() - Start automatic looping
- startAutoLoop(rate) - Start automatic looping with custom
frequency
- stopAutoLoop() - Stop automatic looping
- void update() - Make next image current image and show it
- void animate() - Animate from current image to next image.
Finally, make next image the current image
- clearCurrent(val) - clears the current image
- clearNext(val) - clears the next image
While in steady state (not animating), the autoLoop function loops
through the sources at low speed, 100*numberOfSources, to reduce CPU
load. When animating, the refresh rate needs to be cranked up to reduce
flickering. If during a Pwm loop of N values, the led is turned only
once, the refresh frequency should be at least 100*numberOfSources*N.
For my clock matrix I use 2 sources, and a PWM loop of 10 steps, which
would need a refresh rate of more than 2 kHz.
This is where I have troubles. I cannot reach a high enough refresh
rate. I suspect the bottle neck is the unoptimized LightuinoSink class.
I have tried using the DigitalPin library there as well, but it seems to
throw of the timing of pushing bits. I had a look at the optimized code
you wrote for the LightuinoPWM class, but I must admit I don't really
understand it. I suspect that you crafted it to deliver the most optimal
ASM code, but there I'm out of my depth.
So my question is: would it be possible for you to optimize the
LightuinoSink class similar to the LightuinoPwm class? That would really
help me out!
You do not have permission to delete messages in this group
Copy link
Report message
Show original message
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to toasted-circu...@googlegroups.com
Hi Thijs,
Thanks for this code! I haven't had a chance to look at it closely yet but the AnimatedMatrix class sounds like it could be extremely useful. The LightuinoSink class is not terribly slow if you are using the "fastSet" APIs (which you should be if you are using the default pins for the sinks). Before doing optimization, can you check to see if they will meet your criteria by using the Pwm class. To do this, do not use the "Autoloop" feature of the Pwm class. Instead call "loop()" yourself. And of course, set the values in the array to MAX_BRIGHTNESS-1 to simulate always-on like the Sink class provides.
Cheers! Andrew
Thijs
unread,
Jan 6, 2013, 4:06:09 PM1/6/13
Reply to author
Sign in to reply to author
Forward
Sign in to forward
Delete
You do not have permission to delete messages in this group
Copy link
Report message
Show original message
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to toasted-circu...@googlegroups.com
Hi Andrew,
I decided to take a stab at optimizing the code myself and discovered that the fastSetBy32 is indeed not slow at all and especially the inner loop is quite fast. I did some speed tests on the animated matrix code, specifically the animatedLoop code:
void lightuinoAnimatedMatrix::animatedLoop() { .... curRow++; // At end of all lines (sources) of image.. if (curRow >= startRow+numRows) { // Set first startline curRow=startRow; // Determine which image should be shown videoRamUsed = frameToShow() ? videoRamNext: videoRamCurrent; }
The performance difference of the static loop (198.7 micros, 4.9 kHz) and the animatedLoop (201.0 micros, 5.0 kHz) is quite small. Codewise the difference is the Pwm switching logic, and a separate test indeed shows that the Pwm code (mostly in the frameToShow function) does not contribute much (7.5 micros). The src.shift is also fairly lightweight (4.3 micros). The performance costs are clearly in the sink.set function (191.5 micros).
Next had little stab at optimizing the sink class. The mayor speed increase came from changing the DigitalWrite to fastDigitalWrite (approx. 35 micros), the rest of the speed increase was due to using constants, moving the lookuptable creation out of fastSetBy32 function, loop-unrolling etc. In-lining the Source.Shift code in the AnimatedMatrix class improved speed, but strangely enough, in-lining of the Sink.Set code did not.
All-in-all, I was able to get the total loop time down to 92.8 micros, so I passed the 10 kHz mark! The animations are not perfect, but notably smoother (see movie).