We need to talk about Linux IIO

IIO (Industrial I / O) is a subsystem of the Linux kernel for analog to digital converters (ADC), digital to analog converters (DAC), and various types of sensors. Can be used on high speed industrial devices. It also includes a built-in API for other drivers.





Industrial I/O Linux ( ) , . , sysfs devfs.



IIO:



  • /


IIO :



  • (: )
  • - , DFSDM (, , )
  • , TIM LPTIM
  • SPI I2C


IIO , , ...



IIO



/ :



# https://www.kernel.org/doc/Documentation/i2c/dev-interface
open("/dev/i2c-1", O_RDWR);
# https://www.kernel.org/doc/Documentation/spi/spidev.rst
open("/dev/spidev2.0", O_RDWR);


, :





— ?



"" ( ).



IIO - , - poll .



IIO — .



.



IIO



sysfs ( ):



# cat /sys/bus/iio/devices/iio\:device0/in_accel_x_raw
-493


"" , .



read():



#      
(cd /sys/bus/iio/devices/iio:device0/scan_elements/ && for file in *_en; do echo 1 > $file; done)


:



int fd = open("/dev/iio:device0");
read(fd, buffer, scan_size);
#  scan_size      ,     1  /sys/bus/iio/devices/iio:device0/scan_elements/*_en


scan_size, "" , , .







IIO struct iio_chan_spec:



IIO types



BME280



/* https://elixir.bootlin.com/linux/v5.9-rc1/source/drivers/iio/pressure/bmp280-core.c#L132*/
static const struct iio_chan_spec bmp280_channels[] = {
    {
        .type = IIO_PRESSURE,
        .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
                      BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
    },
    {
        .type = IIO_TEMP,
        .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
                      BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
    },
    {
        .type = IIO_HUMIDITYRELATIVE,
        .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
                      BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
    },
};


, , — .



Linux , .





, kfifo .



, , , .





. , , , , , .



, CLOCK_REALTIME.



IIO Triggered Buffers





"" , user space.



, .



:



# cat /sys/bus/iio/devices/iio\:device0/trigger/current_trigger
icm20608-dev0
# echo > /sys/bus/iio/devices/iio\:device0/trigger/current_trigger
# cat /sys/bus/iio/devices/iio\:device0/trigger/current_trigger
# echo "icm20608-dev0" > /sys/bus/iio/devices/iio\:device0/trigger/current_trigger


Official Trigger Documentation



IIO sysfs trigger



Industrial IIO configfs support



Triggered buffer support trigger buffer support for IIO subsystem of Linux device driver



Device owned triggers



, device tree:



icm20608: imu@0 {
    ...
    interrupt-parent = <&gpio5>;
    interrupts = <11 IRQ_TYPE_EDGE_RISING>;
    ...
};


:



cat /sys/bus/iio/devices/trigger0/name
icm20608-dev0


gpio, , .



Interrupt triggers (also known as gpio trigger)



iio-trig-interrupt



, . gpio, .



, maintainer'a IIO Jonathan Cameron, .



Triggered buffer support trigger buffer support for IIO subsystem of Linux device driver

.



:



[v3,1/6] dt-bindings: iio: introduce trigger providers, consumers



device tree :



trig0: interrupt-trigger0 {
    #io-trigger-cells = <0>;
    compatible = "interrupt-trigger";
    interrupts = <11 0>;
    interrupt-parent = <&gpioa>;
};


sysfs trigger



iio-trig-sysfs



sysfs — , .



:



# echo 10 > /sys/bus/iio/devices/iio_sysfs_trigger/add_trigger


"sysfstrig%d", .



High resolution timer trigger



1 .



# mkdir /sys/kernel/config/iio/triggers/hrtimer/my_trigger_name
# cat /sys/bus/iio/devices/trigger4/name
my_trigger_name
# cat /sys/bus/iio/devices/trigger4/sampling_frequency
100


— "" SoC.



loop trigger



iio-trig-loop



PATCH v1 5/5 iio:pressure:ms5611: continuous sampling support

.



. :



iio:trigger: Experimental kthread tight loop trigger.



DT, , .



Device tree



label , , of_node iio:device — /sys/bus/iio/devices/iio\:device0/of_node/.



https://elixir.bootlin.com/linux/v5.9-rc1/source/Documentation/devicetree/bindings/iio





, IIO, enum iio_chan_type . iio_event_monitor.





IIO iio-buffer-sysfs-interface.



[be|le]:[s|u]bits/storagebitsXrepeat[>>shift]


icm20608:



# cat /sys/bus/iio/devices/iio\:device0/scan_elements/*_type
be:s16/16>>0
be:s16/16>>0
be:s16/16>>0
be:s16/16>>0
be:s16/16>>0
be:s16/16>>0
le:s64/64>>0


:



  • le be c
  • — , s u
  • / ,


:



be:u4/8>>0
be:u4/8>>4


repeat — 1 .



Scaling and offset



:



/sys/bus/iio/devices/iio:deviceX/in_*_raw
/sys/bus/iio/devices/iio:deviceX/in_*_offset
/sys/bus/iio/devices/iio:deviceX/in_*_scale


(raw + offset)*scale, offset'a .



How to do a simple ADC conversion using the sysfs interface



iio_simple_dummy



iio_simple_dummy — IIO :



  • IIO_VOLTAGE
  • IIO_ACCEL
  • IIO_ACTIVITY


The iio_simple_dummy Anatomy



iio_simple_dummy



libiio



libiio Analog Devices.



, / .



/, , Linux, Windows Mac , USB, Ethernet Serial.



iiod:



On remote :



host # iiod


On local :



local $ iio_info -n [host_address]
local $ iio_attr -u ip:[host_address] -d
local $ iio_readdev -u ip:[host_address] -b 256 -s 0 icm20608


Matlab, .





, libiio .



https://github.com/maquefel/icm20608-iio



libiio



sysfs , :



  • , /sys/bus/iio/iio:deviceN/name, /sys/bus/iio/iio:deviceN /dev/iio:deviceN
  • /sys/bus/iio/iio:deviceN/scan_elements/, , *_en
  • /sys/bus/iio/iio:deviceN/enable


.





E libiio.



https://elixir.bootlin.com/linux/v5.9-rc1/source/drivers/iio/industrialio-buffer.c#L574



:



    # bytes -      
    # length -    
    # offset -        
    if (bytes % length == 0)
        offset = bytes;
    else
        offset = bytes - bytes % length + length;

    bytes = offset + length;


libiio, :



  • , (Sign extension)
  • offset,
  • scale,


    input = is_be ? betoh(input) : letoh(input);
    input >>= shift;
    input &= BIT_MASK(bits);
    value = is_signed ? (float)sext(input, bits) : (float)input;
    if(with_offset) value += offset;
    if(with_scale) value *= scale;


: (Sign extension) . SignExtend.



libiio



libiio-loop.c

.



:



#    uri
# uri = "ip:127.0.0.1"
# uri = "local:"
# uri = "usb:"
ctx = iio_create_context_from_uri(uri);

#  
#  device = icm20608
dev = iio_context_find_device(ctx, device);

#   
nb_channels = iio_device_get_channels_count(dev);

#   
for(int i = 0; i < nb_channels; i++)
    iio_channel_enable(iio_device_get_channel(dev, i));

# buffer_size = SAMPLES_PER_READ,    (  )
buffer = iio_device_create_buffer(dev, buffer_size, false);

#    
iio_buffer_set_blocking_mode(buffer, true);

while(true) {
    #  
    iio_buffer_refill(buffer);

    #   -      libiio
    #     "" ,        
    #    
    # ssize_t print_sample(const struct iio_channel *chn, void *buffer, size_t bytes, __notused void *d)
    # const struct iio_channel *chn -     
    # void *buffer -        
    # size_t bytes -    
    # __notused void *d -         iio_buffer_foreach_sample
    iio_buffer_foreach_sample(buffer, print_sample, NULL);
}

#  
iio_buffer_destroy(buffer);

#  
iio_context_destroy(ctx);




, , Zero-Copy.



.



( ):







— DMA + mmap()



  • DMA
  • mmap()
  • ""


High-speed Data Acquisition

using the

Linux Industrial IO framework



SDR.



, , .



4.19 5.4.









https://bootlin.com/pub/conferences/2012/fosdem/iio-a-new-subsystem/iio-a-new-subsystem.pdf



https://archive.fosdem.org/2012/schedule/event/693/127_iio-a-new-subsystem.pdf



https://events19.linuxfoundation.org/wp-content/uploads/2017/12/Bandan-Das_Drone_SITL_bringup_with_the_IIO_framework.pdf



https://programmer.group/5cbf67db154ab.html



https://elinux.org/images/b/ba/ELC_2017_-_Industrial_IO_and_You-_Nonsense_Hacks%21.pdf



https://elinux.org/images/8/8d/Clausen--high-speed_data_acquisition_with_the_linux_iio_framework.pdf





https://linux.ime.usp.br/~marcelosc/2019/09/Simple-IIO-driver



P.S.



Sorry for the links, I couldn't get them to look like they should in markdown, and I'm not sure why.



Space was solved - thanks Exosphere - I incorrectly formatted the links.




All Articles