From 89cbea038ef3e723e511749c3a4ac61262eceae8 Mon Sep 17 00:00:00 2001 From: Robert Wolterman Date: Thu, 1 Dec 2016 05:55:26 +0000 Subject: [PATCH] LRADC support to close out feature #15. Added Utilities to enable and disable the 1.8v pin on U13. Updated README. Updated version to 2.3 --- CHANGELOG.rst | 8 ++ CHIP_IO/LRADC.py | 228 ++++++++++++++++++++++++++++++++++++++ CHIP_IO/OverlayManager.py | 23 +++- CHIP_IO/Utilities.py | 69 ++++++++++++ README.rst | 51 ++++++++- setup.py | 2 +- source/constants.c | 2 +- test/lradc_test.py | 67 +++++++++++ 8 files changed, 442 insertions(+), 8 deletions(-) create mode 100644 CHIP_IO/LRADC.py create mode 100644 CHIP_IO/Utilities.py create mode 100644 test/lradc_test.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index dd694ea..17e9c76 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,3 +1,11 @@ +0.2.3 +---- +* LRADC Support +* Added Utilities + - Enable/Disable the 1.8V Pin + - Change 1.8V Pin to output either 2.0V, 2.6V, or 3.3V + (Current limited to 50mA) + 0.2.2 ---- * Fixes for Issue #16 diff --git a/CHIP_IO/LRADC.py b/CHIP_IO/LRADC.py new file mode 100644 index 0000000..ed67b63 --- /dev/null +++ b/CHIP_IO/LRADC.py @@ -0,0 +1,228 @@ +# Copyright (c) 2016 Robert Wolterman +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import os +import time + +# Global Variables +DEBUG = False +DEVICE_EXIST = True + +# Default Sample Rate Variables +SAMPLE_RATE_32P25 = 32.25 +SAMPLE_RATE_62O5 = 62.5 +SAMPLE_RATE_125 = 125 +SAMPLE_RATE_250 = 250 +SAMPLE_RATES = [] + +# Scale Factor +SCALE_FACTOR = 31.25 + +# File Locations +LRADC_BASE_DEVICE_FILE = "/sys/bus/iio/devices/iio:device0" +AVAILABLE_SAMPLE_RATE_FILE = "/sampling_frequency_available" +SCALE_FACTOR_FILE = "/in_voltage_scale" +CURRENT_SAMPLE_RATE_FILE = "/in_voltage_sampling_frequency" +RAW_VOLTAGE_CHAN0_FILE = "/in_voltage0_raw" +RAW_VOLTAGE_CHAN1_FILE = "/in_voltage1_raw" + +def enable_debug(): + global DEBUG + DEBUG = True + +def setup(rate=250): + # First we determine if the device exists + if not os.path.exists(LRADC_BASE_DEVICE_FILE): + global DEVICE_EXIST + DEVICE_EXIST = False + raise Exception("LRADC Device does not exist") + else: + # Set the Sample Rate + set_sample_rate(rate) + +def get_device_exist(): + return DEVICE_EXIST + +def get_scale_factor(): + # If we do not have a device, lets throw an exception + if not DEVICE_EXIST: + raise Exception("LRADC Device does not exist") + + # Get the data from the file + f = open(LRADC_BASE_DEVICE_FILE+SCALE_FACTOR_FILE,"r") + dat = f.readline() + f.close() + + # Set the Scale Factor + global SCALE_FACTOR + SCALE_FACTOR = float(dat.strip()) + + # Debug + if DEBUG: + print("Current LRADC Scaling Factor: {0}").format(SCALE_FACTOR) + + return SCALE_FACTOR + +def get_allowable_sample_rates(): + # If we do not have a device, lets throw an exception + if not DEVICE_EXIST: + raise Exception("LRADC Device does not exist") + + # Get the data from the file + f = open(LRADC_BASE_DEVICE_FILE+AVAILABLE_SAMPLE_RATE_FILE,"r") + dat = f.readline() + f.close() + + global SAMPLE_RATES + tmp = dat.strip().split(" ") + for i in xrange(len(tmp)): + if "." in tmp[i]: + tmp[i] = float(tmp[i]) + else: + tmp[i] = int(tmp[i]) + SAMPLE_RATES = tmp + + # Debug + if DEBUG: + print("Allowable Sampling Rates:") + for rate in SAMPLE_RATES: + print("{0}").format(rate) + + return tuple(SAMPLE_RATES) + +def set_sample_rate(rate): + # If we do not have a device, lets throw an exception + if not DEVICE_EXIST: + raise Exception("LRADC Device does not exist") + + # Debug + if DEBUG: + print("Setting Sample Rate to: {0}").format(rate) + + # Check to see if the rates were gathered already + global SAMPLE_RATES + if SAMPLE_RATES == []: + tmp = get_allowable_sample_rates() + + # Range check the input rate + if rate not in SAMPLE_RATES: + raise ValueError("Input Rate an Acceptable Value") + + # Write the rate + f = open(LRADC_BASE_DEVICE_FILE+CURRENT_SAMPLE_RATE_FILE,"w") + mystr = "%.2f" % rate + f.write(mystr) + f.close() + + # Verify write went well + crate = get_sample_rate() + if crate != rate: + raise Exception("Unable to write new Sampling Rate") + +def get_sample_rate(): + # If we do not have a device, lets throw an exception + if not DEVICE_EXIST: + raise Exception("LRADC Device does not exist") + + # Get the data from the file + f = open(LRADC_BASE_DEVICE_FILE+CURRENT_SAMPLE_RATE_FILE,"r") + dat = f.read() + f.close() + + dat = dat.strip() + if "." in dat: + dat = float(dat) + else: + dat = int(dat) + + # Debug + if DEBUG: + print("Current Sampling Rate: {0}").format(dat) + + return dat + +def get_chan0_raw(): + # If we do not have a device, lets throw an exception + if not DEVICE_EXIST: + raise Exception("LRADC Device does not exist") + + # Get the data from the file + f = open(LRADC_BASE_DEVICE_FILE+RAW_VOLTAGE_CHAN0_FILE,"r") + dat = f.readline() + f.close() + + dat = float(dat.strip()) + + # Debug + if DEBUG: + print("CHAN0 RAW: {0}").format(dat) + + return dat + +def get_chan1_raw(): + # If we do not have a device, lets throw an exception + if not DEVICE_EXIST: + raise Exception("LRADC Device does not exist") + + # Get the data from the file + f = open(LRADC_BASE_DEVICE_FILE+RAW_VOLTAGE_CHAN1_FILE,"r") + dat = f.readline() + f.close() + + dat = float(dat.strip()) + + # Debug + if DEBUG: + print("CHAN1 RAW: {0}").format(dat) + + return dat + +def get_chan0(): + # If we do not have a device, lets throw an exception + if not DEVICE_EXIST: + raise Exception("LRADC Device does not exist") + + # Get the raw data first + dat = get_chan0_raw() + # Apply scale factor + dat *= SCALE_FACTOR + + # Debug + if DEBUG: + print("CHAN0: {0}").format(dat) + + return dat + +def get_chan1(): + # If we do not have a device, lets throw an exception + if not DEVICE_EXIST: + raise Exception("LRADC Device does not exist") + + # Get the raw data first + dat = get_chan1_raw() + # Apply scale factor + dat *= SCALE_FACTOR + + # Debug + if DEBUG: + print("CHAN1: {0}").format(dat) + + return dat + + diff --git a/CHIP_IO/OverlayManager.py b/CHIP_IO/OverlayManager.py index 7b8f37c..b4d3a0e 100644 --- a/CHIP_IO/OverlayManager.py +++ b/CHIP_IO/OverlayManager.py @@ -1,3 +1,22 @@ +# Copyright (c) 2016 Robert Wolterman +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + import os import shutil import time @@ -79,7 +98,7 @@ def _set_overlay_verify(name, overlay_path, config_path): print("Config path already exists! Not moving forward") print("config_path: {0}".format(config_path)) return -1 - + # MAKE THE CONFIGURATION PATH os.makedirs(config_path) @@ -198,5 +217,5 @@ def unload(overlay): _LOADED[overlay.upper()] = False else: raise ValueError("Invalid Overlay name specified! Choose between: I2C1, SPI2, PWM0, CUST") - + diff --git a/CHIP_IO/Utilities.py b/CHIP_IO/Utilities.py new file mode 100644 index 0000000..76b4739 --- /dev/null +++ b/CHIP_IO/Utilities.py @@ -0,0 +1,69 @@ +# Copyright (c) 2016 Robert Wolterman +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# CHIP_IO Utilities +# Random functions to enable fun stuff on the CHIP! + +# Credit goes to nonokuono (https://bbs.nextthing.co/users/nonokunono) +# for gathering the i2cset commands from the AXP-209 datasheet for 2.0, 2.6, and 3.3V output +# and for figuring out the ADC setup on the AXP-209 + +import subprocess + +# Enable 1.8V Pin on CHIP U13 Header +def enable_1v8_pin(): + # CANNOT USE I2C LIB AS WE NEED TO FORCE THE COMMAND DUE TO THE KERNEL OWNING THE DEVICE + # First we have to write 0x00 to AXP-209 Register 0x91 + subprocess.call('/usr/sbin/i2cset -f -y 0 0x34 0x91 0x00', shell=True) + # Then we have to write 0x03 to AXP-209 Register 0x90 + subprocess.call('/usr/sbin/i2cset -f -y 0 0x34 0x90 0x03', shell=True) + +# Disable 1.8V Pin on CHIP U13 Header +def disable_1v8_pin(): + # CANNOT USE I2C LIB AS WE NEED TO FORCE THE COMMAND DUE TO THE KERNEL OWNING THE DEVICE + # First we have to write 0x05 to AXP-209 Register 0x91 + subprocess.call('/usr/sbin/i2cset -f -y 0 0x34 0x91 0x05', shell=True) + # Then we have to write 0x07 to AXP-209 Register 0x90 + subprocess.call('/usr/sbin/i2cset -f -y 0 0x34 0x90 0x07', shell=True) + +# Change 1.8V Pin on CHIP U13 Header to 2.0V +def change_1v8_pin_to_2v0(): + # CANNOT USE I2C LIB AS WE NEED TO FORCE THE COMMAND DUE TO THE KERNEL OWNING THE DEVICE + # First we have to write 0x20 to AXP-209 Register 0x91 + subprocess.call('/usr/sbin/i2cset -f -y 0 0x34 0x91 0x20', shell=True) + # Then we have to write 0x03 to AXP-209 Register 0x90 + subprocess.call('/usr/sbin/i2cset -f -y 0 0x34 0x90 0x03', shell=True) + +# Change 1.8V Pin on CHIP U13 Header to 2.6V +def change_1v8_pin_to_2v6(): + # CANNOT USE I2C LIB AS WE NEED TO FORCE THE COMMAND DUE TO THE KERNEL OWNING THE DEVICE + # First we have to write 0x80 to AXP-209 Register 0x91 + subprocess.call('/usr/sbin/i2cset -f -y 0 0x34 0x91 0x80', shell=True) + # Then we have to write 0x03 to AXP-209 Register 0x90 + subprocess.call('/usr/sbin/i2cset -f -y 0 0x34 0x90 0x03', shell=True) + +# Change 1.8V Pin on CHIP U13 Header to 3.3V +def change_1v8_pin_to_3v3(): + # CANNOT USE I2C LIB AS WE NEED TO FORCE THE COMMAND DUE TO THE KERNEL OWNING THE DEVICE + # First we have to write 0xF0 to AXP-209 Register 0x91 + subprocess.call('/usr/sbin/i2cset -f -y 0 0x34 0x91 0xF0', shell=True) + # Then we have to write 0x03 to AXP-209 Register 0x90 + subprocess.call('/usr/sbin/i2cset -f -y 0 0x34 0x90 0x03', shell=True) + + diff --git a/README.rst b/README.rst index 5dd6cd4..f899441 100644 --- a/README.rst +++ b/README.rst @@ -193,10 +193,10 @@ Polling inputs:: Waiting for an edge (GPIO.RISING, GPIO.FALLING, or GPIO.BOTH:: -This only works for the AP-EINT1, AP-EINT3, and XPO Pins on the CHIP - GPIO.wait_for_edge(channel, GPIO.RISING) +This only works for the AP-EINT1, AP-EINT3, and XPO Pins on the CHIP + Detecting events:: GPIO.setup("XIO-P0", GPIO.IN) @@ -247,9 +247,34 @@ Use SOFTPWM at low speeds (hundreds of Hz) for the best results. Do not use for If using SOFTPWM and PWM at the same time, import CHIP_IO.SOFTPWM as SPWM or something different than PWM as to not confuse the library. -**ADC**:: +**LRADC**:: - Not Implemented yet +The LRADC was enabled in the 4.4.13-ntc-mlc. This is a 6 bit ADC that is 2 Volt tolerant. +Sample code below details how to talk to the LRADC. + + import CHIP_IO.LRADC as ADC + # Enable Debug + ADC.enable_debug() + # Check to see if the LRADC Device exists + # Returns True/False + ADC.get_device_exists() + # Setup the LRADC + # Specify a sampling rate if needed + ADC.setup(rate) + # Get the Scale Factor + factor = ADC.get_scale_factor() + # Get the allowable Sampling Rates + sampleratestuple = ADC.get_allowable_sample_rates() + # Set the sampling rate + ADC.set_sample_rate(rate) + # Get the current sampling rate + currentrate = ADC.get_sample_rate() + # Get the Raw Channel 0 or 1 data + raw = ADC.get_chan0_raw() + raw = ADC.get_chan1_raw() + # Get the factored ADC Channel data + fulldata = ADC.get_chan0() + fulldata = ADC.get_chan1() **SPI**:: @@ -287,6 +312,24 @@ There is no verification that the Custom Overlay is setup properly, it's fire an **OverlayManager requires a 4.4 kernel with the CONFIG_OF_CONFIGFS option enabled in the kernel config.** +**Utilties**:: + +CHIP_IO now supports the ability to enable and disable the 1.8V port on U13. This voltage rail isn't enabled during boot. + +To use the utilities, here is sample code:: + + import CHIP_IO.Utilities as UT + # Enable 1.8V Output + UT.enable_1v8_pin() + # Set 2.0V Output + UT.change_1v8_pin_to_2v0() + # Set 2.6V Output + UT.change_1v8_pin_to_2v6() + # Set 3.3V Output + UT.change_1v8_pin_to_3v3() + # Disable 1.8V Output + UT.disable_1v8_pin() + **Running tests** Install py.test to run the tests. You'll also need the python compiler package for py.test.:: diff --git a/setup.py b/setup.py index 96a2127..e626b6a 100644 --- a/setup.py +++ b/setup.py @@ -20,7 +20,7 @@ classifiers = ['Development Status :: 3 - Alpha', 'Topic :: System :: Hardware'] setup(name = 'CHIP_IO', - version = '0.2.2', + version = '0.2.3', author = 'Robert Wolterman', author_email = 'robert.wolterman@gmail.com', description = 'A module to control CHIP IO channels', diff --git a/source/constants.c b/source/constants.c index f14c2af..88d2745 100644 --- a/source/constants.c +++ b/source/constants.c @@ -76,6 +76,6 @@ void define_constants(PyObject *module) both_edge = Py_BuildValue("i", BOTH_EDGE); PyModule_AddObject(module, "BOTH", both_edge); - version = Py_BuildValue("s", "0.2.2"); + version = Py_BuildValue("s", "0.2.3"); PyModule_AddObject(module, "VERSION", version); } diff --git a/test/lradc_test.py b/test/lradc_test.py new file mode 100644 index 0000000..2b1552d --- /dev/null +++ b/test/lradc_test.py @@ -0,0 +1,67 @@ +#!/usr/bin/python + +import CHIP_IO.LRADC as ADC + +# == ENABLE DEBUG == +print("ENABLING LRADC DEBUG OUTPUT") +ADC.enable_debug() + +# == SETUP == +print("LRADC SETUP WITH SAMPLE RATE OF 125") +ADC.setup(125) + +# == SCALE FACTOR == +print("GETTING SCALE FACTOR") +scalefactor = ADC.get_scale_factor() +print(scalefactor) +print("") + +# == ALLOWABLE SAMPLING RATES == +print("GETTING ALLOWABLE SAMPLE RATES") +rates = ADC.get_allowable_sample_rates() +print(rates) +print("IS 32.25 IN RATE TUPLE") +print(ADC.SAMPLE_RATE_32P25 in rates) +print("") + +# == CURRENT SAMPLE RATE == +print("CURRENT SAMPLING RATE") +crate = ADC.get_sample_rate() +print(crate) +print("") + +# == SET SAMPLE RATE == +print("SETTING SAMPLE RATE TO 62.5") +ADC.set_sample_rate(62.5) +crate = ADC.get_sample_rate() +print(crate) +print("") + +# == CHAN 0 RAW == +print("READING LRADC CHAN0 RAW") +raw0 = ADC.get_chan0_raw() +print(raw0) +print("") + +# == CHAN 1 RAW == +print("READING LRADC CHAN1 RAW") +raw1 = ADC.get_chan1_raw() +print(raw1) +print("") + +# == CHAN 0 == +print("READING LRADC CHAN0 WITH SCALE APPLIED") +full0 = ADC.get_chan0() +print(full0) +print("") + +# == CHAN 1 == +print("READING LRADC CHAN1 WITH SCALE APPLIED") +full1 = ADC.get_chan1() +print(full1) +print("") + +# == RESET == +print("RESETING SAMPLE RATE TO 250") +ADC.set_sample_rate(250) +