The most important skill for any embedded engineer is an understanding of hardware. You need to understand and recognise how the code you write will interact with each different piece of hardware that makes up your device or system, so that should things go wrong, you will be able to implement a resolution. This is especially true in cases where bespoke boards are being utilised, where there could be a lot of toing and froing between software and hardware developers.
In order to communicate with the outside world, embedded devices have to utilise peripherals such as serial communication interfaces, discrete IO and analogue to digital/digital to analogue converters. Typically the manufacturers of these devices will provide a document known as a data-sheet, which summarises the specifications and essentially acts as an instruction manual on how to interact with their product. As an embedded engineer, you will need the ability to process the information stored in these data-sheets in order to understand the timing and communication requirements, two critical factors when it comes to embedded development.
As we mentioned in the previous article, the number of languages available for an embedded development relies heavily on the hardware being used. Different CPUs are designed with certain languages in mind, however, C and C++ are traditionally the most popular choice. Having a strong understanding of at least one of these languages will give you a good starting point.
As many embedded systems and devices have no operating system, having some grounding in the low-level aspects of Computer Science will be extremely beneficial. Specifically how memory works and how to read and manage it. A background in electronics will certainly help in this regard, however, nothing is stopping you from gaining this knowledge at a later date.
To prevent processing units from constantly checking for inputs from peripherals, interrupt signals can be used to alert processors to high priority processes that require an ‘interruption’ of the current working process. Each time an interrupt occurs, the interrupt service routine code will be run. As an embedded engineer you will need to understand how to write this code, as great care needs to be given that it doesn’t end up blocking the working processes. All of these low-level things are essential knowledge for a bare metal specialist but are not as crucial in cases where an operating system is being used. This is because, for the most part, it will be the operating system that handles them. Should you need to write a bespoke driver however, you will need this lower level understanding regardless of whether an OS is being used.
When working with embedded devices and systems, as we have already mentioned higher up in this article, you will be expected to interface with peripherals and other devices. To describe and help regulate how these different things communicate with one another, there is a whole host of communication protocols that can be put in place on an embedded development. When it comes to communicating with devices on a board, it is worth getting to know SPI, I²C and memory-mapped. Whereas, an understanding of TCP/IP and CAN will stand you in good stead for communicating with the outside world.
Before we bring this article to a close, it’s probably beneficial to highlight the differences between embedded system programming and embedded application programming. Embedded System programming is probably what springs to mind for most people when they think of embedded development. It’s all the really low-level stuff that gets embedded hardware platforms up and running. Writing device drivers, bootloaders, posting or writing operating systems, debugging missing interrupts and worrying about cycles.
Embedded application programming on the other hand is much more similar to desktop applications, and as such not such a stretch in skill requirements. The development environment is much nicer, code can be written, tested and debugged on a desktop computer, you don’t have to think about assembly or GPIO pins, but you do have to work with resource constrained systems. This means you need to think about things like memory usage, execution contexts, code size and portability, but that just makes for an interesting challenge.