Embedded systems tend to lack a display, keyboard, and mouse with which to manipulate the microcontroller that you’re trying to program. So a host computer is used for this function, and typically communicates over a serial cable or more recently, Wi-Fi.
Once you create, edit, and compile code for your embedded system on a host computer, you will have executable (object) code that needs to be uploaded to the microcontroller in your embedded system. There, you can see the code in action, test it, and debug the code by making changes to the code on the host, recompiling, and running it again on the target MCU. But what if you want to alter the contents of a register, memory, or the state of your I/O to see what happens? An In-circuit emulator (ICE) is a debugging tool that allows you to access a target MCU for in-depth debugging. A genuine ICE requires you to remove the microcontroller and to insert the ICE in its place, most commonly using an adapter. In-circuit emulation is rather rare in these days of high-performance, relatively low-cost processors because ICE needs to be invisible to the system, which is difficult to do with extremely fast, memory-intensive chips. Nevertheless, not every system requires a high-performance MCU, and it’s still possible to use ICE. ICE is the best tool for finding difficult bugs and can provide invaluable insight.
ICE consists of a hardware board with accompanying software for the host computer. The ICE is physically connected between the host computer and the target MCU. The debugger on the host establishes a connection to the MCU via the ICE. ICE allows a developer to see data and signals that are internal to the MCU, and to step through the source code (e.g., C/C++ on the host) or set breakpoints; the immediate ramifications of executed software are observed during run time. Since the debugging is done via hardware, not software, the MCU’s performance is left intact for the most part, and ICE does not compromise MCU resources. This type of debugging is also referred to as source-level or run-time debugging, except ICE is as close to the real scenario as possible, as it’s not a simulation but a substitution of the target MCU with an emulation, or accurate mirror, of the target MCU in the ICE itself. The behavior of the MCU will be more accurately reflected in ICE, and in real-time.
The disadvantage of ICE debugging is that the ICE hardware must be physically connected to the MCU. As chips get smaller, adapters can help in connecting tiny surface mounted chips to the ICE. Another disadvantage is that ICE devices come with a learning curve, especially if there will be complex debugging functions, for example, flagging when a register holds a specific value after a conditional branch is taken, etc. And last, disadvantage is that as high-performance chips have come down in price, the accessibility for debugging with ICE has faded to the point where ICE hardware has become rare for anyone who is not still using an 8051-era MCU. In-circuit emulators require fast connectivity and loads of memory, so lower level MCUs (8-, -16-bit and MHz, not GHz) are more likely to have an ICE option available. Furthermore, highly integrated chips may create fewer bugs versus off-chip, board-mounted EEPROMS and interfaces, for example.
References: “The Software Engineer’s Guide to In-Circuit Emulation.” N.p., Oct. 2000. Web. Dec. 2016.