Register for our webinar

How to Nail your next Technical Interview

1 hour
Loading...
1
Enter details
2
Select webinar slot
*Invalid Name
*Invalid Name
By sharing your contact details, you agree to our privacy policy.
Step 1
Step 2
Congratulations!
You have registered for our webinar
check-mark
Oops! Something went wrong while submitting the form.
1
Enter details
2
Select webinar slot
*All webinar slots are in the Asia/Kolkata timezone
Step 1
Step 2
check-mark
Confirmed
You are scheduled with Interview Kickstart.
Redirecting...
Oops! Something went wrong while submitting the form.
close-icon
Iks white logo

You may be missing out on a 66.5% salary hike*

Nick Camilleri

Head of Career Skills Development & Coaching
*Based on past data of successful IK students
Iks white logo
Help us know you better!

How many years of coding experience do you have?

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
Iks white logo

FREE course on 'Sorting Algorithms' by Omkar Deshpande (Stanford PhD, Head of Curriculum, IK)

Thank you! Please check your inbox for the course details.
Oops! Something went wrong while submitting the form.

Help us with your details

Oops! Something went wrong while submitting the form.
close-icon
Our June 2021 cohorts are filling up quickly. Join our free webinar to Uplevel your career
close
blog-hero-image

Top Embedded Software Engineer Interview Questions You Should Learn

by Interview Kickstart Team in Interview Questions
May 30, 2024
Get trained by FAANG Embedded SWEs and nail your next interview!

Top Embedded Software Engineer Interview Questions You Should Learn

Last updated by Vartika Rai on May 30, 2024 at 05:47 PM | Reading time: 24 minutes

You can download a PDF version of  
Download PDF

While there are many different types of software engineer positions, the job responsibilities and interview questions are generally consistent across the field.

If you're interviewing for a position as an embedded software engineer, expect to be asked about your experience with microcontrollers, firmware development, and real-time operating systems.

You'll also likely be asked questions about your problem-solving skills and how you would handle certain development scenarios. The best way to prepare for a FAANG software engineer interview is to upskill and become the kind of embedded software engineer leading tech companies would love to hire.

By preparing for these embedded software engineer interview questions in advance, you can ensure that you're ready to answer any question thrown your way.

If you are preparing for a tech interview, check out our technical interview checklist, interview questions page, and salary negotiation e-book to get interview-ready!

Having trained over 13,500 software engineers, we know what it takes to crack the most challenging tech interviews. Our alums consistently land offers from FAANG+ companies. The highest-ever offer received by an IK alum is a whopping $1.267 Million!

At IK, you get the unique opportunity to learn from expert instructors who are hiring managers and tech leads at Google, Facebook, Apple, and other top Silicon Valley tech companies.

Want to nail your next tech interview? Sign up for our FREE Webinar.

In this article, we’ll cover:

  1. What Interviewers Look for in an Embedded Software Engineer
  2. Technical Embedded Software Engineer Interview Questions and Answers
  3. Behavioral Embedded Software Engineer Interview Questions
  4. Google Embedded Software Engineer Interview Questions
  5. FAQs on Embedded Software Engineer Interviews

What Interviewers Look for in an Embedded Software Engineer

If you're an experienced embedded software engineer, you know that interviews can be nerve-wracking. You want to make sure that you impress your interviewer and demonstrate your skill set. But what exactly are they looking for?

Embedded software engineer interview questions will depend on what the interviewer is looking for based on the role and company requirements. Interviewers will primarily try to uncover if you have the required skills to function as an embedded software engineer. Additionally, they will assess your skill level and whether you are a good cultural fit for the company.

Role of an Embedded Software Engineer

An embedded software engineer develops code optimized for an embedded system to manage a hardware device. For example, embedded software engineers are responsible for the development and maintenance of software that is embedded in devices such as pacemakers, cars, and thermostats.

Embedded software is developed and used for a particular hardware system or platform, keeping end-user needs in mind. Because this software controls critical functions, embedded software engineers must have a strong understanding of both hardware and software design principles. They must also be able to write code that is both efficient and reliable. The role of an embedded software engineer is challenging but also very rewarding.

Learn more about the roles and responsibilities of an Embedded systems engineer here.

Skill Needed to Become an Embedded Software Engineer

Embedded software engineer interview questions will be largely based on embedded software engineering skills. Here are some key skills requirements:

  • Programming language expertise: C, C++, C#, Python
  • Assembly Programming Language
  • Real-time Operating Systems (RTOS)
  • MATLAB
  • ARM
  • Software and Hardware programming at a low level
  • Tensorflow, Linux, RISC-V, Zephyr; other open source technologies
  • System of Chip (SoC) level software optimization - how to optimize memory, performance, and power
  • Microcontrollers, latest MCUs, and Microprocessors
  • System-level designing and software development
  • Communication Protocols: SPI (Serial Peripheral Interface), 12C, GPIO (General Purpose Input Output), USB, Controller Area Network (CAN)
  • Device Drivers
  • Debugging
  • Interrupt-driven design
  • IoT technologies
  • Data Structures
  • Project Management and trouble-shooting
  • Creativity, problem-solving, and analytical thinking

Embedded software engineer interview questions will be devised to discover your expertise in one or more key skills. Interviewers will also look for knowledge of both hardware and software design and embedded systems. You can take an in-depth look into the skills required to become an Embedded systems engineer.

Embedded systems are being adopted at an increasing rate in various industries. As such, embedded software technologies are ever-evolving. Ensure you stay updated on the latest skills and developments in this field to gain a competitive edge.

Take a look at some Embedded Software Engineer Interview Prep Tips here.

Technical Embedded Software Engineer Interview Questions and Answers

Technical interview questions for embedded software engineers will vary depending on the role and the interviewer. Some common questions are as follows:

Q1. What is an embedded system?

An embedded system is a computer system with hardware and software components designed to serve a dedicated function. For example, a smoke detector (fire alarm) can be considered an embedded system. It is made of hardware (sensors, speaker, etc.) and software that starts the alarm when the smoke is detected via sensors.

An embedded system could be designed to work as an independent system or as part of a large system. The smoke detector could be an example of an independent system. We can find several embedded systems in consumer electronics, automobiles, smart watches, household appliances, industrial equipment, and medical equipment.

Let’s understand the basic structure of an embedded system using a fire alarm:

  • Sensor: The sensors (heat, smoke, or carbon monoxide sensors) measure and convert the physical quantity to an electrical signal.
  • A-D Converter: To convert the analog signal sent by the sensor into a digital signal.
  • Processor & ASICs: Processor and other ASICs run the instructions programmed to the fire alarm and process the sensor data by checking the values with the reference/threshold value to produce a suitable output (or no output).
  • D-A Converter: To change the digital data fed by the processor to an analog signal. The actuators often require analog signals.
  • Actuator: As directed by the output data from the processor, the actuator produces a physical signal, such as setting off the alarm, blinking LEDs, etc.

The basic structure of an embedded system using a fire alarm

Q2. What is a spinlock?

Spinlock is a synchronization mechanism used to access shared resources orderly by locking resources for a short amount. At the same time, other consumers wait in a spin (loop) until the shared resource is released/unlocked. For example, two threads named Thread-A and Thread-B would like to access a common resource named Resource-X.  

Let's say Thread-A requests spinlock to access a Resource-X:

If Thread-B is using Resource-X, Thread-A will be waiting in a loop until Thread-B releases/unlocks Resource-X.

If any thread does not use Resource-X, Thread-A will be allowed to acquire the spinlock, and all other threads will wait until Thread-A releases the lock.

A spinlock is a lock that causes a thread trying to acquire it to simply wait in a loop ("spin") while repeatedly checking whether the lock is available.

Because the thread is not performing any task despite being active, the use of this lock puts the thread in a busy waiting state. Spinlock held until explicitly released. However, in some implementations, spinlocks may be automatically released if the thread being waited on “goes to sleep” or blocks. Spinlock is useful in a multiprocessor system.

Q3. What do we mean by virtual memory?

Virtual memory is a memory addressing scheme that offers the illusion of having one large continuous addressing space for an application. Physically, the main memory can be smaller than the virtual memory address. Some virtual memory addresses physically correspond to the main memory, and other addresses physically correspond to the secondary memory.

There will be address translator implementation for the application to utilize one large contiguous address space. The address translation introduces an uncertain delay in the memory response. As a result, many embedded system microcontrollers do not implement virtual memory.

Virtual memory allows users to load multiple bigger-size processors than in the main memory. Now the operating system does not load complete processes into the memory; rather, it loads the different relevant parts of multiple processors into the main memory. Thus effectively using the memory and also increasing the CPU utilization between processes. The size of the virtual memory is determined by the addressing scheme of the given CPU instruction architecture and not by the size of the main memory.

Virtual memory is implemented using both software as well as hardware. It maps memory addresses that a program uses, known as virtual addresses, to physical addresses in the computer's memory. All of a process's memory references are virtual or logical addresses. These logical addresses are then dynamically translated to physical addresses during run time.

Q4. What is your approach for debugging any issue in an embedded system?

Debugging techniques are very specific to the issue and the system. However, the following is a generic step-by-step approach that can be applied to most embedded systems.

1. Understand the system

Understanding the system is always a good idea as it helps a lot in narrowing down the issue. You can start by asking a few basic questions, such as:

  • What is the input to the system?
  • What is the hardware underneath?
  • What is the expected behavior from the system?
  • What are the different states of the system (at a very high level)?

Debugging any issue in an embedded system

Questions such as these can save a lot of time at various stages during debugging.

2. Reproduce the issue

Once you have a basic understanding of the system, you should try reproducing the issue. Hopefully, it is an issue that can be easily reproduced. If you can do these first two steps properly, finding the issue or debugging it becomes much easier.

3. Add instrumentation/logging

Once you can reduce the issue, the next step is to see if it's easy or hard to reproduce the issue. If it's an easy-to-reproduce issue, then you don't worry too much about what are certain scenarios during which you can reproduce the issue. But if it is hard to reproduce the issue, then sometimes just seeing when the issue reproduces usually gives you a clue.

In either of these cases, it is essential to add logging, some debug information, or add instrumentation (Oscilloscope, Signal Generator, Multimeter, etc.), depending on your system.

Now, tracking through the sequences of steps becomes much easier until the issue is reproduced.

In some systems, it's possible that you don't even have access to the signals. In such scenarios, you can try to look through the crash logs. You can then analyze the signals from the instruments or logs for a better understanding of the issue.

4. Isolate the bug/system

After finding where the issue is coming from, you can try to isolate the system (sub-system). You can then use divide-and-conquer techniques such as binary search to figure out the point where the bug is getting introduced.

5. Apply quick fixes

With all the information you gathered, try to form some hypotheses:

  • This is the bug
  • This is the module (sub-system) or line of code the bug is coming from
  • Under these conditions; I can reproduce the issue (these conditions are causing the issue)

So now you can try applying quick fixes to counter the bug and iteratively see if the issue is reproducing again with the conditions identified earlier. If everything is working correctly, you can commit the changes and consider the bug fixed.

Q5. Describe the role of the watchdog timer.

Many microcontrollers have the watchdog timer feature (usually implemented with specific dedicated hardware). It can be used to check if the software running on the microcontroller is hung. Microcontrollers are designed to be stable and durable.

However, there are still many issues that can affect the stability of the hardware. An unhandled combination of software-side events may also occur. Both can cause microcontrollers to get "stuck or hang" either electrically or in an infinite loop in software.

A watchdog timer is a subsystem that must explicitly notify software that everything is running as expected at a certain time. If the watchdog is not receiving the expected notification, it will take some action, such as resetting the microcontroller or even the entire device. This is usually done periodically, and the watchdog timer will take action if it does not receive a notification after a configurable amount of time since the last notification.

Q6. What is a livelock, and how is it different from a deadlock?

First, let’s understand what a deadlock is. In a deadlock, you have two or more concurrent processes waiting for a resource, and one of the processes may be holding the resource. Assuming it's a unitary resource, one process is holding one resource, and the other is holding another resource, so they are both waiting for the other to release the resources while not letting the resources go from themself.

So, basically, in a deadlock, we have a ‘hold and wait’ type of situation between the two processes. Both processes are doing this; therefore, they are in an embrace in which neither will let go so that the wait will be forever - this is what we define as a deadlock situation.

A live lock is the opposite of that. Instead of waiting, the processes try to get a resource, but the process is courteous, so it differs from taking the resource. These processes are not waiting and are running parallel. It means you check if any other process is active, and you assume it will also ask for the same resource, so you differ and back off from using (getting hold of) the resources. So when two processes differ from using the resources out of courtesy that the other process may need, it puts them in a livelock situation.

The loop here is that both processes keep checking for other activity and backing off. Now because they are concurrent, this thing can go on for a long time. None of the threads makes any progress which means they are locked.

To summarize, a deadlock is you're holding and waiting for the resources. But in a livelock, you differ forever from the resource, assuming some other active process will need it.

We can imagine a real-life example of livelock is when two people meet in a narrow hallway, and each of them tries to be polite by moving aside to let the other person pass. Still, they end up swaying from side to side without actually passing the hallway as they repeatedly move the same way at the same time.

To learn more about livelocks, check out our tutorial:

Q7. What are the causes of the interrupt legacy?

The first delay is usually caused by hardware: the interrupt request signal must be synchronous with the CPU clock. Depending on the synchronization logic, up to 3 CPU cycles may elapse before an interrupt request reaches the CPU core.

The CPU usually completes the current instruction, which may take several cycles. On most systems, the time-consuming instructions to get executed are divide, push-multiple, or memory-copy. In addition to the cycles required by the CPU, additional cycles are often required for memory accesses. On an ARM7 system, the STMDB SP!,{R0-R11, LR} instruction is typically a worst-case instruction consisting of 13 32-bit registers and takes 15 clock cycles.

The memory system might require additional cycles for wait states.

Upon completion of the current instruction, the CPU performs a mode switch or pushes registers on the stack. Modern processors such as ARM generally perform mode switching, which takes fewer CPU cycles than saving registers.

Pipeline fill: Most modern CPUs are pipelined. Instruction execution occurs at different stages of the pipeline. The instruction is executed when it reaches its final stage of the pipeline. Since the mode switch has flushed the pipeline, several more cycles are required to refill the pipeline.

Q8. What are static memory allocation and dynamic memory allocation?

Memory Allocation: Memory allocation is the process by which physical or virtual memory space is allocated to computer programs and services. It is done either before or during program execution. There are two types of memory allocation:

  • Static Memory Allocation: Static allocation means that the object is declared with a static storage class or has an external or internal reference. It is initialized only once before the program starts, and its lifetime is for the duration of the program's execution. An example of static memory allocation is a global and static variable.
  • Dynamic Memory Allocation: In C, many library functions, such as malloc, calloc or realloc, etc., are used for dynamic memory allocation. One problem with dynamically allocated memory is that the compiler doesn't destroy it itself; the user is responsible for freeing the allocated memory.

These memory management functions return a pointer to the allocated memory block, and the returned pointer points to the starting address of the allocated memory block. If no space is available, a null pointer is returned.

Here are some sample technical embedded software engineer questions that you can practice:

  1. Explain inline functions
  2. Explain buses in communication
  3. Explain the troubleshooting process for embedded targets
  4. Differentiate between component-based design and object-oriented design
  5. Differentiate between mutexes and semaphores
  6. Name some code testing tools
  7. Name some of the latest technologies
  8. How would you reduce interrupt latency?
  9. What are model transformations?
  10. Why would you need DMAC in ES?
  11. Would you debug ISR using breakpoints?
  12. Why do segmentation fault errors occur?
  13. Write a program using the power-save super loop.
  14. Which software configuration tools are you aware of?

C, C++, Embedded C Software Engineer Interview Questions

In your embedded software engineer interview, you can be asked specific questions on C, C++, and Embedded C, such as:

Q1. What are the type qualifiers in C Programming?

It is a keyword applied to a data type, resulting in a qualified type. For example, const int is a qualified type representing a constant integer, whereas const is a type qualifier to specify that the value will not be changed. The following code declares a constant integer x and sets its value to 10. Now, if we attempt to change x’s value, the compiler will throw an error.  

Similarly, a volatile int is a qualified type representing a volatile integer, meaning its value can change by any external device or hardware. The following code declares a volatile integer y and set’s its initial value to 0, which can be modified.

As of 2014 and C11, there are the following four type-qualifiers in standard C:

  • const (C89): The const keyword is compiler-enforced and says that the program cannot change the object’s value, making the object a nonmodifiable type.
  • volatile (C89): A variable with a volatile-qualified type may be modified in ways the implementation is unaware of, or it may have other unanticipated side effects. The volatile keyword indicates that a value may change between different accesses, even if it does not appear to be modified.
  • restrict (C99): This type of qualifier can be used in pointer declarations. By adding this type of qualifier, a programmer hints to the compiler that for the lifetime of the pointer, no other pointer will be used to access the object to which it points.
  • _Atomic (C11):  The latter has a private name to avoid clashing with user-defined names. _Atomic is used to avoid the race condition if more than one thread attempts to update a variable simultaneously.

Q2. What is the difference between a null pointer and a void pointer?

A null pointer is essentially a null value assigned to a pointer of any data type, while a null pointer is a data type that remains void until it is assigned a data type address.

The data type of a pointer is stored in the memory location to which the pointer points. If you are unsure of the type of data stored in a particular memory location, you must create a void pointer.

A null pointer does not contain a reference to any variable/value; it is NULL, making it a null pointer.

a void pointer is always of type void *

These pointers are mainly used for dynamic memory allocation using the malloc(), calloc(), and realloc() functions. Here, the reserved memory block is a pointer to an empty pointer, and when the pointer value is returned, it must be explicitly cast to the specific type required.

Q3. Explain the use of ‘volatile’ in Embedded C.

A volatile keyword is a type qualifier in C applied to a variable when declared. It tells the compiler the variable may be modified in ways unknown to the implementation or have other unknown side effects. As a result, the compiler cannot make any assumptions about the variable's value. The optimizer must reload the variable every time it reads the value rather than keeping a copy in a register.

Let's take a look at the syntax:

To declare a variable as volatile, you must put the volatile keyword before or after the data type while defining the variable. Look at the following two variable declarations for a volatile unsigned 8-bit integer variable:

Now, it turns out that pointers to volatile variables are pretty common,

You can also declare a pointer to a volatile variable. The following declarations declare v_pot to be a pointer to a volatile unsigned 8-bit integer:

However, using a volatile pointer to non-volatile data is very rare; the following is the syntax for reference:

If you really must have a volatile pointer to a volatile variable, the following is the syntax for your reference:

Q4. Why do we need infinite loops in embedded programming, and how do we code an infinite loop in Embedded C?

As the name suggests, infinite loops repeat indefinitely and never terminate as long as the program is alive. In most other types of programming, infinite loops are created by mistake and don’t have many use cases. However, this is not the case with embedded programming.

Embedded systems are intended to run forever and serve a given task repeatedly. If the embedded system suddenly exits, it means it no longer serves the task it is designed for. If the embedded system completes a given task, it should go into a sleep mood instead of exiting altogether because the next time the task is needed, it should be able to wake up and resume the task.

This infinite loop contains the main instruction the embedded system should execute. You can take the Arduino program template, for example:

Now, let’s see how we create infinite loops in Embedded C.

The following is the definition of the infinite for loop. Here we don’t mention any of the parameters for initialization, condition, or increment/decrement for the loop.

Now, we'll look at how to use a while loop to create an infinite loop. The infinite while loop is defined as shown below. Here we hard code the while condition to true.

The do-while loop can also be used to create the infinite loop. The following is the syntax to create the infinite do-while loop. Here again, we hard code the while condition to true.

Q5. What do sizeof(int) return on 32-bit and 64-bit machines?

According to the C-spec, an integer only needs to be able to represent this (-32767,32767) range of numbers. Essentially the C-spec only says that an integer has to be 16 bits or larger. But in practice, sizeof(int) will return you 4 bytes on both 32-bit and 64-bit machines.

In other words, The C standard only specifies a minimum range for integer types guaranteed to be supported. An int is guaranteed to be able to hold (-32767,32767), which requires 16 bits (2 bytes). However, implementations can go beyond that minimum, as we see that many modern compilers make int 32-bit, i.e., 4 bytes.

However, a long int might have a different size on a 32-bit or 64-bit machine. It is also possible that a long int might be different on Windows versus Linux machines. But on the other hand, long long int is consistently 64 bits but could be implemented as more.

To learn more about it, watch our tutorial:

These are some sample C, C++, and Embedded C software engineer questions that you can practice:

  1. How many storage classes are there in C?
  2. How do you write Function Itoa()


Author
Vartika Rai
Product Manager at Interview Kickstart | Ex-Microsoft | IIIT Hyderabad | ML/Data Science Enthusiast. Working with industry experts to help working professionals successfully prepare and ace interviews at FAANG+ and top tech companies
The fast well prepared banner

While there are many different types of software engineer positions, the job responsibilities and interview questions are generally consistent across the field.

If you're interviewing for a position as an embedded software engineer, expect to be asked about your experience with microcontrollers, firmware development, and real-time operating systems.

You'll also likely be asked questions about your problem-solving skills and how you would handle certain development scenarios. The best way to prepare for a FAANG software engineer interview is to upskill and become the kind of embedded software engineer leading tech companies would love to hire.

By preparing for these embedded software engineer interview questions in advance, you can ensure that you're ready to answer any question thrown your way.

If you are preparing for a tech interview, check out our technical interview checklist, interview questions page, and salary negotiation e-book to get interview-ready!

Having trained over 13,500 software engineers, we know what it takes to crack the most challenging tech interviews. Our alums consistently land offers from FAANG+ companies. The highest-ever offer received by an IK alum is a whopping $1.267 Million!

At IK, you get the unique opportunity to learn from expert instructors who are hiring managers and tech leads at Google, Facebook, Apple, and other top Silicon Valley tech companies.

Want to nail your next tech interview? Sign up for our FREE Webinar.

In this article, we’ll cover:

  1. What Interviewers Look for in an Embedded Software Engineer
  2. Technical Embedded Software Engineer Interview Questions and Answers
  3. Behavioral Embedded Software Engineer Interview Questions
  4. Google Embedded Software Engineer Interview Questions
  5. FAQs on Embedded Software Engineer Interviews

What Interviewers Look for in an Embedded Software Engineer

If you're an experienced embedded software engineer, you know that interviews can be nerve-wracking. You want to make sure that you impress your interviewer and demonstrate your skill set. But what exactly are they looking for?

Embedded software engineer interview questions will depend on what the interviewer is looking for based on the role and company requirements. Interviewers will primarily try to uncover if you have the required skills to function as an embedded software engineer. Additionally, they will assess your skill level and whether you are a good cultural fit for the company.

Role of an Embedded Software Engineer

An embedded software engineer develops code optimized for an embedded system to manage a hardware device. For example, embedded software engineers are responsible for the development and maintenance of software that is embedded in devices such as pacemakers, cars, and thermostats.

Embedded software is developed and used for a particular hardware system or platform, keeping end-user needs in mind. Because this software controls critical functions, embedded software engineers must have a strong understanding of both hardware and software design principles. They must also be able to write code that is both efficient and reliable. The role of an embedded software engineer is challenging but also very rewarding.

Learn more about the roles and responsibilities of an Embedded systems engineer here.

Skill Needed to Become an Embedded Software Engineer

Embedded software engineer interview questions will be largely based on embedded software engineering skills. Here are some key skills requirements:

  • Programming language expertise: C, C++, C#, Python
  • Assembly Programming Language
  • Real-time Operating Systems (RTOS)
  • MATLAB
  • ARM
  • Software and Hardware programming at a low level
  • Tensorflow, Linux, RISC-V, Zephyr; other open source technologies
  • System of Chip (SoC) level software optimization - how to optimize memory, performance, and power
  • Microcontrollers, latest MCUs, and Microprocessors
  • System-level designing and software development
  • Communication Protocols: SPI (Serial Peripheral Interface), 12C, GPIO (General Purpose Input Output), USB, Controller Area Network (CAN)
  • Device Drivers
  • Debugging
  • Interrupt-driven design
  • IoT technologies
  • Data Structures
  • Project Management and trouble-shooting
  • Creativity, problem-solving, and analytical thinking

Embedded software engineer interview questions will be devised to discover your expertise in one or more key skills. Interviewers will also look for knowledge of both hardware and software design and embedded systems. You can take an in-depth look into the skills required to become an Embedded systems engineer.

Embedded systems are being adopted at an increasing rate in various industries. As such, embedded software technologies are ever-evolving. Ensure you stay updated on the latest skills and developments in this field to gain a competitive edge.

Take a look at some Embedded Software Engineer Interview Prep Tips here.

Technical Embedded Software Engineer Interview Questions and Answers

Technical interview questions for embedded software engineers will vary depending on the role and the interviewer. Some common questions are as follows:

Q1. What is an embedded system?

An embedded system is a computer system with hardware and software components designed to serve a dedicated function. For example, a smoke detector (fire alarm) can be considered an embedded system. It is made of hardware (sensors, speaker, etc.) and software that starts the alarm when the smoke is detected via sensors.

An embedded system could be designed to work as an independent system or as part of a large system. The smoke detector could be an example of an independent system. We can find several embedded systems in consumer electronics, automobiles, smart watches, household appliances, industrial equipment, and medical equipment.

Let’s understand the basic structure of an embedded system using a fire alarm:

  • Sensor: The sensors (heat, smoke, or carbon monoxide sensors) measure and convert the physical quantity to an electrical signal.
  • A-D Converter: To convert the analog signal sent by the sensor into a digital signal.
  • Processor & ASICs: Processor and other ASICs run the instructions programmed to the fire alarm and process the sensor data by checking the values with the reference/threshold value to produce a suitable output (or no output).
  • D-A Converter: To change the digital data fed by the processor to an analog signal. The actuators often require analog signals.
  • Actuator: As directed by the output data from the processor, the actuator produces a physical signal, such as setting off the alarm, blinking LEDs, etc.

The basic structure of an embedded system using a fire alarm

Q2. What is a spinlock?

Spinlock is a synchronization mechanism used to access shared resources orderly by locking resources for a short amount. At the same time, other consumers wait in a spin (loop) until the shared resource is released/unlocked. For example, two threads named Thread-A and Thread-B would like to access a common resource named Resource-X.  

Let's say Thread-A requests spinlock to access a Resource-X:

If Thread-B is using Resource-X, Thread-A will be waiting in a loop until Thread-B releases/unlocks Resource-X.

If any thread does not use Resource-X, Thread-A will be allowed to acquire the spinlock, and all other threads will wait until Thread-A releases the lock.

A spinlock is a lock that causes a thread trying to acquire it to simply wait in a loop ("spin") while repeatedly checking whether the lock is available.

Because the thread is not performing any task despite being active, the use of this lock puts the thread in a busy waiting state. Spinlock held until explicitly released. However, in some implementations, spinlocks may be automatically released if the thread being waited on “goes to sleep” or blocks. Spinlock is useful in a multiprocessor system.

Q3. What do we mean by virtual memory?

Virtual memory is a memory addressing scheme that offers the illusion of having one large continuous addressing space for an application. Physically, the main memory can be smaller than the virtual memory address. Some virtual memory addresses physically correspond to the main memory, and other addresses physically correspond to the secondary memory.

There will be address translator implementation for the application to utilize one large contiguous address space. The address translation introduces an uncertain delay in the memory response. As a result, many embedded system microcontrollers do not implement virtual memory.

Virtual memory allows users to load multiple bigger-size processors than in the main memory. Now the operating system does not load complete processes into the memory; rather, it loads the different relevant parts of multiple processors into the main memory. Thus effectively using the memory and also increasing the CPU utilization between processes. The size of the virtual memory is determined by the addressing scheme of the given CPU instruction architecture and not by the size of the main memory.

Virtual memory is implemented using both software as well as hardware. It maps memory addresses that a program uses, known as virtual addresses, to physical addresses in the computer's memory. All of a process's memory references are virtual or logical addresses. These logical addresses are then dynamically translated to physical addresses during run time.

Q4. What is your approach for debugging any issue in an embedded system?

Debugging techniques are very specific to the issue and the system. However, the following is a generic step-by-step approach that can be applied to most embedded systems.

1. Understand the system

Understanding the system is always a good idea as it helps a lot in narrowing down the issue. You can start by asking a few basic questions, such as:

  • What is the input to the system?
  • What is the hardware underneath?
  • What is the expected behavior from the system?
  • What are the different states of the system (at a very high level)?

Debugging any issue in an embedded system

Questions such as these can save a lot of time at various stages during debugging.

2. Reproduce the issue

Once you have a basic understanding of the system, you should try reproducing the issue. Hopefully, it is an issue that can be easily reproduced. If you can do these first two steps properly, finding the issue or debugging it becomes much easier.

3. Add instrumentation/logging

Once you can reduce the issue, the next step is to see if it's easy or hard to reproduce the issue. If it's an easy-to-reproduce issue, then you don't worry too much about what are certain scenarios during which you can reproduce the issue. But if it is hard to reproduce the issue, then sometimes just seeing when the issue reproduces usually gives you a clue.

In either of these cases, it is essential to add logging, some debug information, or add instrumentation (Oscilloscope, Signal Generator, Multimeter, etc.), depending on your system.

Now, tracking through the sequences of steps becomes much easier until the issue is reproduced.

In some systems, it's possible that you don't even have access to the signals. In such scenarios, you can try to look through the crash logs. You can then analyze the signals from the instruments or logs for a better understanding of the issue.

4. Isolate the bug/system

After finding where the issue is coming from, you can try to isolate the system (sub-system). You can then use divide-and-conquer techniques such as binary search to figure out the point where the bug is getting introduced.

5. Apply quick fixes

With all the information you gathered, try to form some hypotheses:

  • This is the bug
  • This is the module (sub-system) or line of code the bug is coming from
  • Under these conditions; I can reproduce the issue (these conditions are causing the issue)

So now you can try applying quick fixes to counter the bug and iteratively see if the issue is reproducing again with the conditions identified earlier. If everything is working correctly, you can commit the changes and consider the bug fixed.

Q5. Describe the role of the watchdog timer.

Many microcontrollers have the watchdog timer feature (usually implemented with specific dedicated hardware). It can be used to check if the software running on the microcontroller is hung. Microcontrollers are designed to be stable and durable.

However, there are still many issues that can affect the stability of the hardware. An unhandled combination of software-side events may also occur. Both can cause microcontrollers to get "stuck or hang" either electrically or in an infinite loop in software.

A watchdog timer is a subsystem that must explicitly notify software that everything is running as expected at a certain time. If the watchdog is not receiving the expected notification, it will take some action, such as resetting the microcontroller or even the entire device. This is usually done periodically, and the watchdog timer will take action if it does not receive a notification after a configurable amount of time since the last notification.

Q6. What is a livelock, and how is it different from a deadlock?

First, let’s understand what a deadlock is. In a deadlock, you have two or more concurrent processes waiting for a resource, and one of the processes may be holding the resource. Assuming it's a unitary resource, one process is holding one resource, and the other is holding another resource, so they are both waiting for the other to release the resources while not letting the resources go from themself.

So, basically, in a deadlock, we have a ‘hold and wait’ type of situation between the two processes. Both processes are doing this; therefore, they are in an embrace in which neither will let go so that the wait will be forever - this is what we define as a deadlock situation.

A live lock is the opposite of that. Instead of waiting, the processes try to get a resource, but the process is courteous, so it differs from taking the resource. These processes are not waiting and are running parallel. It means you check if any other process is active, and you assume it will also ask for the same resource, so you differ and back off from using (getting hold of) the resources. So when two processes differ from using the resources out of courtesy that the other process may need, it puts them in a livelock situation.

The loop here is that both processes keep checking for other activity and backing off. Now because they are concurrent, this thing can go on for a long time. None of the threads makes any progress which means they are locked.

To summarize, a deadlock is you're holding and waiting for the resources. But in a livelock, you differ forever from the resource, assuming some other active process will need it.

We can imagine a real-life example of livelock is when two people meet in a narrow hallway, and each of them tries to be polite by moving aside to let the other person pass. Still, they end up swaying from side to side without actually passing the hallway as they repeatedly move the same way at the same time.

To learn more about livelocks, check out our tutorial:

Q7. What are the causes of the interrupt legacy?

The first delay is usually caused by hardware: the interrupt request signal must be synchronous with the CPU clock. Depending on the synchronization logic, up to 3 CPU cycles may elapse before an interrupt request reaches the CPU core.

The CPU usually completes the current instruction, which may take several cycles. On most systems, the time-consuming instructions to get executed are divide, push-multiple, or memory-copy. In addition to the cycles required by the CPU, additional cycles are often required for memory accesses. On an ARM7 system, the STMDB SP!,{R0-R11, LR} instruction is typically a worst-case instruction consisting of 13 32-bit registers and takes 15 clock cycles.

The memory system might require additional cycles for wait states.

Upon completion of the current instruction, the CPU performs a mode switch or pushes registers on the stack. Modern processors such as ARM generally perform mode switching, which takes fewer CPU cycles than saving registers.

Pipeline fill: Most modern CPUs are pipelined. Instruction execution occurs at different stages of the pipeline. The instruction is executed when it reaches its final stage of the pipeline. Since the mode switch has flushed the pipeline, several more cycles are required to refill the pipeline.

Q8. What are static memory allocation and dynamic memory allocation?

Memory Allocation: Memory allocation is the process by which physical or virtual memory space is allocated to computer programs and services. It is done either before or during program execution. There are two types of memory allocation:

  • Static Memory Allocation: Static allocation means that the object is declared with a static storage class or has an external or internal reference. It is initialized only once before the program starts, and its lifetime is for the duration of the program's execution. An example of static memory allocation is a global and static variable.
  • Dynamic Memory Allocation: In C, many library functions, such as malloc, calloc or realloc, etc., are used for dynamic memory allocation. One problem with dynamically allocated memory is that the compiler doesn't destroy it itself; the user is responsible for freeing the allocated memory.

These memory management functions return a pointer to the allocated memory block, and the returned pointer points to the starting address of the allocated memory block. If no space is available, a null pointer is returned.

Here are some sample technical embedded software engineer questions that you can practice:

  1. Explain inline functions
  2. Explain buses in communication
  3. Explain the troubleshooting process for embedded targets
  4. Differentiate between component-based design and object-oriented design
  5. Differentiate between mutexes and semaphores
  6. Name some code testing tools
  7. Name some of the latest technologies
  8. How would you reduce interrupt latency?
  9. What are model transformations?
  10. Why would you need DMAC in ES?
  11. Would you debug ISR using breakpoints?
  12. Why do segmentation fault errors occur?
  13. Write a program using the power-save super loop.
  14. Which software configuration tools are you aware of?

C, C++, Embedded C Software Engineer Interview Questions

In your embedded software engineer interview, you can be asked specific questions on C, C++, and Embedded C, such as:

Q1. What are the type qualifiers in C Programming?

It is a keyword applied to a data type, resulting in a qualified type. For example, const int is a qualified type representing a constant integer, whereas const is a type qualifier to specify that the value will not be changed. The following code declares a constant integer x and sets its value to 10. Now, if we attempt to change x’s value, the compiler will throw an error.  

Similarly, a volatile int is a qualified type representing a volatile integer, meaning its value can change by any external device or hardware. The following code declares a volatile integer y and set’s its initial value to 0, which can be modified.

As of 2014 and C11, there are the following four type-qualifiers in standard C:

  • const (C89): The const keyword is compiler-enforced and says that the program cannot change the object’s value, making the object a nonmodifiable type.
  • volatile (C89): A variable with a volatile-qualified type may be modified in ways the implementation is unaware of, or it may have other unanticipated side effects. The volatile keyword indicates that a value may change between different accesses, even if it does not appear to be modified.
  • restrict (C99): This type of qualifier can be used in pointer declarations. By adding this type of qualifier, a programmer hints to the compiler that for the lifetime of the pointer, no other pointer will be used to access the object to which it points.
  • _Atomic (C11):  The latter has a private name to avoid clashing with user-defined names. _Atomic is used to avoid the race condition if more than one thread attempts to update a variable simultaneously.

Q2. What is the difference between a null pointer and a void pointer?

A null pointer is essentially a null value assigned to a pointer of any data type, while a null pointer is a data type that remains void until it is assigned a data type address.

The data type of a pointer is stored in the memory location to which the pointer points. If you are unsure of the type of data stored in a particular memory location, you must create a void pointer.

A null pointer does not contain a reference to any variable/value; it is NULL, making it a null pointer.

a void pointer is always of type void *

These pointers are mainly used for dynamic memory allocation using the malloc(), calloc(), and realloc() functions. Here, the reserved memory block is a pointer to an empty pointer, and when the pointer value is returned, it must be explicitly cast to the specific type required.

Q3. Explain the use of ‘volatile’ in Embedded C.

A volatile keyword is a type qualifier in C applied to a variable when declared. It tells the compiler the variable may be modified in ways unknown to the implementation or have other unknown side effects. As a result, the compiler cannot make any assumptions about the variable's value. The optimizer must reload the variable every time it reads the value rather than keeping a copy in a register.

Let's take a look at the syntax:

To declare a variable as volatile, you must put the volatile keyword before or after the data type while defining the variable. Look at the following two variable declarations for a volatile unsigned 8-bit integer variable:

Now, it turns out that pointers to volatile variables are pretty common,

You can also declare a pointer to a volatile variable. The following declarations declare v_pot to be a pointer to a volatile unsigned 8-bit integer:

However, using a volatile pointer to non-volatile data is very rare; the following is the syntax for reference:

If you really must have a volatile pointer to a volatile variable, the following is the syntax for your reference:

Q4. Why do we need infinite loops in embedded programming, and how do we code an infinite loop in Embedded C?

As the name suggests, infinite loops repeat indefinitely and never terminate as long as the program is alive. In most other types of programming, infinite loops are created by mistake and don’t have many use cases. However, this is not the case with embedded programming.

Embedded systems are intended to run forever and serve a given task repeatedly. If the embedded system suddenly exits, it means it no longer serves the task it is designed for. If the embedded system completes a given task, it should go into a sleep mood instead of exiting altogether because the next time the task is needed, it should be able to wake up and resume the task.

This infinite loop contains the main instruction the embedded system should execute. You can take the Arduino program template, for example:

Now, let’s see how we create infinite loops in Embedded C.

The following is the definition of the infinite for loop. Here we don’t mention any of the parameters for initialization, condition, or increment/decrement for the loop.

Now, we'll look at how to use a while loop to create an infinite loop. The infinite while loop is defined as shown below. Here we hard code the while condition to true.

The do-while loop can also be used to create the infinite loop. The following is the syntax to create the infinite do-while loop. Here again, we hard code the while condition to true.

Q5. What do sizeof(int) return on 32-bit and 64-bit machines?

According to the C-spec, an integer only needs to be able to represent this (-32767,32767) range of numbers. Essentially the C-spec only says that an integer has to be 16 bits or larger. But in practice, sizeof(int) will return you 4 bytes on both 32-bit and 64-bit machines.

In other words, The C standard only specifies a minimum range for integer types guaranteed to be supported. An int is guaranteed to be able to hold (-32767,32767), which requires 16 bits (2 bytes). However, implementations can go beyond that minimum, as we see that many modern compilers make int 32-bit, i.e., 4 bytes.

However, a long int might have a different size on a 32-bit or 64-bit machine. It is also possible that a long int might be different on Windows versus Linux machines. But on the other hand, long long int is consistently 64 bits but could be implemented as more.

To learn more about it, watch our tutorial:

These are some sample C, C++, and Embedded C software engineer questions that you can practice:

  1. How many storage classes are there in C?
  2. How do you write Function Itoa()


Recession-proof your Career

Recession-proof your Embedded Systems Software Engineering Career

Attend our free webinar to amp up your career and get the salary you deserve.

Ryan-image
Hosted By
Ryan Valles
Founder, Interview Kickstart
blue tick
Accelerate your Interview prep with Tier-1 tech instructors
blue tick
360° courses that have helped 14,000+ tech professionals
blue tick
57% average salary hike received by alums in 2022
blue tick
100% money-back guarantee*
Register for Webinar

Recession-proof your Career

Recession-proof your Embedded Systems Software Engineering Career

Attend our free webinar to amp up your career and get the salary you deserve.

Ryan-image
Hosted By
Ryan Valles
Founder, Interview Kickstart
blue tick
Accelerate your Interview prep with Tier-1 tech instructors
blue tick
360° courses that have helped 14,000+ tech professionals
blue tick
57% average salary hike received by alums in 2022
blue tick
100% money-back guarantee*
Register for Webinar

Attend our Free Webinar on How to Nail Your Next Technical Interview

Register for our webinar

How to Nail your next Technical Interview

1
Enter details
2
Select webinar slot
By sharing your contact details, you agree to our privacy policy.
Step 1
Step 2
Congratulations!
You have registered for our webinar
check-mark
Oops! Something went wrong while submitting the form.
1
Enter details
2
Select webinar slot
Step 1
Step 2
check-mark
Confirmed
You are scheduled with Interview Kickstart.
Redirecting...
Oops! Something went wrong while submitting the form.
All Blog Posts
entroll-image
closeAbout usWhy usInstructorsReviewsCostFAQContactBlogRegister for Webinar