This week, I have been debugging a high speed 24-bit ADC, connected to an STM32F303 ARM microcontroller. Unfortunately my usual arsenal of debugging tools were starting to creak under the strain. Here I discuss existing methods, plus a new approach which will be of interest to the hobbyist/Arduino community.
The Old Fashioned Way...
With any microcontroller project, during debugging, it is essential that you have the tools available to get data in and out of the micro so that you can see what's going on. Often this may just be a UART link to a serial terminal program which allows you to print out results and enter serial commands to control the application. Frequently, when I start with a new microcontroller, I use a simple framework program that provides the serial link with basic functions such as
putchar(x); // Prints the ASCII character of x, sends x to the uart transmit buffer
print_num(x); // Prints x as an integer
getchar(); // checks to see if there is a character waiting in the uart receive buffer
Now putchar and getchar are as old as the hills, and have been associated with character input and output - probably before C was even thought of. They may be as simple as testing for a uart flag to be set, and then writing or reading the uart tx or rx registers, but once you have these working, and can get characters in and out of your application program, then debugging becomes a whole lot easier. With just putchar you can do hex dumps of memory, send data to a file or even make a very simple realtime horizontal bargraph display - handy if you are looking at time varying analogue data.
My framework program often uses getchar and a switch/case statement to select different modes of working. One example this week was being able to control the sampling and averaging of an ADC that I have been working on, just by sending a single ASCII character to the microcontroller.
Another good technique is to set up a timer channel to count milliseconds. This establishes a time framework to your application program. By reading the millisecond counter, it becomes easy to co-ordinate tasks at given times, say once every 10mS, or once a second, and also to print out the millisecond count at each end of a task - to see how long it takes.
Fairly early on in your developments, you will want to start testing the I/O pins. One technique is to toggle an output port line each time you enter a given routine, this might drive a LED or better still connect a scope probe and use an oscilloscope to time the event. If you are going to be laying out a pcb for your next project, it is very worthwhile to break out some of the spare I/O pins, to say a 2.54mm header, which gives you something to clip a scope probe onto, or use jumper leads to a temporary array of LEDs. Modern microcontroller packages are very small, and the pins are not easy to probe individually - so break a few spare pins out - so you can get at them easily.
This week, I have been debugging a high speed 24-bit ADC, connected to an STM32F303 ARM microcontroller. Not only does this involve high resolution data, but it is output at high speeds, which makes seeing what's going on a little challenging. The particular ADC would be producing 24 bit readings at approaching 20kHz, and data sent at 921,600 baud. Whilst a terminal program, in this case RealTerm would be a start, it's very hard to visualise what's actually happening with streams of hex digits scrolling up the screen at an alarming rate. Clearly a new approach would be needed.
The project involves reading very small changes in voltage signals - down to fractions of microvolts, and as such it is essential to have good analogue design, and use precision low noise components. I found a good application note from Linear Technology, which describes most of the techniques in detail. If you are interested in high resolution analogue datalogging, and low noise analogue techniques - this app-note is well worth a read
Unfortunately, electrical noise is a fundamental property of the universe we live in, so minimising noise to the point where it no longer interferes with your ADC readings, is quite a challenge.
The ADC and microcontroller are mounted on a small pcb, along with voltage regulators, op-amps and an RS232 driver IC. Whilst RS232 might appear a little old fashioned, it is a robust way of communicating between instruments over moderate distances.
The microcontroller produces a 1MHz clock for the ADC, and every 8uS, the ADC interrupts the micro, to announce that it has another reading ready. The micro then reads the ADC using SPI, does some quick calculations on the readings and then passes the results out through the serial port for analysis on a PC.
This might appear simple enough, until you realise that even with some data averaging, the readings are being sent to the PC every 50uS, or 20,000 readings per second, and to achieve this, the UART has to run at 921,600 baud, nearly a megabit per second.
Visualisation of Your Data
During the debugging of this project some simple tools have been invaluable to capture the data, and allow visual analysis on a graphical display. By turning the ADC sample numbers from the sensor into a "scope trace" display I could see in real time what was happening.
|SimPlot - A Simple Serial Plotting Program|
After a quick search, I came across a program, SimPlot (downloadable here) This has been developed within the Arduino community, and allows up to four channels of data to be plotted against time, like an oscilloscope display. A few lines of code will produce the 16 bit integer data in the format needed by SimPlot, and it is very easy to use. The screenshot above shows one channel of data being captured from an Arduino at 115200baud, where the ADC input has been left floating. SimPlot allows you to set both the number of samples in the horizontal axis, and also the range displayed in the vertical axis. By choosing a certain sample rate, and setting the horizontal scale accordingly, it is possible to determine the frequency of the displayed waveform - in the above case it's just 50Hz mains hum.
Fortunately, SimPlot will handle high baudrates, and just typing in 921600 set it up correctly and I was soon able to view the amplitude of my data, noise and all. It is so much easier to see what is happening with a realtime trace, than to try and look at reams of hex data, or capture the data to a file and analyse later using plotting programs such as KST.
As microcontrollers become more sophisticated, and often within the hobbyist community, they are now used to read advanced analogue sensors, such as accelerometers and gyros, having a 4 channel display of analogue data like this is an absolute god-send. You can see in real time the changes in the signal, it's sensitivity to changing external parameters, such as temperature, and monitor drift and noise.
24 bit ADCs - what's available.
24 bit ADCs are now becoming more widely available, at an affordable cost. Most of the recent developments have been with the Delta-Sigma converters, which have an internal architecture that suits high speed digital signal processing and efficient translation into silicon. As a result Delta-Sigma converters tend to be cheaper and more widely available than the more traditional successive approximation (SAR) converters.
However, Delta-Sigma converters are about a magnitude slower than the SAR converters, max sample rates of about 10,000 samples per second, and as you sample faster, the weight of noise increases, so that a 24 bit converter, might only return about 17 noise free bits at 4kHz, rising to 20 bits at 2kHz sample rate.
Nevertheless, there are some good Delta-Sigma converters, and the LTC2440 from Linear Technology is a good representation of what is available. There has been some work done within the Arduino community on this device, and a link to a report on its performance whilst being read by an Arduino is here.
These converters are available for about £11 (Farnell) - but you will need a TSSOP adapter pcb in order to make use of them. They don't exactly lend themselves to breadboard prototyping either.
The resolution of a 24 bit converter is such that if we chose a 5V range, then the voltage represented by a single count would be 298nV - or approximately 0.3 microvolts. Compare this to the 10 bit converter on the Arduino, where the smallest voltage step is 4.88mV, or 16384 times larger. However this resolution is somewhat theoretical, and not really achievable in practice. Most Delta-Sigma converters are used at very low sampling speeds, often below 10Hz, in applications such as weighing scales.
Successive Approximation converters can convert much quicker, and the AD7767 I have chosen for my project can produce a maximum of 128,000 samples per second. The conversion rate is controlled entirely by the clock frequency you supply it with, up to a maximum of 1.024MHz. A new conversion is available every 8 clock cycles. Currently I am clocking it at 800kHz, in order to achieve 100,000 samples per second. These are averaged down, so that a new result is available every 8 samples - or 12.5kSps, or if you only wish one sample, then these can be output at 20KSps - which is limited by the speed of the RS232 interface.