When no serial interface or TCP/IP connection is available, the JTAG communication port lets developers debug embedded applications on the target side. Many embedded debuggers let developers request and set JTAG interface-specific information, like status information or JTAG interface firm-ware. Furthermore, features like memory tests can be defined and applied through the debugging tools directly on the target application. Such a debugging solution is the key to bridging a simulation with a full target debugging solution (Fig. 4).
The next step in the process employs monitor software. Monitoring tools normally download small agents to the target system to handle the communication between the debugger and the target application. A ROM monitor tool can connect to the embedded device, typically through a serial link, and provide complete control over the debugging process. It permits selective execution start and stop, and it includes full access to the peripheral control block registers and other processor features.
A ROM monitor on the target side is typically a high-priority interrupt service routine (ISR), which is invoked whenever an interrupt occurs, generated through the serial connection. This happens when the debugger on the host side sends a command to the target system where the ROM monitor is in-stalled. ROM monitors can be booted from either flash memory to electronically erasable programmable read-only memory (EEPROM) and can be downloaded in conjunction with the application. Alternately, the ROM monitor and the application can be linked together and loaded as one image from EEPROM or flash. However the monitor is used, it enables developers to attain more-detailed information of the application executing on the target.
Testing The Entire Build
Because the embedded application usually has to interact with other applications and the Linux target OS, the final stage of debugging entails testing the entire build on the target system. This permits developers to observe how the application behaves under actual conditions, using the Linux scheduler and sharing cycles with other processes.
While virtually all of the bugs should be out of the application at this time, both performance and scheduling issues will come to light through robust testing of the entire image. Because many target devices have resource constraints, the developer also will be able to determine how the image behaves within the confines of those constraints. Poor performance or unexpected application failures often result from testing the entire image on the targeteven if there's a high level of confidence in the reliability of the individual software components.
At this stage of debugging, developers should use a debugger that can provide information on operating-system and environment-specific behavior and code components, such as task lists, thread lists, semaphores, queues, mailboxes, and OS status information. During this process, the developer should be able to set breakpoints in conjunction with specific task IDs and stop the system at defined times, like when a specific task invokes a special function. This makes it easier to locate inconsistencies in the embedded application.
During the final testing process, one aspect that's frequently overlooked is code-coverage analysis. While many embedded programmers extensively test their code prior to release, there usually isn't a level of confidence as to how much code was tested. Code-coverage tools provide a way to determine which tests execute which code paths and how much of the actual source code has been tested.
In some cases, developers have run a full series of test suites on applications and later discovered through code-coverage analysis that only 50% or fewer of the code lines were exercised. This means that far too much code is re-leased without any testing. Code-coverage analysis provides a mechanism for quantitatively determining how well an application is tested and how stable the code is prior to its release.
While there's no readily available free or GNU code-coverage tool, the investment in a commercial tool yields a better understanding of the testing status of the code, especially in team-development environments where managing the testing process is critical. It's less valuable for a single developer working on a small application, but it's becoming necessary in a team environment because managers and developers need to monitor the progress of testing.
Individual parts of this overall methodology are practiced by many embedded developers today. But by using Linux as the target operating system, with one version of Linux as the target embedded-system OS, it's possible (and increasingly necessary) to develop a more robust and in-depth testing and debugging methodology. Employing an open-source operating system offers significant opportunities in flexibility and licensing costs, but at the expense of the reliability and increasing complexity of the overall system. It's important to manage these and other risks through a well defined methodology, supported by a comprehensive tool chain.
Some of these steps might seem less important to a specific application or end use, but there are no shortcuts to delivering reliable software on a new and complex operating-system platform. The advantages of Linux will be realized only by putting the tools and processes in place to see a project through to a successful completion.
When no serial interface or TCP/IP connection is available, the JTAG communication port lets developers debug embedded applications on the target side. Many embedded debuggers let developers request and set JTAG interface-specific information, like status information or JTAG interface firm-ware. Furthermore, features like memory tests can be defined and applied through the debugging tools directly on the target application. Such a debugging solution is the key to bridging a simulation with a full target debugging solution (Fig. 4).
The next step in the process employs monitor software. Monitoring tools normally download small agents to the target system to handle the communication between the debugger and the target application. A ROM monitor tool can connect to the embedded device, typically through a serial link, and provide complete control over the debugging process. It permits selective execution start and stop, and it includes full access to the peripheral control block registers and other processor features.
A ROM monitor on the target side is typically a high-priority interrupt service routine (ISR), which is invoked whenever an interrupt occurs, generated through the serial connection. This happens when the debugger on the host side sends a command to the target system where the ROM monitor is in-stalled. ROM monitors can be booted from either flash memory to electronically erasable programmable read-only memory (EEPROM) and can be downloaded in conjunction with the application. Alternately, the ROM monitor and the application can be linked together and loaded as one image from EEPROM or flash. However the monitor is used, it enables developers to attain more-detailed information of the application executing on the target.
Testing The Entire Build
Because the embedded application usually has to interact with other applications and the Linux target OS, the final stage of debugging entails testing the entire build on the target system. This permits developers to observe how the application behaves under actual conditions, using the Linux scheduler and sharing cycles with other processes.
While virtually all of the bugs should be out of the application at this time, both performance and scheduling issues will come to light through robust testing of the entire image. Because many target devices have resource constraints, the developer also will be able to determine how the image behaves within the confines of those constraints. Poor performance or unexpected application failures often result from testing the entire image on the targeteven if there's a high level of confidence in the reliability of the individual software components.
At this stage of debugging, developers should use a debugger that can provide information on operating-system and environment-specific behavior and code components, such as task lists, thread lists, semaphores, queues, mailboxes, and OS status information. During this process, the developer should be able to set breakpoints in conjunction with specific task IDs and stop the system at defined times, like when a specific task invokes a special function. This makes it easier to locate inconsistencies in the embedded application.
During the final testing process, one aspect that's frequently overlooked is code-coverage analysis. While many embedded programmers extensively test their code prior to release, there usually isn't a level of confidence as to how much code was tested. Code-coverage tools provide a way to determine which tests execute which code paths and how much of the actual source code has been tested.
In some cases, developers have run a full series of test suites on applications and later discovered through code-coverage analysis that only 50% or fewer of the code lines were exercised. This means that far too much code is re-leased without any testing. Code-coverage analysis provides a mechanism for quantitatively determining how well an application is tested and how stable the code is prior to its release.
While there's no readily available free or GNU code-coverage tool, the investment in a commercial tool yields a better understanding of the testing status of the code, especially in team-development environments where managing the testing process is critical. It's less valuable for a single developer working on a small application, but it's becoming necessary in a team environment because managers and developers need to monitor the progress of testing.
Individual parts of this overall methodology are practiced by many embedded developers today. But by using Linux as the target operating system, with one version of Linux as the target embedded-system OS, it's possible (and increasingly necessary) to develop a more robust and in-depth testing and debugging methodology. Employing an open-source operating system offers significant opportunities in flexibility and licensing costs, but at the expense of the reliability and increasing complexity of the overall system. It's important to manage these and other risks through a well defined methodology, supported by a comprehensive tool chain.
Some of these steps might seem less important to a specific application or end use, but there are no shortcuts to delivering reliable software on a new and complex operating-system platform. The advantages of Linux will be realized only by putting the tools and processes in place to see a project through to a successful completion.