Skip to main content

Ramp

Embedded engineer at Ramp

The typical process shape, common embedded engineer interview questions, and a market salary band for this role.

Process timeline

  1. 1

    Recruiter screen

    A conversation about your background, motivation, and logistics, plus a first check that your experience lines up with the embedded engineer opening.

  2. 2

    Technical phone

    A remote session on the core skills of the role, worked through live with an interviewer rather than answered as trivia.

  3. 3

    Onsite

    A longer block of back-to-back interviews with the team, mixing deeper skill exercises with behavioral questions about how you work.

  4. 4

    Decision

    Interviewers pool their feedback, the hiring manager makes the call, and the recruiter comes back with an outcome or next steps.

Interview questions

Common embedded engineer interview questions that come up across companies like Ramp.

As asked

A sensor produces data at irregular intervals and the device runs on battery. When would you use interrupts instead of polling, and what can go wrong?

Sample answer outline

Interrupts let the CPU sleep and react when the sensor signals data, which is often better for irregular events and power-sensitive devices. Polling can be simpler and more predictable when timing is fixed, the check is cheap, or the hardware interrupt line is unreliable. Keep interrupt service routines short: capture the event, clear the flag, and defer real work to the main loop or RTOS task. Discuss debouncing, missed interrupts, priority inversion, shared data races, and volatile or atomic access. Interviewers want practical embedded judgement, not a blanket rule that interrupts are always better.

Expect these follow-ups

  • How do you safely share data between an ISR and the main loop?
  • When can polling be more deterministic than interrupts?
  • How would you debug an interrupt storm in the field?
firmwareinterruptspower

As asked

Walk me through your decision process for choosing between interrupt-driven I/O and polling on a microcontroller. What factors push you toward one or the other, and can you give me a concrete example where you made that call?

Sample answer outline

A strong answer covers latency requirements, CPU utilization, and event frequency as the key factors. The candidate should explain that polling suits high-frequency, predictable events where the cost of the ISR entry/exit overhead exceeds the polling cost, while ISRs suit low-frequency or latency-critical events. They should mention the danger of blocking inside an ISR and give a concrete scenario such as a UART receive or a GPIO edge detection.

Expect these follow-ups

  • How do you handle ISR latency jitter on an ARM Cortex-M?
  • What happens if your ISR runs longer than the next interrupt period?
interruptsisrpollingcortex-mreal-time

As asked

What is priority inversion, and how does it manifest in an RTOS like FreeRTOS or Zephyr? Walk me through a real scenario and how you would prevent or recover from it.

Sample answer outline

The candidate should describe the classic scenario where a low-priority task holds a mutex needed by a high-priority task, and a medium-priority task preempts the low-priority one, effectively blocking the high-priority task indefinitely. They should mention priority inheritance as the primary mitigation and be aware of ceiling protocols. Bonus points for mentioning that FreeRTOS mutexes implement priority inheritance but binary semaphores do not.

Expect these follow-ups

  • Does FreeRTOS priority inheritance fully solve priority inversion? What are the limits?
  • How would you detect priority inversion on a live system without a JTAG debugger?
rtosfreertospriority-inversionmutexscheduling

As asked

Explain what the volatile keyword does in C, why it matters for embedded firmware, and give me two scenarios where omitting it would cause a real bug that the compiler would not warn you about.

Sample answer outline

The candidate should explain that volatile prevents the compiler from caching a variable in a register across reads, forcing every access to go to memory. Scenario 1: a memory-mapped peripheral register where the compiler might eliminate a read because it sees no writes in the C code. Scenario 2: a flag set inside an ISR and polled in main context, where the optimizer may hoist the read out of a loop. They should also mention that volatile does not imply atomicity.

Expect these follow-ups

  • Is volatile sufficient for sharing data between an ISR and a task on a single-core ARM? Why or why not?
  • What optimizer flags can make volatile bugs appear or disappear?
c-languagevolatilecompilerisrmemory-mapped-io

As asked

Implement a lock-free single-producer single-consumer ring buffer in C for passing bytes between a UART ISR (producer) and a main-loop consumer on a single-core Cortex-M. It must not use mutexes or disable interrupts.

Sample answer outline

The candidate should use separate head and tail indices with volatile qualifiers and ensure that the producer only writes head after writing data, and the consumer only writes tail after reading data. The key is that on a single-core system with a single producer and consumer, no locking is needed as long as head and tail each have a single writer. They should use a power-of-two buffer size and modulo-via-mask, and be careful that size checks use copies of the volatile indices to avoid re-reading a changing value mid-check.

Reference implementation (c)

C
#define BUF_SIZE 256  // must be power of two

typedef struct {
    uint8_t  data[BUF_SIZE];
    volatile uint32_t head;  // written only by producer (ISR)
    volatile uint32_t tail;  // written only by consumer (main)
} RingBuf;

void rb_push(RingBuf *rb, uint8_t byte);
int  rb_pop(RingBuf *rb, uint8_t *byte); // returns 1 if data available
uint32_t rb_used(const RingBuf *rb);

Expect these follow-ups

  • Why do you need volatile on head and tail here even though this is single-core?
  • How does this approach break on a multi-core system, and what is the fix?
ring-bufferisrlock-freeuartc-language

As asked

Tell me about a time you found a race condition in embedded firmware. How did you identify it, what was the impact, and what did you change to fix it?

Sample answer outline

A strong answer describes a specific incident: the setup (what the code was doing, why concurrency was involved), how the bug manifested (intermittent, hard to reproduce), the debugging approach (logic analyzer, added instrumentation, code inspection), the root cause (missing volatile, missing critical section, non-atomic read-modify-write), and the fix (interrupt disable, FreeRTOS mutex, LDREX/STREX). They should quantify the impact and mention what they added to prevent recurrence.

Expect these follow-ups

  • How did you test that your fix actually eliminated the race rather than just making it less frequent?
  • What code review or static analysis process would have caught this before it shipped?
behavioralrace-conditiondebuggingconcurrencystar

Salary band

Use the salary page linked below for embedded engineer bands by city, modeled from BLS, ONS, and Levels.fyi reference medians.

View salary detail

Similar companies