moving code from UNO to MEGA: not working anymore

hello eveyrone,
I'm Giuseppe this is my first post hoping this is the right place

for a quadcopter application, I wrote a llitle piece of code on arduino uno, which reads the input from a receiver of a rc controller applying an interrupt and actuates a brushless motor through an ESC

The code includes PinChangeInt and Servo libraries.

For the next step on my quadcopter project, I transferred the code on an Arduino Mega... but it did not work: neither the input readings from the rc controller nor the motor actuation (I also tried an actuation independent form the rc input).

Is there any known issue moving the code from the Uno to the Mega? Ideas?

thanks

Is there any known issue moving the code from the Uno to the Mega? Ideas?

Not all pins support pin change interrupts on the Mega. Perhaps your mysterious code is expecting things that will never happen.

here is the code, didn't want to bother you all with the whole thing: maybe some issues could have been known...

for now I was just testing one single channel set with
#define ELEVATION_IN_PIN 2

pin 2 allows interrupts on both UNO and MEGA, but on MEGA if I call Serial.println(unElevationIn) I see just bunch of zeros while on UNO it worked...

//
// RC MultiChannels Readings - impostato per 4 canali
//

// include the pinchangeint library
#include <PinChangeInt.h>
#include <Servo.h>

// Assign channel in pins
//NB #define crea dati fissi non modificabili dal codice
// Arduino MEGA pin con interrupts 2, 3, 18, 19, 20, 21 rispettivamente interrupts 0 1 2 3 4 5 
#define ELEVATION_IN_PIN 2
#define ROLL_IN_PIN 3
#define PITCH_IN_PIN 18
#define YAW_IN_PIN 19

// Assign channel ESC pins
//NB #define crea dati fissi non modificabili dal codice
#define ESC_1_OUT_PIN 8
#define ESC_2_OUT_PIN 9
#define ESC_3_OUT_PIN 10
#define ESC_4_OUT_PIN 11

// Servo objects generate
Servo servoESC_1;			//  CONFIGURAZIONE MOTORI 
Servo servoESC_2;			//		esc1     esc2
Servo servoESC_3;			//      	  X
Servo servoESC_4;			//      esc4     esc3

// Riferimento per Bit flags per la verifica di un avvenuto evento di interrupt tramite confronto con bUpdateFlagsShared
//NB #define crea dati fissi non modificabili dal codice
#define ELEVATION_FLAG	1	// = 00000001 in 8 bit
#define ROLL_FLAG 		2	// = 00000010 in 8 bit
#define PITCH_FLAG 		4	// = 00000100 in 8 bit
#define YAW_FLAG 	    8	// = 00001000 in 8 bit

// definizione valori di throttle null, min e max
#define ThrottleMin 1052
#define ThrottleNull 1472
#define ThrottleMax 1892

// variabile di bit-flag condivisa: conforntando coi precedenti verifico l'avvenuto interrupt
volatile uint8_t bUpdateFlagsShared;

//  variabili di input condivise aggiornate dall' ISR dell'interrupt e letti dal loop()
// nel loop vengono create copie locali a interrupt() disabilitato per evitare aggiornarmenti
// anomali durante il loop() dovuti a improvvisi eventi di interrupt. 
volatile uint16_t unElevationInShared;
volatile uint16_t unRollInShared;
volatile uint16_t unPitchInShared;
volatile uint16_t unYawInShared;

// variabili usate per registrare il rising edge dell'impulso
// non necessariamente volatile: sono usate solo nell'interrupt
uint32_t ulElevationStart;
uint32_t ulRollStart;
uint32_t ulPitchStart;
uint32_t ulYawStart;

void setup(){
  Serial.begin(9600);
  Serial.println("multiChannels");

  // attaching servo objects
  servoESC_1.attach(ESC_1_OUT_PIN);
  servoESC_2.attach(ESC_2_OUT_PIN);
  servoESC_3.attach(ESC_3_OUT_PIN);
  servoESC_4.attach(ESC_4_OUT_PIN);

  // using the PinChangeInt library to attach the interrupts
  PCintPort::attachInterrupt(ELEVATION_IN_PIN, calcElevation,CHANGE); 
  PCintPort::attachInterrupt(ROLL_IN_PIN, calcRoll,CHANGE); 
  PCintPort::attachInterrupt(PITCH_IN_PIN, calcPitch,CHANGE); 
  PCintPort::attachInterrupt(YAW_IN_PIN, calcYaw,CHANGE); 
  //SYNTAX: attach.interrupt(PIN, funzione da svolgere all'interrupt, mode)  
}

void loop(){
  // variabili di input locali in cui copiare momentaneamente le condivise in arrivo dagli interrupt
  // aggiornate ad ogni loop
  static uint16_t unElevationIn;
  static uint16_t unPitchIn;
  static uint16_t unRollIn;
  static uint16_t unYawIn;
  // copia locale dello stato delle flag
  static uint8_t bUpdateFlags;	// al primo loop bUpdateFlags = 00000000

  // check : è avvenuto almeno un evento di interrupt? ovvero le flag sono aggiornate? 
  if(bUpdateFlagsShared){ // questa condizione verifica se c'è almeno un 1 in bUpdateFlags (=0000000 nel primo loop)
	//se si si prende una copia locale di tutte le variabili con cui lavorare
    noInterrupts(); 					//disattiva gli interrupts
	bUpdateFlags = bUpdateFlagsShared;	// prende una copia locale del check

    // è avvnuto un evento di update di flag sull'elevazione? 
    if(bUpdateFlags & ELEVATION_FLAG){		// bUpdateFlags == 00000001 ?  & è un AND-bitwise (AND bit per bit)
      unElevationIn = unElevationInShared;	// copia locale delle variabili aggionrate dall'ISR corrispettivo
    }
    if(bUpdateFlags & ROLL_FLAG){			// bUpdateFlags == 00000010 ?  & è un AND-bitwise (AND bit per bit)
      unRollIn = unRollInShared;		// copia locale delle variabili aggionrate dall'ISR corrispettivo
    }
    if(bUpdateFlags & PITCH_FLAG){			// bUpdateFlags == 00000100 ?  & è un AND-bitwise (AND bit per bit)
      unPitchIn = unPitchInShared;            // copia locale delle variabili aggionrate dall'ISR corrispettivo
    }
    if(bUpdateFlags & YAW_FLAG){			// bUpdateFlags == 00001000 ?  & è un AND-bitwise (AND bit per bit)
      unYawIn = unYawInShared;           	// copia locale delle variabili aggionrate dall'ISR corrispettivo
    }
    bUpdateFlagsShared = 0;	// pulizia della flag condiviss, abbiamo quello locale con cui lavorare
    interrupts();			// riattivazione degli interrupt
  }
  // con le copie locali delle variabili si avvia la processazione necessaria
  
  // processazione dati a seconda del particolare interrupt avvenuto 
  //
  //	DA MODIFICARE !!!!!!
  //
  Serial.println(unElevationIn);
  
  if(bUpdateFlags & ELEVATION_FLAG){				// in caso di interrupt su ELEVATION
		//
		// to be continued...
		//
  }                                                 

 if(bUpdateFlags & ROLL_FLAG){						// in caso di interrupt su ROLL
		//
		// to be continued...
		//
  }
  if(bUpdateFlags & PITCH_FLAG){					// in caso di interrupt su PITCH
		//
		// to be continued...
		//
  }
  if(bUpdateFlags & YAW_FLAG){						// in caso di interrupt su YAW
		//
		// to be continued...
		//

  
  bUpdateFlags = 0; // operazioni avvenute quindi azzero la flag
}
  // ///////////////////////////////////////////////

// /////////////////////////////////////////
//         Interrupt Service Routine      //
// /////////////////////////////////////////
void calcElevation(){
  if(digitalRead(ELEVATION_IN_PIN) == HIGH){	//se il PIN legge HIGH al cambio, siamo al rising edge 
    ulElevationStart = micros();				// registro il tempo in microsecondi dall'avvio di arduino
  }
  else{	// altrimenti al change avvenuto il PIN è LOW
    unElevationInShared = (uint16_t)(micros() - ulElevationStart);	// registro il delta -> la durata dell'impulso
    bUpdateFlagsShared |= ELEVATION_FLAG; // con OR-bitwise registriamo l'evento nella FLAG: nuovo segnale ricevuto
  }
}

void calcRoll(){
  if(digitalRead(ROLL_IN_PIN) == HIGH){	//se il PIN legge HIGH al cambio, siamo al rising edge 
    ulRollStart = micros();				// registro il tempo in microsecondi dall'avvio di arduino
  }
  else{	// altrimenti al change avvenuto il PIN è LOW
    unRollInShared = (uint16_t)(micros() - ulRollStart);	// registro il delta -> la durata dell'impulso
    bUpdateFlagsShared |= ROLL_FLAG; // con OR-bitwise registriamo l'evento nella FLAG: nuovo segnale ricevuto
  }
}

void calcPitch(){
  if(digitalRead(PITCH_IN_PIN) == HIGH){	//se il PIN legge HIGH al cambio, siamo al rising edge 
    ulPitchStart = micros();				// registro il tempo in microsecondi dall'avvio di arduino
  }
  else{	// altrimenti al change avvenuto il PIN è LOW
    unPitchInShared = (uint16_t)(micros() - ulPitchStart);	// registro il delta -> la durata dell'impulso
    bUpdateFlagsShared |= PITCH_FLAG; // con OR-bitwise registriamo l'evento nella FLAG: nuovo segnale ricevuto
  }
}

void calcYaw(){
  if(digitalRead(YAW_IN_PIN) == HIGH){	//se il PIN legge HIGH al cambio, siamo al rising edge 
    ulYawStart = micros();				// registro il tempo in microsecondi dall'avvio di arduino
  }
  else{	// altrimenti al change avvenuto il PIN è LOW
    unYawInShared = (uint16_t)(micros() - ulYawStart);	// registro il delta -> la durata dell'impulso
    bUpdateFlagsShared |= YAW_FLAG; // con OR-bitwise registriamo l'evento nella FLAG: nuovo segnale ricevuto
  }
}
// ////////////////////////////////////////

pin 2 allows interrupts on both UNO and MEGA

Pin 2 allows EXTERNAL interrupts on both UNO and MEGA, but pin2 allows pin change interrupts ONLY on the UNO.

Look at the documentation for the SoftwareSerial library (which uses pin change interrupts) to see which pins support pin change interrupts on the Mega.

thanks Pauls, according to attachInterrupt() - Arduino Reference

MEGA allows interrupt on pins 2 3 18 19 20 21

I tried a the following thing and it worked:

  • dismissed the library PinChangeInt.h
  • called in setup attachInterrupt(digitalPinToInterrupt(2), calcElevation,CHANGE);

but I did not understand why it worked and I'm curious... can you enlight me?

here is the new code

//
// RC MultiChannels Readings - impostato per 4 canali
//

// include the pinchangeint library
//#include <PinChangeInt.h>
#include <Servo.h>

// Assign channel in pins
//NB #define crea dati fissi non modificabili dal codice
// Arduino MEGA pin con interrupts 2, 3, 18, 19, 20, 21 rispettivamente interrupts 0 1 2 3 4 5 
#define ELEVATION_IN_PIN 2
#define ROLL_IN_PIN 3
#define PITCH_IN_PIN 18
#define YAW_IN_PIN 19

// Assign channel ESC pins
//NB #define crea dati fissi non modificabili dal codice
#define ESC_1_OUT_PIN 8
#define ESC_2_OUT_PIN 9
#define ESC_3_OUT_PIN 10
#define ESC_4_OUT_PIN 11

// Servo objects generate
Servo servoESC_1;			//  CONFIGURAZIONE MOTORI 
Servo servoESC_2;			//		esc1     esc2
Servo servoESC_3;			//      	  X
Servo servoESC_4;			//      esc4     esc3

// Riferimento per Bit flags per la verifica di un avvenuto evento di interrupt tramite confronto con bUpdateFlagsShared
//NB #define crea dati fissi non modificabili dal codice
#define ELEVATION_FLAG	1	// = 00000001 in 8 bit
#define ROLL_FLAG 		2	// = 00000010 in 8 bit
#define PITCH_FLAG 		4	// = 00000100 in 8 bit
#define YAW_FLAG 	    8	// = 00001000 in 8 bit

// definizione valori di throttle null, min e max
#define ThrottleMin 1052
#define ThrottleNull 1472
#define ThrottleMax 1892

// definizione dei valori min e max ri roll pitch e yaw
#define thetaRmin -30
#define thetaRmax  30
#define thetaPmin -30
#define thetaPmax  30
#define thetaYmin -180
#define thetaYmax  180

// definizione wpto max 
#define wRpto 1 // rad/s2
#define wPpto 1 // rad/s2
#define wYpto 1 // rad/s2

// definizione inerzie del velivolo
#define Ir 1 // kg m2
#define Ip 1 // kg m2
#define Iy 1 // kg m2

// variabile di bit-flag condivisa: conforntando coi precedenti verifico l'avvenuto interrupt
volatile uint8_t bUpdateFlagsShared;

//  variabili di input condivise aggiornate dall' ISR dell'interrupt e letti dal loop()
// nel loop vengono create copie locali a interrupt() disabilitato per evitare aggiornarmenti
// anomali durante il loop() dovuti a improvvisi eventi di interrupt. 
volatile uint16_t unElevationInShared;
volatile uint16_t unRollInShared;
volatile uint16_t unPitchInShared;
volatile uint16_t unYawInShared;

// variabili usate per registrare il rising edge dell'impulso
// non necessariamente volatile: sono usate solo nell'interrupt
uint32_t ulElevationStart;
uint32_t ulRollStart;
uint32_t ulPitchStart;
uint32_t ulYawStart;

void setup(){
  Serial.begin(9600);
  Serial.println("multiChannels");

  // attaching servo objects
  servoESC_1.attach(ESC_1_OUT_PIN);
  servoESC_2.attach(ESC_2_OUT_PIN);
  servoESC_3.attach(ESC_3_OUT_PIN);
  servoESC_4.attach(ESC_4_OUT_PIN);

  // using the PinChangeInt library to attach the interrupts
  //PCintPort::
  attachInterrupt(digitalPinToInterrupt(ELEVATION_IN_PIN), calcElevation,CHANGE); 
  //PCintPort::attachInterrupt(ROLL_IN_PIN, calcRoll,CHANGE); 
  //PCintPort::attachInterrupt(PITCH_IN_PIN, calcPitch,CHANGE); 
  //PCintPort::attachInterrupt(YAW_IN_PIN, calcYaw,CHANGE); 
  //SYNTAX: attach.interrupt(PIN, funzione da svolgere all'interrupt, mode)  
}

void loop(){
  // variabili di input locali in cui copiare momentaneamente le condivise in arrivo dagli interrupt
  // aggiornate ad ogni loop
  static uint16_t unElevationIn;
  static uint16_t unPitchIn;
  static uint16_t unRollIn;
  static uint16_t unYawIn;
  // copia locale dello stato delle flag
  static uint8_t bUpdateFlags;	// al primo loop bUpdateFlags = 00000000

  // check : è avvenuto almeno un evento di interrupt? ovvero le flag sono aggiornate? 
  if(bUpdateFlagsShared){ // questa condizione verifica se c'è almeno un 1 in bUpdateFlags (=0000000 nel primo loop)
	//se si si prende una copia locale di tutte le variabili con cui lavorare
    noInterrupts(); 					//disattiva gli interrupts
	bUpdateFlags = bUpdateFlagsShared;	// prende una copia locale del check

    // è avvnuto un evento di update di flag sull'elevazione? 
    if(bUpdateFlags & ELEVATION_FLAG){		// bUpdateFlags == 00000001 ?  & è un AND-bitwise (AND bit per bit)
      unElevationIn = unElevationInShared;	// copia locale delle variabili aggionrate dall'ISR corrispettivo
    }
    if(bUpdateFlags & ROLL_FLAG){			// bUpdateFlags == 00000010 ?  & è un AND-bitwise (AND bit per bit)
      unRollIn = unRollInShared;		// copia locale delle variabili aggionrate dall'ISR corrispettivo
    }
    if(bUpdateFlags & PITCH_FLAG){			// bUpdateFlags == 00000100 ?  & è un AND-bitwise (AND bit per bit)
      unPitchIn = unPitchInShared;            // copia locale delle variabili aggionrate dall'ISR corrispettivo
    }
    if(bUpdateFlags & YAW_FLAG){			// bUpdateFlags == 00001000 ?  & è un AND-bitwise (AND bit per bit)
      unYawIn = unYawInShared;           	// copia locale delle variabili aggionrate dall'ISR corrispettivo
    }
    bUpdateFlagsShared = 0;	// pulizia della flag condiviss, abbiamo quello locale con cui lavorare
    interrupts();			// riattivazione degli interrupt
  }
  // con le copie locali delle variabili si avvia la processazione necessaria
  
  
 if((bUpdateFlags & ELEVATION_FLAG)){				// in caso di comando su ELEVATION
		Serial.println(unElevationIn);
	}  
  bUpdateFlags = 0; // operazioni avvenute quindi azzero la flag
}

// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//         Interrupt Service Routine      //
// /////////////////////////////////////////
void calcElevation(){
  if(digitalRead(ELEVATION_IN_PIN) == HIGH){	//se il PIN legge HIGH al cambio, siamo al rising edge 
    ulElevationStart = micros();				// registro il tempo in microsecondi dall'avvio di arduino
  }
  else{	// altrimenti al change avvenuto il PIN è LOW
    unElevationInShared = (uint16_t)(micros() - ulElevationStart);	// registro il delta -> la durata dell'impulso
    bUpdateFlagsShared |= ELEVATION_FLAG; // con OR-bitwise registriamo l'evento nella FLAG: nuovo segnale ricevuto
  }
}

void calcRoll(){
  if(digitalRead(ROLL_IN_PIN) == HIGH){	//se il PIN legge HIGH al cambio, siamo al rising edge 
    ulRollStart = micros();				// registro il tempo in microsecondi dall'avvio di arduino
  }
  else{	// altrimenti al change avvenuto il PIN è LOW
    unRollInShared = (uint16_t)(micros() - ulRollStart);	// registro il delta -> la durata dell'impulso
    bUpdateFlagsShared |= ROLL_FLAG; // con OR-bitwise registriamo l'evento nella FLAG: nuovo segnale ricevuto
  }
}

void calcPitch(){
  if(digitalRead(PITCH_IN_PIN) == HIGH){	//se il PIN legge HIGH al cambio, siamo al rising edge 
    ulPitchStart = micros();				// registro il tempo in microsecondi dall'avvio di arduino
  }
  else{	// altrimenti al change avvenuto il PIN è LOW
    unPitchInShared = (uint16_t)(micros() - ulPitchStart);	// registro il delta -> la durata dell'impulso
    bUpdateFlagsShared |= PITCH_FLAG; // con OR-bitwise registriamo l'evento nella FLAG: nuovo segnale ricevuto
  }
}

void calcYaw(){
  if(digitalRead(YAW_IN_PIN) == HIGH){	//se il PIN legge HIGH al cambio, siamo al rising edge 
    ulYawStart = micros();				// registro il tempo in microsecondi dall'avvio di arduino
  }
  else{	// altrimenti al change avvenuto il PIN è LOW
    unYawInShared = (uint16_t)(micros() - ulYawStart);	// registro il delta -> la durata dell'impulso
    bUpdateFlagsShared |= YAW_FLAG; // con OR-bitwise registriamo l'evento nella FLAG: nuovo segnale ricevuto
  }
}
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

but I did not understand why it worked and I'm curious... can you enlight me?

I've tried. You are not listening. The Mega does not support pin change interrupts on pins 2 and 3.