Interrupt handling differences Giga to Uno R4 ?

I'm working on code to sync linear actuators with Hall sensors, and moving to the Giga R1 from my test Uno R4, the board is locking up with this code(4 slow red, 4 fast), that runs correctly on the Uno.

Wondering if I need to define or attach the interrupts differently?

Or maybe I'm missing something else entirely that differs in functionality.

This is a calibration program by Firgelli automations:

/* Modified by RacingToGreen from Firgelli Automations Code

 */

#include <elapsedMillis.h>
elapsedMillis timeElapsed;

#define numberOfActuators 2 
int RPWM[numberOfActuators]={22,23}; //PWM signal right side
int LPWM[numberOfActuators]={24,25}; 
int opticalPins[numberOfActuators]={51,52}; //connect optical pins to interrupt pins on Arduino. More information: https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/
volatile long lastDebounceTime_0=0; //timer for when interrupt was triggered
volatile long lastDebounceTime_1=0;

int Speed = 100; //choose any speed in the range [0, 255]

#define falsepulseDelay 5 //noise pulse time, if too high, ISR will miss pulses. 
volatile int counter[numberOfActuators]={}; 
volatile int prevCounter[numberOfActuators]={}; 
int Direction; //-1 = retracting
               // 0 = stopped
               // 1 = extending

int extensionCount[numberOfActuators] = {}; 
int retractionCount[numberOfActuators] = {}; 
int pulseTotal[numberOfActuators]={}; //stores number of pulses in one full extension/actuation

void setup(){
  for(int i=0; i<numberOfActuators; i++){
    pinMode(RPWM[i],OUTPUT);
    pinMode(LPWM[i], OUTPUT);
    pinMode(opticalPins[i], INPUT_PULLUP);
    counter[i]=0; //initialize variables as array of zeros
    prevCounter[i]=0;
    extensionCount[i] = 0;
    retractionCount[i] = 0;
    pulseTotal[i] = 0;
  }
  attachInterrupt(digitalPinToInterrupt(opticalPins[0]), count_0, RISING);
  attachInterrupt(digitalPinToInterrupt(opticalPins[1]), count_1, RISING); 

  Serial.begin(9600);
  Serial.println("Initializing calibration");
  Serial.println("Actuator retracting...");
  Direction = -1;
  moveTillLimit(Direction, 255); 
  Serial.println("Actuator fully retracted");
  delay(1000);

  for(int i=0; i<numberOfActuators; i++){
    Serial.print("\t\t\t\tActuator ");
    Serial.print(i);
  }

  Direction = 1;
  moveTillLimit(Direction, 255); //extend fully and count pulses
  Serial.print("\nExtension Count:");
  for(int i=0; i<numberOfActuators; i++){
  extensionCount[i]=counter[i];
  Serial.print("\t\t"); 
  Serial.print(extensionCount[i]);
  Serial.print("\t\t\t"); 
  }
  delay(1000);

  Direction = -1;
  moveTillLimit(Direction, 255); //retract fully and count pulses
  Serial.print("\nRetraction Count:");
  for(int i=0; i<numberOfActuators; i++){
  retractionCount[i]=counter[i];
  Serial.print("\t\t"); 
  Serial.print(abs(retractionCount[i]));
  Serial.print("\t\t\t"); 
  }
  Serial.print("\n");

  for(int i=0; i<numberOfActuators; i++){
    Serial.print("\nActuator ");
    Serial.print(i);
    Serial.print(" average pulses: ");
    pulseTotal[i]=(extensionCount[i]+abs(retractionCount[i]))/2; //takes the average of measurements
    Serial.print(pulseTotal[i]); 
  } 
  Serial.println("\n\nEnter these values in the synchronous control progam.");
}

void loop() { 
}

void moveTillLimit(int Direction, int Speed){
  //this function moves the actuator to one of its limits
  for(int i = 0; i < numberOfActuators; i++){
    counter[i] = 0; //reset counter variables
    prevCounter[i] = 0;
  } 
  do {
    for(int i = 0; i < numberOfActuators; i++) {
      prevCounter[i] = counter[i];
    }
    timeElapsed = 0;
    while(timeElapsed < 200){ //keep moving until counter remains the same for a short duration of time
      for(int i = 0; i < numberOfActuators; i++) {
        driveActuator(i, Direction, Speed);
      }
    }
  } while(compareCounter(prevCounter, counter)); //loop until all counts remain the same
}

bool compareCounter(volatile int prevCounter[], volatile int counter[]){
  //compares two arrays and returns false when every element of one array is the same as its corresponding indexed element in the other array
  bool areUnequal = true;
  for(int i = 0; i < numberOfActuators; i++){
    if(prevCounter[i] == counter[i]){
      areUnequal = false;
    } 
    else{ //if even one pair of elements are unequal the entire function returns true
      areUnequal = true;
      break;
    }
  }
  return areUnequal;
}

void driveActuator(int Actuator, int Direction, int Speed){
  int rightPWM=RPWM[Actuator];
  int leftPWM=LPWM[Actuator];

  switch(Direction){
  case 1: //extension
    analogWrite(rightPWM, Speed);
    analogWrite(leftPWM, 0);
  break;

  case 0: //stopping
    analogWrite(rightPWM, 0);
    analogWrite(leftPWM, 0);
  break;

  case -1: //retraction
    analogWrite(rightPWM, 0);
    analogWrite(leftPWM, Speed);
  break;
  }
}

void count_0(){
  //This interrupt function increments a counter corresponding to changes in the optical pin status
  if ((millis() - lastDebounceTime_0) > falsepulseDelay) { //reduce noise by debouncing IR signal 
    lastDebounceTime_0 = millis();
    if(Direction==1){
      counter[0]++;
    }
    if(Direction==-1){
      counter[0]--;
    }
  }
}

void count_1(){
  if ((millis() - lastDebounceTime_1) > falsepulseDelay) { 
    lastDebounceTime_1 = millis();
    if(Direction==1){
      counter[1]++;
    }
    if(Direction==-1){
      counter[1]--;
    }
  }
}

It's driving, in this, two outputs on an XY-160D motor controller.

The pinouts don't match the code, as I've been moving pins around, although, I'ver read that most pins can be used. I'm guessing it's just my not knowing how the interrupts should should be assigned on the Giga.

Hi @murphyslaww69. The problem doesn't have anything to do with the interrupts. It is actually here:

You can learn the pins that are usable with the analogWrite function from the table in the Arduino Language Reference:

https://www.arduino.cc/reference/en/language/functions/analog-io/analogwrite/#:~:text=13%3A%20980%20Hz)-,GIGA%20R1,-**

BOARD PWM PINS * PWM FREQUENCY
GIGA R1 ** 2 - 13 500 Hz

When you use a pin that doesn't have PWM capability, it crashes the Mbed OS operating system on the GIGA R1 WiFi, as indicated by the blink pattern.

If you change the pin numbers in your RPWM and LPWM arrays to pins that have PWM capability, the problem should no longer occur. Make sure to also adjust your circuit accordingly.

Thanks for the reply. I originally had the PWM pins set up as 4-13, and I think it was doing the same, but I'll try it again. The connector including the pins 22-53 are at least screen printed as digital pwm pins, but just not accessible via analogWrite, without additional timing coding?

Thanks for the link, as it also mentions:

**** Only 4 different pins can be used at the same time. Enabling PWM on more than 4 pins will abort the running sketch and require resetting the board to upload a new sketch again.

This may have been my issue as I need 10 pwm pins for my use case, 2 per actuator. Might be an arduino deal killer for my application. It says that is for the nano 33 BLE sense. Hopefully they are accessible in the Giga.

So, it doesn't lock the board up, but also will not run the program using the same pins as the Nano R4 (5,6,10, 11 as PWM, and 2, and 3, as interrupts) It's only using 4 pins as PWM, so that's not the issue.

Using 4,6, 7, 8, and 2,3 as interrupts seemed to confuse it as well.

I don't have unlimited time to sort out this boards peculiarities, so, I think I'll just be ordering a 2560 mega, and shelve some of the more optimistic features I was going to add. I think it's likely going to be an uphill battle adding Giga display buttons, and cloud connectivity.

I think I had to upload a base sketch to clear the memory fully. After running it on a base sketch and then uploading it, it did finally work the same as it does on the Uno R4.

I'll keep moving forward with the Giga, and keep my fingers crossed, that it doesn't act too finicky with the uploads. I'm going to get the base sketch for the single axis tracking running before I revisit the cloud, and then the screen. It did have one snag, so far, it didn't seem to like pins 10,11, so I skipped them, and it seems fine with pins 2-9, and 12, 13.

I'm not sure what you mean by "screen printed as digital pwm pins". There is nothing on the silkscreen of the PCB or header on my GIGA R1 WiFi board to indicate those pins have a PWM capability, and I also don't see such a thing on the board in the product photo in the Arduino Store.

Unfortunately I don't know enough about the complex low level capabilities of the GIGA's STM32H747xI microcontroller to answer that. Maybe one of the other forum helpers can. At the very least it is certainly possible to achieve a "software PWM" on any of the pins.

There are some "gotchas" when using attachInterrupt with the GIGA:

https://github.com/arduino/ArduinoCore-mbed/issues/789#issuecomment-1840246454

the Giga allows a maximum of 16 interrupts at the same time, and the coexistence is based on STM32 peculiar way of handling them (like, PA_0 will share the interrupt with PB_0 , PC_0 and so on). If you instantiate 2 interrupts on the same line the board will "crash" (report it as invaliud).
To associate pin name and pin number you can use this table https://github.com/arduino/ArduinoCore-mbed/blob/main/variants/GIGA/variant.cpp#L31-L160

However, using pins 2 and 3 as interrupts alone should not cause any problems since these pins are on different "lines".

Nice! Thanks for the update.

the digital (pwm) is screened on the plastic of the connector itself, sorry, not the pcb.

I only need 5 interrupt pins, and so far pins 49-53 seem to be working.

This is the project on Hackster.io if interested:

Looks like it's almost working. I ran the calibration program, and the actuators moved as expected, but it's supposed to do a count of hall sensor triggers, and it only pulled data on two of the actuators.

Checking my wiring.

And understanding the code:

Looks like multiple interrupts need their own multiple count routines:

  attachInterrupt(digitalPinToInterrupt(opticalPins[0]), count_0, RISING);
  attachInterrupt(digitalPinToInterrupt(opticalPins[1]), count_1, RISING); 
  attachInterrupt(digitalPinToInterrupt(opticalPins[2]), count_2, RISING);
  attachInterrupt(digitalPinToInterrupt(opticalPins[3]), count_3, RISING);

and:

void count_1(){
  if ((millis() - lastDebounceTime_1) > falsepulseDelay) { 
    lastDebounceTime_1 = millis();
    if(Direction==1){
      counter[1]++;
    }
    if(Direction==-1){
      counter[1]--;
    }
  }
}

void count_2(){
  if ((millis() - lastDebounceTime_1) > falsepulseDelay) { 
    lastDebounceTime_1 = millis();
    if(Direction==1){
      counter[2]++;
    }
    if(Direction==-1){
      counter[2]--;
    }
  }

Interesting, true. Another case of using same connectors as MEGA...

Sometimes helps to have more complete code. Like where is Direction defined? Is it specific to each of the sensors or global settings.

Also note lastDeboundTime_1 is shared in both of these. Guessing you need separate ones for each sensor.

Yeah, found the the lastDebounceTime and added those too.

Sorry, wasn't really asking a question, just pointing out what I had missed was the current problem. That is now solved, now I'm working on what I knew was going to be difficult, the logic in the Loop in the drive program for the synchronizing four, vs, the example code which is just syncing two actuators.

The Calibration program now works perfectly.

Not necessarily looking for help on this yet, but this is what I'm working from, the loop logic to sync two actuators, vs, my four, and I'm sure it will interest some:

void loop() {  
  checkButtons();

  if(Direction==1){                                                   //based on direction of motion identify the leading and lagging actuator by comparing pulse counts
    if(normalizedPulseCount[0] < normalizedPulseCount[1]){
      laggingIndex = 0; 
      leadingIndex = 1;
    }
    else{
      laggingIndex = 1;
      leadingIndex = 0;
    }
  }
  else if(Direction==-1){
    if(normalizedPulseCount[0] > normalizedPulseCount[1]){
      laggingIndex = 0;
      leadingIndex = 1;
    }
    else{
      laggingIndex = 1;
      leadingIndex = 0;
    }
  }
  
  error=abs(normalizedPulseCount[laggingIndex]-normalizedPulseCount[leadingIndex]);
  if(Direction!=0){       
    adjustedSpeed=desiredSpeed-int(error*K_p);                 
    Speed[leadingIndex]=constrain(adjustedSpeed, 0, 255);               //slow down fastest actuator
    Speed[laggingIndex]=desiredSpeed;
  }
  for(int i=0; i<numberOfActuators; i++){
    Serial.print("  ");
    Serial.print(Speed[i]);
    Serial.print("  ");
    Serial.print(normalizedPulseCount[i]*1000);
    driveActuator(i, Direction, Speed[i]);
  }
  Serial.println();
}