BBBCSIO

A2DPort Example Code

 

About the A2DPort Class

The A2DPort class writes to and reads from the one of the seven Analog to Digital On Chip Peripheral (OCP) devices integrated into the Beaglebone Black CPU. In the Linux operating system there are two ways of accessing the A2D devices. The first, called IIO, is the standard and approved Linux technique. IIO is a device driver and if the existence of a A2D port is detected during boot time, the device driver interface will be exposed as a file in the /sys/bus/iio/devices/iio:device0/ directory of the Beaglebone Black file system. The A2D ports will only be detected if that port is appropriately configured in the Device Tree.

The second type of access is called Memory Mapped access and this treats the Beaglebone Black's RAM memory as if it were a file. The A2D port is manipulated as if it were a bit at an offset in a virtual file. The BBBCSIO library does not, at this time, provide a class which utilizes Memory Mapped access to the A2D port - the file system based IIO class named A2DPortFS is the only one available.

There are eight possible A2D ports on a Beaglebone Black however only seven are available for use. If these ports have been correctly configured in the Device Tree, the IIO device driver for that port will be accessible via a file in the /sys/bus/iio/devices/iio:device0/ directory. This file will have a name in the format in_voltage<a2dport>_raw where <a2dport> is the number of the A2D port. Thus the file /sys/bus/iio/devices/iio:device0/in_voltage3_raw is the interface for the IIO device driver on A2D port 3. If you do not see the in_voltage?_raw files in the /sys/bus/iio/devices/iio:device0 directory this means that the A2D device is not correctly configured in the Device Tree. By the way, these files are the sort of files you can open and read text from (like you can do with the SYSFS GPIO subsystem) in order to see the current A2D value . A command like ...

cat /sys/bus/iio/devices/iio:device0
... will show you the state of the A2D values on each input.

Tests indicate that a maximum speed of about 1000 reads/sec is possible with the BBBCSIO A2DPortFS class.

Warnings - READ THIS!!!

You must NEVER put more than 1.8V on one of the A2D inputs or you will burn it out. If you are trying to measure voltages out of that range then you must convert and scale the max and min of the voltages to a voltage range between 0 and 1.8V.

The A2D port used in the examples below is AIN_0 - this must be configured in the Device Tree in order for it to be available for use. However, (on the Beaglebone Black), AIN0 to AIN6 all seem to be muxed in by default if you load either one of the Device Tree overlays. An example of this is below

echo BB-ADC > /sys/devices/bone_capemgr.*/slots

or

echo cape-bone-iio > /sys/devices/bone_capemgr.*/slots

Be aware that the max and min value you get out of the A2DPortFS class Read() call can be scaled by the Device Tree setting in use. The min and max is always representative of 0V and 1.8V respectively. See the notes in comments below for an explanation.

The armhf Linux running on the Beaglebone Black is not a real-time operating system. Any repeated reads will probably have timing differences as the process is pre-emptively swapped in and out by the kernel. If you need deterministic real time reads you can access the A2D Converters in the PRU using the BBBCSIO PRU_Driver class.

An Example of the A2DPort Usage

The code below illustrates how to use the A2DPortFS class to read from an A2D device and then write that value to the console.

        /// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
        /// <summary>
        /// Reads a A2D port until a key is pressed and puts the value 
        /// out to the console. This uses the sysfs version of the A2DPort
        /// 
        /// NOTE: 
        ///   This code assumes that the A2D device has been configured in the 
        ///   device tree as an input. If it is not, then the value read may 
        ///   not be meaningful.
        /// 
        /// NOTE:
        ///    Be aware that the max and min value you get here can be scaled 
        ///    by the Device Tree settings in use. The min and max is always
        ///    representative of 0V and 1.8V respectively, but if you used the
        ///    following overlay 
        ///       echo BB-ADC > /sys/devices/bone_capemgr.*/slots
        ///    then 0V-1.8V is represented by the values 0-4095. If you used
        ///    this overlay
        ///       echo cape-bone-iio > /sys/devices/bone_capemgr.*/slots
        ///    then 0V-1.8V is represented by the values 0-1799. In other words,
        ///    the scaling of the output is not necessarily fixed and it
        ///    is up to you to know what voltage the output numbers represent. 
        /// 
        ///    OK, I'll tell you why there are two. The values 0-1799 represent
        ///    simple millivolts. So if you see a value of 1234 you know there
        ///    is 1.234V on the input. However the A2D inside the BBB is 12 bits
        ///    so if you wish to achieve maximum resolution you can use the
        ///    range 0-4095 (thus you have over double the resolution of the
        ///    0-1799) range. A value 4095 still means 1.8V though - you just
        ///    are measuring the voltage with a finer granularity.
        /// 
        ///  NOTE:
        ///    You must NEVER EVER put more than 1.8V on one of the A2D inputs 
        ///    or you will burn it out. If you are trying to measure voltages 
        ///    out of that range then you must convert the max and min of the 
        ///    voltages to a voltage between 0 and 1.8V. 
        /// 
        /// </summary>
        /// <param name="a2dID">The a2dID</param>
        /// <history>
        ///    20 Aug 15  Cynic - Originally written
        /// </history>
        public void SimpleReadA2D(A2DPortEnum a2dID)
        {
            // open the port
            A2DPortFS a2dPort = new A2DPortFS(a2dID);

            // look for the input until we have a key on the console
            while (Console.KeyAvailable == false)
            {
                uint inVal = a2dPort.Read();
                Console.WriteLine ("inVal = "+inVal.ToString());
                // sleep for a second
                Thread.Sleep(1000);
            }

            // close the port
            a2dPort.Dispose();
        }  
In the above code, the a2dID is passed in when the function was called. This value is a member of the A2DPortEnum class which lists all possible A2D ports which can be present on the Beaglebone Black. The above code is called via a line which looks like:
SimpleReadA2D(A2DPortEnum.AIN_0);