Speeding up analogWrite() C++ Function (Or other ways to speed up Arduino)

I am wanting to speed up a script that reads/writes an array to/from the serial port between LabVIEW and my Arduino. I have found ways to speed up the digitalWrite() commands by using C and writing to the pin without the “protective” functions that reside inside of digitalWrite().

Is there a way to simplify analogWrite() in a similar way?

Other details about my project.
-float array[10]; (changing this to integer values does not speed up the program)
-LabVIEW is constantly writing the array (I don’t want a “write” button. I want to write the array every cycle)
-there are no delay() functions
-baud rate is at 115200
-delay()ing the read function does not seem to speed things up (thought slowing down the read would reduce the amount of demand)

Any other thoughts on how to speed up the script on the Arduino side of things?

Thanks,
Nathan

Demo_Rev4.ino (4.88 KB)

Najossmith:
-I can post the script later if it is really necessary, for now I don't want it to be a distraction from my question.

Including things like this...

Najossmith:
delay()ing the read function does not seem to speed things up

...means that improving YOUR CODE is the question.

The bold sentence with a question mark at the end is my question.
Is there a way to simplify analogWrite() in a similar way?

"Other details about my project" are intended to answer possible FAQ.

Thanks

Yes, in a manner similar to digitalWrite, you need to take control of the timers. Start by studying this.

Hang some numbers on your question.

Do you want simplicity (Why?) or do you want speed (How much? Why?)

DKWatson:
Yes, in a manner similar to digitalWrite, you need to take control of the timers. Start by studying this.

This is exactly what I need. Thank you!!

Najossmith:
I am wanting to speed up a script that reads/writes an array to/from the serial port between LabVIEW and my Arduino. I have found ways to speed up the digitalWrite() commands by using C and writing to the pin without the "protective" functions that reside inside of digitalWrite().

My guess is that the real time-waster is the serial communication which is probably one or two orders of magnitude slower that analogWrite()

But as you have not posted your program ...

...R
Serial Input Basics - simple reliable ways to receive data.

AWOL:
Hang some numbers on your question.

Do you want simplicity (Why?) or do you want speed (How much? Why?)

Right now, I have an approximate 2000 ms delay between updating the values of the array on LabVIEW and seeing them updated back on LabVIEW. If I could get it to below 1000 ms, I would be happy.

Some of the delay is on the LV side I'm sure, but I'm starting with the Arduino side because I'm more familiar with it. As a note of reference, when I do not continuously write the array, but instead only write to it when its updated, I see about a 1000 ms delay.

I have an approximate 2000 ms delay

That delay is not coming from digitalWrite or analogWrite.
That is a guarantee.

Your delay is coming from a timeout in readInt or somesuch - if only we could see your code {sigh}.

You're barking up the wrong tree

analogWrite takes almost no time at all to execute - all it needs to do is write a few registers to set a new PWM value. Unless you are calling it 10,000 times/second, you can forget about getting any benefit from speeding it up. The same goes for both digitalRead and digitalWrite - unless you are either doing something requiring VERY tight timing, or calling them A WHOLE LOT, there is absolutely nothing to be gained by attempting to speed them up, and NONE of them are the source of your problem.

Your first step should be doing some profiling to figure out where the time is REALLY going, rather throwing darts while wearing a blindfold. You will waste FAR less time.

Regards,
Ray L.

Robin2:
My guess is that the real time-waster is the serial communication which is probably one or two orders of magnitude slower that analogWrite()

But as you have not posted your program ...

...R
Serial Input Basics - simple reliable ways to receive data.

I attached my code to the original post. Demo_Rev4.ino

Your post about serial is super useful by the way.

I attached my code to the original post. Demo_Rev4.ino

Why not simply post the code, so that us folks on mobile devices can see it?

RayLivingston:
analogWrite takes almost no time at all to execute - all it needs to do is write a few registers to set a new PWM value. Unless you are calling it 10,000 times/second, you can forget about getting any benefit from speeding it up. The same goes for both digitalRead and digitalWrite - unless you are either doing something requiring VERY tight timing, or calling them A WHOLE LOT, there is absolutely nothing to be gained by attempting to speed them up, and NONE of them are the source of your problem.

Your first step should be doing some profiling to figure out where the time is REALLY going, rather throwing darts while wearing a blindfold. You will waste FAR less time.

Regards,
Ray L.

I just happened to finish some testing on the use of a 595 shift register, the focus being on the time taken by shiftOut() which uses digitalWrite(). Three different algorithms to shift MSBFIRST compared to using shiftOut(),

** shiftOut() 44901.50ns **
** union 11500.00ns **
** shift1 6812.50ns **
** shift2 18687.50ns **

RayLivingston:
Your first step should be doing some profiling to figure out where the time is REALLY going, rather throwing darts while wearing a blindfold. You will waste FAR less time.

Do you have a suggestion on how to profile my script to determine which part is taking the most time to complete?

Thanks,
Nathan

Najossmith:
Do you have a suggestion on how to profile my script to determine which part is taking the most time to complete?

Thanks,
Nathan

Get a scope or logic analyser, and use spare I/O pins and a fast (single cycle) toggle instructions around the sections of code you want timings for.

AWOL:
Why not simply post the code, so that us folks on mobile devices can see it?

//Laser Control
  int LD_Pin = 3; //Set LD pin
  int LD_PWM = 100; //(0 - 255) 0 = off, 200 = 97 mA
  int inc = 5;
  int Laser_Idle_Duty = 150;    // Control laser current (0 - 255)
  int LD_enable = 0;

//TEC Control
  float TEC_PWM = 100; //TEC heat/cool rate PWM value (0 - 255)
  float thermister_voltage = 5.0; //analog read converted to voltage
  float TEC_max = 30;
  float TEC_min = 20;
  int TEC_enable = 0;
  float TEC_current = 0;

//TEC Temperature
  float TEC_temp; //thermister_voltage converted to temperature
  float steinhart;
// which analog pin to connect
  #define THERMISTORPIN A2         
// resistance at 25 degrees C
  #define THERMISTORNOMINAL 10000      
// temp. for nominal resistance (almost always 25 C)
  #define TEMPERATURENOMINAL 25   
// how many samples to take and average, more takes longer but is more 'smooth'
  #define NUMSAMPLES 5
// The beta coefficient of the thermistor (usually 3000-4000)
  #define BCOEFFICIENT 3950
// the value of the 'other' resistor
  #define SERIESRESISTOR 10000   
  uint16_t samples[NUMSAMPLES];

//Internal photo detector
  float PD_analog_read = 2.23; //2.23 is a place holder

//place holder elements
  float element_9 = 9;

//Array to read/write to/from LabVIEW
  float array[] = {thermister_voltage, TEC_temp, TEC_enable, TEC_max, TEC_min, TEC_current, LD_enable, LD_PWM, PD_analog_read, element_9};

void setup() {
  Serial.begin(9600); //init serial port baud rate
  randomSeed(analogRead(0)); //Generate different seed number if pin 0 is unconnected
  pinMode(LD_Pin, OUTPUT); //Declare pin 9 to be an output
  pinMode(7, OUTPUT); // declare pin to be an output
  pinMode(8, OUTPUT); // declare pin to be an output
  pinMode(9, OUTPUT); // declare pin to be an output
}

void loop() {

 //thermister_voltage sampling and conversion
    // read the input on analog pin 0:
        int sensorValue = analogRead(A2);
    // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
        thermister_voltage = sensorValue * (5 / 1023.0);
        array[0] = thermister_voltage;


//TEC temperature sampling and conversion
  uint8_t m;
  float average;
    // take N samples in a row
        for (int m=0; m< NUMSAMPLES; m++) {
          samples[m] = analogRead(A2);
          delay(10);
        }
        
   // average samples
        average = 0;
        for (int n=0; n< NUMSAMPLES; n++) {
          average += samples[n];
        }
         average /= NUMSAMPLES;
         
   // convert to temperature
         average = 1023 / average - 1;
         average = SERIESRESISTOR / average;
         steinhart = average / THERMISTORNOMINAL;     // (R/Ro)
         steinhart = log(steinhart);                  // ln(R/Ro)
         steinhart /= BCOEFFICIENT;                   // 1/B * ln(R/Ro)
         steinhart += 1.0 / (TEMPERATURENOMINAL + 273.15); // + (1/To)
         steinhart = 1.0 / steinhart;                 // Invert
         steinhart -= 273.15;                         // convert to C
         TEC_temp = steinhart;

//READ IN ARRAY FROM SERIAL  
if (Serial.available()) {
    for (int i =0; i <=10; i++){ 
    array[i] = Serial.parseInt();
    }
}

  //TEC Conditionals
    TEC_enable = array[2];
    TEC_max = array[3];
    TEC_min = array[4];
    TEC_current = array[5];
    LD_PWM = array[6];

    TEC_PWM = 0.13977*TEC_current;

      if (TEC_enable == 0) {
          // temp cycle off
            digitalWrite(7,LOW);  
            digitalWrite(8,LOW);
            analogWrite(9,0); 
        }

      else {
          if(TEC_temp >= TEC_max){
            digitalWrite(7,HIGH);  
            digitalWrite(8,LOW);
            analogWrite(9,TEC_PWM); 
          }
          
          if (TEC_temp <= TEC_min){
            digitalWrite(7,LOW);  
            digitalWrite(8,HIGH);
            analogWrite(9,TEC_PWM); 
          }
      }  
             
    //Laser Conditionals
      LD_enable = array[6];
      LD_PWM = array[7];
 
        if (LD_enable == 0){
          analogWrite(LD_Pin, 0);
        }

        if (LD_enable == 1){
          analogWrite(LD_Pin, LD_PWM);
        }
     
    Serial.print(thermister_voltage); //thermister analog converted to 0 - 3.3V
    Serial.print(",");
    Serial.print(TEC_temp); //current temperature of TEC
    Serial.print(",");
    Serial.print(TEC_enable); //TEC max temperature
    Serial.print(",");
    Serial.print(TEC_max); //TEC max temperature
    Serial.print(",");
    Serial.print(TEC_min); //TEC min temperature
    Serial.print(",");
    Serial.print(TEC_PWM); //determines rate of TEC heating and cooling
    Serial.print(",");
    Serial.print(LD_enable); //TEC max temperature
    Serial.print(",");
    Serial.print(LD_PWM); //determines current through laser diode 20mA min, 200mA max
    Serial.print(",");
    Serial.print(PD_analog_read); //place holder for internal photodector analog read
    Serial.print(",");
    Serial.print(element_9); //place holder for element 9
    Serial.print('\n');
    //delay(100);
}

Your delay is coming from a timeout in readInt or somesuch

Yup…

    array[i] = Serial.parseInt();

Damn, I'm good :smiley:

Indeed!

AWOL:
Get a scope or logic analyser, and use spare I/O pins and a fast (single cycle) toggle instructions around the sections of code you want timings for.

So if I am understanding you correctly, something like this

void loop(){

CODE NOT BEING TIMED

digitalWrite(spare IO pin, HIGH); //
delay(100)
digitalWrite(spare IO pin, LOW); //falling edge will be start point

CODE BEING TIMED

digitalWrite(spare IO pin, HIGH); //rising edge will be stop point
delay(100)
digitalWrite(spare IO pin, LOW); //

CODE NOT BEING TIMED

}

Then I'll use the scope to measure the time between the first falling edge and the second rising edge?

Well, yes, except don't use digitalWrite.
Too slow :wink: