Spread the love

Embedded interview questions

____________________________________________________________________________________________________

  

 Q. What is the need for an infinite loop in Embedded systems?

Answer : 

Embedded systems need infinite loops for repeatedly processing/monitoring the state of tasks of the program .

Q. Which way of writing infinite loops is more efficient?

Answer :

Actually, the best way is

for(;;)

as it does not depend on any constant to be infinite.

 Q. What is the function of DMA controller in embedded system?

Answer : 

DMA stands for Direct Memory Access controller as the name suggest it does not involve processor to transfer memory between two devices that handles the allocation of the memory dynamically to the components and allows the data to be transferred between the devices.

The interrupt can be used to complete the data transfer between the devices. It is used to give the high quality performance as, the input/output device can perform the operations that are in parallel with the code that are in execution.

Q. Difference between RISC and CISC processor.

Click here for exact Answer.

 Q. A vast majority of High Performance Embedded systems today use RISC architecture why?

Answer : 

According to the instruction sets used, computers are normally classified into RISC and CISC. RISC stands for ‘Reduced Instruction Set Computing’ .

  • The design philosophy of RISC architecture is such that only one instruction is performed on each machine cycle(the main reason of pipe-lining possible) thus taking very less time and speeding up when compared to their CISC counterparts.
  • Here, the use of registers is optimised as most of the memory access operations are limited to store and load operations.
  • Fewer and simple addressing modes, instruction formats leads to greater efficiency, optimisation of compilers, re-organisation of code for better throughput in terms of space and time complexities. All these features make it the choice of architecture in majority of the Embedded systems.

CISC again have their own advantages and they are preferred whenever the performance and compiler simplification are the issues to be taken care of.

Q. The following code uses __interrupt to define an interrupt service routine. Comment on the code.

Answer :

 

__interrupt double compute_area(double radius) 
{
     double area = PI * radius * radius;

     printf(“\nArea = %f”, area);

     return area;
}

This function has so much wrong with it, it’s almost tough to know where to start.

– Interrupt service routines cannot return a value.

– ISR’s cannot be passed parameters.

– A general rule of thumb is that ISRs should be short and sweet, one wonders about the wisdom of doing floating point math here.

Q. What is Endianness? Explain little endian & big endian How to decide whether given processor is using little endian format or big endian format ?

Answer : 

  • Endianness basically refers to the ordering of the bytes within words or larger bytes of data treated as a single entity.
  • When we consider a several bytes of data say for instance 4 bytes of data,XYZQ the lower byte if stored in a Higher address and others in successively decreasing addresses ,then it refers to the Big Endian and the vice versa of this refers to Little Endian architecture.
/* checking Endianness of system */
#include <stdio.h>
int main() 
{
   unsigned int i = 1;
   char *c = (char*)&i;
   if (*c)    
       printf("Little endian");
   else
       printf("Big endian");
   getchar();
   return 0;
}

                In the above program, a character pointer c is pointing to an integer i. Since size of character is 1 byte when the character pointer is de-referenced it will contain only first byte of integer. If machine is little endian then *c will be 1 (because last byte is stored first) and if machine is big endian then *c will be 0.

Q. What could be the reasons for a System to have gone blank and how would you Debug it?

Answer : 

Possible reasons could be,

  • PC being overheated.
  • Dust having being accumulated all around.
  • CPU fans not working properly .
  • Faulty power connections.
  • Faulty circuit board from where the power is being drawn.
  • Support Drivers not having being installed.

Debugging steps which can be taken are:

  • Cleaning the system thoroughly and maintaining it in a dust-free environment.
  • Environment that is cool enough and facilitates for easy passage of air should be ideal enough.
  • By locating the appropriate support drivers for the system in consideration and having them installed.

Q. Significance of watchdog timer in Embedded Systems & How to implement a WatchDog timer in software ?

Answer :

  • Watchdog timer is basically a timing device that is set for predefined time interval and some event should occur during that time interval else the device generates a time out signal.
/* WatchDog Timer example */
int main( ) 
{ 
        hwinit(); 

        for (;;) 
        { 
            init_WatchDog();            //Load timing value in timer at every time loop restart
            read_sensors(); 
            control_motor(); 
            display_status(); 
        } 
        return 0;
}

                       This will initialize watch dog timer on every completion of loop, if your code is stuck anywhere between infinite, then watchdog timeout occur and system will restart. But in this case we have to calculate the time taken to complete loop cycle and then set the ticks of watchdog timer.

Q. How does the interrupt architecture works?

Answer : 

Interrupt architecture allows the use of interrupt by the processor whenever an Input/output is need service.

The processor in this case calls a special function to handle the request that comes and leave all the work that is getting performed at that time. The special function that is known as interrupt handler or the interrupt service routine(ISR) consists of all the input, and output queries, or the interrupts handled by it. It uses only one function to deal with the interrupts.

Q. Using the #define statement, how would you declare a manifest constant that returns the number of seconds in a year? Disregard leap years in your answer

Answer :

#define SECONDS_PER_YEAR (60UL * 60UL * 24UL * 365UL)

Note :  UL (indicating to compiler that unsigned long)

Q. Write a macro that takes two arguments and returns the smaller of the two arguments.

Answer : 

#define MIN(A,B) ((A) <= (B) ? (A) : (B))

Q. How are macros different from inline functions?

Answer : 

  • We normally use the #define directive to define the values of some constants so in case a change is needed only the value can be changed and is reflected throughout.

                                                           #define mul(a,b) (a*b)

  • Inline functions are expanded whenever it is invoked rather than the control going to the place where the function is defined and avoids all the activities such as saving the return address when a jump is performed. Saves time in case of short codes.
inline float add(float a, float b)
{


       return a+b;
}

 

                           Inline is just a request to the compiler and it is upto to the compiler whether to substitute the code at the place of invocation or perform a jump based on its performance algorithms.

Q. Write a macro that take number and string as a argument and print them.

Answer : 

#include <stdio.h>

#define MACRO(num, str) ({\         //Use '\' to end the line in mulit-line macro
printf("number is %d", num);\
printf("\n%s ", str);\
printf("\n");\
})

int main(void)
{
     int num;
     MACRO(10,"www.firmcodes.com");
     return 0;
}

Q. What is size of character, integer, integer pointer, character pointer?

Answer : 

char = 1 byte, integer = 4 byte, integer pointer = 8 byte, character pointer = 8 byte.

Note : Size of the pointer,  normally 4 for 32-bit machine, and 8 for 64-bit machine. 

Q. Using the variable a, write down definitions for the following:

(a) An integer

(b) A pointer to an integer

(c) A pointer to a pointer to an integer

(d) An array of ten integers

(e) An array of ten pointers to integers

(f) A pointer to an array of ten integers

(g) A pointer to a function that takes an integer as an argument and returns an integer

(h) An array of ten pointers to functions that take an integer argument and return an integer.

Answer : 

(a) int a; // An integer

(b) int *a; // A pointer to an integer

(c) int **a; // A pointer to a pointer to an integer

(d) int a[10]; // An array of 10 integers

(e) int *a[10]; // An array of 10 pointers to integers

(f) int (*a)[10]; // A pointer to an array of 10 integers

(g) int (*a)(int); // A pointer to a function a that takes an integer argument and returns an integer

(h) int (*a[10])(int); // An array of 10 pointers to functions that take an integer argument and return an integer

Q. What are the uses of the keyword static?

Answer :

This simple question is rarely answered completely. Static has two distinct uses in C:

(a) A variable declared static within the body of a function maintains its value between function invocations.

(b) A variable declared static within a file, (but outside the body of a function) is accessible by all functions within that file. It is not accessible by functions within any other module. That is, it is a localized global.

Q. What does the keyword const & following incomplete declarations mean??

const int a;

int const a;

const int *a;

int * const a;

int const * a const;

Answer : 

Const means “read-only”. The first two mean the same thing, namely a is a const (read-only) integer. The third means a is a pointer to a const integer (i.e., the integer isn’t modifiable, but the pointer is). The fourth declares a to be a const pointer to an integer (i.e., the integer pointed to by a is modifiable, but the pointer is not). The final declaration declares a to be a const pointer to a const integer (i.e., neither the integer pointed to by a, nor the pointer itself may be modified).

Q. What does the keyword volatile mean? Give three different examples of its use.

A volatile variable is one that can change unexpectedly. Consequently, the compiler can make no assumptions about the value of the variable. In particular, the optimizer must be careful to reload the variable every time it is used instead of holding a copy in a register. Examples of volatile variables are:

(a) Hardware registers in peripherals (e.g., status registers)

(b) Non-stack variables referenced within an interrupt service routine.

(c) Variables shared by multiple tasks in a multi-threaded application.

Q. Can a parameter be both const and volatile? Explain your answer.

Answer :

Yes. An example is a read only status register. It is volatile because it can change unexpectedly. It is const because the program should not attempt to modify it.

Q. What is void pointer explain with example and why we use it ?

Answer : 

Its is also called generic pointer used to point an unspecified object.

 

int main()
{
     int i = 6;
     char c = 'a';
     void *generic;

     generic = &i;
     printf("generic points to the integer value %d\n", *(int*) generic); // need to do typecast

     generic = &c;
     printf("generic now points to the character %c\n", *(char*) generic); // need to do typecast

     return 0;
}

One common application of void pointers is creating functions which take any kind of pointer as an argument and perform some operation on the data which doesn’t depend on the data contained. The perfect example of void pointer is

 

void * memset ( void * ptr, int value, size_t num );

Q. What is function pointer ? explain it with practical example !

A function pointer is a variable which is used to hold the starting address of a functions and the same can be used to invoke a function. Function pointers do always point to a function having a specific type so, all functions used with the same function pointer must have the same parameters and return type.

#include <stdio.h>

// function prototypes
int add(int x, int y);
int subtract(int x, int y);
int domath(int (*mathop)(int, int), int x, int y);

// add x + y
int add(int x, int y) {
return x + y;
}

// subtract x - y
int subtract(int x, int y) {
return x - y;
}

// run the function pointer with inputs
int domath(int (*mathop)(int, int), int x, int y) {
return (*mathop)(x, y);
}

// calling from main
int main() {
// call math function with add
int a = domath(add, 10, 2);
printf("Add gives: %d\n", a);
// call math function with subtract
int b = domath(subtract, 10, 2);
printf("Subtract gives: %d\n", b);
}

 

Q. Swap the nibble of this single byte 0xAB ?

Answer :

 

/* Less Complex way */
x = ( (byte & 0x0F) << 4 ); // Lower nibble comes out & shifted left by nibble
y = ( (byte & 0xF0) >> 4 ); // Higher nibble comes out & shifted right by nibble

byte = x | y;

or
/* Efficient way */

byte = ( (byte & 0x0F) << 4) | ( (byte & 0xF0) >> 4 )

Q. Given an integer variable a, write two code fragments. The first should set bit 3 of a. The second should clear bit 3 of a. In both cases, the remaining bits should be unmodified.

Answer :

Use #defines and bit masks. This is a highly portable method, and is the one that should be used. My optimal solution to this problem would be:

/* Bit stuff */

#define BIT3 (1 << 3)

static int a;

void set_bit3(void) 
{
       a |= BIT3;
}

void clear_bit3(void) 
{
       a &= ~BIT3;
}

Q. Access specific address 0x67A9 and write the value 0xAA55. The compiler is a pure ANSI compiler. Write code to accomplish this task.

Answer :

 

int *ptr;

ptr = (int *)0x67A9;

*ptr = 0xAA55;

// A more obfuscated approach is:

*(int * const)(0x67A9) = 0xAA55;

Q. Count numbers of ‘1’ occur in an integer(binary representation).

Answer : 

while(n)
{
     count += n & 1;
     n >>= 1;
}
Printf("Count = %d\n",count);

Q. Define structure with bit field.

Answer : 

struct TIME
{
    int second: 6,
    minute: 5,
    hours:5;
};

Q. What will this return malloc ( sizeof(-10) ) ?

Answer : 

It will return a 4 byte address value.

Because -10 is a signed integer(varies from compiler to compiler).

Q. What does the following code fragment output and why?

 

char *ptr;

ptr = (char*)malloc(0) ;

if( ptr == NULL)
{
       printf("Got a null pointer");
}
else 
{
       printf("Got a valid pointer");
}

Answer:

You will got a valid pointer and malloc(0) is implementation defined correctly because malloc accept argument of type size_t. According to the 1999 ISO C standard (C99), size_t is an unsigned integer type of at least 16 bit.

Q. In the two following cases, two pointers to structure dPS and tPS  defined,  Which method (if any) is preferred and why?

#define dPS struct s *

typedef struct s * tPS;

Answer : 

The typedef is preferred. Consider the declarations:

dPS p1,p2;

tPS p3,p4;

The first expands to

struct s * p1, p2;

which defines p1 to be a pointer to the structure and p2 to be an actual structure, which is probably not what you wanted. The second example correctly defines p3 & p4 to be pointers.

Q. Is this construct legal, and if so what does this code do?

int a = 5, b = 7, c;

c = a+++b;

This is absolutely legal this code is treated as:

c = a++ + b;

Thus, after this code is executed, a = 6, b = 7 & c = 12;

 Q. Can we use printf( ) inside the ISR ?

Not effective, because printf( ) is not re-entrant function and its library code is about 1 Kb large which might slow execution or affect effectiveness of ISR. 

Q. Which of the following two code segments is faster?

/* FIRST */
for(i=0;i<10;i++)
for(j=0;j<100;j++)
//do somthing

/* SECOND */
for(i=0;i<100;i++)
for(j=0;j<10;j++)
//do something

 Answer :

At first sight both looks same, but SECOND does more operations than the FIRST. It executes all three parts (assignment, comparison and increment) of the for loop more times than the corresponding parts of FIRST. Here is the difference

  • The SECOND executes assignment(j=0 & i=0) of j & i combined 11 times while FIRST executes only 101 times.
  • The SECOND does 101 + 1100 comparisons (i < 100 or j < 10) while the FIRST does 11 + 1010 comparisons (i < 10 or j < 100).
  • The SECOND executes 1100 increment operations (i++ or j++) while the FIRST executes 1010 increment operation.

You can check it with this code

/* Checking which loops is execute more */
#include<iostream>
using namespace std;

int main()
{
    int count1 = 0, count2 = 0;

    /* FIRST */
    for(int i=0;i<10;i++,count1++)
    for(int j=0;j<100;j++, count1++);
    //do something

    /* SECOND */
    for(int i=0; i<100; i++, count2++)
    for(int j=0; j<10; j++, count2++);
    //do something

    cout << " Count in FIRST = " <<count1 << endl;
    cout << " Count in SECOND = " <<count2 << endl;
    getchar();
    return 0;
}

Q. What is the differnce between embedded systems and the system in which RTOS is running? 

Answer :

Embedded system can include RTOS and cannot include also. it depends on the requirement. if the system needs to serve only event sequencially, there is no need of RTOS. If the system demands the parallel execution of events then we need RTOS.

Q. If you buy some RTOS, what are the features you look for in ?

– Deterministic operating system having guaranteed worst-case interrupt latency and context-switch times.

– Documentation providing for the minimum, average, and maximum number of clock cycles required by each system call

– Interrupt response times should be very minute.

– Context switch time should be very low.

– Compatibility with several plugin devices.

– Overall it should be very reliable.

Q. What is interrupt latency ? How can you recuce it?

Answer :

Interrupt latency is the time required to return from the interrupt service routine after tackling a particular interrupt. We can reduce it by writing smaller ISR routines.

Q. What is priority inversion? and give its possible solutions.

Answer :

In scheduling, priority inversion is the scenario where a low priority task holds a shared resource that is required by a high priority task. This causes the execution of the high priority task to be blocked until the low priority task has released the resource, effectively “inverting” the relative priorities of the two tasks. If some other medium priority task, one that does not depend on the shared resource, attempts to run in the interim, it will take precedence over both the low priority task and the high priority task.

Two Priority Inversion solution

  • Priority Inheritance Protocol: when low priority process accesses the resource, boost its priority to be the same as the highest priority process which is waiting for the resource. This is not very practical because we need to track all processes which are waiting for semaphor at run time.
  • Priority Ceiling Protocol: when low priority process accesses the resource, boost its priority to a predefined level which must be higher than all processes which are possible to access the critical section. Therefore we don’t need to track what processes are waiting for resource at run time. The disadvantage is that we need to predefine the level before run time.

Q. What is priority inheritance?

Priority inversion problems are eliminated by using a method called priority inheritance. The process priority will be increased to the maximum priority of any process which waits for any resource which has a resource lock. This is the programming methodology of priority inheritance.

When one or more high priority jobs are blocked by a job, the original priority assignment is ignored and execution of critical section at the highest priority level of jobs it blocks is performed. The job returns to the original priority level soon after executing the critical section. This is the basic idea of priority inheritance protocol.

If you like this Article, then don’t forget to Click on Social likes buttons.