What is embedded C? Difference between C and embedded C.
Embedded C is nothing but an extension of standard C. C is mainly used for desktop application where it has access to abundant resources of desktop computer like RAM, ROM, OS, I/Os etc. Embedded C is used for microcontroller based application which has limited amount of RAM, ROM, I/Os etc. In other words, embedded C programmer must ensure that his/her program is using available resources in target chip in most optimum way.
What are different program optimization techniques used in embedded programming?
- Speed Optimization
- Memory Optimization
- Power Optimization
What is use of static keyword in C program?
when a variable is declared as static inside function body it will retain its value in between function call.
when a variable is declared as static outside function body, scope of that variable will be limited to C file in which it is declared.
When a function is declared as static in C file that function can be accessed only within in file in which it is declared.
A static variable is defined in file1.c, how to access its value in file2.c?
- Using pointer
- Using function
Can a variable be declared as extern static?
NO, a variable can have only one storage class, declaration will result into compilation error.
What is auto storage class for variable, where these variables are stored?
These is default storage class for local variables, these variables are stored in stack.
What is register storage class? Where to use it?
Local variable can be declared with register storage class, these variables are stored in CPU register instead of RAM which enables faster access to variable. Each CPU has limited number of registers so if registers are occupied then variable will be stored in RAM. In other words, using register storage class does not guarantee that variable will be stored in CPU register.
Register storage class can be used for a local variable required to be accessed frequently, e.g. loop counter.
What is volatile keyword? when to use it?
Volatile keyword is an instruction to compiler to not to optimize source code associated with it.
In embedded programming, we often come across situation where a variable or pointer can be modified by hardware peripheral event or ISR routine or thread in multi-threading application. If keyword volatile is not used for such variable/pointer then compiler may optimize the code and eventually program may not work as expected.
Example1: A global variable is modified by an ISR.
In above example, compiler first come across counter variable declaration and starts parsing main function, compiler takes note that counter variable never appeared on left hand side of assignment operator (e.g. counter = 5) hence its value is not modified before using it and if condition if(20 == counter) will always remain false and should be treated as redundant code. Compiler can completely remove the if condition from while (1) loop in main function to achieve optimization, however that is not the intention of above program. To prevent compiler from doing this optimization, counter variable should be declared as volatile.
Example2: Peripheral status register modified by HW event.
In above example, compiler does not have clue that value at 0x2020 address will get updated when a character is received on UART0. Compiler assumes that value at 0x2020 address (once read at line number 33 in above code) will remain same throughout the program execution and compiler does not use latest value at this address when polling for RX bit (at line number 40 of above code). Correct approach would be to declare ptr as volatile unsigned int *ptr;, this will make sure that always latest value from 0x2020 address will be used.
Example3: A global variable is modified by a multi threaded program
In above example, compiler may optimize access to temperature variable in TASK1_EnableCooling and cooling may never be started by TASK1_EnableCooling even if temperature changes to value greater than 30’c. To avoid this temperature should be declared as volatile.
How to declare a volatile function pointer?
void (*volatile fptr)(void *);
Is it possible to use both volatile and const keyword for a declaration? explain.
int const volatile HwStatusReg;
Yes, here const indicates that HwStatusReg will not be modified by program, volatile indicates it can be modified by external HW events. HW status registers are best example as these registers are updated based on HW events but are read only for program.
What is size of int? explain.
Size of int is machine dependent.
- 8 bit machine – 2 bytes
- 16 bit machine – 2 bytes
- 32 bit machine – 4 bytes
- 64 bit machine – 8 bytes
As per ANSI standard minimum size for int is 16 bit. Some compilers allow to manipulate size of int based on application need.
what is size of pointer? explain.
Size of pointer depends on several factors such as CPU architecture, OS and compiler configurations. Generally, size of pointer is equal to data bits it can process in one shot, that is pointer size is 4 bytes for 32-bit microprocessor. In some processor architecture (modified Harvard) where data and program memory have different bus width, size of data pointer and function pointer may or may not be same.
what is NULL pointer? Can we dereference it?
It is a pointer which is pointing nowhere. It points to base address of segment which is defined as below.
#define NULL 0
int *ptr = NULL;
If you try to dereference a NULL pointer it will result in run time error such as segmentation fault.
NULL pointer is normally used to provide below information to program
- Pointer does not contain valid address and should not be dereferenced.
- Pointer is available to be assigned a new/valid address.
what is void pointer? explain.
It is pointer which can hold address of any data type. void pointer cannot be dereferenced directly, it requires typecasting to standard data type before dereferencing. If you try to dereference a void pointer without type casting, it would result in compilation error.
Example1: void pointer basic example
Example2: void pointer example in sensor based control system.
Write a program to identify system endianness.
What is size of below structure? What is structure padding? Why it is required?
short int d;
size of above structure is 16 bytes considering 32 bit system. In order to ensure that each structure member is aligned to it's respective boundary and structure as a whole aligned to word boundary, compiler automatically adds padding bytes while allocating memory to structure. This is called structure padding. Most processors fetch data from word aligned address only as it is faster to access data from aligned address. To ensure aligned access for processor structure padding is necessary.Above structure after padding should look like as below
char P1; /* padding bytes to make sure next member is aligned */
char P2; /* padding bytes to make sure next member is aligned */
short int d;
char P3; /* padding bytes to make sure struct as whole is aligned */
Which is faster macro or function? why?
Macros are faster compare to function. when a function is called, before execution of first program instruction of this function begins, there are several steps associated which includes storing current register context on to stack, storing return address (address of next instruction to be executed after function call),jump to destination address(where function code is located) and finally allocate/initialize new stack frame for function to be executed. These all steps take some processor cycles before execution of function code begins, these steps are not required when using macros hence macros are faster.
Macro Vs Inline function.
Macros Inline Function Macros are processed at pre-processing time Inline functions are processed at compile time Macros are less readable compare to inline functions Usage of inline function makes code more readable and maintainable Debugging complex macros is a tough job Inline functions are easy to debug No type checking done for macro parameters which may result into undesirable output if macro is not used carefully. Compiler performs type checking for function arguments Using Macro guarantees that macro will be expanded whenever used in code and hence will be executed faster compare to normal function. Inline keyword is only request to complier to make function inline, using inline keyword doesn’t guarantee that function will be inline. If compiler does not accept request to make function inline it will behave as normal function and code within function body will not be executed as fast as macro because of overhead associated with function calling.
If you are to write a “for” loop, which approach would you prefer incrementing loop or decrementing loop? Why?
I would prefer writing decrementing “for” loop.
Incrementing “for” loop.
for (index=0; index <20; index ++)
Decrementing “for” loop.
for (index =20; index; index --)
In case of incrementing loop, processor has to compare value of index with 20 which is not an optimized operation for processor as 20 has to be loaded from ROM to processor register and compare with index. In case of decrementing loop, processor has to compare value of index with zero and that is an optimized operation as zero is stored in special function register of processor. For better understanding check assembly equivalent code of above C code.
Can a C function be called from assembly and vice versa?
YES, C code can be invoked from assembly and assembly from C.