TS-7100-Z ADC

From embeddedTS Manuals

The TS-7100-Z supports five 12-bit ADC inputs using the i.MX6UL CPU's integrated ADC. Four of these inputs can sample 0-12VDC or 0-20mA. The fifth can sample 0-50VDC.

The pin assignments and names for accessing each ADC input are:

CN32 pin[1] Pin label Schematic name CPU signal 6UL GPIO gpio-line-name ADC IIO name Range
27 4 AN_0[2] 6UL_AN_0 GPIO1_IO04 AN_CH0 ADC1_IN4 voltage4 0-50 V
25 5 AN_1_STC 6UL_AN_1 GPIO1_IO05 AN_CH1 ADC1_IN5 voltage5 0-12 V
23 8 AN_2_STC 6UL_AN_2 GPIO1_IO08 AN_CH2 ADC1_IN8 voltage8 0-12 V
21 9 AN_3_STC 6UL_AN_3 GPIO1_IO09 AN_CH3 ADC1_IN9 voltage9 0-12 V
19 0 AN_4_STC 6UL_AN_4 GPIO1_IO00 AN_CH4 ADC1_IN0 voltage0 0-12 V
  1. See the TS-7100 IO Terminal Block section for a pinout illustration of the header, which is labeled CN32 on the schematic and silkscreen.
  2. The 0-50V AN_0 (Analog pin labeled 4) signal has an alternate function of being a high-side switch, as discussed in the GPIO section.

To switch an ADC to 0-20mA current-loop receiver mode, the appropriate enable must be set high. These are EN_CL_1 through EN_CL_4, and are controlled by GPIO commands as shown below.

ADC Table
Pin label Schematic Name IIO Name 0-12 V Select 0-20 mA Loop Select read-back[1]
5 AN_1_STC voltage5 gpioset $(gpiofind EN_CL_1)=0 gpioset $(gpiofind EN_CL_1)=1 gpioget $(gpiofind EN_ADC1_12V)
8 AN_2_STC voltage8 gpioset $(gpiofind EN_CL_2)=0 gpioset $(gpiofind EN_CL_2)=1 gpioget $(gpiofind EN_ADC2_12V)
9 AN_3_STC voltage9 gpioset $(gpiofind EN_CL_3)=0 gpioset $(gpiofind EN_CL_3)=1 gpioget $(gpiofind EN_ADC3_12V)
0 AN_4_STC voltage0 gpioset $(gpiofind EN_CL_4)=0 gpioset $(gpiofind EN_CL_4)=1 gpioget $(gpiofind EN_ADC4_12V)
  1. The read-back sense is inverted from the write values, so reading 1 indicates that voltage is being sampled, and 0 indicates that current is being sampled.
Note: Only the four 0-12 V ADC inputs — corresponding with the pins labeled 5, 8, 9, and 0 in the above tables — can be used as current-loop receivers.

IIO Access to ADCs

The preferred way to access these ADCs is through the Linux Industrial I/O Subsystem (IIO), which provides sample rates up to 6ksps across all inputs. The simplest API it offers for slow speed acquisition is via sysfs (/sys):

cat /sys/bus/iio/devices/iio:device0/in_voltage{4,5,8,9,0}_raw

The fastest API is in C which will get about 6ksps:

/* Build with gcc adc-test.c -o adc-test -liio 
 * Gets ~6ksps
 * At the time of writing this does not support the buffer interface */

#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <errno.h>
#include <iio.h>

uint32_t scale_mv(uint32_t raw, uint32_t max_mv)
{
	/* scale a 0-4095 raw reading to 0-max_mv mV */
	uint32_t val = raw * max_mv / 4095;

	return val;
}

int main(int argc, char **argv)
{
	static struct iio_context *ctx;
	static struct iio_device *dev;
	static struct iio_channel *chn[5];
	int i, ret;
	long long sample;

	ctx = iio_create_default_context();
	assert(ctx);
	dev = iio_context_find_device(ctx, "2198000.adc");
	assert(dev);

	chn[0] = iio_device_find_channel(dev, "voltage4", false);
	chn[1] = iio_device_find_channel(dev, "voltage5", false);
	chn[2] = iio_device_find_channel(dev, "voltage8", false);
	chn[3] = iio_device_find_channel(dev, "voltage9", false);
	chn[4] = iio_device_find_channel(dev, "voltage0", false);

	for (i = 0; i < 5; i++) {
		ret = iio_channel_attr_read_longlong(chn[i], "raw", &sample);
		assert(!ret);

		printf("AN_CH%d_mv=%d\n", i, scale_mv((uint32_t)sample, (i == 0) ? 50000 : 13325));
	}

	return 0;
}

The Python bindings currently achieve about 2ksps with similar code.

#!/usr/bin/env python

import iio

ctx = iio.Context('local:')
dev = ctx.find_device('2198000.adc')

scan_channels = ["voltage4", "voltage5", "voltage8", "voltage9", "voltage0"]

for chan_name in scan_channels:
	chan_n = int(chan_name[len("voltage"):])
	chn = dev.find_channel(chan_name)
	raw = int(chn.attrs['raw'].value)

	# Scale 0-4095 raw value to 0-12 V or 0-50 V for ADC 4.
	voltage_range = 50. if chan_n == 4 else 12.
	scaled = raw * voltage_range / 4095
	print('ADC1_IN{}={:.3f}'.format(chan_n, scaled))