TS-7180 CPU ADC: Difference between revisions

From embeddedTS Manuals
No edit summary
(Mention voltage dividers, but leave as an "exercise for the reader".)
 
(3 intermediate revisions by 3 users not shown)
Line 1: Line 1:
The TS-7180 has four channels of ADC, and those inputs are available on the [[TS-7180#Terminal_Blocks|P3]] connector, as AN_IN_1 through AN_IN_4.  Each input may be configured to measure voltage in two ranges (0-2.5V and 0-10.9V), or a 20mA current-loop.
The TS-7180 has four ADC channels, whose inputs are available on the [[TS-7180#Terminal_Blocks|P3]] connector as <code>AN_IN_1</code> through <code>AN_IN_4</code>.  Each input may be configured to measure voltage in either one of two ranges (0-2.5V and 0-10.9V) or a 20mA current-loop. Voltage measurements outside those ranges can be accomplished by adding an external voltage divider and then also making corresponding adjustments to the scaling applied in the code examples below.


The standard linux kernel offers a simple interface to the ADC that does not require any sort of programming to use. For example, to see the "raw" reading from the AN_IN_1 input, type the following command:
These ADCs are accessed through the IIO layer in Linux. This provides ADC samples up to 6ksps between all channels. The simplest API for slow speed acquisition is through <code>/sys/</code>:


<source lang=bash>
<source lang=bash>
cat /sys/bus/iio/devices/iio\:device0/in_voltage1_raw
cat /sys/bus/iio/devices/iio\:device0/in_voltage4_raw
</source>
</source>


To convert this raw value to a voltage, it must be multiplied by the "scaling factor", which can be found by typing the following command:
To switch to the 10.9V input range, the appropriate enable must be set high.  Each input <code>AN_IN_1</code> through <code>AN_IN_4</code> has its own enable, <code>EN_ADC1_10V</code> through <code>EN_ADC4_10V</code>, and these are controlled by GPIO #10 through #13.  For example, to switch <code>AN_IN_1</code> to the 10.9V range, run the following command:
<source lang=bash>
<source lang=bash>
cat /sys/bus/iio/devices/iio\:device0/in_voltage_scale
gpioset 5 10=1
</source>
 
The result will be in millivolts.  If you have the '''bc''' utility installed, you can enter the following command:
<source lang=bash>
echo `cat /sys/bus/iio/devices/iio\:device0/in_voltage1_raw` \* `cat /sys/bus/iio/devices/iio\:device0/in_voltage_scale` | bc
</source>
 
To switch to the 10.9V input range, the appropriate enable must be set high.  Each input AN_IN_1 through AN_IN_4 has its own enable, EN_ADC1_10V through EN_ADC4_10V, and these are controlled by GPIO #10 through #13.  For example, to switch AN_IN_1 to the 10.9V range, run the following command:
<source lang=bash>
tshwctl -a 10 -w 3
</source>
</source>


Note that the result must now be multiplied by (10.9/2.5).  Note also that the input impedance will now be around 2k ohms.
Note that the result must now be multiplied by (10.9/2.5).  Note also that the input impedance will now be around 2k ohms.


To switch to the 20mA current-loop mode, the appropriate enable must be set high.  These are EN_CL_1 through EN_CL_4, and are controlled by GPIO #6 through #9. First select the 2.5V range as follows:
To switch to the 20mA current-loop mode, the appropriate enable must be set high.  These are <code>EN_CL_1</code> through <code>EN_CL_4</code>, and are controlled by GPIO #6 through #9.
<source lang=bash>
tshwctl -a 10 -w 1
</source>
And then set the EN_CL_1 enable high as follows:
<source lang=bash>
<source lang=bash>
tshwctl -a 6 -w 3
# Select 2.5V
gpioset 5 10=0
# Asssert EN_CL_1
gpioset 5 6=1
</source>
</source>


{|class=wikitable
{|class=wikitable
Line 43: Line 30:
|-
|-
| AN_IN_1
| AN_IN_1
| in_voltage1_raw
| in_voltage4_raw
| GPIO 10
| [[#GPIO|gpio bank 5 io 10]]
| GPIO 6
| [[#GPIO|gpio bank 5 io 6]]
|-
|-
| AN_IN_2
| AN_IN_2
| in_voltage4_raw
| in_voltage5_raw
| GPIO 11
| [[#GPIO|gpio bank 5 io 11]]
| GPIO 7
| [[#GPIO|gpio bank 5 io 7]]
|-
|-
| AN_IN_3
| AN_IN_3
| in_voltage8_raw
| in_voltage8_raw
| GPIO 12
| [[#GPIO|gpio bank 5 io 12]]
| GPIO 8
| [[#GPIO|gpio bank 5 io 8]]
|-
|-
| AN_IN_4
| AN_IN_4
| in_voltage9_raw
| in_voltage9_raw
| GPIO 13
| [[#GPIO|gpio bank 5 io 13]]
| GPIO 9
| [[#GPIO|gpio bank 5 io 9]]
|}
|}
{{Note| The four ADC inputs use the CPU ADC inputs 4,5,8, and 9, corresponding with the 'raw' entries in the above table.}}
The [https://analogdevicesinc.github.io/libiio/ libiio] library provides simple access to the IO.  The fastest API is in C which will get about 6ksps.
<source lang=c>
/* 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)
{
/* scale a 0-4095 raw reading to 0-2500 mV */
uint32_t val = raw * 5000 / (4095 * 2);
return val;
}
int main(int argc, char **argv)
{
static struct iio_context *ctx;
static struct iio_device *dev;
static struct iio_channel *chn[4];
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);
for (i = 0; i < 4; 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));
}
return 0;
}
</source>
The python bindings currently achieve about 2ksps with similar code.
<source lang=python>
#!/usr/bin/env python
import iio
ctx = iio.Context('local:')
dev = ctx.find_device('2198000.adc')
scan_channels = ["voltage4", "voltage5", "voltage8", "voltage9"]
for n, chan_name in enumerate(scan_channels, start=1):
chn = dev.find_channel(chan_name)
raw = int(chn.attrs['raw'].value)
# Scale 0-4095 raw value to 0-2500(mV)
scaled = raw * (2.5/4095)
print('AN_CH{}_V={:.3f}'.format(n, scaled))
</source>

Latest revision as of 14:00, 19 April 2022

The TS-7180 has four ADC channels, whose inputs are available on the P3 connector as AN_IN_1 through AN_IN_4. Each input may be configured to measure voltage in either one of two ranges (0-2.5V and 0-10.9V) or a 20mA current-loop. Voltage measurements outside those ranges can be accomplished by adding an external voltage divider and then also making corresponding adjustments to the scaling applied in the code examples below.

These ADCs are accessed through the IIO layer in Linux. This provides ADC samples up to 6ksps between all channels. The simplest API for slow speed acquisition is through /sys/:

cat /sys/bus/iio/devices/iio\:device0/in_voltage4_raw

To switch to the 10.9V input range, the appropriate enable must be set high. Each input AN_IN_1 through AN_IN_4 has its own enable, EN_ADC1_10V through EN_ADC4_10V, and these are controlled by GPIO #10 through #13. For example, to switch AN_IN_1 to the 10.9V range, run the following command:

gpioset 5 10=1

Note that the result must now be multiplied by (10.9/2.5). Note also that the input impedance will now be around 2k ohms.

To switch to the 20mA current-loop mode, the appropriate enable must be set high. These are EN_CL_1 through EN_CL_4, and are controlled by GPIO #6 through #9.

# Select 2.5V
gpioset 5 10=0
# Asssert EN_CL_1
gpioset 5 6=1
ADC Table
# 'raw' 2.5/10.9V Select 20mA Loop Select
AN_IN_1 in_voltage4_raw gpio bank 5 io 10 gpio bank 5 io 6
AN_IN_2 in_voltage5_raw gpio bank 5 io 11 gpio bank 5 io 7
AN_IN_3 in_voltage8_raw gpio bank 5 io 12 gpio bank 5 io 8
AN_IN_4 in_voltage9_raw gpio bank 5 io 13 gpio bank 5 io 9
Note: The four ADC inputs use the CPU ADC inputs 4,5,8, and 9, corresponding with the 'raw' entries in the above table.

The libiio library provides simple access to the IO. 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)
{
	/* scale a 0-4095 raw reading to 0-2500 mV */
	uint32_t val = raw * 5000 / (4095 * 2);

	return val;
}

int main(int argc, char **argv)
{
	static struct iio_context *ctx;
	static struct iio_device *dev;
	static struct iio_channel *chn[4];
	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);

	for (i = 0; i < 4; 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));
	}

	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"]

for n, chan_name in enumerate(scan_channels, start=1):
	chn = dev.find_channel(chan_name)
	raw = int(chn.attrs['raw'].value)

	# Scale 0-4095 raw value to 0-2500(mV)
	scaled = raw * (2.5/4095)

	print('AN_CH{}_V={:.3f}'.format(n, scaled))