Show Posts
Pages: 1 [2] 3
16  Using Arduino / Programming Questions / Re: Optimization of code for maximum speed, very specific project. on: April 04, 2013, 09:29:03 am
How do you know it's too slow?  And how much too slow IS it?  Can you do the sort of dimming you're looking for, with your existing code, on 16 pins?  2 pins?

Well, I don't yet, to tell the truth. smiley  I just know that the faster I can get the better looking the dimming is going to be.

Hmm.  It looks like the biggest problem you have at the moment is trying to run the timer interrupt too often.  Trying to interrupt in fewer cycles than your service routine takes to execute is a recipe for disaster; you'll essentially end up executing one main program instruction, doing the entire ISR, one more main program instruction, etc...

Yep, I'm going to have to play with this but I have changed it to count to 500 for right now.

Similarly, since serial messages are only occasional and not more than every 50ms, while AC cycles happen every 1/120 s (8.3ms),
get rid your calculations of powerDelay[] in ZeroCrossDetected and move them into the serial receive code.

Those calcs must have be in an earlier version of the code, right now the ZeroCrossDetected function just turns all of the channels off and then assigns the correct powerDelay values from the pre-computed list. So should be good to go here.

How many brightness levels are you trying to get?  Make sure that you're not running your timer interrupt too often, or it will suck up extra cycles in overhead that might be needed elsewhere.  (It looks like this is really bad at the moment!  This is probably the biggest change that needs to happen!)   tickCounter should probably be MUCH smaller than 32bits; ideally you should divide the 8.3mS half-cycle time into exactly N ticks by adjusting the timer prescaling and count, which will give you up to N brightness levels and simplify a LOT of the  math that is happening, assuming that N < 256.

I'm trying to get 256 levels of brightness, but frankly I'm not sure that level is needed.  64 would probably be enough but I want to shoot for 256. I've changed tickCounter to an unsigned 16bit int. I don't think I'm going to be able to run the IRS fast enough to get down to a byte, but you never know. smiley

This code is interesting:
Code:
 if(powerDelay[CHANNEL_PIN_1] <= tickCounter) customDigitalWrite(CHANNEL_PIN_1, HIGH); // turn the channel on here
  if(powerDelay[CHANNEL_PIN_2] <= tickCounter) customDigitalWrite(CHANNEL_PIN_2, HIGH); // turn the channel on here
  if(powerDelay[CHANNEL_PIN_3] <= tickCounter) customDigitalWrite(CHANNEL_PIN_3, HIGH); // turn the channel on here
  if(powerDelay[CHANNEL_PIN_4] <= tickCounter) customDigitalWrite(CHANNEL_PIN_4, HIGH); // turn the channel on here
  if(powerDelay[CHANNEL_PIN_5] <= tickCounter) customDigitalWrite(CHANNEL_PIN_5, HIGH); // turn the channel on here
Because all the array calculations are done at compile time, so it's load memory, load memory, compare, portwrite.
However, the load memory operations are currently 32bits, and since tickCounter is volatile, it is loaded each time (at significant expense.)  Replace with something like:
Code:
 register uint8_t tick = tickCounter;  // get a local copy!
  if(powerDelay[CHANNEL_PIN_1] <= tick) customDigitalWrite(CHANNEL_PIN_1, HIGH);
  if(powerDelay[CHANNEL_PIN_2] <= tick) customDigitalWrite(CHANNEL_PIN_2, HIGH);
  if(powerDelay[CHANNEL_PIN_3] <= tick) customDigitalWrite(CHANNEL_PIN_3,
HIGH);

This was VERY helpful, it has been a LONG time since I've had to think about this kind of stuff. I'm now grabbing a local copy.

Part of the reason I'm so focused on speed here is that I have a number of folks that may be building similar projects by following mine.  While I'm only going to be using 32 channels with 256 dimming levels and a 50ms frame rate from Vixen, these other folks may be using other settings.  The faster I can make this now the more likely the other people will be to not run into major issues, I hope.

Attached is the latest code.
17  Using Arduino / Programming Questions / Re: Optimization of code for maximum speed, very specific project. on: April 03, 2013, 11:48:36 pm
You guys have really made my night.  I can't tell you how much this helps.  I've got to get some sleep but I had to say thanks again.  smiley
18  Using Arduino / Programming Questions / Re: Optimization of code for maximum speed, very specific project. on: April 03, 2013, 11:27:41 pm
Thank you, I hadn't run through most of this code yet.  That probably would have had me scratching my head for a bit.  smiley-red

Attached is the new version.
19  Using Arduino / Programming Questions / Re: Optimization of code for maximum speed, very specific project. on: April 03, 2013, 10:34:33 pm
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.
20  Using Arduino / Programming Questions / Re: Optimization of code for maximum speed, very specific project. on: April 03, 2013, 10:27:08 pm

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
21  Using Arduino / Programming Questions / Re: Optimization of code for maximum speed, very specific project. on: April 03, 2013, 10:16:15 pm
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
22  Using Arduino / Programming Questions / Re: Optimization of code for maximum speed, very specific project. on: April 03, 2013, 10:11:39 pm
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.
23  Using Arduino / Programming Questions / Re: Optimization of code for maximum speed, very specific project. on: April 03, 2013, 09:47:52 pm
Thank you. The file is attached here. smiley
24  Using Arduino / Programming Questions / Re: Optimization of code for maximum speed, very specific project. on: April 03, 2013, 09:34:08 pm
I would have posted the code but it is too long for the forum, thus the link to code.google.com above.
25  Using Arduino / Programming Questions / Optimization of code for maximum speed, very specific project. on: April 03, 2013, 09:28:52 pm
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.

26  Development / Other Hardware Development / Re: Christmas Lights Control System -Arduino Mega - 16 Channel Relay Board on: December 13, 2012, 05:51:31 pm
i can't think of any reason it wouldn't.  If you have issues let me know.
27  Development / Other Hardware Development / Re: Christmas Lights Control System -Arduino Mega - 16 Channel Relay Board on: December 10, 2012, 06:58:20 pm
Well I've pretty much come to the conclusion that even if I could find SSRs to replace the mechanical relays I still wouldn't get the dimming control I want.  For now I'm leaving the project as is, it works and is a good start for me.  That gives me a year to figure out how to create dimming circuits, lol.  The project was fun though. smiley
28  Development / Other Hardware Development / Re: Christmas Lights Control System -Arduino Mega - 16 Channel Relay Board on: December 09, 2012, 08:06:17 pm
Anyone know if it is possible to replace the mechanical relays on the relay board with equivalent solid state relays (non-zero crossing) and if so what would the part number be for the SSRs?
29  Development / Other Hardware Development / Re: Christmas Lights Control System -Arduino Mega - 16 Channel Relay Board on: December 09, 2012, 04:27:30 pm
I've had a few questions from some folks about the project wiring so a made a little video which I'll be uploading to youtube shortly to try to explain it.  Here is a little textual explanation that covers the most important points.  I don't do very well trying to explain things verbally sometimes, which you will notice if you watch the new video. smiley-razz

Basically the key to the project is this:

There are 3 common power bus lines. Ground, Positive and Negative. 

The electrical sockets all have their positive terminals connected together on the common positive bus.

The electrical sockets all have their ground terminals connected on the common ground bus. 

Each electrical socket has its negative terminal connected to one of the relays with the center screw terminal of the relay.

The third screw terminal (common open of the relay) of every relay is connected to the common negative bus.

When a relay closes it connects the electrical socket's negative terminal to the common negative bus thus allowing power to flow through the circuit for that individual electrical socket, causing the lights plugged into that socket to light up.

There are two power sources for the project.  The power source supplying power to the electrical sockets (the orange plug in the project) and the power supply that is powering the relay board and the Arduino board (that little HP power supply in the project).
30  Development / Other Hardware Development / Re: Christmas Lights Control System -Arduino Mega - 16 Channel Relay Board on: December 08, 2012, 06:42:56 pm
Sorry for constantly updating this thread but I keep making code changes.

Code:
// which pins control which channels
#define CHANNEL01  2
#define CHANNEL02  3
#define CHANNEL03  4
#define CHANNEL04  5
#define CHANNEL05  6
#define CHANNEL06  7
#define CHANNEL07  8
#define CHANNEL08  9
#define CHANNEL09  10
#define CHANNEL10  11
#define CHANNEL11  12
#define CHANNEL12  13
#define CHANNEL13  44
#define CHANNEL14  45
#define CHANNEL15  46
#define CHANNEL16  47

// Which pins is the random/Vixen mode switch using
#define RANDOM_MODE_PININ 52
#define RANDOM_MODE_PINOUT 53
#define RANDOM_MODE_SPEED 5000

int channels[] = {CHANNEL01,CHANNEL02,CHANNEL03,CHANNEL04,CHANNEL05,CHANNEL06,CHANNEL07,CHANNEL08,CHANNEL09,
CHANNEL10,CHANNEL11,CHANNEL12,CHANNEL13,CHANNEL14,CHANNEL15,CHANNEL16};

// how many channel will vixen be sending
#define CHANNEL_COUNT 16

// speed for the com port for talking with vixen
#define VIXEN_COM_SPEED 57600

// speed for talking with the serial monitor in the IDE
#define PC_COM_SPEED 57600

// setup your choice of dimming values or just on/off values
// the relays don't seem to be able to dim the lights so it looks
// like I will have to build dimmer circuits for next year. The
// doesn't change, just have to remove the relay bord and replace
// it with a dimmer circuit for each relay.
#define MODE_DIMMING 0
#define MODE_FULL 1
#define MODE MODE_FULL

boolean startingVixen = true;

void setup()
{
  Serial.begin(PC_COM_SPEED);
  Serial1.begin(VIXEN_COM_SPEED);
 
  // set the channel pins to output mode
  for(int channelIndex=0;channelIndex<CHANNEL_COUNT;channelIndex++){
    pinMode(channels[channelIndex],OUTPUT);
  }
 
  // set up the switch for Vixen or Random mode
  pinMode(RANDOM_MODE_PININ, INPUT);
  digitalWrite(RANDOM_MODE_PININ,HIGH); // turn on the internal pull-up resistor
  pinMode(RANDOM_MODE_PINOUT, OUTPUT);
 
  turnLightsOff(); 
  powerOnSelfTest();
}

// !!!! note the PWM values that need to be sent to the relay board are reversed from the
// values comming in from Vixen.  Vixen 0-255 (off-on), Relays 255-0 (off-on)
void loop()
{
  if(digitalRead(RANDOM_MODE_PININ)==LOW){ // blink at random mode
    startingVixen=true;
    doRandomLights();
  }else{ // play from Vixen mode
    if(startingVixen==true)
      turnLightsOff();
    readFromVixen();
  }
}

void powerOnSelfTest()
{
    Serial.println("Power on self test running.");
    for(int channelIndex=0;channelIndex<CHANNEL_COUNT;channelIndex++){
      Serial.print("Channel: ");
      Serial.println(channelIndex+1,DEC);
      analogWrite(channels[channelIndex], 0); // turn on one channel at a time
      delay(500); // wait .5 seconds
      analogWrite(channels[channelIndex], 255);
    }
    turnLightsOff();
}

void turnLightsOff()
{
  //turn them all off
  for(int channelIndex=0;channelIndex<16;channelIndex++){
    analogWrite(channels[channelIndex], 255);
  }
}

void doRandomLights()
{
    randomSeed(analogRead(0));
    Serial.println("Writting random values.");
    for(int channelIndex=0;channelIndex<CHANNEL_COUNT;channelIndex++){
      if(MODE == MODE_DIMMING)
      {
        int randNumber = random(255);
        randNumber = map(randNumber, 0, 255, 255, 0);
        analogWrite(channels[channelIndex], randNumber);
        Serial.print(randNumber, DEC);
        Serial.print(",");
      }
      else // not dimming, just on or off
      {
        int randNumber = random(0, 255);
        randNumber = map(randNumber, 0, 255, 255, 0);
        if(randNumber<=128)
          analogWrite(channels[channelIndex], 0);
        else
          analogWrite(channels[channelIndex], 255);
        Serial.print(randNumber, DEC);
        Serial.print(",");
      }
    }
    Serial.println("");
    delay(random(100,RANDOM_MODE_SPEED));
}

void outputToLights(unsigned char* buffer)
{
    for(int channelIndex=0;channelIndex<CHANNEL_COUNT;channelIndex++){
      analogWrite(channels[channelIndex], buffer[channelIndex]);
      Serial.print(buffer[channelIndex], DEC);
      Serial.print(",");
    }
    Serial.println("");
}

void readFromVixen()
{
  Serial.println("Waiting for data from Vixen.");
  startingVixen = false;
  char *footer="VIXEN_END";
  unsigned char buffer[CHANNEL_COUNT];
  char buffer2[CHANNEL_COUNT];
  int index=0;
  unsigned long time = millis();

  waitForVixenHeader();
  while (true) {
    int inByte = Serial1.read();
    if(inByte==-1){
      if(index==0 && millis()-time>1000) // we haven't read anything in a second
        return;
      continue;
    }
    time = millis();
    int lightByte = map(inByte, 0, 255, 255, 0);
    buffer[index] = lightByte;
    buffer2[index] = inByte;
    buffer[index+1] = 0;
    buffer2[index+1] = 0;
    index++;
    if(index==9 && strcmp(footer,buffer2)==0){
      Serial.println(footer);
      return;
    }
    else if(index==CHANNEL_COUNT){
      outputToLights(buffer);
      index=0;
    }
  }
  Serial.println("");
}

void waitForVixenHeader()
{
  char *header="VIXEN_START";
  char buffer[12];
  int index = 0;
  unsigned long time = millis();

  while (true) {
  int inByte = Serial1.read();
    if(inByte==-1){
      if(index==0 && millis()-time>1000) // we haven't read anything in a second
        return;
      continue;
    }
    time = millis();
    buffer[index] = inByte;
    if(buffer[index]!=header[index]) {// not the right sequence restart
      index=-1;
    }
    buffer[index+1] = 0; // add null
    index++;
    if(index==11 && strcmp(header,buffer)==0){
      Serial.println(header);
      return;
    }
  }
}
Pages: 1 [2] 3