Hi there All, I have a problem which seemed to be defying explanation, but I have come up with a theory. Could I possibly have some feedback on whether the following is likely, plausible, possible, untrue or downright rubbish? If one reads the contents of a CAN or ADC chip register at a particular address, then the label volatile is placed upon that address to prevent the compiler optimising out repeat readings of the address. If one reads the contents of the address into a variable, then the compiler would automatically treat the contents of this variable with similar care. Is it possible that there has been an oversight with statements where the contents of a variable depend on the contents of a volatile by way of an if statement, ie...
normal_var=volatile_var;
normal_var=voltile_var; if (normal_var=0x00) { another_normal_var+=1; }
A couple of things occur to me here: 1) I believe that sbit variables are implicitly volatile, although I've had a look in the manual and cannot seem to find anything to back that up. Maybe plain 'bit' variables are also considered volatile? 2) The compiler would have no difficulty seeing that global_refresh is modified both inside the ISR and in main(). Perhaps it automatically suppresses optimisation in cases like this? Stefan
A couple of things occur to me here: 1) I believe that sbit variables are implicitly volatile, although I've had a look in the manual and cannot seem to find anything to back that up. Maybe plain 'bit' variables are also considered volatile? 2) The compiler would have no difficulty seeing that global_refresh is modified both inside the ISR and in main(). Perhaps it automatically suppresses optimisation in cases like this? Optimisation is entirely optional for the compiler. In practice, writes to global variables tend not to be optimised out because, in general, it is difficult for the compiler to keep track of where else a variable might be read. However, reads of global variables is another matter. In this case SV's code works because it is simply fortunate that the compiler chooses to read the value of global_refresh from memory rather than keeping a copy in a register. With this processor there is probably no benefit in keeping a local copy of a bit, but if global_refresh were to be changed to a char then the code may fail to work as expected. Worse still, the code might work for now, but fail when the compiler is updated!
Hi Stefan, 1. I tried it with char global_refresh and it works too... Regards, S.
I'm using 8051F124 compiler keil v7.08 assembler v7.08a
and exactly to say I tried char xdata global_refresh;
just tried without xdata - it works too...
S V, you're chasing a red herring. What happens in a particular program, using a particular compiler version on a particular platform, if you do not qualify object as volatile which really has to be, misses the point. The point is that by not making this variable volatile, you're inviting the compiler to optimize it in whatever way it thinks. This risks the way actually being chosen to be one that breaks your program. It may not happen today, but that says nothing about what may happen next week, after you added some completely unconspicious pieces of code elsewhere in the program, or upgrade your compiler. Your code as given is buggy, and since you obviously know how to fix that bug, there's no valid excuse for leaving it unfixed. Not making your variable, which is shared between the interrupt handler and the main code, a volatile is a lie by omission. Let's repeat that: Your code lies to the compiler. And as always, this means you will responsible for whatever the consequences of that lie may be. You're causing undefined behaviour --- and trust me, you don't want to do that. Do you really believe it's a good idea to lie to an entity you're supposed to cooperate with to complete the greater project at hand? Lying to your supervisor will get you fired quickly --- lying to the compiler may take a bit longer, but it will ultimately get you fired, too. Don't do it.
just tried without xdata - it works too... And who gives a hoot. Succesful testing does no prove the abscence of bugs, it only proves the abscence of known bugs. Hans-Bernhard states: says nothing about what may happen next week, after you added some completely unconspicious pieces of code elsewhere in the program, or upgrade your compiler He is actually missing the real problem. The interrupt variable may share the location with an extremely rarely accessed variable in the mainstream and when - and only when - the interrupt happens while this little rarely active piece of code is running, you program will go astray. Why discuss "can I get by naking it the wrong way" just make it the right way and go on. Erik
Hello Hans-Bernhard Broeker , thank you very much for you reply and ,believe me, it was a question only for understanding of the things, which have taken place in my project. My project is about 35K of code(I think it's huge enough and it's real complicated) and I've checked this behavior(without volatile) many times in the different stages of the project development and it has never failed. It's clear, that I will use this VOLATILE declaration, but I've yet sad , it's only a question of exact understanding. And I saw such behavior in another projects as for Cx51 as well for Cx166 - it has work faultless! With best regards, S. P.S. I would like to have this snippet of code get failed...
Hi Erik, I think your message hit exact the problem.. "The interrupt variable may share the location with an extremely rarely accessed variable in the mainstream and when - and only when - the interrupt happens while this little rarely active piece of code is running, you program will go astray." Now I try to explain... I use this refresh_global for the display updating with a refresh period of ca.300ms. 1.And change of the display contents is not so fast, may be only in the case if one would rotate the potentiometer. May be here one can not exactly say if one refresh was missed or not(it's just too fast for eye). 2.This variable has only some places in the program where it's changed - it's really rarely accessed variable and I had luck that in that moment this variable was accessed in the mainstream this ISR has not occured. Does it somehow hit the problem? With best wishes, S.
Does it somehow hit the problem? It does hit the reason to apply volatile where needed. Erik
to Erik Thanks, P.S. I've understood you answer that what I've written trying to explain why my code "has not failed" were correct?
I would like to have this snippet of code get failed... Your code as shown may just be too simple to fail. If this has never failed you yet, that only proves you either didn't really check strictly enough, or that you got lucky everytime. Neither of which would justify relying on such behaviour for future projects.
I've understood you answer that what I've written trying to explain why my code "has not failed" were correct? Yes Erik
I would like to have this snippet of code get failed... No guarantee this will work for you. Once when I had to sort out someone elses mess and the person refused to believe me, I managed to show the problrm by setting the timer complete bit while stopped at the mainline routine in the emulator. I doubt a simulator will blow as well as an emulator, but if you do not have an ICE, you can try it. Erik
something more .... dissasembly... some snippets of this code... ////void timer_isr interrupt 1//// 280: global_refresh=1; C:0x66AD 755001 MOV global_refresh(0x50),#refr_en(0x01) 281: if(global_refresh==1)LED=1; C:0x66B0 E550 MOV A,global_refresh(0x50) ////////////////////////////////// ///////////void main////////////// /////while() 56: if(global_refresh==1) C:0x03EB E550 MOV A,global_refresh(0x50) C:0x03ED 6401 XRL A,#refr_en(0x01) .................................... .................some code.......... 317: global_refresh=0; C:0x1367 E4 CLR A C:0x1368 F550 MOV global_refresh(0x50),A 350: if(global_refresh==0) LED=0; C:0x141E E550 MOV A,global_refresh(0x50) //////////////////////////////////// Here one can see - nothing has been put in the register and in all cases it has been read from the same data location memory!(D:0050H PUBLIC global_refresh). Additionaly, what I didn't say before, the timer was not declared with "using x", it means , it uses the same bank as the main(). I think, the main point, why it works that, there is nothing to optimize! with best regards, S.