AD2S1210
AD2S1210 IIO Resolver-to-Digital Converter.
Supported Devices
Evaluation Boards
Reference Circuits
Description
This is a Linux industrial I/O (Linux Industrial I/O Subsystem) subsystem driver, targeting Resolver-to-Digital Converters. The industrial I/O subsystem provides a unified framework for drivers for many different types of converters and sensors using a number of different physical interfaces (i2c, spi, etc). See Linux Industrial I/O Subsystem for more information.
Source Code
Status
Support for the AD2S1210 is in mainline for kernel v6.7 and is backported to v6.1 of the ADI tree. Some additional features are slated for v6.8. The device was previously supported by a staging driver with a different ABI.
Files
Function |
File |
|
|---|---|---|
driver |
||
devicetree |
Documentation/devicetree/bindings/iio/resolver/adi,ad2s1210.yaml |
Adding Linux driver support
Configure kernel with make menuconfig (alternatively use make xconfig or
make qconfig)
Note
The Driver depends on CONFIG_SPI
Linux Kernel Configuration
Device Drivers --->
[*] Staging drivers --->
<*> Industrial I/O support --->
--- Industrial I/O support
-*- Enable ring buffer support within IIO
-*- Industrial I/O lock free software ring
-*- Enable triggered sampling support
*** Resolver to digital converters ***
[--snip--]
<*> Analog Devices AD2S1210 driver
[--snip--]
Driver Usage
To configure the chip, use the attributes according to the device register to IIO ABI mapping below:
Register |
Addr |
IIO ABI (sysfs) |
Units |
Notes |
|---|---|---|---|---|
DOS Overrange Threshold |
0x89 |
events/in_altvoltage0_thresh_rising_value |
mV |
|
DOS Mismatch Threshold |
0x8A |
events/in_altvoltage0_mag_rising_value |
mV |
|
DOS Reset Maximum Threshold |
0x8B |
events/in_altvoltage0_mag_rising_reset_max |
mV |
|
DOS Reset Minimum Threshold |
0x8C |
events/in_altvoltage0_mag_rising_reset_min |
mV |
|
LOT High Threshold |
0x8D |
events/in_angl1_thresh_rising_value |
Radians |
|
LOT Low Threshold |
0x8E |
events/in_angl1_thresh_rising_hysteresis |
Radians |
The value written to the LOT low register is high value minus the hysteresis. |
Excitation Frequency |
0x91 |
out_altvoltage0_frequency |
Hz |
|
Control |
0x92 |
*as bit fields* |
||
Phase lock range |
D5 |
events/in_phase0_mag_rising_value |
Radians |
|
Hysteresis |
D4 |
in_angl0_hysteresis |
Convert to radians by multiplying channel scale |
|
Encoder resolution |
D3:2 |
*not implemented* |
||
Resolution |
D1:0 |
*device tree: assigned-resolution-bits* |
Bits |
10, 12, 14, or 16 |
Soft Reset |
0xF0 |
Soft reset is performed when `out_altvoltage0_frequency` is written. |
||
Fault |
0xFF |
*not implemented* |
Interfacing With the AD2S1210 via iio_attr
Accessing a list of channels:
analog@setup-2-zed:~ $ iio_attr ad2s1210 -c
dev 'ad2s1210', channel 'angl0' (input, index: 0, format: be:U16/16>>0), found 5 channel-specific attributes
dev 'ad2s1210', channel 'anglvel0' (input, index: 1, format: be:S16/16>>0), found 3 channel-specific attributes
dev 'ad2s1210', channel 'timestamp' (input, index: 2, format: le:S64/64>>0), found 0 channel-specific attributes
dev 'ad2s1210', channel 'phase0' (input), found 1 channel-specific attributes
dev 'ad2s1210', channel 'altvoltage0' (output), found 3 channel-specific attributes
dev 'ad2s1210', channel 'altvoltage2' (input), found 1 channel-specific attributes
dev 'ad2s1210', channel 'angl1' (input), found 1 channel-specific attributes
dev 'ad2s1210', channel 'altvoltage0' (input), found 1 channel-specific attributes
dev 'ad2s1210', channel 'altvoltage1' (input), found 1 channel-specific attributes
For example, to get position channel angl0:
analog@setup-2-zed:~ $ iio_attr ad2s1210 -ci angl0
dev 'ad2s1210', channel 'angl0' (input), attr 'hysteresis', value '1'
dev 'ad2s1210', channel 'angl0' (input), attr 'hysteresis_available', value
'0 1'
dev 'ad2s1210', channel 'angl0' (input), attr 'label', value 'position'
dev 'ad2s1210', channel 'angl0' (input), attr 'raw', value '34114'
dev 'ad2s1210', channel 'angl0' (input), attr 'scale', value '0.000095874'
Or velocity channel anglvel0:
analog@setup-2-zed:~ $ iio_attr ad2s1210 -ci anglvel0
dev 'ad2s1210', channel 'anglvel0' (input), attr 'label', value 'velocity'
dev 'ad2s1210', channel 'anglvel0' (input), attr 'raw', value '0'
dev 'ad2s1210', channel 'anglvel0' (input), attr 'scale', value '0.023968449'
Interfacing With the AD2S1210 via /sys/bus
Alternatively, you can read and write data directly from the device path in /sys/bus:
analog@setup-2-zed:~ $ cd /sys/bus/iio/devices/iio\:device1/
analog@setup-2-zed:/sys/bus/iio/devices/iio:device1 $ tree
.
├── buffer
│ ├── data_available
│ ├── direction
│ ├── enable
│ ├── length
│ └── watermark
├── buffer0
│ ├── data_available
│ ├── direction
│ ├── enable
│ ├── in_angl0_en
│ ├── in_angl0_index
│ ├── in_angl0_type
│ ├── in_anglvel0_en
│ ├── in_anglvel0_index
│ ├── in_anglvel0_type
│ ├── in_timestamp_en
│ ├── in_timestamp_index
│ ├── in_timestamp_type
│ ├── length
│ └── watermark
├── current_timestamp_clock
├── dev
├── events
│ ├── in_altvoltage0_mag_rising_label
│ ├── in_altvoltage0_mag_rising_reset_max
│ ├── in_altvoltage0_mag_rising_reset_max_available
│ ├── in_altvoltage0_mag_rising_reset_min
│ ├── in_altvoltage0_mag_rising_reset_min_available
│ ├── in_altvoltage0_mag_rising_value
│ ├── in_altvoltage0_mag_rising_value_available
│ ├── in_altvoltage0_thresh_falling_label
│ ├── in_altvoltage0_thresh_falling_value
│ ├── in_altvoltage0_thresh_falling_value_available
│ ├── in_altvoltage0_thresh_rising_label
│ ├── in_altvoltage0_thresh_rising_value
│ ├── in_altvoltage0_thresh_rising_value_available
│ ├── in_altvoltage1_mag_either_label
│ ├── in_altvoltage2_mag_either_label
│ ├── in_angl1_thresh_rising_hysteresis
│ ├── in_angl1_thresh_rising_hysteresis_available
│ ├── in_angl1_thresh_rising_label
│ ├── in_angl1_thresh_rising_value
│ ├── in_angl1_thresh_rising_value_available
│ ├── in_anglvel0_mag_rising_label
│ ├── in_phase0_mag_rising_label
│ ├── in_phase0_mag_rising_value
│ └── in_phase0_mag_rising_value_available
├── in_altvoltage0_label
├── in_altvoltage1_label
├── in_altvoltage2_label
├── in_angl0_hysteresis
├── in_angl0_hysteresis_available
├── in_angl0_label
├── in_angl0_raw
├── in_angl0_scale
├── in_angl1_label
├── in_anglvel0_label
├── in_anglvel0_raw
├── in_anglvel0_scale
├── in_phase0_label
├── name
├── of_node -> ../../../../../../../../firmware/devicetree/base/axi/spi@e0006000/ad2s1210@0
├── out_altvoltage0_frequency
├── out_altvoltage0_frequency_available
├── out_altvoltage0_label
├── power
│ ├── autosuspend_delay_ms
│ ├── control
│ ├── runtime_active_time
│ ├── runtime_status
│ └── runtime_suspended_time
├── scan_elements
│ ├── in_angl0_en
│ ├── in_angl0_index
│ ├── in_angl0_type
│ ├── in_anglvel0_en
│ ├── in_anglvel0_index
│ ├── in_anglvel0_type
│ ├── in_timestamp_en
│ ├── in_timestamp_index
│ └── in_timestamp_type
├── subsystem -> ../../../../../../../../bus/iio
├── trigger
│ └── current_trigger
├── uevent
└── waiting_for_supplier
analog@setup-2-zed:/sys/bus/iio/devices/iio:device1 $ cat name
ad2s1210
analog@setup-2-zed:/sys/bus/iio/devices/iio:device1 $ cat in_angl0_raw
34115
Hysteresis can be enabled or disabled this way. To do so, first check the output of in_angl0_hysteresis_available:
root@setup-2-zed:/sys/bus/iio/devices/iio:device1# cat in_angl0_hysteresis_available
0 1
To turn hysteresis off, write the first value from the output to in_angl0_hysteresis:
root@setup-2-zed:/sys/bus/iio/devices/iio:device1# echo 0 > in_angl0_hysteresis
To turn it on, write the second value (which is dependent on the assigned bits for resolution and may not always be 1):
root@setup-2-zed:/sys/bus/iio/devices/iio:device1# echo 1 > in_angl0_hysteresis
Triggered buffer
To generate samples using the triggered buffer, you will need a trigger. You can create an hrtimer trigger and test it by retrieving samples like this:
root@setup-2-zed:~# mkdir /sys/kernel/config/iio/triggers/hrtimer/test
root@setup-2-zed:~# iio_readdev ad2s1210 -t test -s 1000 -T 10000 | hd
WARNING: High-speed mode not enabled
00000000 85 41 00 00 00 00 00 00 82 e1 7d ad 09 54 9e 17 |.A........}..T..|
00000010 85 41 00 00 00 00 00 00 00 70 16 ae 09 54 9e 17 |.A.......p...T..|
00000020 85 42 00 00 00 00 00 00 5f 06 af ae 09 54 9e 17 |.B......_....T..|
00000030 85 41 00 00 00 00 00 00 3f a2 47 af 09 54 9e 17 |.A......?.G..T..|
00000040 85 42 00 00 00 00 00 00 7f 32 e0 af 09 54 9e 17 |.B.......2...T..|
00000050 85 41 00 00 00 00 00 00 41 c8 78 b0 09 54 9e 17 |.A......A.x..T..|
00000060 85 41 00 00 00 00 00 00 ab 64 11 b1 09 54 9e 17 |.A.......d...T..|
00000070 85 41 00 00 00 00 00 00 fb f6 a9 b1 09 54 9e 17 |.A...........T..|
00000080 85 41 00 00 00 00 00 00 85 8b 42 b2 09 54 9e 17 |.A........B..T..|
00000090 85 41 ff ff 00 00 00 00 13 22 db b2 09 54 9e 17 |.A......."...T..|
000000a0 85 42 00 00 00 00 00 00 e3 b8 73 b3 09 54 9e 17 |.B........s..T..|
000000b0 85 42 00 00 00 00 00 00 53 4f 0c b4 09 54 9e 17 |.B......SO...T..|
000000c0 85 41 00 00 00 00 00 00 6a e8 a4 b4 09 54 9e 17 |.A......j....T..|
000000d0 85 41 00 00 00 00 00 00 24 7d 3d b5 09 54 9e 17 |.A......$}=..T..|
000000e0 85 41 ff ff 00 00 00 00 7c 13 d6 b5 09 54 9e 17 |.A......|....T..|
000000f0 85 41 00 00 00 00 00 00 2c a9 6e b6 09 54 9e 17 |.A......,.n..T..|
...
Important
using the -t option to specify the trigger with iio_readdev resets the sampling rate of the hrtimer trigger back to 100Hz!
For other apps, we probably want a high sample rate. You can change the rate like this:
root@setup-2-zed:~# iio_attr -d test sampling_frequency 10000
10000.000000
Reading IIO Events
See iio_event_monitor for an example of a program designed to read IIO events.
Fault to event mapping:
Fault |
Channel |
Type |
Direction |
Notes |
|
|---|---|---|---|---|---|
Sine/cosine inputs clipped |
D7 |
altvoltage1 |
mag |
either |
The chip does not differentiate between fault on sine vs. cosine so there will also be an event on the altvoltage2 channel. |
Sine/cosine inputs below LOS |
D6 |
altvoltage0 |
thresh |
falling |
|
Sine/cosine inputs exceed DOS overrange |
D5 |
altvoltage0 |
thresh |
rising |
|
Sine/cosine inputs exceed DOS mismatch |
D4 |
altvoltage0 |
mag |
rising |
|
Tracking error exceeds LOT |
D3 |
angl1 |
thresh |
rising |
|
Velocity exceeds maximum tracking rate |
D2 |
anglvel0 |
mag |
rising |
|
Phase error exceeds phase lock range |
D1 |
phase0 |
mag |
rising |
|
Configuration parity error |
D0 |
*writes to kernel log* |
Usage With the EVAL-AD2S1210SDZ Evaluation Board
Interfacing With a Raspberry Pi
Wiring
AD2S1210 Pin |
Eval Board Pin |
RPi Header Pin |
RPi Function |
Notes |
|---|---|---|---|---|
RES0 |
LK6 |
15 |
GPIO22 |
There aren’t J4 pins for RES0/1 so have to use jumper pins. It is also possible to hard-wire resolution pins RES0/1, but device tree would need to be changed accordingly. |
RES1 |
LK7 |
16 |
GPIO23 |
There aren’t J4 pins for RES0/1 so have to use jumper pins. It is also possible to hard-wire resolution pins RES0/1, but device tree would need to be changed accordingly. |
A0 |
J4-12 |
18 |
GPIO24 |
|
A1 |
J4-11 |
22 |
GPIO25 |
|
WR/FSYNC |
J4-4 |
24 |
SPI0 CE0 |
|
SAMPLE |
J4-1 |
12 |
GPIO18 |
|
VDRIVE |
J704-1 |
1 |
3.3V |
|
DGND |
J704-2 |
9 |
GND |
|
SCLK |
J4-10 |
23 |
SPI0 SCLK |
|
SDI |
J4-9 |
19 |
SPI0 MOSI |
|
SDO |
J4-8 |
21 |
SPI0 MISO |
AD2S1210 Pin |
Eval Board Pins (Jumpered) |
Eval Board Signal |
|---|---|---|
RD |
J4-3, J4-7 |
VDRIVE |
CS |
J4-2, J4-6 |
DGND |
Eval Board Signal |
Eval Board Jumper |
Position |
Notes |
|---|---|---|---|
SAMPLE |
LK1 |
B |
|
CS |
LK2 |
C |
|
RD |
LK3 |
C |
|
A0 |
LK 4 |
C |
|
A1 |
LK5 |
C |
|
RES0 |
LK6 |
C |
There aren’t J4 pins for RES0/1 so have to use jumper pins. It is also possible to hard-wire resolution pins RES0/1, but device tree would need to be changed accordingly. |
RES1 |
LK7 |
C |
There aren’t J4 pins for RES0/1 so have to use jumper pins. It is also possible to hard-wire resolution pins RES0/1, but device tree would need to be changed accordingly. |
SOE |
LK9 |
B |
|
VDRIVE |
LK703 |
B |
Device Tree
Add dtoverlay=ad2s1210 to /boot/config.txt.
Overlay: ad2s1210-overlay.dts
Sample Images
Eval board connections:
Raspberry Pi connections:
Zedboard
See ad2s1210_sdz for a detailed setup guide