There is a string buffer referenced by both an ISR and the main(). The ISR collects a sentence from UART and put it into the buffer. Once the received sentence is completed a flag is raised. The main() checks the flag and copies the sentence to another buffer. The code is like
unsigned char xdata RxBuffer[]; unsigned char xdata buffer[]; bit RxFlag = 0; void uart( void ) { //receive data from sbuf RxBuffer[] = sbuf; //if done RxFlag = 1; } void main( void ) { while( 1 ) { if( RxFlag ) strcpy( buffer, RxBuffer ); } }
"Should I declare RxBuffer as volatile?" Yes. "RxFlag doesn't need to be volatile" Yes it does, although it may be the case that bit variables are implicitly volatile in Keil. I'm not sure. To the compiler 'volatile' essentially means "don't optimise any usage of this variable". "Does the reentrancy play any significant role here" No, as you are not calling functions from your ISR. "What is the difference between memcpy() and strcpy()? What are the advantages and disadvatages on each?" memcpy() copies the specified number of bytes from source to destination, strcpy() copies bytes until the first zero byte in source. Check your C book. Stefan
You will have to be more careful to avoid that the ISR overwrites parts of the buffer the main routine is currently working on. I.e. you'll need more status than just a single bit, so the main() function the ISR where in the buffer it currently is. In the end, you'll most probably end up with a ring buffer. Both the ISR and main maintain one pointer (or index) into the ring each, and check that theirs doesn't run over the location of the pointer maintained by the other. Both of these pointers will have to be made volatile. RxFlag doesn?t need to be volatile because it is an automatic variable. Wrong. It's most definitely not an automatic, as shown, and it has to be flagged volatile. You should flag the array volatile, too, because its contents do change without the current thread of control knowing about it.
For an example of interrupt-driven serial IO with ring buffers, see the examples section of this very site!
To the compiler 'volatile' essentially means "don't optimise any usage of this variable". Not quite. volatile applies specifically to reloading a variable rather than using a possible cached copy in registers. It has no effect on other optimizations. See the other current thread: http://www.keil.com/forum/docs/thread3371.asp its contents do change without the current thread of control knowing about it This is a much better way of stating it. If a variable can change for any reason unbeknownst to the local code (with a very limited point of view, as when the code generator is spitting out that line of code), then the variable should be declared volatile. Common reasons for needing volatile include hardware registers which update all by themselves and addresses to which you may need to generate actual writes, especially double writes to unlock a register, perhaps. But possible reasons also include memory shared between different execution contexts, including both main/ISRs and multiple tasks.
"Not quite. volatile applies specifically to reloading a variable rather than using a possible cached copy in registers." That's pretty much exactly how I see volatile. I was trying to offer a simple explanation in the context of the OP's situation. Perhaps I should have said: "don't perform any optimisations that will screw up what I'm trying to do here" "It has no effect on other optimizations." Having re-read the section on volatile in H&S I'm not convinced about this, but I found the explanation a bit unclear. Maybe someone can quote the text from the standard if that makes it any clearer? Stefan
The standard's wording boils down to this: all operations on an object qualified as "volatile" must happen in exactly the same way and order as expressed by the standardized semantics of the source code. They define the effects of all C statements and operators in terms of some virtual machine executing the C program, and the effect of "volatile" as making the behaviour of the C program on the actual execution machine the same as that of the virtual machine, as far as "volatile" objects are concerned. In practice this forbids all register-caching and code reordering optimizations. It still allows optimizations like, e.g., common exit code unification to save space, or function inlining, and quite some others.