RoadTest: Keithley Bench Digital Multimeter
Author: neuromodulator
Creation date:
Evaluation Type: Test Equipment
Did you receive all parts the manufacturer stated would be included in the package?: True
What other parts do you consider comparable to this product?:
What were the biggest problems encountered?:
Detailed Review:
Keithley Instruments was founded in 1946 by Joseph F. Keithley after earning a Bachelor of Science and a Master of Science degree from the MIT. The company began its operations in a small workshop at the end of an alley in Cleveland, and hired its first employee, John Yeager in 1950. Throughout its history, the company has mainly focused on DC instruments, and made a reputation out of the high quality DMMs, SMUs, and sensitive instruments such as electrometers, picoammeters and nanovoltmeters. These days Keithley Instruments is part of Tektronix, which along with Fluke are part of Fortive, a diversified conglomerate that spun off from Danaher.
The digital multimeter (DMM) DMM6500 and the data acquisition system DAQ6510, introduced in the first half of 2018, are part of the ongoing effort of Keithley to modernize the user interface and experience of their test equipment. “Touch, test, invest” (TTI) is the name of Keithleys new line of touchscreen-based test equipment, which was launched in 2013 with the 2450 SMU, and is slowly replacing its previous VFD-based line. The DMM6500 and DAQ6510 come 3 years after the release of the first TTI DMM, the 7½ digits DMM7510.
Compared to previous 6½ digits Keithley DMMs, the DMM6500 offers increased sensitivity and a wider range of measurements. The measurement capabilities of the instrument are:
• DC and AC true RMS voltage
• DC and AC current
• 2- and 4-wire resistance
• Continuity
• Capacitance
• Frequency and period
• Diode forward voltage drop
• Thermocouple, thermistor, 2-, 3- and 4-wire RTD temperature
• Voltage digitalization
• Current digitalization
The following table shows how the instrument compares to other Keithley DMMs.
Source: Tek/Keithley
The next image shows the measurement capabilities of the 3 TTI DMMs that have been launched so far:
Source: Tek/Keithley + edition
As it can be seen, the DMM6500 and the DAQ6510 have very similar measuring capabilities, with the maximum supported current being the only difference. This is because their main difference lies in the back of the instrument, whereas the DMM6500 has rear inputs, including a 10 A current input, the DAQ6500 does not, and uses the freed-up space for two plug-in card slots instead. The DMM6500 comes with a single plugin-in card slot, but does not support the same cards than the DAQ6510. As the DAQ6510 is meant to be used for data acquisition, it supports a greater variety of plug-in cards compared to the DMM6500.
One way to visualize the features that make the DMM6500 a modern instrument is to contrast it to what could be considered its VFD predecessor, the Keithley 2000.
Source: Tek/Keithley + edition
The table shows major improvement over the Keithley 2000 that go beyond just better specs. The new hybrid button + touchscreen interface increases productivity through faster and simpler access to the DMM functions, easier readability and graphing abilities. The addition of voltage and current waveform digitization with 7 million points of memory allow the study of transients. USB ports were added to either control the instrument remotely or store data, that does not fit in the internal memory, in a pen drive. The added LAN connectivity allows easy remote access to either control or program the instrument. LUA programmability was added to the instrument through the Test Script Processor (TSP) scripting language, which contains instrument-specific control commands that can be run directly on the instrument. TSP-enabled instruments can even operate connected to other TSP-enabled instruments as a tightly synchronized multi-instrument system.
The user interface is the space where the interaction between the operator and the machine occurs. An important goal of user interface design is to produce a user interface which is simple, intuitive and efficient to the user. Good interface design makes a huge difference in productivity, it reduces the interaction time, chances of making mistakes, and repetitive and tedious tasks.
The DMM6500 can be controlled directly by physical interaction, through its web server, the Kickstart application, remotely through SCPI or TSP commands and TSP scripts running directly on the instrument. In the next sections I will describe the different interfaces of the instrument.
Test equipment user interfaces have gone a long way since the early days. At the beginning instruments were analog, making measurements was very time consuming as it required reading the analog output, and then transcribing the values. The LED and LCD digital readout display based test equipment changed that, reading values became easier, and remote control of the instruments through interfaces such as GPIB or RS-232 removed the burden of transcribing data. VFD based test equipment improved the readability and the amount of information that could be presented in the display. Color LCD display instruments added greater displaying possibilities, instruments were able to plot graphs and integrate complex GUIs. The integration of the ethernet port allowed instruments to be controlled from a web browser. Finally, the integration of touchscreens simplified the instrument usage by allowing the user to interact directly with what is being displayed, making the control of the instrument a seamless process.
Source: Tek/Keithley
In the front panel of the instrument we can see that Keithley took a hybrid approach and integrated physical and virtual buttons in their TTI instruments; physical buttons have the advantage of giving physical feedback and being harder to press by mistake, virtual buttons have the advantage of being flexible and customizable to the current state of the instrument. Keithley implemented as physical buttons the buttons the user may want to press independent of the current state of the instrument. The touchscreen also supports gestures such as swiping, pinching and zooming. I found that the easiest way to use the touchscreen is with the fingers parallel to the screen, if they are perpendicular, non-tightly-trimmed fingernails could interfere with the touch detection.
In the rear panel we have two slots for plugin cards, one for communication and the other for multichannel measurements. We also have the LAN and USB remote control interface, input and output trigger terminals and an additional 10 A current connector.
Source: Tek/Keithley
The Keithley DMM6500 comes with a crisp 5” 800x480 screen with good color reproduction at wide viewing angles. When powered on it takes around 15 s to initialize to start and switch to the direct current voltage measurement screen. The measurement screen has three regions, a status, a measurement and tab region. The status region displays information of how the instrument is being accessed (locally or remotely), the active reading buffer, the running script, the triggering mode and the error log. The measurement region shows measurement related information and provides a button to select the measurement range. The tab region provides different tabs to perform a varied set of tasks.
The measurement screen provides multiple buttons and swiping regions. Left or right tab switching can be done by either swiping the bottom region or pressing the “invisible” left and right buttons next to the middle dot of the middle region. The measurement region can be maximized through either swiping the middle region to the bottom or pressing either of the arrows in the middle region. At the top of the screen there are multiple regions that allow configuring the instrument or checking the system log.
There are 5 basic tabs, which can be expanded to 6 through scripts (or more when using a multichannel card). The statistics tab provides statistics of the data that has been captured. The secondary tab can be used to make a secondary measurement at the same time, on some measurement combinations this could cause continuous relay activity to quickly switch between the primary and secondary measurement. The function tab provides buttons to select between 15 different measurements. The settings tab provides measurement specific settings. The graph tab plots the data from the active reading buffer as measurements are made.
The maximization of the primary measurement removes related measurement information and makes digits bigger and easier to read from the distance.
Multi-level menus are often tedious and confusing to navigate because of the complexity of their tree structure. Accessing a deep node in such systems may require multiple selections of child submenus or presses of the MORE soft-key, making the navigation very time consuming.
Keithley kept the menu navigation simple and efficient by providing a single level menu, making the access to the desired selection just a single icon press, similar to how its done on smartphones.
The captured data can be visualized in three different ways, as a graph, as a histogram or as a table of values. The graph plot can be panned and zoomed in or out through gestures or through manually entering the values. Analog to oscilloscopes, it also supports cursors that aid in making measurements. The histogram can be configured either automatically or manually and supports up to 700 bins as it can be seen in the screen capture. The table displays the content of the selected buffer as a table of values and also includes a plot that can be used to navigate the data.
The DMM6500 web interface can be used to check the instrument status, modify its settings (IP configuration, web password, and date/time), control it remotely through either the virtual front panel or through commands, and download buffer data as CSV files. The virtual front panel displays a real-time copy of the screen at a rate of ~3 refreshes/s and supports clicking/pushing and dragging/panning gestures. I found the virtual front panel particularly useful during development of TSP code as I could test the script without having to turn my head away from the computer screen. SCPI or TSP commands can be sent directly through the web interface and the command returned values read back as it can be seen in the screen capture.
KickStart is a program sold by Keithley that simplifies data collection of their power supplies, SMUs, dataloggers and DMMs. KickStart can be used with the DMM6500 as a datalogger when a multi-channel card has been attached, or as a DMM. The DMM mode simplifies the process of setting the instrument up for data acquisition and allows real-time inspection of the captured data. Captured data can be inspected as a table of values or a graph, and can be exported as CSV, XLSX, or as a graph image.
The most flexible (and eventually time consuming) way to control the instrument is through SCPI or TSP commands, or TSP scripts. Besides the web interface, remote commands can be sent through either Telnet (port 23), VXI-11 (port 1024) or raw sockets (port 5025). SCPI and TSP commands are roughly equivalent, but TSP supports scripts that can be executed from a stand-alone instrument. SCPI commands still have their niche, as the SCPI interface can emulate the Keithley 2000 or the Keysight 34401, making code developed for those DMMs compatible with the DMM6500.
TSP can be used in two different ways, as a series of commands sent by a computer, analog to how SCPI commands work on any other instrument, or as a script that runs in a stand-alone instrument. A TSP script can be loaded into the instrument from a remote computer or an USB drive. TSP commands can be function-based or attribute-based, function-based commands are commands that control actions or activities, attribute-based commands define characteristics of an instrument feature or operation.
An example of a short sequence of TSP commands that a computer could send to the instrument to make a 4-wire resistance measurement is shown below:
-- Reset the instrument settings to their default values reset() -- Set the measurement mode to 4 Wire resistance dmm.measure.func = dmm.FUNC_4W_RESISTANCE -- Make the measurement, concatenate the string to " Ohm" and print it print(dmm.measure.read() .. " Ohm")
The command sequence produced the following output on my computer when tested on a 4.7K resistor:
4696.5598276 Ohm
And the following output on the DMM screen:
To load a script from a USB drive into the instrument, the script must be stored in the drive as text file with “tsp” as extension and then copied with the script manager into the instrument memory. A script can also be loaded remotely using the “loadscript” and “endscript” commands as shown in the example below:
-- Initial marker that tells the instrument that the next lines are part of a script called “DiodeVF” loadscript DiodeVF -- Reset the instrument settings to their default values reset() -- Set the measurement mode to 4 Wire resistance dmm.measure.func = dmm.FUNC_DIODE -- Set the bias level to 10 mA dmm.measure.bias.level = 0.01 -- Make first measurement vf0 = dmm.measure.read() -- Switch to user tab display.changescreen(display.SCREEN_USER_SWIPE) -- Print the first measurement as specified by the format in the first row of the user tab display.settext(display.TEXT1, string.format("Vf0: %.3f V", vf0)) -- Wait 10 s delay(10) -- Make second measurement vf1 = dmm.measure.read() -- Print the second measurement as specified by the format in the second row of the user tab display.settext(display.TEXT2, string.format("Vf1: %.3f V", vf1)) -- Marker that tells the instrument that the script ends here endscript
After remotely executing the previous sequence of commands, the code between "loadscript" and "endscript" is stored in a script called "DiodeVF". When the script button is pressed, a list of available scripts appears, a second press over the script immediately executes it. When execution begins the script button displays the name of the script next to a runner. The script example measures the forward voltage at 10 mA bias, keeps the LED on for 10 s at that bias and then makes a second measurement. The results are displayed in the user tab, which is a special tab that can be used by scripts to print results. I ran the example script with a white LED, and as expected the heating of the LED reduced the forward voltage drop.
Keithley provides two tools to send remote commands to the instrument, the Keithley Test Script Builder (TSB), and the Keithley Communicator. The TSB is an Eclipse-based IDE with syntax highlight and debugging capabilities. The Communicator is a lightweight tool that lacks syntax highlight and debugging.
In the next experiments I will show how the instrument can be used to perform more realistic tasks. None of these experiments are meant to be taken as examples of how to perform precise measurements (as that would require a far greater effort), the focus of this section is to explore how to use the different instrument features.
A diode is a two-terminal electronic device that facilitates current conduction in one direction and blocks it in the opposite direction. There are many different types of diodes with different electrical characteristics. One way to characterize them is through their I-V curve, which describes the relationship between the current and the voltage of a device. An I-V curve can be traced easily with an SMU, such as a the Keithley 2450, but here I’ll show how the DMM6500 could be used to get a crude trace of the first I-V quadrant of a diode, without the need of any other instrument.
To make good measurements some key parameters of the instrument must be set, the autozero, the autodelay, the aperture and the filter. Autozero reduces the instrument measurement drift by making it automatically check the reference measurements whenever a signal measurement is made. Autodelay adds a delay period at the end of a measure-related setting change to allow cables or internal circuitry to settle for best measurement accuracy. The aperture (amount of time the signal is measured) affects the time required to make the measurement, the level of noise, and the amount of drift (as seen in the figure) of the measurements. The filter reduces noise by averaging multiple measurements.
Source: Tek/Keithley
The diodes were measured with autozero and autodelay enabled and the filter disabled. To avoid heating the LEDs and at the same time get good accuracy, the aperture was set to 1 PLC (power line cycle) which is 20 ms where I live. The measurements were performed at 4 current levels: 10 μA, 100 μA, 1 mA and 10 mA. The used script is shown below:
-- Switch to user swipe screen and clear it display.changescreen(display.SCREEN_USER_SWIPE) display.clear() -- Set the diode function parameters dmm.measure.func = dmm.FUNC_DIODE dmm.measure.autozero.enable = dmm.ON dmm.measure.autodelay = dmm.DELAY_ON dmm.measure.nplc = 1 dmm.measure.filter.enable = dmm.OFF -- Measure diode at 10 mA and print results on screen dmm.measure.bias.level = 1e-2 v2 = dmm.measure.read() text2 = string.format("V2: %.3f", v2) display.settext(display.TEXT2, text2) -- Measure diode at 1 mA and print results on screen dmm.measure.bias.level = 1e-3 v3 = dmm.measure.read() text2 = string.format("V3: %.3f, ", v3) .. text2 display.settext(display.TEXT2, text2) -- Measure diode at 100 uA and print results on screen dmm.measure.bias.level = 1e-4 v4 = dmm.measure.read() text1 = string.format("V4: %.3f", v4) display.settext(display.TEXT1, text1) -- Measure diode at 10 uA and print results on screen dmm.measure.bias.level = 1e-5 v5 = dmm.measure.read() text1 = string.format("V5: %.3f, ", v5) .. text1 display.settext(display.TEXT1, text1) -- Return all measured values to the Python program print(v5) print(v4) print(v3) print(v2)
The script execution was controlled by a python program that communicated to the instrument through the PyVisa library. The program first loads the previous script into the instrument and names is “DiodeIV”. Every time the user presses Enter, the program executing the “DiodeIV” script and then stores the results in a list. Pressing the Esc key saves the list in a file and exits the program.
import visa import numpy import time import keyboard # Connect to the instrument, set the timeout and clear the buffer keithley = visa.ResourceManager().open_resource('TCPIP0::192.168.0.30::inst0::INSTR') keithley.timeout = 30000 keithley.clear() # Delete script if it script exists, then load the script from the file keithley.write('reset()') keithley.write('script.delete("DiodeIV")') keithley.write('loadscript DiodeIV') with open("DiodeIV.tsp") as file: keithley.write(file.read()) keithley.write('endscript') # Set initial values for the measurement list, and the last time a measurement was made iv = [] lastProbe = 0 while True: # if Enter is pressed and more than 1 second has passed since the last time we made a measurement if keyboard.is_pressed('enter') and (time.time() - lastProbe > 1.): # Execute the script, read values and append them to the measurement list keithley.write('DiodeIV()') v5 = float(keithley.read()) v4 = float(keithley.read()) v3 = float(keithley.read()) v2 = float(keithley.read()) iv.append([v5, v4, v3, v2]) # print the forward voltages print("Vfs: %.4f, %.4f, %.4f, %.4f" %(v5, v4, v3, v2)) # Save the last time that a measurement was made lastProbe = time.time() # If Esc is pressed save data and quit if keyboard.is_pressed('esc'): numpy.save("Data.npy", iv) keithley.close() quit()
8 Different LEDs were tested and their I-V curves were plotted in a semi-log graph. As expected, in most cases the diode curves looked very close to a straight line, with the exception of the green LED, which at at higher currents "bends" likely due to its high series resistance.
To show why diode I-V curve looks like straight line in a semi-log graph we will need the Shockley diode equation, which defines the relationship between current and voltage across a diode:
Where:
I is the diode current.
Is is the reverse bias saturation current.
V is the voltage across the diode.
n is the quality factor.
VT is the thermal voltage (~25.7 mV at 25 ºC).
The thermal voltage is defined as:
Where:
k is the the Boltzmann (1.38064852×10−23 J/K).
T is the absolute temperature of the p-n junction.
q is the magnitude of the electrical charge on the electron (1.6021766208×10−19 C).
Usually the LEDs will be driven at voltages where:
So we can rewrite the Shockley equation as:
If we apply a logarithm to the previous approximation we get:
As we can see, the right side of the equation is a line equation with slope of 1/(nVt) and an intercept of log(Is). With that in mind with 2 points we can solve the slope and intercept, and from those 2, also solve the "n" and the "Is":
I computed the the Is and n values out of the 10 μA and 10 mA points and then computed the voltage and current of the points at 100 μA and 1 mA.
When using the voltage to compute the current, the error was:
11.6% at the 100 μA measurement
10.5% at the 1 mA measurement
When using the current to compute the voltage, the error was:
0.467% at the 100 μA measurement
0.388% at the 1 mA measurement
And here we can see the plot in a log and non-log current scale:
Of course there are many other ways to fit a curve, for instance the curve could have been fitted with a linear regression taking into account all 4 measurements, or the curve could be a piecewise function where Is and n could be computed for each of the 3 intervals, or the non-approximated Shockley equation could also have been fitted to the measurements through the use of numerical methods.
Human hearing has a high dynamic range and is capable of sensing sounds that go from roughly 20 to 20,000 Hz. To characterize analog audio signals, we ideally need an instrument with high dynamic range, but not necessarily high bandwidth.
As shown previously, the instrument can digitize voltage or current at a resolution of 16 bit and a sampling rate that goes from 1 k/s to 1 MS/s. The digitized data can be stored in the internal memory of 7 MS or, depending on the sampling frequency, streamed to a computer. Kickstart is especially useful for digitization, but not as flexible TSP scripting, which is what I will show next.
There are many different tests that can be performed to characterize audio equipment, let’s see how we can use TSP scripts and Python code to record the signal for analysis.
On my first audio experiment I wanted to compare two audio signal sources, a sound card and a 14-bit DDS function generator and see which of the two generates the purest 1 kHz sine wave. I used the Python “sounddevice” library to play a 1 kHz sine wave on the sound card (if required), ran a TSP script to capture the data, and then downloaded the data as 32-bit floating-point numbers (Single-precision IEEE Std 754) from the instrument. The TSP script and Python program are shown below:
-- The Python program replaces the format specifiers with values before uploading the script to the instrument sampleRate = %i time = %f range = %i count = math.ceil(sampleRate * time) -- Reset the instrument reset() -- Switch to user swipe screen and inform that we are "digitizing" display.changescreen(display.SCREEN_USER_SWIPE) display.clear() display.settext(display.TEXT1, "Digitizing...") -- Make as much memory available as possible by setting the default buffers to their minimum size, then create the audio buffer defbuffer1.capacity = 10 defbuffer2.capacity = 10 audioBuffer = buffer.make(count) -- Set the digitizer parameters dmm.digitize.func = dmm.FUNC_DIGITIZE_VOLTAGE dmm.digitize.range = range dmm.digitize.samplerate = sampleRate dmm.digitize.count = count -- Begin digitization dmm.digitize.read(audioBuffer) -- Inform the Python program that we are ready to upload data, and display that on the screen print("U") display.settext(display.TEXT1, "Uploading...") -- Set data format and upload data format.data = format.REAL32 format.byteorder = format.LITTLEENDIAN printbuffer(1, audioBuffer.n, audioBuffer.readings) -- Inform that execution is "complete" display.settext(display.TEXT1, "Complete!")
import time import visa import numpy import sounddevice # play audio? playAudio = True if playAudio: # Wave parameters rate = 192000 freq = 1000 duration = 90 # Generate the the sine wave t = numpy.arange(0, duration, 1. / rate) f = numpy.sin(2. * numpy.pi * freq * t).transpose() # Connect to the instrument, set the timeout and clear the buffer keithley = visa.ResourceManager().open_resource('TCPIP0::192.168.0.30::inst0::INSTR') keithley.timeout = 90000 keithley.clear() if playAudio: # Begin playing the generated wave without blocking the execution and wait 3 seconds to make sure the playback has began sounddevice.play(f, rate) time.sleep(3) # Delete script if it script exists, then load the script from the file and set the "sampleRate", "time" and "range" variables keithley.write('script.delete("Digitizer")') keithley.write('loadscript Digitizer') with open('Digitizer.tsp') as file: keithley.write(file.read() % (20000, 60, 10)) keithley.write('endscript') # Execute the script keithley.write('Digitizer()') print('Digitizing...') # Digest the 'U' script output, which indicates that the instrument is ready to upload keithley.read() if playAudio: # Stop playback sounddevice.stop() # Download data as a numpy.array print('Downloading...') v = keithley.read_binary_values(datatype = 'f', is_big_endian = False, container= numpy.array) # Save data print('Complete!') numpy.save('Data.npy', v) keithley.close()
Then I estimated the power spectral density (PSD) with Welch’s method:
The plot shows that the sound card has a lower and flat noise floor while the function generator appears to show 1/f noise. The harmonics, an indicator of linearity, shows again that the sound card performed better than the function generator.
On my second experiment I wanted to see how an amplifier affects an input signal, but instead of probing the effect of the amplifier in a single frequency I probed it in the whole human hearing spectrum. I performed a linear 20 to 20,000 Hz sweep with a function generator that was synchronized to the DMM6500 through the triggering port. Triggers on the DMM6500 can be set and used either directly or in conjunction with the trigger model. Direct usage usually requires fewer lines of code (unless trigger model templates are used). On the other, the trigger model, which a small program that runs on a separate processor and coordinates triggers and measurements, gives greater flexibility and tighter control, but usually at higher programming complexity.
The used TSP script and Python code are shown below:
-- Reset the instrument reset() -- The Python program replaces the format specifiers with values before uploading the script to the instrument sampleRate = %i time = %f range = %i count = math.ceil(sampleRate * time) -- Switch to user swipe screen and inform that we are "waiting" for the trigger display.changescreen(display.SCREEN_USER_SWIPE) display.clear() display.settext(display.TEXT1, "Waiting...") -- Make as much memory available as possible by setting the default buffers to their minimum size, then create the audio buffer defbuffer1.capacity = 10 defbuffer2.capacity = 10 audioBuffer = buffer.make(count) -- Set the digitizer parameters dmm.digitize.func = dmm.FUNC_DIGITIZE_VOLTAGE dmm.digitize.range = range dmm.digitize.samplerate = sampleRate dmm.digitize.count = count -- Set the external trigger and wait until the rising edge gets detected or function times out trigger.extin.edge = trigger.EDGE_RISING trigger.extin.clear() triggered = trigger.extin.wait(time) if triggered then -- A rising edge was detected, inform the Python that we are digitizing print("D") display.settext(display.TEXT1, "Digitizing...") dmm.digitize.read(audioBuffer) -- Inform the Python program that we are ready to upload data, and display that on the screen print("U") display.settext(display.TEXT1, "Uploading...") -- Set data format and upload data format.data = format.REAL32 format.byteorder = format.LITTLEENDIAN printbuffer(1, audioBuffer.n, audioBuffer.readings) -- Inform that execution is "complete" display.settext(display.TEXT1, "Complete!") else -- No riding edge was detected, inform the Python program and display error on the screen print("E") display.settext(display.TEXT1, "No trigger detected!") end
import visa import numpy # Connect to the instrument, set the timeout and clear the buffer keithley = visa.ResourceManager().open_resource('TCPIP0::192.168.0.30::inst0::INSTR') keithley.timeout = 90000 keithley.clear() # Delete script if it script exists, then load the script from the file and set the "sampleRate", "time" and "range" variables keithley.write('script.delete("TriggerDigitizer")') keithley.write('loadscript TriggerDigitizer') with open("TriggerDigitizer.tsp") as file: keithley.write(file.read() % (100000, 30, 10)) keithley.write('endscript') # Execute the script keithley.write('TriggerDigitizer()') print("Waiting...") # if the script outputs 'D', digitization has begun if (keithley.read() == 'D\n'): print("Digitizing...") # Digest the 'U' script output, which indicates that the instrument is ready to upload keithley.read() # Download data as a numpy.array print("Downloading...") v = keithley.read_binary_values(datatype = 'f', is_big_endian = False, container= numpy.array) # Save data print("Complete!") numpy.save('Data.npy', v) else: # the script outputted 'E\n' (error), which means that the instrument did not detect a rising edge print("No trigger detected!") keithley.close()
I then computed the spectrogram and PSD of the of the input and output (speaker ouput) amplifier signals:
By comparing the input and output spectrograms it can be observed that even though the input signal contains harmonic components, the amplifier increases them. Its also noticeable that the amplifier also increases the overall noise. When looking at the PSD plot, it can be seen that the amplifier does a fairly good job at reproducing the input frequency response.
To see the effect that the tone control knobs have on the signal I recorded multiple sweeps on different conditions: with tone defeat button on or off and with the bass and treble knobs moved to the minimum or maximum:
The tone defeat button allows the signal to bypass the tone control circuitry, but in practical terms, every time I tested the button (with music), I could not sense any difference between its active and non-active state (with the bass and treble at their neutral position). The PSD on the other side clearly shows that the frequency response of the activation of the tone defeat is much closer to the input signal than when it is turned off. The last plot shows that the bass and treble knobs mostly affect what is below or above 1 kHz.
One common challenge of internet of things (IoT) devices is to reduce its power consumption so that they can make the best use of their limited available energy. Many microcontrollers and sensor support different operating modes to reduce power consumption. One way microcontrollers can reduce the consumption is by staying in sleep mode most of the time and only briefly waking up to perform their programmed tasks such as acquiring sensor data, processing it and transmitting it wirelessly. Here I will show how to use the DMM6500 programmatically to profile the current consumption of an ESP32 battery-powered microcontroller board.
The ESP32 is a low-cost 240 MHz dual-core microcontroller with integrated WIFI and Bluetooth support. My ESP32 board also comes with a 128x64 organic LED (OLED) screen, an 18650-battery holder, USB-bridge and battery charging integrated circuits (ICs) and LEDs.
There are many different approaches to reduce the ESP32 power consumption (clock speed reduction, wireless usage minimization, ultra-low power (ULP) coprocessor usage, etc.), but I will only explore the sleeping modes of the microcontroller. The ESP32 provides two sleeping modes, light and deep sleep. Light sleep keeps the current state of the microcontroller and allows it to continue the execution from where it went to sleep, Deep sleep, on the other hand, requires the reinitialization of the microcontroller.
To measure the current consumption, I wrote a simple ESP32 program that sets pin 21 high 5 ms before and after doing any of the following tasks:
The purpose of sleeping for 0 ms is to compute the time and consumption overhead of each sleeping mode. The program is shown below:
#include <arduino.h> #include "esp_sleep.h" const uint8_t ledPin = 16; const uint8_t triggerOut = 21; const int separation = 5; const int modeDuration = 100; const int uploadDuration = 15000; RTC_DATA_ATTR unsigned restart = 0; auto begin() -> void { digitalWrite(triggerOut, 1); delay(separation); } auto end() -> void { delay(separation); digitalWrite(triggerOut, 0); } auto setup() -> void { restart++; delay(separation); pinMode(triggerOut, OUTPUT); digitalWrite(triggerOut, 1); delay(1); digitalWrite(triggerOut, 0); pinMode(ledPin, OUTPUT); digitalWrite(ledPin, 1); Serial.begin(115200); if (restart == 1) { for (int i = 0; i < 10; i++) { digitalWrite(ledPin, 0); delay(500); digitalWrite(ledPin, 1); delay(500); } } else delay(uploadDuration); if (restart == 1) { Serial.print("\n\nDeep sleep (no delay)...\n"); Serial.flush(); esp_sleep_enable_timer_wakeup(0); begin(); esp_deep_sleep_start(); } if (restart == 2) { Serial.print("\n\nDeep sleep (delayed)...\n\n\n"); Serial.flush(); esp_sleep_enable_timer_wakeup(1000 * modeDuration); begin(); esp_deep_sleep_start(); } if (restart > 2) for (int mode = 0; mode < 4; mode++) { if (mode == 0) { Serial.print("Light Sleep (no delay)...\n"); Serial.flush(); esp_sleep_enable_timer_wakeup(0); begin(); esp_light_sleep_start(); end(); } if (mode == 1) { Serial.print("Light Sleep (delayed)...\n"); Serial.flush(); esp_sleep_enable_timer_wakeup(1000 * modeDuration); begin(); esp_light_sleep_start(); end(); } else if (mode == 2) { Serial.print("Idle...\n"); begin(); delay(modeDuration); end(); } else if (mode == 3) { Serial.print("Computation...\n"); volatile int i0 = 1234567890; volatile int i1 = 12345; volatile int iv; volatile float f0 = 1/3; volatile float f1 = 2/3; volatile float fv; volatile double d0 = 1/3; volatile double d1 = 2/3; volatile double dv; begin(); auto t0 = millis(); while (true) { for (int i = 0; i < 50; i++) iv = i0 + i1; iv = i0 - i1; iv = i0 * i1; iv = i0 / i1; fv = f0 + f1; fv = f0 - f1; fv = f0 * f1; fv = f0 / f1; fv = std::pow(f0, f1); dv = std::sin(d0); dv = d0 + d1; dv = d0 - d1; dv = d0 * d1; dv = d0 / d1; dv = std::pow(d0, d1); dv = std::sin(d0); if (millis() - t0 > modeDuration) break; } end(); } delay(uploadDuration); } Serial.print("Restarting...\n"); delay(5000); esp_restart(); } void loop() { }
I used a power supply at 3.7 V to power the microcontroller battery connectors with the DMM6500 in series to measure the current. Instead of manually waiting for the trigger to detect a rising edge, as in the previous audio experiment, I used the trigger through a trigger model. A trigger model is program that run on a separate processor and coordinates measurements and trigger inputs and outputs. A trigger model can be built either through the instruments interface or programmatically. My trigger model begins measuring current as soon as it detects a rising edge at pin 21 of the ESP32. The code to build the trigger model and its graphical representation are shown below:
trigger.model.setblock(1, trigger.BLOCK_BUFFER_CLEAR, currentBuffer) trigger.model.setblock(2, trigger.BLOCK_WAIT, trigger.EVENT_EXTERNAL, trigger.CLEAR_ENTER) trigger.model.setblock(3, trigger.BLOCK_MEASURE_DIGITIZE, currentBuffer, trigger.COUNT_AUTO)
A trigger model always begins with an Idle block at position 0. The execution of the model stays at the Idle block until the model is initialized, and just then it moves to the next block at position 1. In my model, the position 1 block clears the buffer. The wait block clears any previously detected external trigger input signal and waits for a new external trigger input signal. The external trigger input is configured outside of the trigger model to detect raising edges, and whenever one is detected, a signal is sent to the trigger model processor, which will move execution to the next block. The block 3 begins the digitization of the current until the buffer gets filled. The execution then moves back to the Idle block and and stays there until the model is reinitialized.
The TSP code was divided into two parts, the first part initializes the environment, by setting the buffer, the current digitizer, the trigger, the trigger model and the data upload format. The second part initializes the trigger model, uploads the results to the Python program and displays information on the instruments screen. By dividing the TSP code in two parts, only the second part is called every time a new digitization is required.
-- The Python program replaces the format specifiers with values before uploading the script to the instrument sampleRate = %i time = %f range = %i count = math.ceil(sampleRate * time) -- Reset the instrument reset() -- Make as much memory available as possible by setting the default buffers to their minimum size, then create the current buffer defbuffer1.capacity = 10 defbuffer2.capacity = 10 currentBuffer = buffer.make(count) -- Set the digitizer parameters dmm.digitize.func = dmm.FUNC_DIGITIZE_CURRENT dmm.digitize.range = range dmm.digitize.samplerate = sampleRate dmm.digitize.count = count -- Set the external trigger to detect rising edges trigger.extin.edge = trigger.EDGE_RISING -- Create trigger model trigger.model.setblock(1, trigger.BLOCK_BUFFER_CLEAR, currentBuffer) trigger.model.setblock(2, trigger.BLOCK_WAIT, trigger.EVENT_EXTERNAL, trigger.CLEAR_ENTER) trigger.model.setblock(3, trigger.BLOCK_MEASURE_DIGITIZE, currentBuffer, trigger.COUNT_AUTO) -- Set data format format.data = format.REAL32 format.byteorder = format.LITTLEENDIAN
-- Switch to user swipe screen and inform that we are running the trigger model display.changescreen(display.SCREEN_USER_SWIPE) display.clear() display.settext(display.TEXT1, "Running model...") -- Initiate trigger model and wait until it finishes trigger.model.initiate() waitcomplete() -- Inform the Python program that we are ready to upload data, and display that on the screen print("U") display.settext(display.TEXT1, "Uploading...") -- Upload the data printbuffer(1, currentBuffer.n, currentBuffer.readings) -- Inform that the upload is complete display.settext(display.TEXT1, "Complete!")
import time import visa import numpy # Time of the beginning of the execution t0 = time.time() # Print message with timestamp def log(s): print('[%.1f] %s' % (time.time() - t0, s)) # Connect to the instrument, set the timeout and clear the buffer keithley = visa.ResourceManager().open_resource('TCPIP0::192.168.0.30::inst0::INSTR') keithley.timeout = 90000 keithley.clear() # Setup the instrument with the specified sampling rate, digitizing time, and current range. Then create the "currentDigitizer" script. with open("currentDigitizerSetup.tsp") as file: keithley.write(file.read() % (1000000, 0.3, 1)) keithley.write('script.delete("currentDigitizer")') keithley.write('loadscript currentDigitizer') with open("currentDigitizerBegin.tsp") as file: keithley.write(file.read()) keithley.write('endscript') # Digitize current of ESP32 operating modes m = [] for i in range(6): # Execute the script keithley.write('currentDigitizer()') log("Running trigger model...") # Digest the 'U' script output, which indicates that the instrument is ready to upload keithley.read() # Download data as a numpy.array and append it to the list log("Downloading...") i = keithley.read_binary_values(datatype = 'f', is_big_endian = False, container= numpy.array) m.append(i) # Save data numpy.save('MCU.npy', numpy.array(m).transpose()) log("Complete!") keithley.close()
Measurements were repeated 16 times, averaged and decimated to reduce the effect of current spikes in the plot:
The results show that deep sleep consumes the least amount of current (15.1 mA), followed by light sleep (17.4 mA), Idle (80.2 mA) and computation (115.3 mA). It is interesting to note that there is an important difference in the time overhead between the light sleep (0.6 ms) and deep sleep (168.4 ms).
To measure the charge overhead to entering and leaving a sleep mode I measured the consumed charge for 0 ms deep and light sleep modes:
The plot shows that the net charge overhead compared to idling is almost negligible for both sleeping modes. With these measurements we can calculate when each of the sleeping modes should be used. For my specific board and test firmware I found that for periods shorter than 1100 ms, light sleep consumes less charge than deep sleep, past that threshold deep sleep consumes less than light sleep.
Multimeters have come a long way since the early days, they have become more precise and have been modernized in every aspect. They have turned into very flexible instruments, able to perform many different types of measurements either directly or remotely. Keithley has gone one step further by adding LUA scripting support and touchscreen interface to their TTI instrument line.
The DMM6500 is a great 6.5 digits DMM that supports a wide variety of measurement functions, including the ability to digitize voltage or current at 1 MS/s with 16 bits of resolution. It uses a modern touchscreen-based GUI and supports programming either through remote SCPI or TSP commands, or TSP scripts running directly on the instrument.
Basic usage of the instrument is intuitive enough to not require the reading of the user manual. The GUI is responsive and the navigation between menus, quick and efficient. Programming the instrument is relatively simple, but some concepts require extra effort to understand, such as the triggering system. The documentation is extensive and good, the user and reference manuals are 107 and 1257 pages long respectively, but I felt that a few complex programming topics could have been introduced in a way that is easier to follow. Kickstart and TSB worked fine without any issues. Kickstart can get you very quick results, but you can not beat the flexibility of using the instrument through TSP scripts, so I barely used Kickstart. TSB on the other hand was very useful to debug code before implementing it on my Python code and I used it extensively. I found a few non-serious firmware bugs in the firmware, but we know Keithley is serious about fixing bugs, so this should not be a deal breaker. My overall experience with the instrument was very good and at the instruments price range it offers greater flexibility than any other alternative.
Finally, I would like to thank those that made this review possible, Element14 and Keithley, and especially to Randall (Element14) for his support and to Bradley (Keithley) for responding my emails with useful information.
Top Comments
Fine if you can improve it - but - I liked your (sufficiently detailed) description of some actual useful stuff that you did.
@Gerald
I certainly don't expect a road test to include checks of calibration…
Nice & interesting review - the DMM6510 makes a pretty good low cost audio analyzer.
Not as good as the fancy R&S or Keysight jobs but a tiny fraction of the price.
MK
Nice test report.
DAB