ModDAQ:  USB to SPI Controller and Modular DAQ

Control the universe from your PC

The Blog for this project

To access the ExpressPCB .PCB and .SCH files for this page, use this .ZIP archive.

Here are the Labview files for the VI (Voltage  / Current) source running on the USB DAQ board.

-- Dave

PC Interfacing
Serial and parallel ports have disappeared from most PCs. PCI bus design is only for serious pros, and modern operating systems have made it harder for the average programmer to access PC hardware. USB is, well, universal, but also complex and hard to program. To build a custom device from scratch, prepare to write a hairy PC driver, install a bunch of tools, develop embedded code and only then can you interface to your PC's USB port. For years, FTDI came to the rescue with their easy to use USB to Serial and parallel chips. But serial to what? There are very few hardware-only serial devices on earth. Most serial devices are based on a microprocessor, so if you want to build one, again, expect to develop embedded code.  

I have always been a fan of SPI. It is fast and fairly simple, and looks kind of like a bus since multiple devices can supported. There are lots of SPI things to control,  from ADCs, DACs, GPIO ports, temperature, memories, accelerometers, and lots of other stuff. Even the ubiquitous SD card is basically an SPI device.  FTDI supports SPI as well as other serial protocols like I2C and JTAG with their MPSSE (Multi-Protocol Serial Engine). Its software support isn't great, and until recently supported only full speed USB. But with the new H parts such as the FT232H, all that has changed. This part is a single USB to serial port, but can not only do RS232 at very fast speeds, but SPI, I2C, JTAG and a few parallel busses. Basically it can talk to just about any device out there.

So what is the catch? Generally USB implies slow speed, not real-time. True, you don't have micro-second control of hardware, but I am very impressed with the FT232H's ability to drive devices at high speed, to handle both writing and reading data, and to minimize the time between operations. I am able to do thousands of ADC conversions from a simple 100KHz ADC with no interruptions between cycles. You can even mix SPI devices and maintain pretty fast data There are tricks which I will share with you. FTDI doesn't really talk about time much so I made lots of measurements. It is quite fast. FTDI is modest about it's capabilities.

I liked the looks of the chip so bought a module: the UM232H. Wired it up on a Radio Shack breadboard to a few SPI devices and voila! The two 8-pin chips on the board  are a Microchip dual 12 bit DAC (MCP4822) and an aging TI, 12 bit ADC (ADS7816). I wrote up some LabView code to control them.

SPI Proto 1

Here is the simple schematic. The pull-up resistors are to make sure the SPI chip selects  (CSn/) are all disabled high before the FT232 is initialized.
First Test Schematic

This simple test showed that the FT232H is quite capable. It was able to keep up with the ADC at its full speed of 100K samples per second, sampling up to about 100K samples in a single command.

The trick to making an FT232H go fast is to send multiple commands in a single write packet. When you send multiple packets, each with a separate SPI command, the FTDI driver introduces about 300-500 uS of delay between SPI operations. But when multiple commands are sent in one packet, there is only about 300nS between commands. Nice! So if you want to collect 1000 samples at the fastest rate, send a packet with 1000 SPI commands. So as long as you can pre-calculate all your SPI commands, full speed can be achieved.

But for how many samples? There is no spec for this, but after doing some empirical testing (increase the amount until it crashes, then back it off a bit), I found that the limit is the number of bytes sent to the device in a single FT_Write(). The limit is apparently about 1 MB, probably due to a buffer size in the DLL. When measuring ADC values, it takes 3 bytes to assert CS, 2 or 3 bytes to get the ADC data, and 3 more to de-assert CS for a total of 9 or 10 bytes. The limit is 1MB so about 100K samples can be collected with no interruptions. This is pretty good. A non-real-time operating system communicating with a non-real-time bus and achieving full speed hardware control. Nice! In fact I didn't quite understand how, since the FT232 chip only has about 4KB of buffer for transmit and for receive data. The ADS7816 is a 12 bit part that sends 16 bits of data. But it does. My explanation is that the FTDI driver must continue to unload data from the buffer while SPI reads are still occurring. I am guessing since FTDI doesn't provide any details at that level. The concern is that if they choose to reduce driver buffer sizes, applications will break.

The FTDI MPSSE protocol performs low level serial commands such as setting the clock, sending SPI bytes, receiving them, setting GPIO pins direction  and state, and a few other niceties. GPIO commands only take about 300nS, so setting SPI chip selects with them is quite fast. Get your digital scope ready because you'll want to see the fast timing.  I use AD[3:7] for the first 5 chip selects. AC[7:0] can also be used as additional chip selects or simply as fast GPIO pins. 

Another consideration is the delay after a write and before a read. The example code from FTDI uses a delay( ) of about 10ms, followed by a call to determine how many bytes are in the read buffer. Then a read of that many bytes. I found that if you know how many bytes are in the read buffer, you can skip the delay and the status read, and just read that many bytes. The challenge with this approach is that if you are off in your calculation, the FTDI DLL will hang. 

Here is the Labview screen of 1000 measurements of a DC level and showing its stats in order to quantify the ADC noise. I haven't yet figured out where the larger + and - noise spikes are from.

test 1 labview
      screen shot

I decided to design a PC board with the FT232H that provides modular control hardware. it supports up to 4 modules, but the 3 most common features I need are already on the main board: 8 channel AtoD (ADC), DACs and GPIO.  Here is the feature set for the base board and for some of the planned modules.
USB Modular DAQ

I have the board controlling my VI system. Compared the the NI USB6009 USB DAQ that I used to use, it adds isolation, 4 DAC channels vs 2, higher speed, much lower cost, improved accuracy and improved noise. The VI is a 2 quadrant device that provides 0 to +20V at up to +2.5A and can sink up to -5A. It is ideal for testing many devices, particularly batteries and high current LEDs. More on this project....

A few lessons learned:
DAC lessons
The ADI AD5327 quad 12 bit DAC turned out to be a poor choice due to its INL (Integral Non-Linearity) spec of 16LSBs, and 60mV offset. 16 LSBs basically makes this a good 8 bit DAC, but it is sold and priced as a 12 bit device. 60mV of offset is nearly 100 codes at 610uV/LSB! I had  better results with the Microchip MCP4822, but it's only a dual. Microchip doesn't make a quad 12 bit SPI DAC. A better choice is the AD5624 quad or AD5628 octal with 10mV offset and 1 LSB INL at 12 bits. INL is a critical spec. The DAC can be no more accurate at converting digital to analog than it's INL. You can often compensate for gain and offset errors by calibrating those errors out. But unless you want to measure and build a table for every DAC value. INL errors cannot be corrected. Stay away from the AD5327 if you really want 12 bits.

Another source of errors to watch for is offset error. Low cost DACs, sometimes called "String DACs", use a resistor ladder and CMOS switches to generate voltages. This approach has advantages: inherent monotonicity: each code is larger than the one below it. Good offset and gain errors too. But the INL, or overall linearity isn't so good since the little resistors in the ladder do not all match. The ladder is a high impedance structure, so a voltage buffer is required to get a low impedance voltage output. Unfortunately the buffer is a source of offset error, usually dominating the DAC ladder offset errors. With a positive offset, the output doesn't go to ground when you apply code 0. With a negative offset error, several of the lowest codes cause no change in output. So don't depend on the DAC output to go all the way to ground, and don't even expect the lowest 16 or so codes (on a 12 bit DAC) to do anything. The fix for this is to add in a fixed analog offset downstream, then add 16 or so codes to the desired code.  If you do this you can get to 0, and you can also calibrate out the offset error either in hardware (trim) or in software. This is a problem with unipolar circuits, but not with bipolar circuits that typically have a 1/2 of full scale offset downstream.

ADC Lessons
The 12 bit TI ADS7844 was another problem part. It has quite bad channel-to-channel crosstalk, around 6-8 LSBs. Crosstalk is a particularly ugly error because you cannot calibrate it out. This makes the ADS7844 a 9 bit ADC for any application where you switch channels. I curse TI for not specifying crosstalk on the ADS7844. Every other multi-channel ADC does. It's bas enough that you need to read and understand a 30 page data sheet, but TI forces you to read between the lines and anticipate missing specs that they are apparently ashamed to publish. A better choice for 12 bit 8 channel ADC is the AD7927.

In evaluating 3 different ADCs, I found ADC dependent errors in each. Most, including the ADS7844 crosstalk, were dependent on the driving circuit. Modern ADCs use a are capacitive charge balancing approach. Each conversion is begun by the input charging a sample capacitor to capture the input voltage.  This capacitor is usually 20-30pF. This doesn't sound like much, but most source circuits will be disturbed when asked to charge a capacitor abruptly. The ADCs allow less than 1 us Acquisition Time to charge the cap, then whatever voltage the cap has, gets measured by the ADC circuitry. If the driver circuitry cannot charge the cap accurately in the alloted time, errors result. It takes 9 RC time constants to charge a cap to 1/2 LSB at 12 bits -ln (1/8192). If the acquisition time is 300nS and the  input cap is 30pF, the maximum resistance is 1K.  R*C * 9 = 300nS. I use LM358A's as my go-to op-amp. Driving an ADC directly with an LM358 induces large (100s of mV) glitches on the op-amp output (the ADC input). a 500 ohm series resistor helps a lot. If the op-amp doesn't settle in response to this disturbance fast enough, within the ADC's acquisition time, errors result. To quiet the glitch you can ad a resistor in the 200-50 ohm range in series. This limits the disturbance to the op-amp but doesn't cause ADC errors. Another trick I found was to bias the op-amp output either high or low to a power supply, via a resistor or current source that draws a few milliamps.  When a bipolar op-amp output drives a DC current, the output impedance of its emitter-follower output transistors is much reduced and the ADC error is reduced. I didn't try using a faster op-amp but I suspect it would help also, maybe because of the extra output stage quiescent current. You could use a capacitor to GND to absorb the glitch, but the math is ugly: to get 1/2LSB charge error on a 12 bit ADC with Cin of 30pF requires 2^12 * 2 * 30pF or .25uF on every input. When you evaluate ADCs, always observe at the input glitch during acquisition and be careful about your driving source.

ADC Input Mitigation
Big capacitor (.2uF) to GND
Simple, low cost
Slow response, hard to drive
Dielectric absorption may be an issue
Op-amp and series resistor,  2-500 ohms
Small DC errors
Source resistance >= 1K ohms
Simple, low cost May not be enough to minimize op-amp disturbance
Fast op-amp
Good AC performance
Introduces DC errors
Expensive, especially multi-channel
Op-amp plus pull-down or pull-up (2-5ma)
Simple, accurate
Extra power draw. Can cause power-up issues

Virtually every modern CMOS ADC uses this un-buffered capacitor input approach and so most ADCs have peculiar and sometimes unstated requirements on source impedance. This includes the ones on your favorite microprocessor. The manufacturer's don't discuss this much, but there are some papers out there on it. I am talking about a slow ADC measuring slowly changing or DC voltages. When you measure low distortion audio or RF and the problems get much bigger. Fortunately there are ADC buffer amplifiers specifically designed for those apps.

Watch the op-amp DC errors too. 12 bits at 2.5V full scale is 610uV per LSB. A 5mV offset error op-amp causes 8LSBs of error. And op-amp gain also multiplies op-amp offset errors.

Some combination of these approaches can be used. Say some ADC inputs are measuring a 10K thermistor with a 10K pull-up resistor. A large cap might be the best solution since it doesn't add much cost, doesn't introduce DC errors, and response time probably isn't an issue. 0.2uF x 10K = 2mS RC time constant. 9 time constants (1/2 LSB at 12 bits) is only 20mS.

With LM358 op-amps, a 470 ohm resistor does a decent job with most ADCs. For even better performance, add a 1-3 mA pull-up resistor from the op-amp output to V+.

Differences in SPI interfaces
One downside of most Analog Devices SPI parts, is that they require the serial clock to be HI by default, pulsing low. This is unfortunate since just about everyone else uses LO clock, pulsing high. The FT232H can deal with this, but it adds a bit of extra complexity to SPI control.

Revision to USB DAQ
I decides that the original USB DAQ had too much modularity.  This capability was somewhat useful while I was evaluating ADCs, but even there I tended to use only one module at a time. I still like the modules, but a typical system would use the baseline ADC, one of 2 DAC options, and 16 GPIOs. Even as parts on the main board, these can be installed or deleted, plenty of modularity for me. Also I wanted the DAQ to be capable to be used as a module, like a large DIP, capable of being plugged into a carrier.

So the new USB DAQ MOD meets these needs, and still supports one plug-in module.  I increased the module pinout to 12 pins. There was nothing magic about 10 pins, and the 12 pins fit fine on the 1.2" square modules and allowed one more control pin plus a spare connection.

The module size is 1.6" x 3". It can be built as a DIP plug-in (connector pins facing down)  or as a stand-alone board (connectors facing up). It has four corner mounting holes for solid mounting either way. Here is the board layout. Boards will be arriving soon...


Visit the Blog for this project

Back to Dave's Home Page

This page was last updated 12/1/12