I have to simulate an ADC that behaves as an I2C slave. The simulated values that the ADC shall expose are sent over serial, saved on an attribute and are requested by a master device over I2C.

A simplified solution is the following. I have a struct ADC that describes the converter:

struct ADC 
  uint32_t register_1;
  uint32_t register_2;

  void write_register_1(uint32_t data){
    register_1 = data;

  void write_register_2(uint32_t data){
    register_2 = data;

  uint8_t read(){
    return register_1;

  // some other methods to setup...

In loop(), I read the serial in order to update the ADC::register value and in the onRequest handler I eventually send the requested data by accessing ADC::register:

ADC adc{};

void setup(){
  // setup adc, Wire and Serial here

void loop(){
  if (Serial.available() > 0)
     // read serial, parse received data and check them
     uint32_t data = parse_serial(); // do anything is needed to check data...

     // update adc attribute
     uint8_t oldSREG = SREG;
     noInterrupts(); // disable interrupts to update uint32
     SREG = oldSREG;

void slaveTransmitterHandler(){

void slaveReceiverHandler(){
  uint32_t i2c_received_data;
  while (Wire.available){
    // fill i2c_received_data with Wire.read()

I'm not sure if I have to declare the adc object as volatile (this would mean to declare all ADC methods and variables as volatile). Is it safe to use an object inside the I2C handler called by the I2C interrupt?

As far as I know, it is not (I can find no reason why it should be different from non-class variables), but I have always worked with non-class variables and never with cpp objects. Also, I can't find any information about this topic.

It could be possible that I'm wrong with the whole design, even if it seems to me to be very consistent. I'm open to change it for something better, so please if this design is nonsense, comment on that! I'm here to learn :)



Edit: Some clarification, since my question seems not to be clear enough: I'm doing HIL simulation, that is simulating the real hardware with its real interfaces with a simulated environment (that includes sensors and actuators). See here for more info.

One of my sensors measures a voltage and stores it in a register of an ADC (that has multiple registers). I'm simulating the behaviour of ADC registers in Arduino, and they shall communicate via I2C with the real hardware.

Hope this is more clear now.

  • I don't think the class has to be volatile here. Nothing in the ISR is changing anything about the class, so there's no chance that the ISR fires in the middle of something else accessing the class and getting corrupted data. The only possibility for corruption here would be if the ISR fired diring the write function but you seem to have handled that with a critical section around it. It would be different if the ISR wrote to the object, but as written it only reads from it. I think you're ok here.
    – Delta_G
    Commented Nov 3, 2023 at 18:56
  • @Delta_G This looks like an answer. Please post one and not a comment. Thank you.
    – Nick Gammon
    Commented Nov 4, 2023 at 5:17
  • Why are you doing Wire.onRequest(slaveTransmitterHandler)? That looks like you really are using I2C and not simulating it.
    – Nick Gammon
    Commented Nov 4, 2023 at 5:23
  • @Delta_G thanks! Let's say that I'm also setting some attributes of the adc object in an interrupt. How can I deal with that case? I've edited the original post to include this case (see slaveReceiverHandler). Shall I declare the object (and the whole class attributes and methods) as volatile? I guess so, but it seems that it's not really clear to me what volatile means when used in a C++ class (en.cppreference.com/w/cpp/language/cv this page goes above my understanding).
    – lumaca96
    Commented Nov 4, 2023 at 11:08
  • 2
    This isn't a forum. If you want to expand on the question please edit the question. Any answers given should address the question (as edited), not the question plus random comments. Nor should the answer be in a comment (not your fault).
    – Nick Gammon
    Commented Nov 4, 2023 at 21:40

1 Answer 1


If this is a simulation, and not actually using interrupts, then you hardly need to declare anything volatile. However your use of the Wire library makes it look less like a simulation. Personally I think your problem is under-explained. Please post all of your code. If you are simulating you won't need to worry about hardware interrupts. If you are using the Wire library you will.

Your other post Get address of a I2C transaction when multiple addresses are registered seems to be relevant here.

  • He is using the Arduino to fake an I2C ADC. The I2C link is real. The ADC readings are fake. Commented Nov 4, 2023 at 9:08
  • @EdgarBonet is right. I've edited the question with some more details.
    – lumaca96
    Commented Nov 4, 2023 at 11:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.