[SOLVED] Data type confusion

I have a question, I hope somebody could help me.
In the following code the program runs as I expect, but if I comment (//) the line: Serial.println(bufPos); inside the While(1) it never goes inside the if.

How is affecting Serial.println(bufPos) to bufPos variable and why it is changing If behavior?

Thanks in advance.

#include "pins_arduino.h"

// what to do with incoming data
byte command = 0;
byte compression = 0;
byte dataLengthLSB = 0;
byte dataLengthMSB = 0;
byte acknowledgeCode = 129;
byte statusCode = 0;

char buf [100];
byte bufPos;

void setup (void)
{
  // Serialdebugging
  Serial.begin (115200);   
  
  // have to send on master in, *slave out*
  pinMode(MISO, OUTPUT);

  // turn on SPI in slave mode
  SPCR |= _BV(SPE);

  // turn on interrupts
  SPCR |= _BV(SPIE);
  SPDR = 0;
  
  bufPos = 0;
  
  Serial.println("Setup done.");
  
}  // end of setup


// SPI interrupt routine
ISR (SPI_STC_vect)
{
  byte c = SPDR;
  if (bufPos < 100)
  {
  buf [bufPos++] = c;
  }  // end of room available

}  // end of interrupt service routine (ISR) SPI_STC_vect

void loop (void)
{
  while(1){
    Serial.println(bufPos);
    if (bufPos > 0) {
      Serial.println(buf [bufPos]);
      bufPos = bufPos -1;
    }
  }
}  // end of loop

bufPos needs to be declared volatile.

http://www.gammon.com.au/interrupts

You are usingchanging bufPos and buf[] inside an ISR so they should be declared volatile:

volatile char buf [100];
volatile byte bufPos;

By declaring them as such, the compiler knows they can change at any time (because of an interrupt). If you don't it doesn't know about the interrupts, sees 'bufPos' as Zero when it gets to the main loop (it is set as such at the end of setup) and decides "if (bufPos > 0)" will thus never be true as bufPos cannot as far as it is aware change, so it optimises it out. By adding the Serial.print() statement to the loop, it has to read in bufPos from the SRAM to print it, and for all it knows the print() function could affect bufPos. The result is it cannot gaurantee that the value doesn't change, so the if statement doesn't get optimised out.

Declaring them as volatile should fix the problem.

Hi Tom, Nick,

Thanks for your fast reply. It sounds very good to me. I will try as soon as I can, I will comment.

I've been using volatile without criteria. Is there any link to find more information about volatile? I haven't found it on arduino website. What are the side effects of using volatile always? My understanding is that processing ISR will take much longer but, the physical memory used will be the same, it isn't?

buf doesn't actually need to be volatile, its not changing (its a pointer to chars, not the chars themselves). Declaring volatile is good practice though as it marks those variables as being used in an interrupt routine (ie can change under your feet in the main body of the code).

Volatile prevents the compiler from applying certain optimisations that can be unsafe if used between contexts.

The cpu uses registers, so variables in ram are copied to a register for computation. This information isn't tracked, so which does the ISR use; the ram copy or the register. Volatile ensures the register is flushed to ram before it loses context.

So, yes your ISR can be slower as more instructions can be emitted for volatile data.

All you were right. It's working fine! As MarkT said, there is no need to declare pointers as volatile.

Thanks.