Error: cannot declare member function 'static void i2c_master::buttonPressed()' to have static linkage [-fpermissive] static void i2c_master::buttonPressed ()

Hi, I am trying to write library files for communication between I2C Master and Slave. In the Master library I get the following error:

i2c_master.cpp:71:42: error: cannot declare member function 'static void i2c_master::buttonPressed()' to have static linkage [-fpermissive]
static void i2c_master::buttonPressed ()

I have declared butonPressed as static void function, the member used is also of static int type, and the function is called in attachinterrupt(). I dont understand the error. Can anyone help me to figure it out. My .cpp file is as below:

#include "i2c_master.h"
#include "Arduino.h"
/***************************************************************************
CLASS * I 2 C M A S T E R
**************************************************************************/
i2c_master::i2c_master(int SDA_PIN, int SCL_PIN, int INTR, int LED, int buttonPushCounter, int I2C_SLAVE_ADDR)
{
_pin_a = SDA_PIN;
_pin_b = SCL_PIN;
_pin_c = INTR;
_pin_d = LED;
_val_a = buttonPushCounter;

	_addr = I2C_SLAVE_ADDR;

	pinMode(_pin_a, OUTPUT);
	pinMode(_pin_b, OUTPUT);
	pinMode(_pin_c, OUTPUT);
	pinMode(_pin_d, OUTPUT);
}

	void i2c_master::PinSetup() {

		Wire.begin(_pin_a, _pin_b);   // join i2c bus
		attachInterrupt (_pin_c , i2c_master::buttonPressed, CHANGE);
	}
	
	void i2c_master::sequence() {
		static unsigned long lastReadMillis = 0;

		if (millis() - lastReadMillis > 1000) {
			if (_val_a > 0){
				Serial.println(requestI2C());
				if(requestI2C() == 'H')
				   digitalWrite(_pin_d, HIGH);
				else
				   digitalWrite(_pin_d, LOW);
			}
			lastReadMillis = millis();
		}
	}

	static void i2c_master::buttonPressed ()
	{
	  Serial.println("test response");

	  _val_a++;
	}

	char i2c_master::requestI2C()
	{
		WireSlaveRequest slaveReq(Wire, _addr, MAX_SLAVE_RESPONSE_LENGTH);
		slaveReq.setRetryDelay(5);
		bool success = slaveReq.request();

		if (success) {
			while (1 < slaveReq.available()) {    // loop through all but the last byte
					  char c = slaveReq.read();       // receive byte as a character
					  Serial.print(c);           // print the character
					  return c;        
			}
		}
	}

Thank you.

Post the full code: .h, .cpp, .ino
Use Code Tags for all the code, not just part of it like you did in the original post.

1 Like

i2c_master - Copy.cpp (1,6 KB)
i2c_master - Copy.h (1,4 KB)
i2c_master.ino (165 Bytes)

@gfvalvo I have attached all the required attachments.

Thank you (:

Great, now post them inline with Code Tags as requested.

attachInterrupt (_pin_c , i2c_master::buttonPressed, CHANGE);

You can't use an object member function as an ISR. You have to make that function 'static' so it is the same function for all objects of the class.

static void i2c_master::buttonPressed ()
{
  Serial.println("test response");

  _val_a++;
}

The class static function doesn't know which object you mean so it can't increment '_val_a'. One way to work around that is to have a class static pointer to the object:
static i2c_master *Instance;

Then initialize it to "this" in the constructor:
Instance = this;

And then the static buttonPressed() function can reference the variable with:
Instance->_val_a++;

1 Like

Hello @johnwasser ,

Thank you very much for the detailed solution. But however I'm a little confused as I am new to Arduino and C++, What does Instance = this; mean? and Do I need to initialize it within my class i2c_master or in PinSetup()?

Thankyou

@johnwasser Thank you very much for your time. After some trials, this solution worked for me :point_down:

I2C_master *I2C_master::Instance = NULL;

I2C_master::I2C_master(int SDA_PIN, int SCL_PIN, int INTR, int LED, int buttonPushCounter, int I2C_SLAVE_ADDR)
{
	Instance = this;
	
	_pin_a = SDA_PIN;
	_pin_b = SCL_PIN;
	_pin_c = INTR;
	_pin_d = LED;
	_val_a = buttonPushCounter;
	_addr = I2C_SLAVE_ADDR;

	pinMode(_pin_a, OUTPUT);
	pinMode(_pin_b, OUTPUT);
	pinMode(_pin_c, OUTPUT);
	pinMode(_pin_d, OUTPUT);
}

	void I2C_master::PinSetup() {

		Wire.begin(_pin_a, _pin_b);   // join i2c bus
		attachInterrupt (_pin_c , I2C_master::buttonPressed, CHANGE);
	}
	
	void I2C_master::sequence() {
		static unsigned long lastReadMillis = 0;

		if (millis() - lastReadMillis > 1000) {
			if (_val_a > 0){
				Serial.println(requestI2C());
				if(requestI2C() == 'H')
				   digitalWrite(_pin_d, HIGH);
				else
				   digitalWrite(_pin_d, LOW);
			}
			lastReadMillis = millis();
		}
	}

	void I2C_master::buttonPressed ()
	{
	  Serial.println("test response");

	  Instance->_val_a++;
	}

It means "Set the class static pointer 'Instance' to the object instance being created by this constructor." The reserved word 'this' used inside an object method means 'the current instance'.

Like I said, in the constructor: i2c_master::i2c_master()

1 Like