Showing posts with label Micro-controllers. Show all posts
Showing posts with label Micro-controllers. Show all posts

Friday, November 14, 2014

Volatile : Demistyfied


  

Introduction
"Volatile" is a qualifier in 'C' which is applied to a variable when it is declared. So, what does it tells to the compiler? It gives the information to the compiler that the value of the variable may change at any time during the execution of the code without the knowledge of the compiler. If proper precautions are not taken, we might not get the desired results. A variable should be declared volatile whenever its value could change unexpectedly.


The syntax for declaring the variable as volatile is given below,
volatile dataTpye variable;  

Let us understand the “Volatile” keyword in deep through the following examples.


Example 1:
Let us consider small and simple example as shown in the Fig:1 to study the behavior of the 'volatile' keyword in C.

Fig 1: Code without the use of volatile.
In the above example the intention of the programmer is to keep polling inside the while loop until 'flag' value becomes 1(one).But the compiler, while compiling the code applies the optimization techniques and compiler will notice that no other code can possibly change the value stored in 'flag', and therefore assume that it will remain equal to 0(Zero) all times. The compiler will then replace the function body with an infinite loop as shown in the below Fig 2

                Fig 2: Optimization applied by the compiler to the code shown in fig1.

Let we check the size of the assembly code generated by the compiler as shown in the below Fig 3.

Fig 3: Size of assembly code generated by the compiler.


Now, if you observe Fig 3, the size can be found as 482 bytes in the 5th column. Now, we will apply the volatile keyword to the flag variable to the code shown in Fig 1, as shown in the below Fig 4,

                 Fig 4: Code with volatile  
Let we check the size of the assembly code generated by the compiler as shown in the below Fig 5.
Fig5: Size of assembly code generated by the compiler after applying 'volatile' keyword.


Now, if you observe Fig 5, the size can be found as 501 bytes in the 5th column. So, when we compare the sizes of both the codes with & without volatile keyword, obviously one can observe that the compiler is not optimizing the variable flag when it is qualified as “Volatile”.

Let we still experiment further to explore where the compiler is optimizing the code, to do this apply the vimdiff command to the assembly codes generated earlier, the difference is shown in the below fig 6:


Fig 6: Difference between the assemblies codes generated without & with volatile keyword.
From the above figure, we can conclude that volatile keyword prevents the application of optimization techniques by the compiler.

Example 2
Let us consider another example, where “for” loops are used commonly in the Embedded C code for the generation of the delays. Let us see how the compiler will optimize the code containing the “for” loops in the embedded C code without the use of the qualifier “Volatile” as shown in the Fig 7 below,

Fig7: For loop without volatile qualifier.
Let us generate the assembly code for the above given example, using the command given in the note 2, and getting the size of the assembly code using the “ls” command is given below in Fig 8,

Fig8: Size of assembly code generated by the compiler without volatile qualifier.
Now, we will apply the volatile keyword to the “i” variable in the code shown in Fig 7, as shown in the below Fig 9,

Fig9: Code with volatile keyword.
Let us generate the assembly code for the above given example, using the command given in the note 2, and getting the size of the assembly code using the “ls” command is given below in Fig 10,

Fig10: Size of assembly code generated by the compiler with volatile qualifier.
Comparing the sizes in the Fig 8 & 10, one can identify the compiler is applying the optimization techniques without the volatile qualifier. The dis-assembly code for both with & without volatile keyword is shown below in Fig  11,

Fig 11: Difference between the assemblies codes generated without & with volatile keyword.
Example 3 : Global variables accessed by multiple tasks within a multi-threaded application
Let us consider one more example to show how the global variable will be affected by the compiler optimization in the multi-threaded application. The example code snippet is shown as below in Fig 12,

Fig 12: Demo code to show how global variable will be affected in multi threaded program.
In the above demo program, the compiler doesn't have any knowledge of context switching between the two threads. If the compiler optimizations are turned “ON” then the compiler will assume that global_item_count variable is always “ZERO” and no other part of the thread is attempting to modify it. So, the compiler may replace the line no. 11 in the demo code like this

 
Which is nothing but the infinite loop, so in-order to avoid such optimizations by the compiler, it is safe to declare the variable global_item_count as “volatile”.

Similarly, one can realize the effect of producer-consumer problem accessing the global variable without declaring it as “Volatile”. Refer the link below


Example 4: Interrupt service routines
Let us consider another example given in the fig 13, where “volatile” plays a very important role in the ISR.
Fig 13: Volatile keyword used in ISRs


In the above example, if the flag is not declared as “Volatile” , then the compiler may optimize the code assuming always the flag is ZERO and replace the while(!flag) to while(TRUE) in line no.11, which is nothing but infinite loop. But the flag value will change when the interrupt occurs.

Whether to declare the variable as 'Volatile' or not is cross compiler dependent, anyhow it is good practice to declare the variable as 'Volatile' to achieve the portability of the code.

Conclusion:
The main use of volatile keyword is to prevent compiler from optimizing the code in terms of time complexity by generating a code that uses CPU registers as faster ways to represent variables. By declaring the variable as “Volatile” forces compiled code to access the exact memory location in RAM on every access to the variable to get the latest value of it which may have been changed by another entity.

A variable should be declared volatile whenever its value could change unexpectedly. In real time, three types of variables could change,

1. Memory-mapped peripheral registers

2. Global variables modified by an interrupt service routine

3. Global variables accessed by multiple tasks within a multi-threaded application  


Thursday, April 3, 2014

Pit-falls of Bit-fields




In the past few posts we have been checking various aspects related to bit fields. In this blog, let we focus on how bit-lengths will pose a serious issue to achieve portability in case of bit-fields structures.

Portability is basically about having the same program or application running across various processor architecture. When it comes to embedded systems portability plays a very important role as they have diversified set of hardware. 


To start withlet us take a simple program as given below in Fig 1:




Fig 1: Bit-length pose and portability issue. 
 
After running the above code, output is shown in the given below Fig 2:

Note: source code is tested under gcc (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2 version.

 Fig 2: Output of the source code given in Fig 1.

From the above figure 2, it is clear that when we declare the bit-length more than the sizeof(int)[ In our case , it is 4 bytes] , which is compiler dependent we are getting the error at the compile time. The above code perfectly works fine , if the machine WORD size is 64 bits, but fails to work with lower WORD size, which results in portability issue.

Pointers & Bit-fields
I want to focus on one more problem, why pointers cannot be applied for the bit-fields.let me practically explain this problem by taking an example shown in the fig 3 below,

Fig 3: Pointer operation and bit fields

The output of the above source code is given below,


 Fig 4: Output of the source code shown in fig 3.

One can observe from the above fig 4, when tried to reference the bit-field structure variable, compiler is generating an error, this is because direct addressing of the bit-fields structure variables is not possible in C, since the smallest unit of addressable memory in C is a sizeof(char) i.e byte addressable not an bit addressable. This is one of the pit-fall of the bit-field structure in C programming.

From the above two examples, we can conclude that how portability issue is major concern with the bit-fields, and also we saw direct addressing of the bit-fields is not possible in C programming. Apart from this two issues, even sizeof() operator cannot also be applied for the bit-fields since sizeof always returns size in bytes not in terms of bits. Use bit-wise operators instead, they are 100% safe and portable.

Sunday, February 16, 2014

Stack overflow - ‘Interrupts’ your ‘flow’

This is my first step to blogging world, where words matter and quality counts. I was befuddled while searching for my first blog topic. For last one month I was working on PIC 16F877 faced some challenges which i was not aware of. So finalized that I'm going to write on issues I faced.

In this blog would like to start with stack-overflow in embedded-systems. First of all, I gone through Wikipedia description of stack overflow. There’s nothing wrong with the description – it’s just incomplete from an embedded systems perspective. So decided to investigate on that and start a blog.

What’s your stack size set to?

Most embedded systems compilers are designed to work with a particular family of processors. The low end of the family may have a tiny amount of memory (e.g. 128 bytes). For example 8 bit PIC architecture is that the stack size is fixed. It varies from a depth of 2 for the really low end devices to 31 for the high end 8 bit devices. The most popular parts (such as the 16F877) have a stack size of 8.

Which stack is overflowing?

Many processors implement multiple stacks. A typical separation is a call stack (upon which the return addresses of functions are stored) and a data or parameter stack (upon which automatic variables are stored). Once you’ve made the determination which stack is overflowing then finding out exactly what gets placed on that stack will help lead you to the solution to your problem. If you can see no high level language construct that is causing the problem, then the single most likely cause of your misery is an interrupt service routine. 

Reasons
  1.  An interrupt service routine can use up a huge amount of space on the stack. This problem is arise if your system allows interrupts to be nested (that is, it allows an ISR to itself be interrupted).
  2. Certain library functions (like printf and companions) can use an enormous amount of stack space.
  3. Calling functions in nested manner, going beyond your stack size.
  4. If you are writing partially in assembly language, and you failing to pop every register that you pushed? This often occurs if you have more than one exit point from a function or ISR.
  5. If you are writing entirely in assembly language, and you are not setting up the stack pointer correctly, and you don't know which way the stack grows?
  6. Have you made the mistake of programming a micro-controller that you don’t understand? For example, low end PIC processors have a tiny call stack which is easily overflowed. If you are programming a PIC and don’t know about this limitation, then I’m not surprised you are having problems.
If none of the above solve your problem, then you are most likely in to a stack over-write problem. That is, a pointer is being de-referenced that results in the stack being overwritten. This can often arise when you allocate an array on the stack and then access an element beyond the end of the array.

Next blog we will see how to compute your stack size.