Post Go back to editing

ADIS1640 Read

Category: Software
Product Number: ADIS16460
Software Version: libiio v1.0 on Linux Analog Devices Kuiper Linux

I am currently working on configuring SPI for the ADIS16460 using the following setup:

  • Raspberry Pi 4B+ running Analog Devices Kuiper Linux.
  • libiio v1.0, compiled from the source in the main branch.
  • Two ADIS16460 devices connected to SPI, and their information can be accessed and displayed using iio_info.

iio_info

iio_info version: 1.0 (git tag:7b973b58)
Libiio version: 1.0 (git tag: 7b973b58) backends: local ip usb xml
IIO context created with local backend.
Backend version: 1.0 (git tag: 7b973b58)
Backend description string: Linux analog 5.10.63-v7l+ #1 SMP Fri Mar 10 16:35:58 UTC 2023 armv7l
IIO context has 4 attributes:
	attr  0: hw_carrier value: Raspberry Pi 4 Model B Rev 1.5
	attr  1: dtoverlay value: vc4-kms-v3d,adis16460
	attr  2: local,kernel value: 5.10.63-v7l+
	attr  3: uri value: local:
IIO context has 7 devices:
	hwmon0: cpu_thermal
		1 channels found:
			temp1:  (input)
			1 channel-specific attributes found:
				attr  0: input (temp1_input) value: 46251
		No trigger on this device
	hwmon1: rpi_volt
		1 channels found:
			in0:  (input)
			1 channel-specific attributes found:
				attr  0: lcrit_alarm (in0_lcrit_alarm) value: 0
		No trigger on this device
	iio:device0: adis16460 (buffer capable)
		8 channels found:
			anglvel_x:  (input, index: 0, format: be:S32/32>>0)
			2 channel-specific attributes found:
				attr  0: raw (in_anglvel_x_raw) value: 984392
				attr  1: scale (in_anglvel_scale) value: 0.000000001
			anglvel_y:  (input, index: 1, format: be:S32/32>>0)
			2 channel-specific attributes found:
				attr  0: raw (in_anglvel_y_raw) value: 5555135
				attr  1: scale (in_anglvel_scale) value: 0.000000001
			anglvel_z:  (input, index: 2, format: be:S32/32>>0)
			2 channel-specific attributes found:
				attr  0: raw (in_anglvel_z_raw) value: -851792
				attr  1: scale (in_anglvel_scale) value: 0.000000001
			accel_x:  (input, index: 3, format: be:S32/32>>0)
			2 channel-specific attributes found:
				attr  0: raw (in_accel_x_raw) value: 9895935
				attr  1: scale (in_accel_scale) value: 0.000000037
			accel_y:  (input, index: 4, format: be:S32/32>>0)
			2 channel-specific attributes found:
				attr  0: raw (in_accel_y_raw) value: 131071
				attr  1: scale (in_accel_scale) value: 0.000000037
			accel_z:  (input, index: 5, format: be:S32/32>>0)
			2 channel-specific attributes found:
				attr  0: raw (in_accel_z_raw) value: -261816320
				attr  1: scale (in_accel_scale) value: 0.000000037
			temp0:  (input, index: 6, format: be:S16/16>>0)
			3 channel-specific attributes found:
				attr  0: offset (in_temp0_offset) value: 500
				attr  1: raw (in_temp0_raw) value: 42
				attr  2: scale (in_temp0_scale) value: 50
			timestamp:  (input, index: 7, format: le:S64/64>>0)
		2 device-specific attributes found:
			attr  0: current_timestamp_clock value: realtime

			attr  1: sampling_frequency value: 2048.000000
		Current trigger: trigger0(adis16460-dev0)
	iio:device1: adis16460 (buffer capable)
		8 channels found:
			anglvel_x:  (input, index: 0, format: be:S32/32>>0)
			2 channel-specific attributes found:
				attr  0: raw (in_anglvel_x_raw) value: 823395
				attr  1: scale (in_anglvel_scale) value: 0.000000001
			anglvel_y:  (input, index: 1, format: be:S32/32>>0)
			2 channel-specific attributes found:
				attr  0: raw (in_anglvel_y_raw) value: 4403151
				attr  1: scale (in_anglvel_scale) value: 0.000000001
			anglvel_z:  (input, index: 2, format: be:S32/32>>0)
			2 channel-specific attributes found:
				attr  0: raw (in_anglvel_z_raw) value: 1639127
				attr  1: scale (in_anglvel_scale) value: 0.000000001
			accel_x:  (input, index: 3, format: be:S32/32>>0)
			2 channel-specific attributes found:
				attr  0: raw (in_accel_x_raw) value: -10027008
				attr  1: scale (in_accel_scale) value: 0.000000037
			accel_y:  (input, index: 4, format: be:S32/32>>0)
			2 channel-specific attributes found:
				attr  0: raw (in_accel_y_raw) value: 6946815
				attr  1: scale (in_accel_scale) value: 0.000000037
			accel_z:  (input, index: 5, format: be:S32/32>>0)
			2 channel-specific attributes found:
				attr  0: raw (in_accel_z_raw) value: 263716863
				attr  1: scale (in_accel_scale) value: 0.000000037
			temp0:  (input, index: 6, format: be:S16/16>>0)
			3 channel-specific attributes found:
				attr  0: offset (in_temp0_offset) value: 500
				attr  1: raw (in_temp0_raw) value: 4
				attr  2: scale (in_temp0_scale) value: 50
			timestamp:  (input, index: 7, format: le:S64/64>>0)
		2 device-specific attributes found:
			attr  0: current_timestamp_clock value: realtime

			attr  1: sampling_frequency value: 2048.000000
		No trigger assigned to device
	iio_sysfs_trigger:
		0 channels found:
		2 device-specific attributes found:
			attr  0: add_trigger value: ERROR: Permission denied (-13)
			attr  1: remove_trigger value: ERROR: Permission denied (-13)
		No trigger on this device
	trigger0: adis16460-dev0
		0 channels found:
		No trigger on this device
	trigger1: adis16460-dev1
		0 channels found:
		No trigger on this device

The SPI speed is configured in the Device Tree to a maximum of 2MHz. Given the 2048SPS conversion rate of the sensor, this setup enables sampling data from it at a frequency of 2kHz.

#include <iio/iio.h>
#include <iio/iio-debug.h>
#include <string.h>
#include <stdio.h>

int main(void)
{

    // Context
    struct iio_context *ctx;

    // Channel name
    const char *chn_name = "accel_z";

    // Streaming devices
    struct iio_device *dev0;
    struct iio_device *trigger0;
    // Channels
    struct iio_channel *dev0_chn;

    // Masks
    struct iio_channels_mask *dev0_mask;

    // Buffers
    struct iio_buffer *dev0_buff;

    // Streams
    struct iio_stream *dev0_stream;

    // Sample Size
    size_t dev0_sample_sz;

    // Error
    int err;

    printf("* Acquiring IIO context *\n");
    ctx = iio_create_context(NULL, "local:");

    printf("* Acquiring ADI14640 streaming device *\n");
    dev0 = iio_context_find_device(ctx, "iio:device0");

    printf("* Acquiring trigger0 streaming device *\n");
    trigger0 = iio_context_find_device(ctx, "trigger0");    

    iio_device_set_trigger(dev0, trigger0);
    printf("Check if trigger0 is a trigger: %d\n", iio_device_is_trigger(iio_device_get_trigger(dev0)));

    printf("* Acquiring IIO channels *\n");
    dev0_chn = iio_device_find_channel(dev0, chn_name, false);
    printf("* Channelname: %s *\n", iio_channel_get_id(dev0_chn));

    printf("* Acquiring IIO channel mask *\n");
    dev0_mask = iio_create_channels_mask(iio_device_get_channels_count(dev0));

    printf("* Enabling IIO channel mask *\n");
    iio_channel_enable(dev0_chn, dev0_mask);

    printf("* Creating IIO buffers *\n");
    dev0_buff = iio_device_create_buffer(dev0, 0, dev0_mask);
    size_t sample = iio_device_get_sample_size(dev0, dev0_mask);

    printf("Error: %d\n", iio_err(dev0_buff));

    printf("* Creating IIO streams *\n");
    dev0_stream = iio_buffer_create_stream(dev0_buff, 4, 4);

    printf("Error: %d\n", iio_err(dev0_stream));

    printf("* Reading IIO streams *\n");
    const struct iio_block* block = iio_stream_get_next_block(dev0_stream);
    
    return 0;
}

I've configured a C file to interface with an ADIS16460 sensor, connecting the trigger to it. Initially, my focus is on reading a single channel, with plans to expand to all channels later. I've created a buffer and initiated the buffer stream. According to the Libiio v1.0 documentation, the recommended method for reading sensor data is through iio_stream_get_next_block. However, I encounter an error: "ERROR: iio:device0: Unable to enable buffer: Invalid argument (22)." If I successfully obtain iio_stream_get_next_block, I'm unsure how to extract the channel data into a float value. Any guidance on this would be greatly appreciated.

Full C Log:

sudo ./main 

* Acquiring IIO context *
* Acquiring ADI14640 streaming device *
* Acquiring trigger0 streaming device *
Check if trigger0 is a trigger: 1
* Acquiring IIO channels *
* Channelname: accel_z *
* Acquiring IIO channel mask *
* Enabling IIO channel mask *
* Creating IIO buffers *
Error: 0
* Creating IIO streams *
Error: 0
* Reading IIO streams *
ERROR: iio:device0: Unable to enable buffer: Invalid argument (22)

I have an additional inquiry: why is it necessary to initiate the program using sudo? Without it, the program fails to create a buffer, encountering a permission error.

  • Hello ,

    I will start by answering the additional inquiry, basically, this is a constraint from the IIO sub-system from Linux. LibIIO is simply reading and writing from /sys/bus/iio/devices/ and some of the files can be written only with sudo access. You may look up the access right, for example, in the buffer directory.

    Moving on to your problem, if you successfully obtain the data stream I think you can use iio_buffer_foreach_sample API to obtain each raw sample, after which you should apply the scale of the channel to obtain the float value: converted_value = raw_value * scale. Although, I only used this approach with LibIIO v0.25, in this iio_wrapper for a ROS2 application: https://github.com/analogdevicesinc/imu-ros2/blob/main/src/iio_wrapper.cpp#L467 

    LibIIO v 1.0 is not yet released and it is still in development. Indeed there are not many examples which show exactly how to use these APIs.

    What I can recommend, if it is alright for you, is to use the latest LibIIO release, v0.25. You will find some LibIIO clients, like iio_wrapper mentioned above or like IIO Oscilloscope: https://github.com/analogdevicesinc/iio-oscilloscope which already use LibIIO APIs to retrieve data and they can be used as development examples for your application.