Reading ADC, get "cat: in_voltage0_raw: Device or resource busy"

Anyone have any advice on why I can't seem to read the ADC? Thanks!

Yes.

cat /sys/bus/iio/devices/iio:device0/in_voltageX_raw is single shot mode. If you’re running in continuous mode you need to read from /dev/iio:device. So you get this “error” when attempting to use single shot channel files, when the ADC is operating in continuous mode.

If I were you, I’d just use single shot mode, as ADC reads through iio is dog slow. single-shot is around 5x or maybe slightly more - faster. iio could be faster if you could figure out how the buffer is structured, and make it very large( to cut down on system interrupts ). But if you need “fast” ADC, you’d be better off using either mmap on the ADC registers directly, or use the PRU’s.

Thanks, William. Questions below

Yes.

cat /sys/bus/iio/devices/iio\:device0/in_voltageX_raw is single shot mode. If you're running in continuous mode you need to read from /dev/iio:device. So you get this "error" when attempting to use single shot channel files, when the ADC is operating in continuous mode.

I'm using it the same way I always have. On my other BBB running a 3.8.13-bone68 kernel and an older Debian, I'm able to read it just fine with the BB-ADC dtbo loaded. As far as I know, I've never set anything to be continuous (or one-shot, for that matter).

How do I tell what mode it's in, and how do I change it?

If I were you, I'd just use single shot mode, as ADC reads through iio is dog slow. single-shot is around 5x or maybe slightly more - faster. iio *could* be faster if you could figure out how the buffer is structured, and make it very large( to cut down on system interrupts ). But if you need "fast" ADC, you'd be better off using either mmap on the ADC registers directly, or use the PRU's.

I don't need ADC faster than 100 Hz (on each of up to three channels). I'd love to move it to the PRU, but right now I'm using a library that downloads firmware to both PRU cores to bitbang LED control. I'll have to modify that to add my own ADC needs, and I'm not ready to do that right now.

I can consider using mmap; is there an example of this?

Thanks!

I’m using it the same way I always have. On my other BBB running a 3.8.13-bone68 kernel and an older Debian, I’m able to read it just fine with the BB-ADC dtbo loaded. As far as I know, I’ve never set anything to be continuous (or one-shot, for that matter).

You can check the mode the ADC is in by running:

cat /sys/bus/iio/devices/iio:device0/mode - Output should be either oneshot or continuous

Which kernel are you running on that board ? Anyway, run lsmod and make sure the ti_am335x_adc module is loaded. But the ADC dts file I have is as such . . .

/dts-v1/;

/ {
compatible = “ti,beaglebone”, “ti,beaglebone-black”, “ti,beaglebone-green”;
part-number = “BB-ADC”;
version = “00A0”;
exclusive-use = “P9.31”, “P9.40”, “P9.37”, “P9.38”, “P9.33”, “P9.36”, “P9.35”, “tscadc”;

fragment@0 {
target = <0xdeadbeef>;

overlay {
status = “okay”;

adc {
ti,adc-channels = <0x0 0x1 0x2 0x3 0x4 0x5 0x6>;
};
};
};

fixups {
tscadc = “/fragment@0:target:0”;
};
};

I don’t need ADC faster than 100 Hz (on each of up to three channels). I’d love to move it to the PRU, but right now I’m using a library that downloads firmware to both PRU cores to bitbang LED control. I’ll have to modify that to add my own ADC needs, and I’m not ready to do that right now.

Anything can do 100Hz, as long as there is not much using the ARM processor core. It won’t be deterministic though if you’re in userspace.

I can consider using mmap; is there an example of this?

https://github.com/ehayon/BeagleBone-GPIO

Was written with the white in mind, but works fine. Personally, I ripped out all that PIN crap, and everything that was not somehow related to the ADCs. Then wrote a couple custom functions. I wont share my own code though, because I have no way of testing it for validity yet.

I'm using it the same way I always have. On my other BBB running a 3.8.13-bone68 kernel and an older Debian, I'm able to read it just fine with the BB-ADC dtbo loaded. As far as I know, I've never set anything to be continuous (or one-shot, for that matter).

You can check the mode the ADC is in by running:

cat /sys/bus/iio/devices/iio\:device0/mode - Output should be either oneshot or continuous

Hmm, I don't have this file:

# ls /sys/bus/iio/devices/iio\:device0/
dev in_voltage0_raw in_voltage1_raw in_voltage2_raw name power/ subsystem@ uevent

Which kernel are you running on that board ? Anyway, run lsmod and make sure the ti_am335x_adc module is loaded. But the ADC dts file I have is as such . . .

I seem to not have the ti_am335x_adc module, but I also don't have it on the one that works

This one doesn't work:

# uname -r
3.8.13-bone72

# lsmod
Module Size Used by
uio_pruss 4066 0
g_ether 23958 0
libcomposite 15028 1 g_ether
8192cu 449033 0
omap_rng 4062 0
mt7601Usta 458758 0

# cat /sys/bus/iio/devices/iio\:device0/in_voltage0_raw
cat: /sys/bus/iio/devices/iio:device0/in_voltage0_raw: Device or resource busy

This one works:

# uname -r
3.8.13-bone68

# lsmod
Module Size Used by
snd_usb_audio 100405 1
snd_hwdep 4885 1 snd_usb_audio
snd_usbmidi_lib 15375 1 snd_usb_audio
g_multi 50407 0
libcomposite 15028 1 g_multi
uio_pruss 4066 2

# cat /sys/bus/iio/devices/iio\:device0/in_voltage0_raw
3680

So, I tried making the same changes as that patch in my 3.8 kernel. It was straightforward, but had no effect. Both the -bone68 and -bone72 have identical code that patch changes, so I know that's not it, because it works fine on the -bone68 board.

I tried enabling all the channels (I was only using 0-2), but that had no effect, either.

There's something else going on.

So, I just noticed that only reading channel 0 do I get the busy error:

# cat /sys/bus/iio/devices/iio\:device0/in_voltage0_raw
cat: /sys/bus/iio/devices/iio:device0/in_voltage0_raw: Device or resource busy
# cat /sys/bus/iio/devices/iio\:device0/in_voltage1_raw
109
# cat /sys/bus/iio/devices/iio\:device0/in_voltage2_raw
681

Moreover, ch 1 and ch 2 are on P9_39 and P9_40, respectively. But the docs say 39 is AIN0 and 40 is AIN1.

What's up with that?

The only other difference to my working board is perhaps the U-boot version? Unfortunately I can't easily connect a serial cable to it, and don't know how else to determine its version number.

And, I'm wrong. I rebooted, and now none of them reads successfully. I fucking hate this shit.