Volatile and dead code removal

Discussions about all user software around SAM Series.

Moderator: nferre

seanfalloy
Posts: 11
Joined: Tue Sep 27, 2011 6:51 pm

Volatile and dead code removal

Sat Mar 22, 2014 7:13 pm

This post is as much a tutorial (for those of you in the same boat as I was yesterday) as it is inviting of corrections or better ways of making sure that the compiler does not ignore your code.

As all my embedded experience before this was in assembly this is the first time I have encountered this in "c".

The system I am currently working on involves a global struct that is passed through a series of functions to control the outputs as well as parts of that struct being modified in interrupts.

The issue with this is that I do not want to make the global struct * volatile as it is passed to functions from the ISR as well as from the regular program space and when made volatile the passing of the pointer generates warnings about the removal of the volatile nature of the pointer. It also will strip away optimization that I would want included in the firmware.

In the main loop there are wait states that require the changing of a variable inside the global struct by the ISRs before the code execution can continue. As embedded systems developers almost every one here has or will have run into that.

Code: Select all

while(_global_struct->important_data != important_state){/* do nothing */}
gcc (and probably all optimizing compilers) will not update the important_data for each loop because as far as its concerned the important_data will not change as none of the code in the loop changes it.

and short of making _global_struct* volatile (which will generate more warnings than I want to filter through) the software will hang indefinitely.

Now (after the long winded situational explanation(I want this to be found by a google search when beginners dont know what they are searching for)) as far as I can tell this is the correct way to cast important_data to volatile.

Code: Select all

while(*(volatile data_type*)&_global_struct->important_data != important_state){/* do nothing */}
By casting the address of important_data to a volatile pointer and then de-referencing it the compiler will update the data each time through the loop.

Please if any of you pros out there have any insight into this or a better "more-correct" method of doing this let us know.
blue_z
Location: USA
Posts: 1560
Joined: Thu Apr 19, 2007 10:15 pm

Re: Volatile and dead code removal

Mon Mar 24, 2014 10:40 pm

seanfalloy wrote:The system I am currently working on involves a global struct that is passed through a series of functions to control the outputs as well as parts of that struct being modified in interrupts.
Seems like you have found a solution to a code problem, but perhaps that problem could have been avoided by a better design.
You may be bundling too many elements into one structure, instead of following modularity and cohesion rules for data structures just like code modules.
Passing a structure around that is also global (declared as extern) usually does not make sense.
Sharing a data structure between an interrupt handler and user code is not good practice.

Long time ago when I was doing assembly language programming, I read about Object Oriented Programming. I have been able to incorporate a key concept, data encapsulation, with structured programming, when programming in assembly language and C.
I suspect that if your project was redesigned with structured programming and data encapsulation techniques that this "volatile" usage might disappear.

seanfalloy wrote: The issue with this is that I do not want to make the global struct * volatile as it is passed to functions from the ISR as well as from the regular program space ...
Your description is vague, but normally data shared between an ISR and baselevel is a critical region and must be protected with a mutual-exclusion mechanism, e.g. a mutex lock.
But even better is to avoid creating critical regions when they are not needed. That rule meshes with data encapsulation perfectly.

Regards
seanfalloy
Posts: 11
Joined: Tue Sep 27, 2011 6:51 pm

Re: Volatile and dead code removal

Tue Mar 25, 2014 8:20 am

blue_z wrote:Seems like you have found a solution to a code problem, but perhaps that problem could have been avoided by a better design.
You may be bundling too many elements into one structure, instead of following modularity and cohesion rules for data structures just like code modules.
Passing a structure around that is also global (declared as extern) usually does not make sense.
Sharing a data structure between an interrupt handler and user code is not good practice.

Long time ago when I was doing assembly language programming, I read about Object Oriented Programming. I have been able to incorporate a key concept, data encapsulation, with structured programming, when programming in assembly language and C.
I suspect that if your project was redesigned with structured programming and data encapsulation techniques that this "volatile" usage might disappear.
Thanks for the response.
What your saying makes sense to me and most your points I have learned along the way (whether I understand and implement them properly is still up for debate.)
I have attempted to follow an OOP structure with my C code (I have done minimal work in Java & C++)
blue_z wrote: Your description is vague, but normally data shared between an ISR and baselevel is a critical region and must be protected with a mutual-exclusion mechanism, e.g. a mutex lock.
But even better is to avoid creating critical regions when they are not needed. That rule meshes with data encapsulation perfectly.
My project involves turning 2 brushless motors (PMSM) it is not a vector drive as I am attempting to control 2 motors from one controller and I did not think there would be enough processor time to implement FOC for both.
The Timer ISR update the commutation states of the motors at a regular interval. I have created 2 struct pointers (one for each of my drives(motors)) that the ISRs have access to. I do not want the timer to set a flag that the main loop will execute later on as timing is critical and I can be in wait states and other time consuming things while the motors keep turning. (The majority of processor time is spent in the ISRs while the motors are turning.) I have implemented a mutex lock for one buffer that blocks the PWM update ISR while filling but the design does not need more than that. All other data fields are updated in the main loop and carried out by the ISRs. As far as the rest of the user code is concerned all data is passed around as if it were not globally declared.

The need for the volatile casting (assuming that the way I did it was the best way) was during a wait state in an emergency stop function that waits for the motor to stop turning and if it does not stop within X amount of time (msec) turn the power off to the drive.

Sorry if some of this doesn't make sense as it has been 15 hours behind the screen today and its bed time.

EDIT: Now that I have had some sleep I can finally think through this a little better. Thanks for your input Im reworking my code now (and fixing my shortcuts :D )

Return to “Software”

Who is online

Users browsing this forum: No registered users and 1 guest