[SOLVED] for loop not executed when calling two array

Hi,

First time posting on a forum. I’m working on a project to run 2 LRA (vibration motor) simultanously through Arduino. I’m using a RedBoard which basically acts like an UNO. Drivers for the LRA are already installed and working.

The LRA runs normally through analogWrite by using a PWM signal. I created arrays to store the values for when the LRA’s should run. When I have the code run 1 LRA using the for loop which iterates through the array, the code runs fine. It is only when I have the code run both LRA through the same for loop that it decides not to execute anything.

My initial guess it is that it can’t handle running 2 LRA that quickly, so I added a delay and it still didn’t work. The exact same thing happens if I try to print the values of the arrays, for 1 it woks but for both it doesn’t.

Each LRA uses its own array.

I attached a simple version of the code which underlines the issue.

Let me know if I need to specify anything else. Thank you for any help you can give.

help.ino (1.51 KB)

You might want to show the "real" version of the code using code tags. What you've posted lacks anything in setup indicating you're starting serial or setting pin modes etc. Don't expect folks try to find faults stripped-down "simplified" code that may have "new" errors introduced.

Or is the lack of setup() code the problem?

@jackrobot which doc file?

@blackfin, yeah I know what you mean and I thought about it but it seemed like posting the whole code would cause more confusion than anything because it simply goes through defining I2C and drivers. I’ll post it.

If the setup has anything to do with it, I really don’t understand why it would work with just 1 analogWrite.

#include <Wire.h>
#include "Adafruit_DRV2605.h"
#include "math.h"
extern "C" { 
#include "utility/twi.h"  // from Wire library, so we can do bus scanning
}

#define TCAADDR 0x70

//Pin names
int PinFirst = 11;
int PinSecond = 10;

//Values of the signals in msec
const int Duration1 = 200;
const int Duration2 = 200;
const int SOA = 110;
const int FullDur = Duration1 + SOA;
int Interval1 = Duration1 - SOA;
int Interval2 = Duration2 - Interval1;
float Strength1 = 255;
float Strength2 = 255;

//Name DRV Drivers
Adafruit_DRV2605 drv0;
Adafruit_DRV2605 drv1;
Adafruit_DRV2605 drv2;
Adafruit_DRV2605 drv3;

/**************************************************************************/

void tcaselect(uint8_t i) 
{ 
  if (i > 7) return;
  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << i);
  Wire.endTransmission(); 
  Wire.begin(); 
}

/**************************************************************************/

void tcainit()
{
    while (!Serial); 
    delay(1000);
    Wire.begin();
    //Serial.println("\nI2C Scanning Ready!");
    
    for (uint8_t t=0; t<8; t++) {
      tcaselect(t);
      //Serial.print("TCA Port #"); Serial.println(t);
      for (uint8_t addr = 0; addr<=127; addr++) {
        if (addr == TCAADDR) continue;
        uint8_t data;
        if (! twi_writeTo(addr, &data, 0, 1, 1)) {
           //Serial.print("Found DRV2605L: I2C 0x");  Serial.println(addr,HEX);
        }
      }
    }
    //Serial.println("I2C Scanning Complete");
    //Serial.println();
    
  tcaselect(0);  if(!drv0.begin())  {  Serial.println("Ooops, DRV 00 not detected ... Check your wiring!");  }  
  tcaselect(1);  if(!drv1.begin())  {  Serial.println("Ooops, DRV 01 not detected ... Check your wiring!");  }
  tcaselect(2);  if(!drv2.begin())  {  Serial.println("Ooops, DRV 02 not detected ... Check your wiring!");  }
  tcaselect(3);  if(!drv3.begin())  {  Serial.println("Ooops, DRV 03 not detected ... Check your wiring!");  }   
}

/**************************************************************************/

void calibrate(Adafruit_DRV2605 drv)
{   
   drv.useLRA();     
   drv.setMode(DRV2605_MODE_PWMANALOG); 
   drv.writeRegister8(DRV2605_REG_CONTROL3, 0x82);
   drv.writeRegister8(DRV2605_REG_FEEDBACK, 0xAA);
   drv.writeRegister8(0x1B, 0x90);
   drv.go();
}

/**************************************************************************/

void setup()
{ 
  Serial.begin(115200);
  //Serial.println("Haptic Sketch 01"); 
  //Serial.println("by: TU Delft Pi-Touch Group"); 
  //Serial.println("Version No: 0.2");
  //Serial.println("Board Required: Arduino Uno");

// Initialize pins
  pinMode(PinFirst, OUTPUT);
  pinMode(PinSecond, OUTPUT);
  pinMode(12, INPUT_PULLUP); // Enable internal pull-up resistor on pin 12
  digitalWrite(12, HIGH);
  
  tcainit();
  
// Initialize DRVs
  drv0.begin();
  drv1.begin();
  drv2.begin();
  drv3.begin();
  //Serial.println("DRV2605L's Initialized");

// Setting mode to PWM through I2C 
   tcaselect(0);
   calibrate(drv0);
   tcaselect(1);
   calibrate(drv1); 
   tcaselect(2);
   calibrate(drv2); 
   tcaselect(3);
   calibrate(drv3); 

//Serial.println("Setup Complete");
//Serial.println(" ");
}

/**************************************************************************/

void waitForSerial(){
  Serial.println("Type key to play waveform..."); 
  while (!Serial.available()){}  // wait for a character
  Serial.read();
  Serial.flush();
  delay(500);
}

/**************************************************************************/

void loop()
{ 
    waitForSerial();

    float Wave1[FullDur] = {0};
    float Wave2[FullDur] = {0};
    delay(10);
    
    for (int j=0; j < Duration1; j++)
    {
      Wave1[j] = 1.0*(j*255UL)/(199);
    }
    for (int i=(FullDur-Duration2); i<FullDur; i++)
    {
      Wave2[i] = 1.0*((i-(FullDur-Duration2))*255UL)/(Duration2-1);
    }
    delay(100);

    for (int i = 0; i < sizeof(Wave1)/sizeof(Wave1[0]); i++) { //it stops working only when calling both Wave1 and Wave2
      /*
      analogWrite(PinFirst, Wave1[i]);
      analogWrite(PinSecond, Wave2[i]);
      delay(100);
      */
      Serial.print("pin1: ");
      Serial.println(Wave1[i]);
      Serial.print("pin2: ");
      Serial.println(Wave2[i]);
      delay(100);
    }
    

    analogWrite(PinFirst, 0);
    analogWrite(PinSecond, 0);
    
}

If each LRA runs fine on its own but it fails when you have them both plugged in you might look into the electrical specs of the LRAs and how they are connected to the Arduino and its power supply.

They both run at the same time without a problem.

That is something I forgot to mention, the following snippet works normally. I just checked and it even works when I put it in the for loop too. I think the issue is from calling the arrays.

analogWrite(PinFirst, 255);
analogWrite(PinSecond, 255);
delay(1000);
analogWrite(PinFirst, 0);
analogWrite(PinSecond, 0);

What happens when you use the loop but feed canned values:

for( int i = 0; i < sizeof(Wave1)/sizeof(Wave1[0]); i++ ) 
{ 
    //it stops working only when calling both Wave1 and Wave2

    analogWrite(PinFirst, 255 );
    analogWrite(PinSecond, 127 );
    delay(100);

    Serial.print("pin1: ");
    Serial.println(Wave1[i]);
    Serial.print("pin2: ");
    Serial.println(Wave2[i]);
    delay(100);
}

When I feed it canned values it works, this runs as you would expect:

for (int i = 0; i < sizeof(Wave1)/sizeof(Wave1[0]); i++) {
      analogWrite(PinFirst, 255);
      analogWrite(PinSecond, 120);
      delay(100);
      analogWrite(PinFirst, 0);
      analogWrite(PinSecond, 0);
      delay(100);

    }

But this doesn’t: (note that I still try to print the array values afterwards)

for (int i = 0; i < sizeof(Wave1)/sizeof(Wave1[0]); i++) {

      analogWrite(PinFirst, 255);
      analogWrite(PinSecond, 120);
      delay(100);
      analogWrite(PinFirst, 0);
      analogWrite(PinSecond, 0);
      delay(100);

      
      Serial.print("pin1: ");
      Serial.println(Wave1[i]);
      Serial.print("pin2: ");
      Serial.println(Wave2[i]);
      delay(100);
      

    }

I just noticed Wave1 and Wave2 are arrays of floats. analogWrite takes a single byte, ranging from 0 to 255.

Does this do anything (casting the floats to bytes)?

for (int i = 0; i < sizeof(Wave1)/sizeof(Wave1[0]); i++) { //it stops working only when calling both Wave1 and Wave2
      
      analogWrite( PinFirst, (byte)Wave1[i] );
      analogWrite( PinSecond, (byte)Wave2[i] );
      delay(100);

      Serial.print("pin1: ");
      Serial.println(Wave1[i]);
      Serial.print("pin2: ");
      Serial.println(Wave2[i]);
      delay(100);
    }
   

    analogWrite(PinFirst, 0);
    analogWrite(PinSecond, 0);
}

It could, but wouldn’t that mean that running just one analogWrite should also give an issue? This runs without any issues:

for (int i = 0; i < sizeof(Wave1)/sizeof(Wave1[0]); i++) {
      analogWrite(PinFirst, Wave1[i]);
      delay(100);
    }

A fair point.

So casting the argument doesn't work?

Nope :(

Thanks for trying to help though

UPDATE:

Even calling 2 arrays one after the other outside of the for loop doesn’t work. I don’t think the for loop was part of the problem.

This code doesn’t print any lines after the waitForSerial() function unless I comment out one of the Serial.print(Wave ). When I don’t comment it out, the script manages to print “Arrive1” but nothing afterwards.

void loop()
{ 
    waitForSerial();

    Serial.println("Arrive1");

    float Wave1[FullDur] = {0};
    float Wave2[FullDur] = {0};
    delay(10);
    
    Serial.println("Arrive2");

    for (int j=0; j < Duration1; j++)
    {
      Wave1[j] = 1.0*(j*255UL)/(199);
    }
    for (int i=(FullDur-Duration2); i<FullDur; i++)
    {
      Wave2[i] = 1.0*((i-(FullDur-Duration2))*255UL)/(Duration2-1);
    }
    delay(100);

    Serial.println("Arrive3");

    Serial.print("pin1: ");
    Serial.println(Wave1[(byte)150]);
    Serial.print("pin2: ");
    Serial.println(Wave2[(byte)250]);    
}

Try turning off optimizations for loop. Declare the function as follows:

void __attribute__((optimize("O0"))) loop()
{
.
.
.

}//loop

and see if that helps.

There is some sort of memory issue going on. When the arrays are declared globally, the floats run out of memory and the compiler complains. With the local declarations the byte arrays work as desired, one float and one byte array also work, but the two float arrays do not.

int PinFirst = 11;
int PinSecond = 10;
//Values of the signals in msec
const int Duration1 = 200;
const int Duration2 = 200;
const int SOA = 110;
const int FullDur = Duration1 + SOA;
int Interval1 = Duration1 - SOA;
int Interval2 = Duration2 - Interval1;
float Strength1 = 255;
float Strength2 = 255;

//byte Wave1[FullDur] = {0};
//byte Wave2[FullDur] = {0};
//float Wave1[FullDur] = {0};
//float Wave2[FullDur] = {0};
void setup() {
  pinMode(PinFirst, OUTPUT);
  pinMode(PinSecond, OUTPUT);
  Serial.begin(115200);

  delay(10);
}

void loop()
{
  waitForSerial();

  //float Wave1[FullDur] = {0};
  //float Wave2[FullDur] = {0};
  byte Wave1[FullDur] = {0};
  byte Wave2[FullDur] = {0};
  delay(10);

  for (int j = 0; j < Duration1; j++)
  {
    Wave1[j] = 1.0 * (j * 255UL) / (199);
    Serial.println(Wave1[j]);
  }
  Serial.println();
  for (int i = (FullDur - Duration2); i < FullDur; i++)
  {
    Wave2[i] = 1.0 * ((i - (FullDur - Duration2)) * 255UL) / (Duration2 - 1);
    Serial.println(Wave2[i]);
  }
  Serial.println();
  delay(1000);

  Serial.print("pin1: ");
  Serial.println(Wave1[(byte)150]);
  Serial.print("pin2: ");
  Serial.println(Wave2[(byte)250]);
}

void waitForSerial() {
  Serial.println("Type key to play waveform...");
  while (!Serial.available()) {} // wait for a character
  Serial.read();
  Serial.flush();
  delay(500);
}

cattledog: There is some sort of memory issue going on. When the arrays are declared globally, the floats run out of memory and the compiler complains. With the local declarations the byte arrays work as desired, one float and one byte array also work, but the two float arrays do not.

The OPs float arrays have 310 elements each; that's 1240 bytes each.

If he's using an Uno he's already out of RAM using float arrays (2480 bytes >> 2048 bytes of RAM.)

OP, did you see any compilation warnings or errors?

OP, did you see any compilation warnings or errors?

In my testing, I did not see any warning when the arrays were local to loop(). When globally declared, there was a warning when one was declared as a float.

Since these values are going to analogWrite() there is no reason not to declare them as byte.

cattledog: In my testing, I did not see any warning when the arrays were local to loop(). When globally declared, there was a warning when one was declared as a float.

I wouldn't expect a complaint as the local variables go on the stack. Similar to compiler not complaining if you do

float *ptr = (float *) malloc (10000 * sizeof(float));

Interesting. On my Mega, if I run:

const int Duration1 = 8082;
const int SOA = 110;
const int FullDur = Duration1 + SOA;

void setup() 
{
    Serial.begin(9600);

}

void loop() 
{
    float TooBig[FullDur];

    Serial.println( "foo" );
    
}

I get this error:

sketch_oct30a:13:25: error: size of array 'TooBig' is too large

     float TooBig[FullDur];

                         ^

exit status 1
size of array 'TooBig' is too large

but if I change the size of Duration1 to 8081 I don’t get any error (even though it’s still too large for the Mega’s RAM).

Sketch uses 1800 bytes (0%) of program storage space. Maximum is 253952 bytes.
Global variables use 192 bytes (2%) of dynamic memory, leaving 8000 bytes for local variables. Maximum is 8192 bytes.

Weird bit of compiler voodoo there.

I wouldn't expect a complaint as the local variables go on the stack.

Yes, but I would hope that the compiler could/would see that both arrays are being pulled into RAM at the same time by the code, and would warn you.

But, I guess not. It's rare that we are smarter than the compiler.

cattledog:
There is some sort of memory issue going on. When the arrays are declared globally, the floats run out of memory and the compiler complains. With the local declarations the byte arrays work as desired, one float and one byte array also work, but the two float arrays do not.

int PinFirst = 11;

int PinSecond = 10;
//Values of the signals in msec
const int Duration1 = 200;
const int Duration2 = 200;
const int SOA = 110;
const int FullDur = Duration1 + SOA;
int Interval1 = Duration1 - SOA;
int Interval2 = Duration2 - Interval1;
float Strength1 = 255;
float Strength2 = 255;

//byte Wave1[FullDur] = {0};
//byte Wave2[FullDur] = {0};
//float Wave1[FullDur] = {0};
//float Wave2[FullDur] = {0};
void setup() {
  pinMode(PinFirst, OUTPUT);
  pinMode(PinSecond, OUTPUT);
  Serial.begin(115200);

delay(10);
}

void loop()
{
  waitForSerial();

//float Wave1[FullDur] = {0};
  //float Wave2[FullDur] = {0};
  byte Wave1[FullDur] = {0};
  byte Wave2[FullDur] = {0};
  delay(10);

for (int j = 0; j < Duration1; j++)
  {
    Wave1[j] = 1.0 * (j * 255UL) / (199);
    Serial.println(Wave1[j]);
  }
  Serial.println();
  for (int i = (FullDur - Duration2); i < FullDur; i++)
  {
    Wave2[i] = 1.0 * ((i - (FullDur - Duration2)) * 255UL) / (Duration2 - 1);
    Serial.println(Wave2[i]);
  }
  Serial.println();
  delay(1000);

Serial.print("pin1: ");
  Serial.println(Wave1[(byte)150]);
  Serial.print("pin2: ");
  Serial.println(Wave2[(byte)250]);
}

void waitForSerial() {
  Serial.println(“Type key to play waveform…”);
  while (!Serial.available()) {} // wait for a character
  Serial.read();
  Serial.flush();
  delay(500);
}

Yes! Thats what it was! Turning the arrays into bytes also got the motors running correctly.

I am also surprised that Arduino didnt give me a warning too, but now that I knew what to look for, it did tell me that I had 1300 bytes left for local variables. That should’ve been a red flag if I paid attention. I guess it can’t give an early warning about local variable memory usage since it can’t look into when a variable will be created or when it will be deleted from memory.

Anyways thank you all very much for the help! I grealty appreciate it! :slight_smile: