200 Embedded and IoT Software Engineering Interview Questions – Part 1

I remember the time I was actively looking for an embedded software engineer job as a fresher, I was looking for some good resources to test my skills, but I found only a very few useful ones and that too not directly related to embedded engineering jobs. I am writing this article to serve that purpose as a good resource to test yourself before you go for embedded engineering interviews.

Usually, any technical interview will have questions from these 3 categories

  1. Questions about yourself
  2. Questions about the projects you have done
  3. Questions to test your subject knowledge

I will only briefly touch upon the 1st  two question types as they are specific to each individual, then we will go on to see the about 200 questions you can expect that will test your subject knowledge along with answers and explanations. I will also divide the questions by both category and difficulty levels so that you can see where you stand in each particular category.

Okay, so let’s begin!

Questions about yourself

This category of questions is usually the same for any job and it will involve questions like

  • Tell me about yourself
  • Tell me about your educational background
  • What are your strengths and weaknesses etc,

These are covered by many sources all over the web, so we will not cover it here. If you need to prepare for these questions, I would suggest going to youtube or google and searching for top HR interview questions and you will find many relevant results.

Questions about the projects you have done

You can expect half the interview questions about the projects you have done. Since these days it is easy to do projects of high complexity just by taking code from online resources with no proper education, the interviewers would like to test your knowledge levels through these questions. Since each of you would have done a different project, I am going to take a simple example project of an IoT weather station just to give you an overview of what kind of interview questions you can expect from such a project.

Project: IoT Weather Station

Questions you can expect

  1. What microcontroller did you use?
  2. What architecture was this microcontroller based on?
  3. Can you explain the reason behind choosing this particular microcontroller?
  4. What sensors did you use in your project?
  5. How was the communication done between the micro-controller and the sensor?
  6. Did you use polling or interrupts to gather the data from the sensors?
  7. If polling then what was the frequency of polling?
  8. How did you output the data? 
  9. How did you connect your device to the internet?
  10. If wifi, then what bandwidth was used? 
  11. In what WiFi channel did your device transmit on?
  12. Did you check the throughput of your device?
  13. What protocol was used to send the data to the server?
  14. Was the device battery-powered or powered through a cable?
  15. What was the power consumption of the device?
  16. Can you explain the protocol on the server?
  17. Can you give us a demo?
  18. How was the LED code written?

These are just some possible questions you can expect to hear on the day of the interview. So make sure that you know the projects in your resume thoroughly!

Okay lets next get to the real focus of this article which is the subject knowledge type questions

Questions to test your subject knowledge

I have divided this article into 7 parts. On each part, I will cover one topic and on each topic, I will give questions on 3 difficulty levels: Easy, Medium and Hard.

The 7 topics that I am gonna be covering are listed below.

  1. C Programming Language
  2. Basics of Electronics
  3. Microcontroller and Peripherals
  4. Operating Systems
  5. Computer Networking
  6. Software Engineering and
  7. Debugging Skills

An embedded engineer is expected to have strong knowledge in these particular areas.

If you would like to do this as a test, then I suggest you stop reading this article and go to this ***link and give me your email, so that I can send you the questions in a pdf format. You can try giving the test and come back here for the answers so that you can score yourselves and identify which areas need more attention!

Alright, let’s go ahead and look at the questions in our first category of C Programming Language.

C Programming Language

Difficulty level: Easy

Question #1: Write a simple hello world program in C in this piece of paper/notepad/whiteboard

Answer #1: This question will test your command on C, to see if you can write a simple program without the help of an IDE with all the essential syntax and including all the necessary header files.

#include <stdio.h>

int main()
{
    printf("Hello World");
    return 0;
}

Question #2: Explain the use of pointers in C

Answer#2: Pointers are variables in C, used to store the address of another variable.

Also, it is important to note that an integer pointer can only point to an integer variable. In a more general sense, pointers of given types can only point to those particular types.

Pointers are widely used in embedded systems programming and you must know the answer to this one!

Question #3: What does a preprocessor do?

Answer #3: The preprocessor just replaces all #include statement with the entire header files

For example in the code for question number 1, the line #include <stdio.h>  is replaced using the stdio.h header file

The preprocessor also replaces all the macros defined using #define and replaces them using the actual values.

Let’s say we have the program 

#define X_VAL 154

void main()
{
	int x = X_VAL;
.
.
.
}

After preprocessing the code will look like

void main()
{
	int x = 154;
.
.
.
}

Question #4: Describe the function of  Compiler

Answer #4: Compiler takes a C source file as input and produces an object file as output.

In other words, it translates the C source code into binary op-codes that can be understood by a processor. It does this in 2 steps. First, it translates the C code into assembly language code, then it turns these assembly language codes into object code or machine code.

Question #5: Describe the function of  Assembler

Answer #5: Assembler translates assembly language into binary op-codes. 

This is a simple one-one conversion as each assembly language instruction has a specific opcode mapped to it.

Question #6: Describe the function of  Linkers

Answer #6: Linker combines several object files into one executable binary

It does its job by resolving the cross-references and by completing the symbol table. Thus the final output will know where in the combined executable binary each function is implemented and where each extern variable is declared.

Question #7: Describe the function of  Locator

Answer #7: Locator changes the relative offset addresses into actual addresses

The output produced by the Linker will have a relative addressing scheme. This needs to be transformed into absolute addresses before it can be loaded onto the microcontroller.

In other words, it basically takes the code produced by the linker as input and assigns addresses to the various sections like .bss .text and .data sections, so that the microcontroller will know where to keep these sections.

Question #8: Explain the difference between definition and declaration of a variable

Answer #8: Declaration allocates space for the variable in memory, definition initializes that space with a value

Eg,

int x; // declaration

x = 100; //definition

Question #9: Explain the use of bitwise operators in C with an example

Answer #9: There are 5 bitwise operators in C

  • Bitwise AND &
  • Bitwise OR |
  • Bitwise NOT ~
  • Left shift  <<
  • Right shift >>

Basically, these operators work on the binary version of integers and are very useful in setting/resetting bits in a control register in embedded systems.

Let’s see the use of some of these operators using an example. Let’s say you got a simple GPIO output register as shown below and you need to set pin number 3 to 1 without disturbing the other pins. 

GPIO Register

Then you can write to the pins as 

GPIO_OUT |= 0x08  

Now it will take the previous value of the register which is 0x52 and then changes the bit number 3 to 1 by doing a bitwise OR operation with 00001000 (0x08), hence just changing the bit 3 to 1 giving a final value of 0x5A as shown in the figure below.

Question #10: Explain the different scopes of variables available in C

Answer #10: In C variables can have 3 scopes. Based on their scopes, variables can be classified into the following 3 types

  • An extern variable is declared outside all functions and it can be accessed on all the files in a given C project. They are allocated space on the data segment of the RAM
  • Local variables, which are declared inside the functions can only be accessed within the function it is declared in. They are allocated space on the stack portion of the RAM. They are also known as automatic variables.
  • static is a special keyword in C which has 2 possible applications depending on where it is used
    • If a variable is declared outside of any functions and declared as static, then the scope of the variable is limited to the C file it is declared in. In other words only the functions inside a particular C file can access static external variables
    • If a variable is declared static inside a function then the scope of the variable is limited to the function itself. But the difference of static vs non-static local variable is that the static locals are allocated space on the data segment of the RAM (unlike on the stack as non-static locals) and they can hold their values through multiple function calls. 

Question #11: Explain the difference between a struct and a union in C

Answer #11: 

Considered this example below

struct customer {
 int phone_number;
 long account_balance;
};

struct customer Adam;
struct customer Nick;

Here a group of related data is stored together in a user-defined data-type called struct customer.

The struct is basically a complex user-defined data type used to store related data together.

On the other hand, Unions are declared mostly the same way, replacing the term struct with the term union as below. 

union union_type {
int a,
long b
};

union_type x, y;

Here even though there are 2 variables a and b, the amount of memory allocated will be only for only one (the largest of the members). So at any given time, a union can hold only sizeof(long). 

You can test this using the following example code

#include <stdio.h>
 
struct struct_type {
   int a;
   long b;
};
 
union union_type {
   int a;
   long b;
};
 
int main()
{
   printf("sizeof(int) = %d\n", sizeof(int));
   printf("sizeof(long) = %d\n", sizeof(long));
   printf("sizeof(struct_type) = %d\n", sizeof(struct_type));
   printf("sizeof(union_type) = %d\n", sizeof(union_type));
   return 0;
}
 
 
Output:
sizeof(int) = 4
sizeof(long) = 8
sizeof(struct_type) = 16
sizeof(union_type) = 8

Difficulty level: Medium

Question #1: Describe the several C standards

Answer #1: There are basically 5 standards of C throughout the years

  • K&R C
  • ANSI C
  • C99
  • C11 and
  • Embedded C

C language was developed by Dennis Ritchie between 1969 and 1973 at Bell Labs. Later in 1978 Brian Kernighan and Dennis Ritchie published a book on the language called The C Programming Language (link to Amazon) and that’s where K&R standard came from (Kernighan & Ritchie). Although it is an “Unofficial Standard” it is still considered to be the first-ever standard of C language. 

Later between 1978 and 1988, everybody started developing their own flavor of C since there was no official standard in place. Then came the ANSI C standard to standardize the language. 

ANSI stands for American National Standards Institute, who made a standard in 1988 as part of the POSIX standard. POSIX stands for Portable Operating System Interface, which is a standard by IEEE to make software that is compatible across various operating systems. It was later adopted by ISO in 1990. 

Later in 1999 some more keywords are added to the language like _Bool and _Complex to make the C99 standard. Then in 2011, the latest C standard came out with some more keywords like _Atomic, _Alignas and _Alignof

Embedded C was released in 2008, which included features to help program embedded systems. More on this in the next question’s answer.

You can read more about C standards in this article by Deepu Benson over at opensourceforu.com

Question #2: What is the difference between C and embedded C?

Answer #2:

Embedded C standard was a completely different breed from the other C standard, which focussed on the use of the C language in embedded systems. It was released back in 2008.  It included some features like fixed-point arithmetic to make the computing of decimal math easier, named address spaces to manage the memory better and basic I/O hardware addressing to make it easy to access the hardware.

Question #3: Explain the difference between compilers and interpreters

Answer #3:

They both help to translate code in a high-level language like C and C++ into machine language for execution by the CPU.

The main difference between them is the fact that compilers take in an entire file or project, then produces a machine language output which is then executed on a given machine. On the other hand, interpreters take in one line of code at a time, translates it, then executes it, then go for the next line in the code.

Question #4: Explain the use of volatile keyword in C

Answer #4: This keyword is mainly used in embedded C programming.

On all modern compilers, some optimization options are available, which takes in C source code, removes unused variables and give out a more memory-efficient code. 

But the problem with embedded code is the fact that not all variables will be changed by the code itself, as hardware registers, say like GPIO input registers can be changed by the external environment.

So say we have a code like this

int main()
{
   uint8_t x = GPIO_REG;
   while (1) {
       delay_ms(500);
       x = GPIO_REG;
       printf("x = %d\n", x);
   }
}

Here say we have a GPIO_REG register that we need to check every 500 milliseconds and print its value out. Here when optimizations are turned on, the compiler will think, why are we reading the value of x again and again as there is no explicit code to change the content of the GPIO register and it will hence remove the line 6 and produce a code like this.

int main()
{
   uint8_t x = GPIO_REG;
   while (1) {
       delay_ms(500);
       printf("x = %d\n", x);
   }
}

Here as you can see, the value of x printed will be the initial values of GPIO register and hence result in a code that does not do what we wanted it to do.

So in situations like these, we introduce a volatile keyword into our declaration like below.

int main()
{
   volatile uint8_t x = GPIO_REG;
   while (1) {
       delay_ms(500);
       x = GPIO_REG;
       printf("x = %d\n", x);
   }
}

Now even if the optimizations are turned on, the compiler will still keep line number 6, since we have used the volatile keyword in the declaration of x.

Hence volatile keywords are used to tell the compiler that the variable declared as volatile can change outside the code and hence don’t optimize it out.

Question #5: Explain stack overflow errors

Answer #5: If the stack size allocated is not enough to hold the local variables then the data is put into the memory region adjacent to the stack, hence corrupting the region and causing unexplained behaviors. I have written a separate article about it here

Question #6: Explain buffer overflow errors

Answer #6: It is very similar to stack overflow, where you write to an array past its end. But it is much more difficult to identify as instead of going into a runtime error, the program will happily write to the next memory location on the RAM, thus corrupting the data present there.

Question #7: Explain the use of void pointers in C

Answer #7: Void pointers are generic pointers that can be used to point to any data type. They need to be cast to a particular data type pointer before they can be dereferenced.

It is generally used by library functions that need to return a generic pointer. 

For example, see the use of void pointer in dynamic memory allocation below.

int * a = (int *)malloc (10* sizeof(int));

Here space for 10 integers is allocated on the memory and malloc returns a void pointer which is cast to an integer pointer type before being given to the variable a.

Question #8: Best practices to pass a struct as function arguments in C

Answer #8: 

Struct type variables are generally passed in as pointers instead of the entire structure. Passing in the entire structure, say has a size of 100 bytes would mean that it has to be stored on the stack and passed, this will mean that there is a lot of overhead to the function call as once the function returns, all the 100 bytes have to be popped out of the stack again. 

Also, this can cause stack overflow errors if the stack is not big enough.

Question #9: What standard library function should be used if you want to search for a keyword inside a given string?

Answer #9: strstr(input_string, keyword);

For example

#include<string.h>
 
void main()
{
   char * input_string = "Hello from Embedded Inventors!";
   char * keyword = "Embedded";
   char * keyword_pointer = strstr(input_string, keyword); // returns the pointer to the letter E in Embedded
}

If the string is not found a NULL pointer is returned.

Question #10: Explain the use of register keyword.

Answer #10: The register keyword is used to tell the compiler that a particular local variable needs to be allocated on a CPU register instead of the stack.  This is used if a given variable is going to be used very frequently, so allocating them space on the CPU register can speed up the operation of the code. But the compiler can choose to ignore this and just allot space for it on the stack as normal local/automatic variables.

Question #11: Explain the parts of a typical toolchain used to make a C binary for an embedded system 

Answer #11: A typical toolchain can consist of the following parts

  • Text editor to write the programs
  • Preprocessor, 
  • Compiler, 
  • Assembler, 
  • Linker 
  • Locator 

The final binary produced out of the Locator block is then downloaded onto the target embedded device and ran.

Difficulty level: Hard

Question #1:  Explain the use of function pointers in C

Answer #1: The main use is to implement callback mechanisms. This is common in library functions that give the user some control over some of the functionality.

A famous example is the library function qsort, which uses a function written by the end-user for comparing the variables passed in.

Question #2: What is the size of int variables?

Answer #2: The language standard says that the size of an integer variable must be 2 to 4 bytes. Whether it is 2 or 4 bytes depend on the compiler and the microprocessor. 

Earlier when 8-bit and 16-bit processors were prevalent, the size was given to be 2 bytes or 16bits. But nowadays after the advent of 32bit and 64bit architectures, int variables usually occupies 4 bytes or 32bits. 

The best way to determine it is by using the sizeof() standard library function. 

Question #3: Explain the places to use dynamic memory allocation in embedded programming

Answer #3: dynamic memory allocation is used when dealing with data of unknown size at compile time. These typically involve run-time inputs to determine the data size. 

On embedded systems, user inputs are usually limited to turning on and off the device and changing modes and the data inputs to the system are predictable to some reliable degree and hence it’s considered it’s good practice to allocate enough memory during compile time itself, thereby preventing the use of dynamic memory allocation.

The reasons behind this practice include the following

  • Dynamic memory allocation can fail if there is no memory, and this can affect the functionality of the system
  • Embedded systems typically execute the same loop over and over again and it is pointless to allocate and free memory all the time during these loops as this will make the system unnecessarily slow and so it’s better to have a large enough buffer to hold the data under consideration
  • The main use of dynamic memory is the reuse of space on the RAM, that is if suddenly more memory is needed at some point in the execution code, it can allocate space, use it then free it and this space can be reused in some other portion of the code. But as we said embedded systems have predictable behavior so it’s better to use large enough buffers than to use dynamic memory
  • If the code is not implemented properly, dynamic memory allocation can cause memory leaks.

For more information, you can refer to this link

Question #4: What standard library function would you use to copy 10 bytes from one location in memory to another?

Answer #4: The library function to use is memcpy which belongs to string.h

void * memcpy(void * dest, void * src, size_t num_bytes_to_copy) 

dest – pointer containing the destination address

src – pointer containing the source address

num_bytes_to_cpy – number of bytes to be copied from the source address to the destination address

Return value: pointer to the destination address on either success or failure, so no need to check the return value

Question #5: What standard library function would you use to set 20 bytes in memory starting from an Address A, to a particular value V?

Answer #5: The library function to use is memset which also belongs to string.h

void *memset(void *addr, int val, size_t num_bytes) 

addr − is the pointer containing the starting address.

val − The value to be set

num_bytes − Number of bytes to be set

Return value: The function returns the pointer to the starting address addr on either success or failure hence it is best to ignore this return value.

Question #6: Give the output of this code snippet and explain

int a[] = {1, 2, 3, 4};
printf (“%d\n”, *a);
printf(“%d\n”, *(a+3));

Answer #6:

1

4

Explanation:

a  is a constant pointer to the first element of the array. *a dereferences this and hence the first line of the output is the first element of the array

a+3 points to a[3] which is 4 and hence the second line of the output is 4

Question #7: Give the output of the following code snippet

int x = 0x08;
int y = 0xF1;
int z = x | y;
printf("0x%x\n", z);
z = x &amp; y;
printf("0x%x\n", z);

Answer #7: 

0xf9

0x0

Explanation:

| is bitwise OR operator

0x08 is 00001000

0xF1 is 11110001

Doing bitwise OR we get 11111001 which is 0xf9

 & is bitwise AND operator 

Doing bitwise AND between 0x08 and 0xF1 we get 00000000 which is 0x0

Question #8: Give the output of the following code

int z = 2 * 3 > 2 % 2;
printf(“%d\n”, z);

Answer #8: 

1

Explanation:

Here according to operator precedence * sign takes the first priority and the equation becomes

z = 6 > 2 % 2

Next, the % operator takes precedence over > operation and it becomes

z = 6 > 0

Since the above equation is true it becomes 

z = 1

And hence the output is 1.

Question #9: Give the output of the following program.

int i = 2;
printf(“%d\n”, i++);
printf (“%d\n”, ++i);

Answer #9:

2

4

Explanation:

i++ is post increment so the value of i is incremented after the first printf statement is executed.

So once the first 2 statements are executed the value of i becomes 2. 

In the second printf statement, ++i is pre-increment, so the value of i becomes 3 and then the printf is executed and hence the output.

Question #10:  Given an integer, how to divide it by a number which is a power of 2 (2, 4, 8, 16, …)  in the most efficient manner.

Answer #10: 

Using bitwise right shift operator

Example 

18 >> 1 is 9

16 >> 2 is 4

Here shifting one bit gives the same result as dividing by 2. 

Similarly, the left shift operator can be used to do multiplications with powers of 2!

Alright, that’s Part 1 of this series done!

In the next part, let’s look at some interview questions on the Basics of electronics!

Hope this article was of some value to you and helped you test your C skills!

You can email us or contact us through this link if you have any questions or suggestions.

If you liked the post, feel free to share this post with your friends and colleagues!

I will see you guys in the next part!

EI

We’re passionate about inventing embedded devices and we hope you are too! This blog deals with a wide variety of topics from C programming to IOT to networking certifications and more. Hope you enjoy your time spent here and hope you get some value out of our blog!

You may also like...