Skip to content

Analog Input

Ytai Ben-Tsvi edited this page May 31, 2023 · 7 revisions

Analog Input

Background

In many real-life situations we want to measure voltage. Ever so often, it is not the voltage itself we care about, but some other physical quantity that has been converted to voltage by some sort of sensor or transducer. Perhaps the simplest example is a potentiometer: when connected in a certain way, it will present the different possible rotation angles of its knob as different voltages on one of its pins. But this is only one simple example out of a vast variety of sensors for measuring almost every imaginable physical quantity, and many of which reporting their measurements as voltage.

IOIO has 16 pins, commonly known as "Analog Inputs", which are capable of measuring voltage levels between 0V-3.3V, with a precision of about 3mV. You must ensure not to supply voltage levels outside this range on those pins, or else you'll potentially damage your hardware. In some cases where the input to measure is outside of this range, a simple resistor ladder can scale down the voltage, while in other cases an amplifier circuit will be needed. At the time of writing this, the answers to these questions seem a little bit over-long for this guide.

Internally, as soon as you open an analog input, the IOIO starts sampling the voltage at even intervals, and sends these samples to the Android device. When reading them, you have a choice on whether to read the most recent value captured, or to read them on a sample-by-sample basis.

The analog pins are marked on the back-side of the board by squares surrounding the pins.

Usage

Using the IOIO pins as analog inputs is done via the AnalogInput interface. An instance of this interface corresponds to a physical pin on the board, configured to work in analog input mode. AnalogInput instances are obtained by calling:

AnalogInput in = ioio.openAnalogInput(pinNum);

This opens pin number pinNum for analog input.

Once an instance of AnalogInput is obtained, the pin value can be read by:

float value = in.read();

returning a value between 0 and 1, covering the entire range of permitted voltage. This method might block for a few milliseconds if called immediately after the pin is open. If an absolute measurement in Volts is more appropriate, use:

float volts = in.getVoltage();

When you are done using the pin, call:

in.close();

in order to return the pin to a "floating" state and possibly be able to re-open it in the same or in a different mode. The pin becomes useless after this call - it is illegal to do anything with it.

Buffered Reading

In the previous usage, we're always interested in the most recent value of the signal. However, sometimes it is important to obtain data that has been sampled at evenly-spaced times (e.g. for plotting graphs, or for measuring the change rate of a signal). In this case, we cannot allow samples to be lost if we're reading too slowly and we cannot allow a sample to be read twice if we're reading too fast. Often, we may be also willing to compromise latency in order to relax the requirements about how often we need to poll. For that purpose, buffered reading has been introduced. In order to start using buffered reading, once a pin has been opened for AnalogInput, you should enable buffering by calling:

in.setBuffer(capacity);

The capacity argument determines how many unread samples the buffer can store before it starts to overflow. A smaller buffer uses less memory, but forces you to read more frequently in order to avoid overflow. When an overflow occurs, the oldest (least recent) samples in the buffer will be dropped.

In order to read samples from the buffer, use:

float sample = in.readBuffered();

or:

float volts = in.getVoltageBuffered();

These methods will block until at least one sample is available in the buffer, and then return that sample. If blocking is undesirable, you can first call:

int samples = in.available();

which will tell you how many samples are already available in the buffer. If an overflow occurred, you can determine how many samples have been lost since initializing the buffer by calling in.getOverflowCount(). Lastly, you can programmatically query the sample rate (currently constant, but might change) by calling in.getSampleRate().

A note on bandwidth / sample rate: currently analog input pins are sampled 1000 times a second (1KHz). For some applications (such as audio signal measurements) this is unacceptable. This sample rate is not a physical limitation of the IOIO (in fact, the physical limitation is 500KHz for all open channels combined) and may be increased in the future.