A Cellphone/Tablet Becomes a Modern User Interface for a Classic Signature Analyzer
A complex circuit isn’t working as it should. Which component is to blame? A signature analyzer can give you the answer. Brian shows how the ubiquitous cellphone can give new visibility and utility to a critical trouble-shooting tool.
Seven years ago, I published a Circuit Cellar article (Issue 337) describing a signature analyzer that contained its own user interface and display screen. It used a Teensy 3.5 module (containing an NXP ARM MCU) and a 4.3” TFT touchscreen. It was quite a complex project and not inexpensive, due to the cost of the Teensy 3.5 module as well as the FT800-based TFT display. Many things have progressed since then, and I thought it would be interesting to come up with a more modern design.
Recently, I came across the Microchip MCP3910 high-speed 24-bit dual-channel ADC device. I spent quite some time with it, as part of a Circuit Cellar column (Issue 417) about three high-resolution ADCs that I had recently used. This device is very well-suited for a signature analyzer, due to its features:
- High-resolution (24-bits)
- Two built-in programmable gain amplifiers (Gains of 1, 2, 4, 8, 16, and 32)
- Two independent ADC channels which enable it to do voltage and current measurements simultaneously
- High-speed- up to 46000sps, in this application
- Available on a module—helpful as the MCP3910 chip comes in a tiny TSSOP package
In many ways, this device is much better than the 16-bit ADC that I used in the earlier signature analyzer. The ADC in that project was the NXP ARM MCU’s internal ADC which had an effective resolution of only 12to 13 bits. It also needed two external PGA chips for amplification, as well as numerous relays for range switching.
My earlier unit used a Mikroelektronika Connect-Eve TFT touchscreen, which uses the FTDI (now Bridgetek) FT800 controller family. These are nice 4.3” displays, but this time I wanted to use either a cellphone or a tablet as the complete user interface. This would result in the unit being much smaller and much less expensive to build. Personally, I have a Lenovo tablet with an 11” screen, so the user interface could be much larger and easier to use. The GUI-O app that I used to develop the user interface on the tablet, only runs on Android, which is the OS that the Lenovo tablet uses.
Basic Theory of Operation
To obtain a “signature” of a given component, you need to place a variable voltage across it and measure the resulting current through it (at each voltage level). In many cases, a component’s normal operating mode will include both positive and negative voltages across it. So, the tester must provide an AC voltage source.
For most testing purposes you would use a sine wave voltage source, since most AC calculations are done using sine waves. The value of this AC voltage source must be adjustable. I decided upon five ranges: 0.5V, 1V, 2V, 5V and 10V (peak, not RMS). To measure the voltage across the component, I used an instrumentation amplifier with a gain of one, in conjunction with the MCP3910’s channel 0 PGA and ADC.
To monitor current, I measured the voltage across a 1.2Ω resistor placed in the ground return path and converted that to current using Ohms law. I provide four full-scale current measurement ranges from 0.1mA to 100mA. These four ranges are implemented using a PGA gain of four for the 100mA range and 32 for all lower current ranges. Software scaling was used to normalize the chart Y axis (current) display for the 0.1mA to 10mA ranges.
You can’t just place an AC voltage, of any given amplitude, across a component and hope that the component will be able to handle the resulting current without damage. You must place a resistor in series with the component to limit the current flow. That resistor may need to vary in value over several decades, depending upon the component being tested. In my tester, I provided a switchable resistor bank with four values between 100Ω and 100kΩ, in decade steps.
Figure 1 shows a block diagram of the basic tester circuitry. The user interface is handled by an Android cellphone or tablet and is not shown here. The ESP32 MCU contains two 8-bit DACs. This is probably a high enough resolution to work with this application, but there are other problems. The ESP32 MCU contains a dedicated hardware cosine generator block which can operate at frequencies well beyond what is needed here. However, I could see no easy way of synchronizing the measurements to the start of a waveform generated that way. I tried several methods of feeding these 8-bit DACs directly from my program code, but they were all much too slow. Similarly, if you use DMA to feed the ESP32 DACs, the synchronization of the voltage/current measurements would be a problem in this case as well.
Instead, I settled on a Microchip MCP4922 12-bit dual DAC, which uses an SPI interface. To generate a 128-segment sine wave at the highest frequency setting used (360Hz) requires the DAC to be capable of being loaded in about 4µs—this takes into consideration that both ADC channels must also be read at each sample point. The MCP4922 is capable of SPI clock rates up to 25MHz. The highest ESP32 SPI port speed available, which is less than or equal to 25MHz, is 20MHz, which is what I used. Also, I was unable to get both the MCP4922 DAC and the MCP3910 ADC to co-exist on a single SPI port—even though they each had separate -CS lines. Rather than try to figure out why the driver library routines for each device would not cooperate with each other, I placed the DAC on the ESP32’s HSPI port and the ADC on its VSPI port.
The MCP4922 DAC generates an output voltage, which has a full-scale value equal to the DAC’s external reference voltage or, optionally, 2x that voltage. I used a 2.5V reference chip and a trimpot that was adjusted to provide a 2.16V reference. This odd reference voltage will be explained later. Regardless of what reference voltage you use, the MCP4922 will only provide a unipolar signal from zero to that reference voltage (optionally 2x). What is needed in this project is a bipolar signal, referenced to GND.
The DAC output must be followed by a power op-amp to be able to supply the ±100mA required for the highest current range. I could have configured this output buffer as an inverting amplifier and fed in an offset voltage to shift the DAC’s output to a bipolar, GND-referenced signal. However, to achieve the five voltage ranges, I use a combination of the following two methods:
- I used three different sine wave tables to feed the DAC, depending on voltage range.
- I used both of the MCP4922 DAC ranges (i.e., Vref and Vref x 2).
Using this method results in the DAC output waveform being centered on either Vref/2 or Vref/4, depending upon which full-scale option I am using for that particular range. This would require that the offset bias I applied to the output buffer to have to change from range to range.
To simplify the circuitry, I made use of the MCP4922’s dual DAC. When feeding the DAC with the sine wave values, I feed DACA with the sine signal, and DACB with the inverse of the sine signal. In other words, the DAC produces two sine waves that are 180° out of phase. The output buffer chip is configured as a differential amplifier. When fed with these 180° out of phase signals, the DC offsets present in both DAC outputs, are common-mode signals and cancel out. This produces a bipolar sine wave signal at the output of the output buffer chip. This sine wave signal can be set for frequencies of 50Hz, 60Hz, 180Hz, or 360Hz.
I used an LM675 power op-amp as the DAC output buffer. It has a gain of 2.3 (using common resistor values for R2, R3, R4, R5). This provides a maximum peak AC signal to 10V on the 10V range, when the DAC is putting out it’s maximum output ( 2.16V x 2 or 4.32V). The LM675 amplifier is easily able to provide enough drive current for the highest current range of 100mA, even without a heatsink.
The buffer amplifier’s output must be fed through a resistor before being applied to the component under test. I settled upon four, decade-related resistance values—100Ω, 1000Ω, 10kΩ, and 100kΩ. Selecting among these resistors would be somewhat difficult electronically, due to the AC voltages present and the reasonably high current (up to 100mA). Therefore, I used four relays to accomplish this. The Cotu 9007-05-1 reed relays are perfectly suited to this task. They can handle 1A current and more importantly, their coils will operate on 3.3V, drawing less than 10mA current. That allowed me to drive them directly using the ESP32’s GPIO pins. This version of the relay also contains a built-in diode to protect the ESP32’s GPIO lines from the inductive spike that occurs when they are shut off.
To supply a bipolar sine signal with a peak amplitude of 10V and a 100mA peak current capacity, I needed to supply the LM675 with ±12V. I chose the most compact and reasonably priced power source that I could find: a Traco Power TMH-0512D isolated DC/DC converter. This takes an input voltage of 5V and outputs an unregulated ±12V. I had to make a small compromise here—the TMH-0512D has a maximum output current of 83mA, which is just shy of the 100mA current on the highest current range.
As mentioned earlier, an MCP3910 ADC is used to measure both the voltage across the component under test, and the current through it. Specifically, I used a MikroElektronika Power Meter 2 Click board (part number MIKRO-3150). This Click board is one of more than 1000 Click boards that MikroElektronika produces, all of which share a common PCB pinout. Figure 2 shows this module with the three modifications that I made to it. The MIKRO-3150 board contains the MCP3910 ADC, a crystal, and some passive components. The MCP3910 requires an external clock crystal, which can go up as high as 16MHz. Although MikroElektronika’s schematic for this board shows a 20MHz crystal, that is incorrect—a 12MHz crystal is what is mounted.

This shows the MIKRO-3150 Click board containing the MCP3910 ADC. The three modifications that I made are shown.
Figure 3 shows a diagram of the ADC input circuitry on the MIKRO-3150 module. Note that, from the factory, this module has JP1 set to measure the board’s Vcc. That jumper must be changed to measure the voltage across J1 (the Voltage input to Channel 0 of the MCP3910 ADC). The board implements a 40:1 attenuator using a 39kΩ and 1kΩ resistor. This was chosen to provide a full-scale voltage range of 24V. For this project, I shorted out the 39kΩ resistor (R2) and used an external 20kΩ resistor in its place (R12 on my schematic). This reduces the full-scale voltage range to ±12.8V, which is ideal given the maximum range of ± 10V that I am using.
To measure current, the MIKRO-3150 module uses an 0.03Ω resistor (R4) and places it in the ground return path of the load being measured. Because I only needed to measure currents up to 100mA, I replaced R4 with a 1.2Ω resistor. Both resistor changes can be seen in Figure 2, as well as the change to JMP1 jumper, which is also necessary.
Because the load impedance of Channel0 of the MCP3910 is only 21k, due to the resistive divider, I can’t read the voltage across the component under test directly, without undue loading of the component itself. Also, I needed to measure the voltage across the component under test itself. While the ADC is measuring with respect to ground, the component has a 1.2Ω resistor in its ground path, which would introduce some error. Therefore, I added a TPA1286 instrumentation amplifier, with a gain of one, between the component under test and the Channel 0 input of the MIKRO-3150 module. The TPA1286 positive and negative inputs are connected directly across the component under test. At the output of the TPA1286 amplifier, I added a 20kΩ resistor to replace the 39kΩ resistor (R2) that I shorted out on the MIKRO-3150 module.
Figure 4 shows the schematic of this unit. Most of the circuitry has been previously described. Power for the unit is supplied by a 5V adapter that is capable of at least 2A. This 5V feeds the TMH-0512D DC/DC converter, which supplies the unregulated ±12V. It also feeds 5V to the DF Robot DFR0654 module containing the ESP32 MCU. As well, the MCP4922 DAC is fed this 5V power, allowing it to produce DAC outputs greater than 4V.
To allow this unit to easily provide component signatures for two matching components, on separate boards, I added S6, a double pole, double throw (DPDT) switch, which expands the single input into two channels—A and B. One part of the DPDT switch is connected to the ESP32’s GPIO A1 line. While the A1 line is normally an analog input, in this case it is configured as a digital input and must be pulled high by R13. Depending upon whether you are measuring the A or B channel, the display software will plot the voltage vs. current data on one of two available charts, labeled accordingly.
The ESP32 Firmware
I planned on using an Android cellphone or tablet for the entire user interface—both of which I had available. To communicate between the Signature Tester and the phone/tablet, I planned to use Bluetooth with the GUI-O program, which runs only on Android devices. I’ll discuss the GUI-O program later, but for now, I’ll just mention that for this application, I must run the GUI-O program using the legacy Bluetooth mode. From past experience, I’ve found that the BLE protocol is too slow for transferring the amount of data needed to plot the necessary charts. The Bluetooth legacy protocol is fine, however.
This means that I had to use a legacy ESP32 MCU, as later versions only support the BLE protocol. I chose the DF Robot DFR-0654 module, as it contains the proper ESP32 MCU. I keep this module on hand because it has some features that I find useful, even though not specifically needed here.
It was obvious to me right from the start, that generating a sine wave at frequencies up to about 400Hz, would involve some critical timing considerations. To provide what I considered to be the minimum resolution of the voltage vs. current chart, I decided that the sine waveform would be made up of 128 samples. At 400Hz, this would involve a sampling rate of 128×400 or 51,200sps. Unfortunately, the crystal on the MIKRO-3150 board, containing the MCP3910, was only 12MHz—not the maximum 16MHz at which the MCP3910 is rated. With this 12MHz crystal, and configuring the MCP3910 for a minimum of oversampling, I could achieve either a 46,875Hz or a 93,750Hz sample rate. To load the two DACs takes 5µs and to read both channels of the MCP3910 takes 13µs. There are many other operations/calculations that must take place for each sample, but the ADC and DAC SPI transfers take up the bulk of the time, per sample. The 18µs for DAC + ADC SPI transfers implies a maximum sample rate of 55.5KHz. I am therefore using a sample rate of 46,876.8Hz
With 128 sine wave segments, this set the highest sine wave frequency at 366.225Hz. For the lower frequency ranges, I used various oversampling ratios by averaging samples:
- 183.1Hz — two samples averaged
- 61Hz — six samples averaged
- 52Hz — seven samples averaged
In addition to the oversampling shown, which occurs for each of the 128 DAC values making the sine waveform, I also take an average over successive sine wave cycles. The higher the sine wave frequency, the more individual cycles get averaged. Therefore, regardless of the frequency setting, between 64 and 72 discrete ADC measurements are averaged, before sending them to be charted.
While 61Hz and 52Hz are not exact power line frequencies, they are close enough eliminate any small amount of 50Hz or 60Hz noise that might be picked up. In my user interface, I decided to label the frequencies 50Hz, 60Hz, 180Hz, and 360Hz.
Timing for the sine wave generation/sample collection was done by monitoring the MCP3910’s Data Ready signal, from within the sine wave generation program loop. This occurs every 21.33µs at the 46,876.8Hz sample rate. This Data Ready signal is an active-low signal which only lasts for 180ns. The only way to reliably capture this event, is by using a falling-edge pin-change interrupt on the ESP32. The ISR that services this interrupt merely sets a Boolean flag variable that is monitored in the sine wave generation loop.
Rather than entering a formula in my code to produce the 128 sine wave values, I used an online calculator to produce a 128-entry lookup table, which I then cut/pasted into my program. I use three such tables:
- One utilizing the full 12-bit number range (-2048 to +2047)
- One using the 12-bit full-scale divided by 5 (-400 to +400)
- One using the 12-bit full scale divided by10 (-200 to +200)
The first lookup table is used for the 10V and 5V range (using both of the DAC’s Vref and 2x Vref voltage options). The second table is used for the 2V and 1V range. The third table is used for the 0.5V range.
As mentioned earlier, at each sine wave segment, I feed the lookup table value into the MCP4922’s DAC A and a sign-inverted value into DAC B. This provides the 180° phase shift between DAC A and DAC B, needed for the LM675 differential buffer amplifier, which follows the DAC outputs. Also, in both cases, I add an offset of 2048 to the table values, to center the sine wave in the middle of the DAC’s voltage range. Figure 5 shows the LM675 output at 61Hz/10V and Figure 6 shows the 365Hz output. I use a 100Ω resistor (R6) in series with a 0.1µF capacitor (C4) across the LM675’s output to smooth out the 128-step digital sine wave produced by the DAC.
While the MCP3910 contains 24-bit ADCs, the raw values that it returns are nowhere near as accurate as the 24-bit resolution would lead you to believe. This device contains registers for both offset and gain calibration and it is imperative that you at least run a calibration routine to zero out any offset. This offset varies substantially for each of the six PGA gains that are available. In my program, I set both DAC A and DAC B to a value of 2047, which produces zero volts at the output of the LM675 buffer amplifier. I select the 100Ω series resistor and then take 64 ADC readings for each MCP3910 ADC channels. I repeat this for each of the six PGA gains. The average offset value for each channel, at each of the six PGA gains, is then stored, as a structure, in the ESP32’s (flash-emulated) EEPROM memory. When the unit is powered up, this offset calibration structure is retrieved. Whenever an MCP3910 PGA gain is set, the corresponding 24-bit offset value is loaded into the MCP3910’s offset register, thus compensating for the inherent offset error present in the PGA/ADC signal chain. The MCP3910 also has provisions to compensate for gain inaccuracy, for each channel and PGA setting. However, I found that the gain inaccuracy was less than 1% on all PGA ranges. In this project, that amount of error was not significant, so I did not perform any gain calibration.
For each of the five voltage ranges, I select a PGA gain that utilizes most of the ADC’s full-scale range. The modified MIKRO-3150 board has a full-scale range of ± 12.8V. Depending upon the voltage scale selected, I use PGA gains between 1 (10V range) and 16 (0.5V range).
The GUI-O User Interface
The main reason for re-designing this project was to eliminate the circuitry and cost of a graphic TFT display and user interface. I briefly considered using the Wi-Fi capability of the ESP32 in conjunction with a webserver-based dashboard. The ESP32 has good web-server libraries available but to provide the necessary X-Y charts would require some Javascripts. I’m not really experienced in anything beyond basic webpage generation. While it’s easier to write native Android apps than IOS apps, I haven’t had much experience with these options either.
However, I have experience using the GUI-O Android app, which allows you to write all the necessary code in your host MCU program. The connection to either an Android phone or tablet can occur using Wi-Fi, legacy Bluetooth, BLE or a USB-serial cable.
GUI-O is available through the Google Play app. I’ve had it for some time now so when I check it out on the Google Play store, it only tells me that I have already paid for it- not its current price. However, it was $10 USD when I started using it.
I wrote a complete article about the GUI-O app in Circuit Cellar Issue 389. I’ll just cover some highlights of the GUI-O app here. The GUI-O Android app is basically an interpreter that parses commands coming in via the various connection methods mentioned earlier. These are ASCII-based command mnemonics and all the parameters associated with each command are also ASCII-based. In general, almost any object that you might find on an Android screen can be generated using one of GUI-O’s widgets. All these widgets can be tailored to your needs using the various parameters associated with that widget. Also, most of the sensors present in smartphones can be read and reported back to the host MCU, using the GUI-O app.
The GUI-O app supports multiple screens if your application requires that level of sophistication. My projects that utilize GUI-O, tend to favor the use of a tablet rather than a smartphone, which has allowed me to confine my dashboards to a single, large screen. Just as important, GUI-O supports both portrait and landscape mode: since I use a tablet, landscape mode is the better choice.
Whenever you develop a graphical user interface (GUI), positioning all the screen items can be an involved task, especially given that the physical co-ordinates and size/aspect ratios of the various screen items must be determined. Having developed many GUIs for PCs, using Visual Basic, I was accustomed to the ease of Visual Basic’s drag-and-drop method for placing and customizing these screen items.
The developer of GUI-O provides a free PC program called GUI-O Designer. This program runs under Windows or Linux. While not quite as slick as Visual Basic’s operation, the GUI-O designer program allows you to choose the widgets that you need and set their characteristics. As you insert these widgets, they appear on your phone/tablet in real time. Therefore, it’s relatively easy to configure each widget in terms of position, size, and other characteristics. The communication between your PC and the target phone/tablet, used by this GUI-O Designer app, is either via a USB-serial cable connected to the phone or a Wi-Fi TCP/IP connection. Figure 7 is a screen capture of this program. The middle window contains the widgets you have chosen, and the adjacent window to the right will show all the parameters available for any chosen widget. There is also a status window at the far right, which displays all messages coming in from the phone (i.e., those messages that are sent when you push a button or move a slider, on the phone). Figure 8 shows a subset of the GUI-O widgets that are available.
Figure 9 shows this project’s dashboard as displayed on my Lenovo tablet. There are two X-Y charts: Chan A and Chan B. The voltage across the component is graphed on the X axis, and the current through it is on the Y axis. This unit has two inputs, labeled A and B. The idea here is to take the signature of component(s) on a working PCB or circuit, using one of the A,B inputs, which will be displayed on the corresponding chart. The corresponding component on the non-functioning PCB board is measured by switching to the other input. You can visually compare the two charts to see if they differ—in which case you have either found the bad component, or there is another component connected to it that can also cause the discrepancy in the charts.

This is a screen capture of the dashboard for this instrument, as displayed on my Lenovo Tablet.
Below the two charts are the four parameters you can select. The frequency slider is self-explanatory. The voltage slider sets the peak output voltage provided by the DAC. Since this is a symmetrical sine wave, the peak-to-peak voltage will be twice this number. You can select between the four series resistors in the 100Ω to 100kΩ range using the resistance slider. The sensitivity of the current measurement can be varied between 0.1mA and 100mA using the F.S. Current slider. When adjusting the voltage and current sliders, the scaling on the chart will be adjusted to reflect these full-scale values.
— ADVERTISMENT—
—Advertise Here—
If you had many different components to test, it would make sense that the corresponding charts for good components could be saved in some way. I use the ESP32’s LittleFS file system for this purpose. When developing/flashing this project’s sketch, I had to select the following Partition, using the Arduino Tools menu:
No OTA, 2MB APP/ 2MB SPIFFS
This basically allocates the ESP32’s 4MB Flash memory to use 2MB for program space, 2MB for the LittleFS filespace and no space for Over The Air re-programming. A file for each component is 512 bytes for the chart X-Y data plus 16 bytes for the four parameters. I am uncertain how LittleFS allocates the Flash memory in terms of file sector size. However, even if it uses 1024 bytes per record, the 2MB file partition should hold more than 1000 component signatures.
I didn’t implement a fancy file naming structure for this feature. Instead, the filenames are merely sequentially numbered, starting at 1. To save the currently displayed signature, shown in Chan A in Figure 9, you do one of the following:
- Enter the desired signature number in the yellow window labelled Current Signature #. Then press Save.
- Press Save Next to save it to the next number following the one showing in the Current Signature # window.
- To load a signature (always goes to the Chan B chart), you do one of the following:
- Enter the desired signature in the yellow window.
- Use the Load Next or Load Prev. to cycle through other saved signatures.
I mentioned that the unit has two inputs, which are selected by a physical toggle switch on the unit itself. The A and B status lights will reflect that setting, and the appropriate chart will be used to display the signature for the component connected to that input.
The offset calibration routine, that I mentioned earlier in the article, is triggered by pressing the Calibrate button. I have found that the offset values for each PGA setting, do not change markedly over time, so this procedure will only have to be performed infrequently, and it only takes a few seconds.
Looking at Chan A in Figure 9, the linear ramp is representative of what you would see for a resistor or other strictly resistive component. A (good) diode will show a trace in which the current is virtually zero until it’s forward and reverse breakdown voltage thresholds are reached, after which the current will rise rapidly. The same thing would apply to bipolar transistor junctions. Capacitors will show an oval shape—tending toward a circle if the capacitor has a low enough reactance at the relatively low frequencies used in this unit. Small value capacitors will just display a basically level horizontal line.
With any component measurement, you must select a DAC voltage output that is safe for the component being tested. You would also tend to select a high value for the series resistor and then work your way down if there was negligible current being drawn, as it appears on the Y-axis.
Fewest Possible Components
Figure 10 shows a photo of the circuit board for the unit. It contains all the components except for the 5V 2A power adapter, the DPDT A-B switch and the A-B inputs (female banana sockets). Figure 11 shows the completed unit.

This is the circuit board for the project. Only the power adapter and input switch/sockets are not shown.
By utilizing a cellphone/tablet user interface, I’ve managed to reduce the components needed for such an instrument down to what I consider to be the least number of parts possible. This version of a signature analyzer has many fewer components than my earlier version and costs about a quarter of what that unit did. Some of that reduction can be attributed to the versatility of Microchip’s MCP3910 Dual ADC chip, which eliminated much of the analog circuitry used in the previous version.
RESOURCES
3Peak | https://www.3peak.com
DF Robot | https://www.dfrobot.com
Microchip | https://www.microchip.com
MikroElectronika | https://www.mikroe.com
Traco Power | https://www.tracopower.com
SOURCES
DF Robot ESP32 FireBeetle 2 board (DFR-0654):
https://www.dfrobot.com/product-2231.html?srsltid=AfmBOoo7ER8dE65iOwnTOUWYjBJChfouuetMujc5scn4a9Pgr2UoIyqM
Microchip MCP3910 Datasheet:
https://ww1.microchip.com/downloads/aemDocuments/documents/MSLD/ProductDocuments/DataSheets/MCP3910-3V-Two-Channel-Analog-Front-End-Data-Sheet-DS20005116D.pdf
Microchip MCP4922 DAC Datasheet: MCP4902/4912/4922 Data Sheet
MikroElectronika MIKRO-3150 Click board: PWR Meter 2 click | Mikroelektronika
Traco Power DC/DC converter TMH-0512D: TMH 0512D | Traco Power
TPA1286 Instrumentation Amplifier datasheet: TPA1286 – Instrumentation Amplifiers – 3PEAK

Brian Millier runs Computer Interface Consultants. He was an instrumentation engineer in the Department of Chemistry at Dalhousie University (Halifax, NS, Canada) for 29 years.








