Pages: [1] 2 3   Go Down
Author Topic: Optimization of code for maximum speed, very specific project.  (Read 3194 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 1
Posts: 41
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

A while back I built a Christmas lights controller that used Vixen to create the light sequences.  That project used mechanical relays and, while it worked fine, it didn't provide any real dimming capabilities.  I've since moved on to version 2 of the controller using random-cross SSRs instead of the mechanical relays, the hardware is done, now and I'm working on the software.  I'm trying to do full dimming of 32 channels of lights all controlled via the Vixen sequencing software.

I've already done most of what I can think of to speed it up, even before bothering to do real testing on it. (I've already tested the hardware side)  My normal rule would be make it work then make it work fast. Unfortunately in this case if it isn't fast it just won't work.  smiley I've put comments in the code explaining why I thought doing certain things would speed it up. I've also put in TODO: comments every place I'm curious about the method I used or think there is a better, faster way to do something.

What I would like is a little help or pointers in the right direction for squeezing every extra cycle possible out of the sketch.  I've put the old (version 1) and new (version 2) code up here:

https://code.google.com/p/arduino-christmas-lights-control-system-for-vixen/

The new code is the XmasLightControllerForVixenSSRs.ino download.  I'm using 1.0.1 version of the Arduino IDE right now.

The basics of the sketch are:

1> reads 32 channels of data from Vixen via an FT232R breakout board on Serial1, Vixen sends me 32 channels (bytes) every 50ms but this is adjustable. I want to be able to handle the data at the fastest possible speed
2> uses an AC zero-cross detection circuit to trigger an interrupt so I can calculate when in the AC cycle to turn the digital pins on/off (this is the dimming, turn on later in the cycle makes the lights dimmer)
3> uses portions of the Faster Digital Write library to do port manipulations
4> has a random lights mode (you can ignore all the code related to this as it doesn't need to be fast)
5> uses Timer/Counter 1 in CTC mode to keep track of number of ticks (cycles) via an interrupt
6> The methods that have to execute as fast as possible are:  loop(), readFromVixen(), ZeroCrossDetected(), ISR(TIMER1_COMPA_vect) - everything else can run slower.
7> uses an ArdunioMega 2560

Any insights you can give would be greatly appreciated. Thanks.

Logged

Offline Offline
Newbie
*
Karma: 1
Posts: 41
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I would have posted the code but it is too long for the forum, thus the link to code.google.com above.
Logged

Global Moderator
Dallas
Online Online
Shannon Member
*****
Karma: 200
Posts: 12779
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
unsigned long time = millis();
...is pointless.  millis always returns zero during the RTL initialization.
Logged

Global Moderator
Dallas
Online Online
Shannon Member
*****
Karma: 200
Posts: 12779
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I would have posted the code but it is too long for the forum, thus the link to code.google.com above.

Files can be attached to posts.
Logged

Global Moderator
Dallas
Online Online
Shannon Member
*****
Karma: 200
Posts: 12779
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
// speed for the comm port for talking with vixen, this is the comm
// port on the FT232R breakout board.
#define VIXEN_COM_SPEED 57600

// speed for talking with the serial monitor in the IDE, this is the
// comm port built into the ardunio with the USB port
#define PC_COM_SPEED 115200

If possible, use higher baud rates.  250000, 500000, 1000000 are good choices.
Logged

Offline Offline
Newbie
*
Karma: 1
Posts: 41
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thank you. The file is attached here. smiley

* XmasLightControllerForVixenSSRs.ino (46.85 KB - downloaded 23 times.)
Logged

Global Moderator
Dallas
Online Online
Shannon Member
*****
Karma: 200
Posts: 12779
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
 randomSeed(analogRead(0));

...in most cases is the same as this...

Code:
 randomSeed( 614 );

In any case, randomSeed should be called once in setup.  Calling it more often indicates you do not trust the generator.  In that case the generator should be replaced with one you do trust.
Logged

Global Moderator
Dallas
Online Online
Shannon Member
*****
Karma: 200
Posts: 12779
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
 delay(RANDOM_MODE_SPEED);
Code:
 if(waitForVixenHeader()) // we got the data header now read the channel data
Code:
void readFromVixen()
...is where you start optimizing.  The most effective way to optimize Arduino code is to get rid of blocking code like delay.
« Last Edit: April 03, 2013, 09:58:56 pm by Coding Badly » Logged

Global Moderator
Dallas
Online Online
Shannon Member
*****
Karma: 200
Posts: 12779
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


If the ISR / digital I/O code is a bottleneck (I highly doubt it is) using "port manipulation" should allow you to speed it up.  You would be able to manipulate eight bits / eight I/O pins with a few machine instructions.
Logged

Offline Offline
Newbie
*
Karma: 1
Posts: 41
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks again. I've been reading this link about the time ISRs take, found a reference to it in another post here.  Seems I completely under estimated the cycles it takes just to get into and out of an ISR.  Maybe it won't be a problem though. 

I'd like to do 255 levels of dimming but I suppose if I find I can't make that happen I can change that to something smaller like 32 or 64.  Vixen lets you define the lower and upper bounds of the channel values.
Logged

Offline Offline
Newbie
*
Karma: 1
Posts: 41
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The delay() call shouldn't be a problem, where it is, as it is used in the POST and the random mode which isn't an issue because there is no dimming happening there and there is no reading data from Vixen. So thumbs up on that one. smiley
Logged

Offline Offline
Newbie
*
Karma: 1
Posts: 41
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


If the ISR / digital I/O code is a bottleneck (I highly doubt it is) using "port manipulation" should allow you to speed it up.  You would be able to manipulate eight bits / eight I/O pins with a few machine instructions.


So I know you don't have time to go totally in depth but: With the little bit you have been able to look, do you think the code I have in the ISRs is a bad (slow) way to structure it? Sounds like you think that should be fast enough the way it is.  I guess my next move is to truly hook this up and see what happens,   smiley-razz
Logged

Global Moderator
Dallas
Online Online
Shannon Member
*****
Karma: 200
Posts: 12779
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I guess my next move is to truly hook this up and see what happens,

That's what I would do.   smiley-wink
Logged

Offline Offline
Newbie
*
Karma: 1
Posts: 41
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Just noticed I have the powerDelayPreCalc array backwards, lol. Higher channel values need lower powerDelay values to make them turn on earlier in the AC cycle.
Logged

Des Moines, WA - USA
Offline Offline
God Member
*****
Karma: 25
Posts: 779
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Does v2 run as you expect?

This code fragment, picked out of the array at random, has me thinking not.

Code:
TICK_HALF_CYCLE * ( 12 / 255)


'TICK_HALF_CYCLE' is defined as -

Code:
#define TICK_HALF_CYCLE 133333

The signed integer literal '133333' is outside the range of an unsigned integer which on the ArdunioMega 2560 is 2 bytes wuth a range of -32766 to 32767.

Next we have the signed integer literal 12  to be divided by the signed integer 255 which should result in 0.

You then want to multiply the out of range 'TICK_HALF_CYCLE' by 0 which should then result in an array entry of 0

It looks to me as if the whole table 'powerDelayPreCalc' should be filled with 0's
Logged

Pages: [1] 2 3   Go Up
Jump to: