EMBEDDED FIRMWARE DESIGN


Not every bit of software writing requires venturing into the labyrinth of assembly code, but when something does, we're not afraid to go there.


 

We serve customers who develop products that leverage original work in the deeply embedded space. We're experts on:

  • How to organize and partition tasks (and hide information) for modularity, code reuse, and ease of debugging.

  • What makes a good API, and how to present one to an application programmer so that he doesn't have to get bogged down in the embedded space.

  • How to split functionality across hardware and software, aligning the necessities of engineering and manufacturing "cost of goods sold" with the demands of product development timelines and the economic realities of market windows.

  • Where device initialization can go wrong and how to avoid the pitfalls.

  • How semaphores and mailboxes work, and how tasks can be unintentionally blocked or have their priorities scrambled as a result of not having proper access to resources.

  • How to implement linear time invariant (LTI) systems for critical control feedback loops.

  • How to write "spectrally pure" code for digital signal processing systems so that software isn't polluting data with high harmonics due to the system jitter that can be inherent to non-deterministic algorithm timings.

  • Where commercial operating systems can and cannot meet the constraints of a hard real-time deadline.

  • How to do big math on small machines.

  • Interrupt latency, and where it can take a project off track if it's not calculated carefully.

  • Where exceptions can occur and how to implement graceful fault recovery.

  • How to plan ahead for tools usage so that your system is debuggable with minimal effort, and how debugging tools themselves can mask problems in certain circumstances.

We design both hardware and software, so we have a clear understanding of how the boundary between them may be moved in one direction for speed, in another to reduce memory footprint, and in still another to juggle the tradeoff between one-time non-recurring development costs and per-unit costs (COGS) for new products.Members of our team collectively have hundreds of years of experience writing embedded code. Several of us began our careers when NACA was rechristened NASA and computers were just starting to supplant slide rules to crunch the numbers to put Project Mercury into space. Not every bit of software writing requires venturing into the labyrinth of assembly code, but when something does, we're not afraid to go there. Some of us were there already when Bob Pease was growing his first beard.

We've designed software simulators and microprocessor emulators, and we've written real-time operating systems. Some of us have even reverse-engineered "closed" microprocessor architectures – and picked the locks that let us into their JTAG debugger ports. So we're intimately familiar with how the world looks from the silicon's point of view. We may use somebody else's SDK's when we're writing an application and it's convenient, but when an SDK is unavailable, we can create one from scratch.We may understand microprocessors at the level of the state machine that is the microcode engine, but we also know what a good C-callable function looks like. We know what needs to be presented through an API to the higher-level code that runs above it, and we know what's much better when it remains hidden from the calling function. Even when we're writing "assembly," we're frequently thinking "object model."

If we're writing something custom, we're writing it to be as modular and reusable as possible. Or we're designing it to have at least an API that's common to other callable routines so that changes at the embedded level don't percolate up to become major application rewrites later.

A thorny low-level software problem – a system that has to run in real time and fails, an application that's crashing for reasons you can't understand at application level, or code that just doesn't fit the target device – may be caused by conflicts at the embedded level. And they're frequently impossible to find above the device driver's API.

We'll venture into the deeply embedded space and locate the fault so that you don't have to. (Unless you want to, in which case, we can be your guide.) If you only want to work in the upper levels of application space, we'll give you the API's and the measurable milestones in their development that'll keep your overall project on track. We're fast and efficient in our coding, and we want to give you the metrics you need to track the progress of your embedded development.