From 207c54a5e75959bf6071d21738d5374a8ca1928d Mon Sep 17 00:00:00 2001 From: Nandkishor Sonar Date: Thu, 1 May 2014 16:36:11 +0100 Subject: [PATCH] aio: add initial analog input support Signed-off-by: Nandkishor Sonar Reviewed-by: Brendan Le Foll --- api/aio.h | 82 +++++++++++++++++ examples/CMakeLists.txt | 2 + examples/analogin_a0.c | 48 ++++++++++ src/CMakeLists.txt | 2 + src/aio/aio.c | 199 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 333 insertions(+) create mode 100644 api/aio.h create mode 100644 examples/analogin_a0.c create mode 100644 src/aio/aio.c diff --git a/api/aio.h b/api/aio.h new file mode 100644 index 0000000..619b831 --- /dev/null +++ b/api/aio.h @@ -0,0 +1,82 @@ +/* + * Author: Nandkishor Sonar + * Copyright (c) 2014 Intel Corporation. + * + * 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. + */ + +#pragma once + +#include +#include + +#include "maa.h" +#include "gpio.h" + +#define TOTAL_ANALOG_INPUTS_ON_BOARD (6) + +static const unsigned int A0 = 0; +static const unsigned int A1 = 1; +static const unsigned int A2 = 2; +static const unsigned int A3 = 3; +static const unsigned int A4 = 4; +static const unsigned int A5 = 5; + +#define ADC_RAW_RESOLUTION_BITS (12) +#define ADC_SUPPORTED_RESOLUTION_BITS (10) +#define ADC_COMMON_GATE_A4_A5 (29) + +static const unsigned int +adc_gate_pins[TOTAL_ANALOG_INPUTS_ON_BOARD] = {37, 36, 23, 22, 21, 20}; + +typedef struct { + unsigned int channel; + FILE *adc_in_fp; +} maa_aio_context; + +/** Initialise an Analog input device, connected to the specified pin + * + * @param aio_channel channel number to read ADC inputs + * + * @returns pointer to maa_aio_context structure after initialisation of Analog + * input pin successfully, else returns null. + */ +maa_aio_context* maa_aio_init(unsigned int aio_channel); + +/** Read the input voltage, represented as an unsigned short in the range [0x0, + * 0xFFFF] + * + * @param dev - pointer to maa_aio_context structure initialised by + * maa_aio_init() + * + * @returns 16-bit unsigned integer representing the current input voltage, + * normalised to a 16-bit value + */ +unsigned int maa_aio_read_u16(maa_aio_context* dev); + +/** Close the analog input context + * - Will free the memory for the context. + * + * @param dev - pointer to maa_aio_context structure initialised by + * maa_aio_init() + * + * @return maa_result_t - result type. + */ +maa_result_t maa_aio_close(maa_aio_context* dev); diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 9da7162..49de0b3 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -2,6 +2,7 @@ add_executable (i2c_HMC5883L i2c_HMC5883L.c) add_executable (hellomaa hellomaa.c) add_executable (cycle-pwm3 cycle-pwm3.c) add_executable (blink-io8 blink-io8.c) +add_executable (analogin_a0 analogin_a0.c) include_directories(${PROJECT_SOURCE_DIR}/api ${PROJECT_SOURCE_DIR}/include) @@ -9,3 +10,4 @@ target_link_libraries (hellomaa maa) target_link_libraries (i2c_HMC5883L maa m) target_link_libraries (cycle-pwm3 maa) target_link_libraries (blink-io8 maa) +target_link_libraries (analogin_a0 maa) diff --git a/examples/analogin_a0.c b/examples/analogin_a0.c new file mode 100644 index 0000000..e73285c --- /dev/null +++ b/examples/analogin_a0.c @@ -0,0 +1,48 @@ +/* + * Author: Nandkishor Sonar + * Copyright (c) 2014 Intel Corporation. + * + * 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. + */ + +#include + +#include "aio.h" + +int main () +{ + maa_aio_context* adc_a0; + unsigned int adc_value = 0; + int i = 0; + + adc_a0 = maa_aio_init(A0); + if (adc_a0 == NULL) { + return 1; + } + + for(i = 0; i < 10; i++) { + adc_value = maa_aio_read_u16(adc_a0); + fprintf(stdout, "ADC A0 read %X\n", adc_value); + } + + maa_aio_close(adc_a0); + + return MAA_SUCCESS; +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ee8c0b5..2498009 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -9,6 +9,7 @@ set (maa_LIB_HEADERS ${PROJECT_SOURCE_DIR}/api/i2c.h ${PROJECT_SOURCE_DIR}/api/pwm.h ${PROJECT_SOURCE_DIR}/api/spi.h + ${PROJECT_SOURCE_DIR}/api/aio.h ${PROJECT_SOURCE_DIR}/include/smbus.h ${PROJECT_SOURCE_DIR}/include/version.h ) @@ -27,6 +28,7 @@ set (maa_LIB_SRCS ${PROJECT_SOURCE_DIR}/src/i2c/smbus.c ${PROJECT_SOURCE_DIR}/src/pwm/pwm.c ${PROJECT_SOURCE_DIR}/src/spi/spi.c + ${PROJECT_SOURCE_DIR}/src/aio/aio.c # autogenerated version file ${CMAKE_CURRENT_BINARY_DIR}/version.c ) diff --git a/src/aio/aio.c b/src/aio/aio.c new file mode 100644 index 0000000..35734f3 --- /dev/null +++ b/src/aio/aio.c @@ -0,0 +1,199 @@ +/* + * Author: Nandkishor Sonar + * Copyright (c) 2014 Intel Corporation. + * + * 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. + */ + +#include + +#include "aio.h" + +static maa_result_t aio_get_valid_fp(maa_aio_context* dev) +{ + char file_path[64]= ""; + + //Open file Analog device input channel raw voltage file for reading. + snprintf(file_path, 64, "/sys/bus/iio/devices/iio:device0/in_voltage%d_raw", + dev->channel ); + + if (NULL == (dev->adc_in_fp = fopen(file_path, "r"))) { + fprintf(stderr, "Failed to open Analog input raw file %s for " + "reading!\n", file_path); return( MAA_ERROR_INVALID_RESOURCE); + } + + return MAA_SUCCESS; +} + +/** Configure multiplexer for Analog Input + * + * @param aio_channel = Analog input channel to read + * + * @return maa_result_t - result type. + * + */ +static maa_result_t maa_aio_set_mux(unsigned int aio_channel) +{ + maa_result_t result; + maa_gpio_context* aio_gate; + + //Initialise VINx multiplexer gate pins + aio_gate = maa_gpio_init(adc_gate_pins[aio_channel]); + + if (NULL == aio_gate) { + fprintf(stderr, "Failed to initialise first gate pin %d for ADC " + "channel %d !\n", adc_gate_pins[aio_channel], aio_channel); + return MAA_ERROR_INVALID_RESOURCE; + } + + //Set direction to output for the ADC input gate + result = maa_gpio_dir(aio_gate, MAA_GPIO_OUT); + + if (MAA_SUCCESS == result) { + // Write gate configuration output value + result = maa_gpio_write(aio_gate, 0); + + if (MAA_SUCCESS == result) { + //For A4 and A5 Analog common gate pin should be high for the + // Galileo board revision D + if (A4 == aio_channel || A5 == aio_channel) { + aio_gate = maa_gpio_init(ADC_COMMON_GATE_A4_A5); + + //Set direction to output for the gate + if (NULL == aio_gate) { + fprintf(stderr, "Failed to initialise second gate pin %d " + "for ADC channel %d !\n", ADC_COMMON_GATE_A4_A5, + aio_channel); + return(MAA_ERROR_INVALID_RESOURCE); + } + + result = maa_gpio_dir(aio_gate, MAA_GPIO_OUT); + if (MAA_SUCCESS == result) + // Write gate configuration output value + result = maa_gpio_write(aio_gate, 1); + } + } + } + + if (NULL != aio_gate) + free(aio_gate); + + return (result); +} + +/** Initialise an Analog input, connected to the specified channel + * + * @param aio_channel Analog input channel to read + * + * @returns pointer to maa_aio_context structure after initialisation of + * Analog input pin connected to the device successfully, else returns NULL. + */ +maa_aio_context* maa_aio_init(unsigned int aio_channel) +{ + maa_aio_context* dev; + + // Validate input pins 0-5 + if (aio_channel > TOTAL_ANALOG_INPUTS_ON_BOARD) { + fprintf(stderr, "Invalid Analog input channel %d specified!\n", + aio_channel); + return NULL; + } + + //Set-up multiplexer for the Analog input channel + if (MAA_SUCCESS != maa_aio_set_mux(aio_channel)) { + fprintf(stderr, "Failed to set-up Analog input channel %d " + "multiplexer!\n", aio_channel); return NULL; + } + + //Create ADC device connected to specified channel + dev = (maa_aio_context*) malloc(sizeof(maa_aio_context)); + if (NULL == dev) { + fprintf(stderr, "Insufficient memory for specified Analog input channel " + "%d !\n", aio_channel); + return NULL; + } + dev->channel = aio_channel; + + //Open valid analog input file and get the pointer. + if (MAA_SUCCESS != aio_get_valid_fp(dev)) { + free(dev); + return NULL; + } + + return dev; +} + +/** Read the input voltage, represented as an unsigned short in the range [0x0, + * 0xFFFF] + * + * @param pointer to maa_aio_context structure initialised by + * maa_aio_init() + * + * @returns + * 16-bit unsigned int representing the current input voltage, normalised to + * a 16-bit value + */ +unsigned int maa_aio_read_u16(maa_aio_context* dev) +{ + char buffer[16] = ""; + unsigned int raw_value=0; + unsigned int analog_value=0; + unsigned int shifter_value=0; + + if (NULL == dev->adc_in_fp) { + aio_get_valid_fp(dev); + } + + fseek(dev->adc_in_fp, SEEK_SET, 0); + fread(buffer, sizeof(buffer), 1, dev->adc_in_fp); + fseek(dev->adc_in_fp, SEEK_SET, 0); + + raw_value = atoi(buffer); + + /* Adjust the raw analog input reading to supported resolution value*/ + if (ADC_RAW_RESOLUTION_BITS == ADC_SUPPORTED_RESOLUTION_BITS) { + analog_value = raw_value; + } + else { + if (ADC_RAW_RESOLUTION_BITS > ADC_SUPPORTED_RESOLUTION_BITS) { + shifter_value = ADC_RAW_RESOLUTION_BITS - ADC_SUPPORTED_RESOLUTION_BITS; + analog_value = raw_value >> shifter_value; + } else { + shifter_value = ADC_SUPPORTED_RESOLUTION_BITS - ADC_RAW_RESOLUTION_BITS; + analog_value = raw_value << shifter_value; + } + } + + return analog_value; +} + +/** Close the analog input and free context memory + * + * @param dev - the analog input context + * + * @return maa result type. + */ +maa_result_t maa_aio_close(maa_aio_context* dev) +{ + if (NULL != dev) + free(dev); + + return(MAA_SUCCESS); +}