|
| 1 | +#!/bin/bash |
| 2 | +# vim: nowrap ts=4 |
| 3 | + |
| 4 | +# Sysfs setup for ADS1015 ADC |
| 5 | + |
| 6 | +ADC_PATH=/sys/bus/i2c/devices/5-0049/iio:device1 |
| 7 | + |
| 8 | +function ads1015_init () { |
| 9 | + # Tell the kernel where our ADC is |
| 10 | + echo ads1015 0x49 | sudo tee /sys/bus/i2c/devices/i2c-5/new_device > /dev/null |
| 11 | + |
| 12 | + # To remove the driver from the kernel, echo the address to delete_device |
| 13 | + # echo 0x49 | sudo tee /sys/bus/i2c/devices/i2c-5/delete_device > /dev/null |
| 14 | + |
| 15 | + # The ADC can now be found under the Industrial I/O (iio) at the following path, |
| 16 | + # look there for all the options (sampling_frequency_available, scale_available, input configurations) |
| 17 | + # The lowest sample freq gives the best accuracy, but is slower. That doesn't matter here because we don't read continously. |
| 18 | + # scale_available: 0.125000000 0.250000000 0.500000000 1.000000000 2.000000000 3.000000000 |
| 19 | + # sampling_frequency_available=128 250 490 920 1600 2400 3300 3300 |
| 20 | + # ADC_PATH=/sys/bus/i2c/devices/5-0049/iio:device1 |
| 21 | + |
| 22 | + # Setup the ADC. |
| 23 | + # The internal reference voltage is 2.048V, and the resolution is 12-bit for differential inputs, |
| 24 | + # but we're using them in single-ended mode (one input is ground) so we'll get 11-bit resolution. |
| 25 | + # By selecting a scale of 2, the input range is 4.096V but the actual voltage may not exceed 3.3V, the ADC's supply voltage. |
| 26 | + # |
| 27 | + # CH0 is the potentiometer next to the telemetry module |
| 28 | + # CH0 range: 0 .. 3.3V |
| 29 | + # CH1 is the potentiometer next to the I2C connectors |
| 30 | + # CH2 is the battery voltage divided by 10 |
| 31 | + # CH3 is the external voltage on the white connector between the potentiometers |
| 32 | + # |
| 33 | + # In the end, the raw ADC values are available in in_voltage{0.3}_raw. These have to be calculated to voltages, see below. |
| 34 | + |
| 35 | + |
| 36 | + # Set scale for potentiometers, CH0 and CH1 |
| 37 | + echo 2 | sudo tee $ADC_PATH/in_voltage0_scale > /dev/null |
| 38 | + echo 2 | sudo tee $ADC_PATH/in_voltage1_scale > /dev/null |
| 39 | + |
| 40 | + # Set scale for VBat/10 (2.048V range is ok here), CH2 |
| 41 | + echo 1 | sudo tee $ADC_PATH/in_voltage2_scale > /dev/null |
| 42 | + |
| 43 | + # Set scale for Vext, CH3 (set to scale 2 since we expect the input to be 0 .. 3.3V) |
| 44 | + echo 2 | sudo tee $ADC_PATH/in_voltage3_scale > /dev/null |
| 45 | + |
| 46 | + # Optionally set the sample frequency |
| 47 | + echo 1600 | sudo tee $ADC_PATH/in_voltage0_sampling_frequency > /dev/null |
| 48 | + echo 1600 | sudo tee $ADC_PATH/in_voltage1_sampling_frequency > /dev/null |
| 49 | + echo 1600 | sudo tee $ADC_PATH/in_voltage2_sampling_frequency > /dev/null |
| 50 | + echo 1600 | sudo tee $ADC_PATH/in_voltage3_sampling_frequency > /dev/null |
| 51 | + |
| 52 | + # Apparently the ADC or the kernel needs some time to set itself up. |
| 53 | + sleep 1 |
| 54 | +} |
| 55 | + |
| 56 | +function ads1015_delete () { |
| 57 | + echo 0x49 | sudo tee /sys/bus/i2c/devices/i2c-5/delete_device > /dev/null |
| 58 | +} |
| 59 | + |
| 60 | +function ads1015_get_settings () { |
| 61 | + # Read back the settings for verification |
| 62 | + raw0=$(cat $ADC_PATH/in_voltage0_raw) |
| 63 | + raw1=$(cat $ADC_PATH/in_voltage1_raw) |
| 64 | + raw2=$(cat $ADC_PATH/in_voltage2_raw) |
| 65 | + raw3=$(cat $ADC_PATH/in_voltage3_raw) |
| 66 | + echo "CH0: scale=$(cat $ADC_PATH/in_voltage0_scale), sampling_frequency=$(cat $ADC_PATH/in_voltage0_sampling_frequency), raw=$raw0" |
| 67 | + echo "CH1: scale=$(cat $ADC_PATH/in_voltage1_scale), sampling_frequency=$(cat $ADC_PATH/in_voltage1_sampling_frequency), raw=$raw1" |
| 68 | + echo "CH2: scale=$(cat $ADC_PATH/in_voltage2_scale), sampling_frequency=$(cat $ADC_PATH/in_voltage2_sampling_frequency), raw=$raw2" |
| 69 | + echo "CH3: scale=$(cat $ADC_PATH/in_voltage3_scale), sampling_frequency=$(cat $ADC_PATH/in_voltage3_sampling_frequency), raw=$raw3" |
| 70 | +} |
| 71 | + |
| 72 | +function ads1015_get_voltages () { |
| 73 | + # To calculate the voltages from the raw value, use the following formula: |
| 74 | + # Vchn = raw * Vref/2^(12-1) * scale |
| 75 | + |
| 76 | + # In bash, using bc as our calculator this would look like this: (scale=3 is bc's precision and not our ADC scale). |
| 77 | + raw0=$(cat $ADC_PATH/in_voltage0_raw) |
| 78 | + raw1=$(cat $ADC_PATH/in_voltage1_raw) |
| 79 | + raw2=$(cat $ADC_PATH/in_voltage2_raw) |
| 80 | + raw3=$(cat $ADC_PATH/in_voltage3_raw) |
| 81 | + read volt0 <<< "$(bc <<< "scale=3; $raw0 * 2.048/(2^(12-1)) * 2")" |
| 82 | + read volt1 <<< "$(bc <<< "scale=3; $raw1 * 2.048/(2^(12-1)) * 2")" |
| 83 | + read volt2 <<< "$(bc <<< "scale=3; $raw2 * 2.048/(2^(12-1)) * 1 * 10")" # note ADC scale=1 and x10 for Vbat |
| 84 | + read volt3 <<< "$(bc <<< "scale=3; $raw3 * 2.048/(2^(12-1)) * 2")" |
| 85 | + read percent0 <<< "$(bc <<< "scale=1; 4096/3300 * $raw0 / 2048 * 100")" |
| 86 | + read percent1 <<< "$(bc <<< "scale=1; 4096/3300 * $raw1 / 2048 * 100")" |
| 87 | + |
| 88 | + echo "CH0_volt="$(printf "%1.3f" $volt0)", CH0_percent=$percent0" |
| 89 | + echo "CH1_volt="$(printf "%1.3f" $volt1)", CH1_percent=$percent1" |
| 90 | + echo "CH2_volt=$volt2" |
| 91 | + echo "CH3_volt=$volt3" |
| 92 | +} |
| 93 | + |
| 94 | +# MAIN |
| 95 | +if [ "$1" == "init" ]; then |
| 96 | + ads1015_init |
| 97 | + ads1015_get_settings |
| 98 | + exit 0 |
| 99 | +elif [ "$1" == "delete" ]; then |
| 100 | + ads1015_delete |
| 101 | + exit 0 |
| 102 | +elif [ "$1" == "getsettings" ]; then |
| 103 | + ads1015_get_settings |
| 104 | + exit 0 |
| 105 | +elif [ "$1" == "getvoltages" ]; then |
| 106 | + ads1015_get_voltages |
| 107 | + exit 0 |
| 108 | +else |
| 109 | + echo "Usage: $0 init|delete|getsettings|getvoltages" |
| 110 | + exit 1 |
| 111 | +fi |
| 112 | + |
0 commit comments