Go Down

Topic: [SOLVED] Data type confusion (Read 565 times) previous topic - next topic

gism

Oct 31, 2012, 01:08 am Last Edit: Nov 01, 2012, 06:44 pm by gism Reason: 1
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.

Code: [Select]

#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


Nick Gammon

bufPos needs to be declared volatile.

http://www.gammon.com.au/interrupts
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Tom Carpenter

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

Code: [Select]
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.
~Tom~

gism

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?


MarkT

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).
[ I won't respond to messages, use the forum please ]

pYro_65

#5
Oct 31, 2012, 05:22 pm Last Edit: Oct 31, 2012, 05:25 pm by pYro_65 Reason: 1
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.

gism

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

Thanks.

Go Up