i2c variable

Hi everyone,
i have a question about i2c variable in this example:

Code for Master:

#include <Wire.h>

void setup() {
  Wire.begin(); // join i2c bus (address optional for master)
}

byte x = 0;

void loop() {
  Wire.beginTransmission(8); // transmit to device #8
  Wire.write("x is ");        // sends five bytes
  Wire.write(x);              // sends one byte
  Wire.endTransmission();    // stop transmitting

  x++;
  delay(500);
}

Code for the Slave:

#include <Wire.h>

int a = 0;

void setup() {
  Wire.begin(8);                // join i2c bus with address #8
  Wire.onReceive(receiveEvent); // register event
  Serial.begin(9600);           // start serial for output
}

void loop() {
  delay(100);
  while (!a) {
   delay(1);
  }
  Serial.println("out!");
  a = 0;
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany) {
  while (1 < Wire.available()) { // loop through all but the last
    char c = Wire.read(); // receive byte as a character
    Serial.print(c);         // print the character
  }
  int x = Wire.read();    // receive byte as an integer
  Serial.println(x);         // print the integer
  a++;
}

If i comment the "delay(1)" in the Slave code, the variable "a" not change. Why that happen?

  1. Wire is I2C not SPI.

  2. a needs to be volatile if it is going to be changing inside that interrupt code.

volatile int a = 0;

Delta_G:

  1. Wire is I2C not SPI.

Ops, my mistake.

Delta_G:
2. a needs to be volatile if it is going to be changing inside that interrupt code.

volatile int a = 0;

The Arduino r3 has the interrupts pins not in SDA (A4) and SCL (A5).
But the ATmega328P Chip has a hardware I2C, so is it an "internal" interrupt?

Is that code being called from setup or loop? Nope. So it must be being called by an interrupt. There are lots of interrupts besides the ones on pins 2 and 3. This is the one that fires when there is new I2C data.

Delta_G:
Is that code being called from setup or loop? Nope. So it must be being called by an interrupt.

Is that code being called from setup or loop? Yes. So it must not be being called by an interrupt. Can this statement be inferred from the above quotation?

The statement in setup():

Wire.onReceive(receiveEvent); // register event

is not calling receiveEvent. It's just passing the callback function pointer to the library, which will call them from an ISR.

I think the reference pages for Wire.onReceive() and Wire.onRequest() should mention that the callback function will be called from an ISR with a link to the attachInterrupt() reference page, which describes the limitations/recommendations for ISR code.

GolamMostafa:
Is that code being called from setup or loop? Yes. So it must not be being called by an interrupt. Can this statement be inferred from the above quotation?

Where is that called from setup or loop?

Delta_G:
Where is that called from setup or loop?

In the following sketch, I am calling upon the delay(1000) function from loop(); the program is blinking L (the built-in LED of UNO). However, we know that the delay() function works on TC0 interrupt -- a fact that can be established by including cli() instruction in the setup.

void setup() 
{
  pinMode(13, OUTPUT);
  //cli();
}

void loop() 
{
  digitalWrite(13, HIGH);
  delay(1000);
  digitalWrite(13, LOW);
  delay(1000);
}

GolamMostafa:
In the following sketch, I am calling upon the delay(1000) function from loop(); the program is blinking L (the built-in LED of UNO). However, we know that the delay() function works on TC0 interrupt -- a fact that can be established by including cli() instruction in the setup.

void setup() 

{
  pinMode(13, OUTPUT);
  //cli();
}

void loop()
{
  digitalWrite(13, HIGH);
  delay(1000);
  digitalWrite(13, LOW);
  delay(1000);
}

We are working on the OP's code. This coded has absolutely nothing to do with the question we are working on for @markcalaway. If you have questions about how delay works then post your own thread. Please don't hijack and derail this one. Have a little bit of consideration for others Golam.

Delta_G:
We are working on the OP's code. This coded has absolutely nothing to do with the question we are working on for @markcalaway. If you have questions about how delay works then post your own thread. Please don't hijack and derail this one. Have a little bit of consideration for others Golam.

markcalaway:
If i comment the "delay(1)" in the Slave code, the variable "a" not change. Why that happen?

Even the delay(1) is under comment, the variable a is changed from 0 to 1 (Fig-1); but, it is not seen by the loop(). In order to make it available to the loop(), Post#1 has suggested to declare the variable a as volatile taking into account that void onReceive() is an 'interrupt context event handler', and it has solved the problem for the OP (Fig-2).
sm17.png
Figure-1: (with //delay(1) under comment; int a= 0)

sm18.png
Figure-2: (with //delay(1) under comment; volatile int a = 0)

If the delay(1) is kept in the loop(), there is no need to impose volatile modifier on the variable a; the value of the variable (a) is changed from 0 to 1 and the loop() finds it alright (Fig-3).
sm19.png
Figure-3: (with delay(1) in loop); int a = 0)

The dilemma remains unresolved -- is void onReceive() an 'interrupt context event handler' or a 'non-interrupt event handler'. Also, the role of the delay(1) in the loop() is not understood at all in respect of controlling the value of the variable a.

sm17.png

sm18.png

sm19.png

GolamMostafa:
The dilemma remains unresolved -- is void onReceive() an 'interrupt context event handler' or a 'non-interrupt event handler'.

There is no dilemma, read the source code (the ultimate documentation). Wire.cpp, Wire.h, twi.c, and twi.h clearly show that the function called via the pointer passed to Wire.onReceive() is called from ‘ISR(TWI_vect)’ -- Assuming Uno Board. Thus, it’s absolutely in the interrupt context.

gfvalvo:
There is no dilemma, read the source code (the ultimate documentation). Wire.cpp, Wire.h, twi.c, and twi.h clearly show that the function called via the pointer passed to Wire.onReceive() is called from ‘ISR(TWI_vect)’ -- Assuming Uno Board. Thus, it’s absolutely in the interrupt context.

ISR(TWI_vect){} is called upon again and again to read arrived data byte (s) from TWDR Register and store them onto the Arduino unseen FIFO Buffer. After that, the control goes to the void onReceive() handler to give the user an opportunity to bring out the received data bytes from the unseen FIFO Buffer and put them into user variables for processing.

It is noticed in OP's code that the delay(1) updates the variable a even the variable was not declared as volatile.

Multiple issues. My post merely refuted your claim that there was a 'dilemma' regarding the context in which the callback function is called. There clearly is not.

Regarding the delay() and 'volatile':

You'd have to dig into the final assembly code produced by the optimizing compiler. Using 'volatile' forces the compiler to use the variable's memory location (rather than a value saved in a register) for every access. Not using 'volatile' gives the compiler freedom to do what it wants. Perhaps adding the delay() makes the value of 'a' no longer available in a register.

Point is, it's stupid to ask why things happen the way they do when you've clearly violated the rules. It's like asking why strange and indeterminate things happen when you over-run an array. Do it the right way (in this case use 'volatile') and you won't have to worry about it.

EDIT:
Well, it may not be "stupid", but it is pointless.

Again @Golam, please stop derailing threads because you don't understand how code works. If you have questions then start a thread. Please be respectful of the OP and keep your crazy stuff on another thread. If you have questions about how code works then start your own thread and ask them. But please do not add confusion to the OP by displaying your ignorance on his or her thread.

Thanks,

gfvalvo:
Point is, it's stupid to ask why things happen the way they do when you've clearly violated the rules. It's like asking why strange and indeterminate things happen when you over-run an array. Do it the right way (in this case use 'volatile') and you won't have to worry about it.

EDIT:
Well, it may not be "stupid", but it is pointless.

Delta_G:
Again @Golam, please stop derailing threads because you don't understand how code works. If you have questions then start a thread. Please be respectful of the OP and keep your crazy stuff on another thread. If you have questions about how code works then start your own thread and ask them. But please do not add confusion to the OP by displaying your ignorance on his or her thread.

Who will give the opinion if the above two reactions are in-line or conflicting?

I don't even know what you mean by that sentence. I'm going to report this and hope that maybe one of the mods will help you understand what I mean when I'm asking you to be respectful of the OP and keep this to your own thread. Maybe one of the mods will split it off for you.

@GolamMostafa - if you have a question about how callbacks and interrupts work, please start a new thread, don't hijack someone else's thread.

Who will give the opinion if the above two reactions are in-line or conflicting?

No, I don't understand that one either.