Adequate testing means more than just checking against the specification

Scott Rosenthal

(SLTF Consulting – Technology with Business Sense; July, 1995)

 

Testing an embedded system involves many more issues than the testing of a PC program. Not only does the embedded system contain a program analogous to the PC, it must also contend with startup code, hardware-control issues and asynchronous power interruptions. Hence, embedded-system testing requires not only testing to a requirements document, but it also demands of the tester an innate system knowledge, skepticism-and a healthy dose of luck. No matter how detailed the document, my experience is that this process finds few system problems. If you think about it, the reason for this truth should be obvious. Consider that any designer worth his salt develops systems to address the design’s requirements. Who ever set out purposely to design something that didn’t meet the system’s requirements?

Therefore, the most likely places defects show up are in a system’s “undocumented requirements.” For example, I once designed an analyzer for use in a grain elevator. One of these instruments came back for repair after having been in the field for a while. Inside the instrument was a soft rubber wheel for moving grain. Apparently, this soft rubber was also ideal for mice to use in whatever it is mice do with soft rubber. The wheel was chewed apart, and we had to switch to a hardier wheel. The instrument met the requirements testing, which apparently didn’t take into account all environmental conditions.

 

Xilinx revisited

Proving that these problems don’t ever go away, in a previous column (Ref 1) I detailed a problem with a Xilinx chip powering up into an illegal state from a brownout condition. Although none of us were smart enough to anticipate this type of problem, any good tester will tell you, once you’ve identified a weakness in the system, there’s a good chance that additional problems are hiding down the same path. With that lead in, let me describe a really neat tool we used with Xilinx debugging, fixing and testing.

First, a quick review of the problem: In a brownout condition (caused by quickly switching the instrument Off then On), the Xilinx chip wouldn’t reset properly unless one of two conditions was met: either Vcc has to drop below ~0.1V or a specific timing sequence had to occur. The tough problem was how to devise a test that would guarantee that the Xilinx problem was really fixed. That’s how I came across a simple tool to verify my fix.

A recent article (Ref 2) describes this tool, called Poc-it from MicroTools Inc (Simsbury, CT (800) 651-6170). It switches AC power On and Off either directly or through a relay. In addition, to close the loop, the instrument can also count the occurrences of two TTL-level inputs representing good and bad results. What you end up with is a simple tool (aren’t the best ones simple?) that inexpensively allows you to design a true test of the Xilinx problem.

I connected four UUTs to the instrument’s switched AC outlet and set it to quickly cycle the power- 10 msec On and 25 msec Off-and started it on its torture testing. Within 100 cycles, all four instruments had their Xilinx chips fail to reset properly! Great, I now had a definitive test of the problem. I then installed a patch board with a PIC processor for controlling the Xilinx reset and reran the procedure. I stopped it after 20,000 cycles and had no failures! The Poc-it allowed me to run a controlled test, which not only proved that it could detect failures, but it proved the fix.

 

What’s next?

After seeing the Poc-it’s success, I thought of other ways to automate our testing. I put together an extensible automated tester that allowed me to design tests around system requirements while adding tests to challenge the system in unexpected ways. The tester also gives me traceability, which is important in today’s regulatory environment.

The automated tester, like Poc-it, is simple in concept and implementation. When designing a test system for an embedded device, obviously the first thing to do is figure out how it can stimulate the UUT. One of the more-obvious places is through its keypad. For generating simulated user inputs, three basic options are available: implement solenoids to physically press the keys, use a serial port to simulate keypresses or wire relays in parallel with the keys on the keypad. I went with the relays because this option requires no changes to the UUT software, and wiring the relays is relatively easy on most embedded systems. With the relay in parallel with a switch, closing the relay stimulates the hardware in the same fashion as pressing a key.

The UUT for which I originally designed the test system sports a 16-position keypad. It also has four other digital inputs, including a Door Open switch and a Lamp On signal. To stimulate this device, I purchased a CIO-ERB24 relay card from ComputerBoards Inc (Mansfield, MA (508) 261-1123), which provides 24 Form C relays. I controlled the board with an old laptop computer (no hard drive, single floppy) using CBI’s PPIO-DIO24H box connected to the parallel printer port. I then wired the relays in a matrix arrangement that matched the UUT’s keypad and attached a passthrough connector on the end of the cable. With it I can remove the keypad cable in the UUT, plug the relay cable into the UUT and reattach the keypad cable to the relay cable. This arrangement gives me the option to press the keys with my fingers or simulate pressing the keys with a relay. I then connected the remaining relays to the other digital inputs to simulate their functions. Now, with just a bit of software, I had the beginnings of a powerful test system.

When putting together a home-brew system, basically you have two choices: First, assume you’ll never need this setup again and not design an extensible system. We’ve all been guilty of this crime-justifying it with complaints that there’s no time or budget to do anything else. Whatever the excuses, the result is a monolithic program that’s fragile and difficult to change.

The alternative is to take a few hours and craft an extensible program that you can use for a long time. For my test application, I started with one of my monitor programs (see Refs 3 and 4) and added a new command to activate a script processor. To control the relays and specify test sequences, I designed a simple script language. It’s not fancy, but it does allow an easy path to develop new test scripts. Also, because I wrote the code, I can add new elements to the “language” any time. The program design is small and written in C for easy future extensibility.

The language concept is simple. I created an object type (see Listing 1) with various properties, including the instance name, the script string code and the relay to use.

Listing 1-Testing object
 typedef struct {
 char *Name; /* name of this data */
 char *Code; /* character code for test script */
 int Default; /* the default value on program start */
 int RelayPort; /* the relay port to use */
 unsigned int Mask; /* the mask to use for the I/O port */
 int (*Function)(void *ObjectPtr); /* the function to execute */
 char *StatusMsg[2]; /* status message for 0 and 1 */
 /* the program fills the following: */
 int CurrentValue; /* the current value of this data */
 long Value; /* the value of the object */
 } TObject;
 /* functions for relay and time delay control, and keypresses */
 int RelayFunction(TObject *ObjectPtr);
 int TimeFunction(TObject *ObjectPtr);
 int KeyFunction(TObject *ObjectPtr);
 /* always present, the delay object */
 TObject Wait = {"Time Delay", "T", NO, EOF,
 0x08, (void*)TimeFunction, "", ""};
 /* F1 key */
 TObject Key1 = {"Key 1", "k1", NO, PORTC,
 0x20, (void*)KeyFunction, "", ""};

 

I then made instances of the object for each function I wanted to control, for example Door, Key1 and Wait. The script language itself is also simple. It consists of a command and a parameter. The command is just the code for an object instance. Again, it could be Door, Key1 or Wait. The parameter is some condition for the command. For example, with Door, 0 could mean open the door and 1 could mean close the door. For Wait, the parameter is the delay time in milliseconds. For Key1, the parameter indicates how long to pause after pressing the key. Another idea might be to indicate how long to hold down the key. Now, it’s easy to string these object instances together to create a test script (see Listing 2).

Listing 2-Typical test script
 ; all test after a semi-colon are
 ; comments
 k1,0 ; press key 1
 k2,1000 ; press key 2 and wait 1
 ; second
 lamp,1 ; turn on the lamp
 t,10000 ; wait 10 seconds
 k3,0 ; press key 3
 ; this sequence will now repeat
 ; indefinitely

The script processor works by reading the script file one line at a time and processing it. At the end of the list, it starts over. In the future, I plan to add features including digital inputs, feedback and script linking. Having written the code myself and keeping it object-oriented, I can easily add new objects as needed. Hence, you can use the same program fundamentals for testing different systems.

 

Other benefits

In addition to the obvious advantages of automated testing, this effort also offers other benefits. For example, it uncovered a number of subtle defects in my compiler, but the one that might strike many developers is a caution about using a heap with malloc(). The function malloc() allows a program to grab space on the heap. Conversely, the function free() returns this space to the heap. The problem I had was that after calling free(), the next malloc() started looking for available heap space at the last location freed with free() instead of at the beginning of the heap as I would’ve thought. Hence, depending upon the sequence of key presses, the program would at times severely fragment the heap, which in combination with the free() idiosyncrasy gradually stepped the pointer to the top of the heap higher in memory until it ran out of room. The result was that the UUT ran out of memory even though there was plenty of unused memory available. Once I figured out what was happening it became clear that the only way to fix the problem was to rework the operation of the malloc() function, a process that would be difficult at best-even if I could sweet talk my compiler vendor out of the source code for the built-in functions.

Finally I decided that since the only way I found this problem was through a torture test, the error was an acceptable situation. However, regardless of the outcome, I’m still ahead because I now know about a potentially dangerous “quirk” in my compiler, and I have a system to automate the testing of my products. PE&IN

 

References
  1. Rosenthal, S, ” It sometimes takes a microcontroller to boot up an FPGA,”PE&IN, Nov 1994, pgs 75-78.
  2. Japenga, B, “If it’s not tested it doesn’t work!” PE&IN, Apr 1995, pgs 53-56.
  3. Rosenthal, S, ” For digging out hardware bugs, monitor programs fill the bill,” PE&IN, July 1994, pgs 56-58.
  4. Rosenthal, S, ” Monitors are valuable, easy to use and create,” PE&IN, Sept 1994, pgs 73-78.

Adapted from an article that appeared in Personal Engineering & Instrumentation News.

Copyright c 1998-2000 SLTF Consulting. All rights reserved. Used with permission.