From 58406e180ac24231883390bf9627bf8bba27b00b Mon Sep 17 00:00:00 2001 From: SpaceVR Date: Wed, 6 Jul 2016 11:07:12 -0700 Subject: [PATCH] Initial commit of my suggested changes Added wrapper functions and better documenration. Not fully tested yet. --- GPIOSetup.sh | 44 ++++ GPIOTestApplication | Bin 0 -> 20893 bytes GPIOTestApplication.cpp | 105 ++++++++++ JetsonGPIO.cpp | 433 ++++++++++++++++++++++++++++++++++++++++ JetsonGPIO.h | 115 +++++++++++ 5 files changed, 697 insertions(+) create mode 100644 GPIOSetup.sh create mode 100644 GPIOTestApplication create mode 100644 GPIOTestApplication.cpp create mode 100644 JetsonGPIO.cpp create mode 100644 JetsonGPIO.h diff --git a/GPIOSetup.sh b/GPIOSetup.sh new file mode 100644 index 0000000..560fd72 --- /dev/null +++ b/GPIOSetup.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# file: GPIOSetup.sh +# http://elinux.org/Jetson/GPIO +# + +$ sudo su +$ cat /sys/kernel/debug/gpio + +$ echo 57 > /sys/class/gpio/export +$ echo out > /sys/class/gpio/gpio57/direction +$ echo 1 > /sys/class/gpio/gpio57/value +$ cat /sys/kernel/debug/gpi + +$ echo 57 > /sys/class/gpio/unexport +$ cat /sys/kernel/debug/gpi + +$ exit + +# AFTER cat /sys/kernel/debug/gpio RUNS +# GPIOs 0-255, platform/6000d000.gpio, tegra-gpio: +# gpio-58 (vdd-lcd-bl-en ) out lo +# gpio-59 (panel rst ) out lo +# gpio-63 (avdd-hdmi-pll ) out lo +# gpio-70 (temp_alert ) in hi +# gpio-82 (raydium-irq ) in lo +# gpio-84 (raydium-reset ) out lo +# gpio-86 (vdd-hdmi ) out hi +# gpio-108 (usb0-vbus ) in lo +# gpio-109 (usb1-usb2-vbus ) in hi +# gpio-111 (hdmi_hpd ) in hi +# gpio-122 (vdd-lcd-bl ) out lo +# gpio-128 (Power ) in hi +# gpio-132 (sdhci_wp ) in hi +# gpio-136 (sdmmc-en-supply ) out lo +# gpio-138 (reg-dcdc-1v2 ) out hi +# gpio-143 (headphone detect ) in hi +# gpio-170 (sdhci_cd ) in hi +# GPIOs 1016-1023, platform/as3722-pinctrl, as3722-gpio, can sleep: +# gpio-1018 (as3722-gpio2-supply ) out hi +# gpio-1020 (as3722-gpio4-supply ) out lo +# + +# AFTER echo 57 > /sys/class/gpio/export RUNS +# gpio-57 (sysfs ) out hi #gpio-57 NOW SHOWS UP IN TABLE diff --git a/GPIOTestApplication b/GPIOTestApplication new file mode 100644 index 0000000000000000000000000000000000000000..e9b7481a594cd44ee5e61f4f5f0a464fb5cea590 GIT binary patch literal 20893 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 US3*g9lrmDEYbC_j^umDuKjmDPGXMYp literal 0 HcmV?d00001 diff --git a/GPIOTestApplication.cpp b/GPIOTestApplication.cpp new file mode 100644 index 0000000..25aed54 --- /dev/null +++ b/GPIOTestApplication.cpp @@ -0,0 +1,105 @@ +/* GPIOTestApplication.cpp + * An example main driver program to excerise JetsonGPIO.cpp + * + * Author: Blaze Sanders SpaceVR(TM) June 2016 + * Link: http://elinux.org/Jetson/GPIO + * + * Note: The GPIO pins on Jetson TK1 are all 1.8V logic and can only + * supply a few milli-amps of current, so you can't simply attach common + * 5V or 3.3V logic signals or devices. One-way opto-isolated level shifter + * are the preffered method for connecting the TK1 to external devices, + * since its a more rugged method (www.sparkfun.com/products/9118). + */ + +#include //Standard input/output stream objects, needed to use cout() +#include //High accuracy microsecond timing +#include //Standard symbolic constants & types, needed to use usleep() + +#include "JetsonGPIO.h" + +using namespace std; + +//Compiled using g++ GPIOTestApplication.cpp JetsonGPIO.cpp -std=c++11 -o GPIOTestApplication + +int main(int argc, char *argv[]) +{ + //Arrays to hold command line input parameters + unsigned int DIRECTION_ARRAY[MAX_GPIO_PINS]; + unsigned int VALUE_ARRAY[MAX_GPIO_PINS]; + + //Example using 3 General Purpose Input/Output (GPIO) pins - 2 Output and 1 Input + unsigned int NUMBER_OF_GPIO_PINS = 3; + JetsonGPIO K1_GPIO_Pin[NUMBER_OF_GPIO_PINS]; + K1_GPIO_Pin[0] = JetsonGPIO(GPIO_PU0, OUTPUT_PIN, LOW); + K1_GPIO_Pin[1] = JetsonGPIO(GPIO_PU1, OUTPUT_PIN, LOW); + K1_GPIO_Pin[2] = JetsonGPIO(GPIO_PU2, INPUT_PIN, LOW); + + //Command line input error parsing + if(argc < 4){ + printf("Usage: %s n DIRECTION_ARRAY[n] VALUE_ARRAY[n]\n", argv[0]); + printf("N: Number of GPIO pins to create (max=%d)\n", MAX_GPIO_PINS); + printf("DIRECTION_ARRAY[%d]: Array to control direction of pins (INPUT PIN = 0 and OUTPUT PIN =1) \n", MAX_GPIO_PINS); + printf("VALUE_ARRAY[%d]: Array to state of pins (LOW = 0 and HIGH =1) \n\n", MAX_GPIO_PINS); + exit(0); + } + + sscanf(argv[1], "%d", &NUMBER_OF_GPIO_PINS); + if(NUMBER_OF_GPIO_PINS > MAX_GPIO_PINS){ + printf("ERROR: You tried to create more GPIO pins then possible (MAX = %d) on the NVIDIA K1. \n", MAX_GPIO_PINS); + printf("For the first command line argument please enter an integer less than or equal to %d.\n", MAX_GPIO_PINS); + exit(0); + } + + //Parse the direction command line arguments 2 to (2+NUMBER_OF_GPIO_PINS) + for(int i = 0; i < NUMBER_OF_GPIO_PINS; i++){ + sscanf(argv[(2+i)], "%d", &DIRECTION_ARRAY[i]); + } + + //Parse the value (output pins only) command line arguments (2+2*NUMBER_OF_GPIO_PINS+1) to (2+2*NUMBER_OF_GPIO_PINS+1) + for(int j = 0; j < NUMBER_OF_GPIO_PINS; j++){ + sscanf(argv[(2+(2*NUMBER_OF_GPIO_PINS)+1+j)], "%d", &VALUE_ARRAY[j]); + } + + //Setup time variables to track Mission Elapsed Time (MET) + time_t now; + struct tm MissionStart; + double elapsedSeconds; + + auto start = chrono::high_resolution_clock::now(); + time(&now); /* get current time; same as: now = time(NULL) */ + + MissionStart = *localtime(&now); + MissionStart.tm_hour = 0; MissionStart.tm_min = 0; MissionStart.tm_sec = 0; + MissionStart.tm_mon = 0; MissionStart.tm_mday = 1; + + elapsedSeconds = difftime(now,mktime(&MissionStart)); + auto elapsed = chrono::high_resolution_clock::now() - start; + long long elapsedMircoSeconds = std::chrono::duration_cast(elapsed).count(); + + + cout << "TEST #1:" << endl; + printf("Mission Elaspe Time (MET) rising edge TRIGGER timeStamp (i.e Month-MonthDay-Hour-Minutes-Seconds-MilliSeconds) = %d-%d-%d-%d-%f-", + MissionStart.tm_mon, MissionStart.tm_mday, MissionStart.tm_hour, MissionStart.tm_min, elapsedSeconds); + cout << elapsedMircoSeconds << endl; + + K1_GPIO_Pin[0].WritePinState(HIGH); //Set trigger pin high + + + printf("Mission Elaspe Time (MET) EXPOSURE timeStamp (i.e Month-MonthDay-Hour-Minutes-Seconds-MilliSeconds) = %d-%d-%d-%d-%f-", + MissionStart.tm_mon, MissionStart.tm_mday, MissionStart.tm_hour, MissionStart.tm_min, elapsedSeconds); + cout << elapsedMircoSeconds << endl; + + //Toggle exposure pin at 50% duty cycle with period of 32 millisecons + K1_GPIO_Pin[1].WritePinState(HIGH); + usleep(16000); + K1_GPIO_Pin[1].WritePinState(LOW); + usleep(16000); + K1_GPIO_Pin[1].WritePinState(HIGH); + + cout << "TEST #2:" << endl; + unsigned int testInputPinState = K1_GPIO_Pin[2].ReadPinState(); + cout << "testInputPinState = " << testInputPinState << endl; + + cout << "Test complete! Have a nice day :)" << endl; + +}//END MAIN diff --git a/JetsonGPIO.cpp b/JetsonGPIO.cpp new file mode 100644 index 0000000..1ce62a8 --- /dev/null +++ b/JetsonGPIO.cpp @@ -0,0 +1,433 @@ +/* JetsonGPIO.cpp + * A program that creates custom sized General Purpose Input / Output + * (GPIO) pin group on TK1 connectors J3A2 and J3A1 and controls their + * state (Input or Output and High, Low, or Pulse Width Modulation). + * + * Author: RidgeRun 2011 + * Editted: Blaze Sanders SpaceVR(TM) June 2016 + * Link: http://elinux.org/Jetson/GPIO + * + * Note: The GPIO pins on Jetson TK1 are all 1.8V logic and can only + * supply a few milli-amps of current, so you can't simply attach common + * 5V or 3.3V logic signals or devices. One-way opto-isolated level shifter + * are the preffered method for connecting the TK1 to external devices, + * since its a more rugged method (www.sparkfun.com/products/9118). + */ + +#include //Standard input/output stream objects, needed to use cout() +#include //High accuracy microsecond timing + +#include //Functions to manipulate C strings and arrays, needed to use write() +#include "JetsonGPIO.h" + +//Header files to use system close(), open() and ioctl() functions. +#include +#include +#include + +using namespace std; + +/**Default Constructor with error message. + */ +JetsonGPIO::JetsonGPIO(){ + cout << "I'm sorry Dave, I'm afraid I can't do that. K1 General Purpose Input / Output (GPIO) pin was NOT created!" << endl; +} + +/**Default Destructor to close all General Purpose Input / Output (GPIO) pins. + */ +JetsonGPIO::~JetsonGPIO(){ + if (DEBUG) cout << "All General Purpose Input / Output (GPIO) pin were deleted." << endl; + + gpio_unexport(GPIO_PU0); + gpio_unexport(GPIO_PU1); + gpio_unexport(GPIO_PU2); + gpio_unexport(GPIO_PU3); + gpio_unexport(GPIO_PU4); + gpio_unexport(GPIO_PU5); + gpio_unexport(GPIO_PU6); + gpio_unexport(GPIO_PH1); + //TO-DO: DETERMINE PORT NUMBER gpio_unexport(GPIO_PH2); +} + +/**Standard Constructor to create a single GPIO pin + * @param name Name of the GPIO pin to create and open on the NVIVDA K1 (i.e GPIO_PU0 or GPIO_PH1) + * @param direction Direction of IO pin (i.e. INPUT, OUTPUT, or TO-DO:PWM) + * @param initValue Initial value of an output pin. + * @see Note: Input pins default to LOW before first attempted read in Constructor + */ +JetsonGPIO::JetsonGPIO(unsigned int name, unsigned int direction, unsigned int initValue){ + + //Check that NVIDIA K1 specific GPIO name constant is being used + if(gpio_export(name) && DEBUG){ + cout << "Failed to create GPIO PIN #" << name << " on NVIVDA K1." << endl; + cout << "Please use one of the following six GPIO pin name constants:" << endl; + cout << "GPIO_PU0 (connected to gpio160 on Expansion Connector J3A2 pin 40)" << endl; + cout << "GPIO_PU1 (connected to gpio161 on Expansion Connector J3A2 pin 43)" << endl; + cout << "GPIO_PU2 (connected to gpio162 on Expansion Connector J3A2 pin 46)" << endl; + cout << "GPIO_PU3 (connected to gpio163 on Expansion Connector J3A2 pin 49)" << endl; + cout << "GPIO_PU4 (connected to gpio164 on Expansion Connector J3A2 pin 52)" << endl; + cout << "GPIO_PU5 (connected to gpio165 on Expansion Connector J3A2 pin 55)" << endl; + cout << "GPIO_PH6 (connected to gpio166 on Expansion Connector J3A2 pin 58)" << endl; + cout << "GPIO_PH1 (connected to gpio57 on Expansion Connector J3A1 pin 50)" << endl; + //TO-DO: cout << "GPIO_PH2 (connected to gpio?? on Expansion Connector J3A1 pin 48)" << endl; + } + else{ + //Check that valid direction constant (INPUT_PIN or OUTPUT_PIN) is being used + if(gpio_set_dir(name, direction) && DEBUG){ + cout << "Failed to change direction type of GPIO pin #" << name << " on NVIVDA K1." << endl; + cout << "Please use one of the following three GPIO direction type constants:" << endl; + cout << "INPUT" << endl; + cout << "OUTPUT" << endl; + //TO-DO: cout << "PWM" << endl; + } + else{ + //Determine if creating an input pin or ouput pin + switch(direction){ + case OUTPUT_PIN: + //Check that valid value/state constant (INPUT_PIN or OUTPUT_PIN) is being used + if(gpio_set_value(name, initValue) && DEBUG){ + cout << "Failed to set state of GPIO PIN #" << name << " on NVIVDA K1." << endl; + cout << "Please use one of the following three GPIO direction type constants:" << endl; + cout << "LOW" << endl; + cout << "HIGH" << endl; + //TO-DO: cout << "???_PERCENT" << endl; + } + if(DEBUG) cout << "The " << name << " GPIO pin was created, set as OUTPUT and has a value of " << initValue << "." << endl; + break; + case INPUT_PIN: + //Get input state on GPIO pin + inputPinValue = 0; //Default input pin state to LOW + if(gpio_get_value(name, &inputPinValue) && DEBUG){ + cout << "Failed to get state of GPIO PIN #" << name << " on NVIVDA K1." << endl; + } + if(DEBUG) cout << "The " << name << " GPIO pin was created, set as INPUT and has a value of " << inputPinValue << "." << endl; + break; + /* TO-DO: case PWN_PIN: + * Is PWM cose enough to Output Pin Type case PWM: + * //TO-DO: ??? + * if(DEBUG) cout << "The " << name << " GPIO pin was created, set as OUTPUT PWM and has a duty cycle of " << initValue << "." << endl; + * break; + */ + default: + if(DEBUG) cout << "Invalid direction type for GPIO pin #" << name << endl; + }//END SWITCH + + }//END 2nd ELSE + }//END 1st ELSE +}//END JetsonGPIO() function + +/**Read the logic level on the choosen GPIO pin + * @param name Name of the GPIO pin to read logic level from (i.e GPIO_PU0 or GPIO_PH1) + * @return State of GPIO input pin 0 (LOW) or 1 (HIGH) + */ +unsigned int JetsonGPIO::ReadPinState(){ + + if(gpio_get_value(name, &inputPinValue) && DEBUG){ + cout << "Failed to get state of GPIO PIN #" << name << " on NVIVDA K1." << endl; + } + return inputPinValue; +} + +/**Set the value/state of an output pin to a new level + * @param value Value to output on the GPIO pin + */ +void JetsonGPIO::WritePinState(unsigned int value){ + + if(gpio_set_value(name, value) && DEBUG){ + cout << "Failed to set state of GPIO PIN #" << name << " on NVIVDA K1." << endl; + cout << "Please use one of the following three GPIO direction type constants:" << endl; + cout << "LOW" << endl; + cout << "HIGH" << endl; + //TO-DO: cout << "???_PERCENT" << endl; + } +} + +/** Unit Test: Create and test an array of three GPIO pins (two outputs and one input) + * @see Test #1 - Time stamp a rising edge trigger and PWM exposure event to a resolution of 1 microsecond + * @see Test #2 - Get state of inoput pint and print value + */ +void JetsonGPIO::UnitTest(){ + + //Make sure to run the compiled executable under admin / sudo privileges + + unsigned int NUMBER_OF_GPIO_PINS = 3; + JetsonGPIO K1_GPIO_Pin[NUMBER_OF_GPIO_PINS]; + K1_GPIO_Pin[0] = JetsonGPIO(GPIO_PU0, OUTPUT_PIN, LOW); + K1_GPIO_Pin[1] = JetsonGPIO(GPIO_PU1, OUTPUT_PIN, LOW); + K1_GPIO_Pin[2] = JetsonGPIO(GPIO_PU2, INPUT_PIN, LOW); + + time_t now; + struct tm MissionStart; + double elapsedSeconds; + + auto start = chrono::high_resolution_clock::now(); + time(&now); /* get current time; same as: now = time(NULL) */ + + //Setup time variables to track Mission Elapsed Time (MET) + MissionStart = *localtime(&now); + MissionStart.tm_hour = 0; MissionStart.tm_min = 0; MissionStart.tm_sec = 0; + MissionStart.tm_mon = 0; MissionStart.tm_mday = 1; + + elapsedSeconds = difftime(now,mktime(&MissionStart)); + auto elapsed = chrono::high_resolution_clock::now() - start; + long long elapsedMircoSeconds = std::chrono::duration_cast(elapsed).count(); + + cout << "TEST #1:" << endl; + printf("Mission Elaspe Time (MET) TRIGGER timeStamp (i.e Month-MonthDay-Hour-Minutes-Seconds-MilliSeconds) = %d-%d-%d-%d-%f-", + MissionStart.tm_mon, MissionStart.tm_mday, MissionStart.tm_hour, MissionStart.tm_min, elapsedSeconds); + cout << elapsedMircoSeconds << endl; + + K1_GPIO_Pin[0].WritePinState(HIGH); //Set trigger pin high + + printf("Mission Elaspe Time (MET) EXPOSURE timeStamp (i.e Month-MonthDay-Hour-Minutes-Seconds-MilliSeconds) = %d-%d-%d-%d-%f-", + MissionStart.tm_mon, MissionStart.tm_mday, MissionStart.tm_hour, MissionStart.tm_min, elapsedSeconds); + cout << elapsedMircoSeconds << endl; + + //Toggle exposure pin at 50% duty cycle with period of 32 millisecons + K1_GPIO_Pin[1].WritePinState(HIGH); + usleep(16000); + K1_GPIO_Pin[1].WritePinState(LOW); + usleep(16000); + K1_GPIO_Pin[1].WritePinState(HIGH); + + cout << "TEST #2:" << endl; + unsigned int testInputPinState = K1_GPIO_Pin[2].ReadPinState(); + cout << "testInputPinState = " << testInputPinState << endl; + + cout << "Test complete!" << endl; + +} + + +/**Add GPIO pin to /sys/kernel/debug/gpio table + * @param gpio Name of the GPIO pin to open on the NVIVDA K1 (i.e GPIO_PU0 or GPIO_PH1) + * @link https://github.com/derekmolloy/boneDeviceTree/tree/master/gpio + * @see GPIOSetup.sh file for command line example + * @return FALSE = 0 if no errors, TRUE = 1 otherwise + */ +int JetsonGPIO::gpio_export(unsigned int gpio){ + int fd, len; + char buf[MAX_BUF]; + + fd = open(SYSFS_GPIO_DIR "/export", O_WRONLY); + + if (fd < 0) { + perror("gpio/export"); + return fd; + } + + len = snprintf(buf, sizeof(buf), "%d", gpio); + write(fd, buf, len); + close(fd); + + return 0; +} + +/**Remove GPIO pin to /sys/kernel/debug/gpio table + * @param gpio Name of the GPIO pin to open on the NVIVDA K1 (i.e GPIO_PU0 or GPIO_PH1) + * @link https://github.com/derekmolloy/boneDeviceTree/tree/master/gpio + * @see GPIOSetup.sh file for command line example + * @return FALSE = 0 if no errors, TRUE = 1 otherwise + */ +int JetsonGPIO::gpio_unexport(unsigned int gpio){ + int fd, len; + char buf[MAX_BUF]; + fd = open(SYSFS_GPIO_DIR "/unexport", O_WRONLY); + + if (fd < 0) { + perror("gpio/export"); + return fd; + } + + len = snprintf(buf, sizeof(buf), "%d", gpio); + write(fd, buf, len); + close(fd); + + return 0; +} + +/**Set direction of GPIO output pin (i.e INPUT_PIN or OUTPUT_PIN) + * @param gpio Name of the GPIO output pin to change on the NVIVDA K1 (i.e GPIO_PU0 or GPIO_PH1) + * @param out_flag Desired direction of pin (INPUT_PIN = 0 or OUTPUT_PIN = 1) + * @link https://github.com/derekmolloy/boneDeviceTree/tree/master/gpio + * @see GPIOSetup.sh file for command line example + * @see JetsonGPIO.h for pin constants + * @return FALSE = 0 if no errors, TRUE = 1 otherwise + */ +int JetsonGPIO::gpio_set_dir(unsigned int gpio, unsigned int out_flag){ + int fd; + char buf[MAX_BUF]; + + snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/direction", gpio); + fd = open(buf, O_WRONLY); + + if (fd < 0) { + perror("gpio/direction"); + return fd; + } + + if (out_flag == OUTPUT_PIN) + write(fd, "out", 4); + else + write(fd, "in", 3); + + close(fd); + + return 0; +} + +/**Set value of GPIO output pin (i.e LOW, HIGH, or TO-DO: PWM) + * @param gpio Name of the GPIO output pin to change on the NVIVDA K1 (i.e GPIO_PU0 or GPIO_PH1) + * @param value Desired value/state of pin (LOW = 0, HIGH = 1, or TO-DO: TWO_PERCENT = 2) + * @link https://github.com/derekmolloy/boneDeviceTree/tree/master/gpio + * @see GPIOSetup.sh file for command line example + * @see JetsonGPIO.h for pin constants + * @return FALSE = 0 if no errors, TRUE = 1 otherwise + */ +int JetsonGPIO::gpio_set_value(unsigned int gpio, unsigned int value){ + int fd; + char buf[MAX_BUF]; + + snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio); + fd = open(buf, O_WRONLY); + + if (fd < 0) { + perror("gpio/set-value"); + return fd; + } + + if (value==LOW) + write(fd, "0", 2); + else + write(fd, "1", 2); + + close(fd); + + return 0; +} + +/**Get value of GPIO input pin (i.e LOW or HIGH) + * @param gpio Name of the GPIO output pin to change on the NVIVDA K1 (i.e GPIO_PU0 or GPIO_PH1) + * @param value Current value/state of pin (LOW = 0 or HIGH = 1) + * @link https://github.com/derekmolloy/boneDeviceTree/tree/master/gpio + * @see GPIOSetup.sh file for command line example + * @see JetsonGPIO.h for pin constants + * @return FALSE = 0 if no errors, TRUE = 1 otherwise + */ +int JetsonGPIO::gpio_get_value(unsigned int gpio, unsigned int *value){ + int fd; + char buf[MAX_BUF]; + char ch; + + snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio); + fd = open(buf, O_RDONLY); + + if (fd < 0) { + perror("gpio/get-value"); + return fd; + } + + read(fd, &ch, 1); + + if (ch != '0') { + *value = 1; + } else { + *value = 0; + } + + close(fd); + + return 0; +} + +/**??? + * @param gpio Name of the GPIO output pin to change on the NVIVDA K1 (i.e GPIO_PU0 or GPIO_PH1) + * @param edge ??? + * @link https://github.com/derekmolloy/boneDeviceTree/tree/master/gpio + * @see GPIOSetup.sh file for command line example ??? + * @see JetsonGPIO.h for pin constants + * @return FALSE = 0 if no errors, TRUE = 1 otherwise + */ +int JetsonGPIO::gpio_set_edge(unsigned int gpio, char *edge){ + int fd; + char buf[MAX_BUF]; + + snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/edge", gpio); + fd = open(buf, O_WRONLY); + + if (fd < 0) { + perror("gpio/set-edge"); + return fd; + } + + write(fd, edge, strlen(edge) + 1); + + close(fd); + + return 0; +} + +/**??? + * @param gpio Name of the GPIO output pin to change on the NVIVDA K1 (i.e GPIO_PU0 or GPIO_PH1) + * @link https://github.com/derekmolloy/boneDeviceTree/tree/master/gpio + * @see GPIOSetup.sh file for command line example ??? + * @see JetsonGPIO.h for pin constants + * @return FALSE = 0 if no errors, TRUE = 1 otherwise + */ +int JetsonGPIO::gpio_fd_open(unsigned int gpio){ + int fd; + char buf[MAX_BUF]; + + snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio); + fd = open(buf, O_RDONLY | O_NONBLOCK ); + + if (fd < 0) { + perror("gpio/fd_open"); + } + + return fd; +} + +/**??? + * @param gpio Name of the GPIO output pin to change on the NVIVDA K1 (i.e GPIO_PU0 or GPIO_PH1) + * @link https://github.com/derekmolloy/boneDeviceTree/tree/master/gpio + * @see GPIOSetup.sh file for command line example ??? + * @see JetsonGPIO.h for pin constants + * @return FALSE = 0 if no errors, TRUE = 1 otherwise + */ +int JetsonGPIO::gpio_fd_close(int fd){ + return close(fd); +} + +/* Copyright Derek Molloy, School of Electronic Engineering, Dublin City University + * www.derekmolloy.ie + * + * Based on Software by RidgeRun + * Copyright (c) 2011, RidgeRun + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the RidgeRun. + * 4. Neither the name of the RidgeRun nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY RIDGERUN ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL RIDGERUN BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/JetsonGPIO.h b/JetsonGPIO.h new file mode 100644 index 0000000..02d6f41 --- /dev/null +++ b/JetsonGPIO.h @@ -0,0 +1,115 @@ +/* JetsonGPIO.h + * A program that creates custom sized General Purpose Input / Output + * (GPIO) pin group on TK1 connectors J3A2 and J3A1 and controls their + * state (Input or Output and High, Low, or Pulse Width Modulation). + * + * Author: RidgeRun 2011 + * Editted: Blaze Sanders SpaceVR(TM) June 2016 + * Link: http://elinux.org/Jetson/GPIO + * + * Note: The GPIO pins on Jetson TK1 are all 1.8V logic and can only + * supply a few milli-amps of current, so you can't simply attach common + * 5V or 3.3V logic signals or devices. One-way opto-isolated level shifter + * are the preffered method for connecting the TK1 to external devices, + * since its a more rugged method (www.sparkfun.com/products/9118). + */ + +#ifndef JETSON_GPIO_H +#define JETSON_GPIO_H + +#define DEBUG 1 //Toggle error messages on and off + +//Pin value/state constants +#define LOW 0 +#define HIGH 1 +//TO-DO: #define PWM_TWO_PERCENT to PWM_HUNDRED_PERCENT in two percent steps + +//Pin direction constants +#define INPUT_PIN 0 +#define OUTPUT_PIN 1 +//TO-DO: define PWM + + +//NVIDIA specific GPIO pin constants +#define MAX_GPIO_PINS 9 //GPIO_PU0 to GPIO_PU6 + GPIO_PH1 + GPIO_PH2 +#define GPIO_PU0 0x0160 //Expansion Connector J3A2 pin 40 Available for general use (INPUT OR OUTPUT) +#define GPIO_PU1 0x160 //Expansion Connector J3A2 pin 43 Available for general use (INPUT OR OUTPUT) +#define GPIO_PU2 0x162 //Expansion Connector J3A2 pin 46 Available for general use (INPUT OR OUTPUT) +#define GPIO_PU3 0x163 //Expansion Connector J3A2 pin 49 Available for general use (INPUT OR OUTPUT) +#define GPIO_PU4 0x164 //Expansion Connector J3A2 pin 52 Available for general use (INPUT OR OUTPUT) +#define GPIO_PU5 0x165 //Expansion Connector J3A2 pin 55 Available for general use (INPUT OR OUTPUT) +#define GPIO_PU6 0x166 //Expansion Connector J3A2 pin 58 Available for general use (INPUT OR OUTPUT) +#define GPIO_PH1 0x57 //Expansion Connector J3A1 pin 50 Backlight PWM (INPUT) LCD_BL_PWM +//TO-DO DETERMINE PORT NUMBER #define GPIO_PH2 ?? //Expansion Connector J3A1 pin 48 Backlight enable (INPUT) LCD_BL_EN +//string GPIO_PU0 = "gpio160"; //Defaults to 1.8V +//const char * GPIO_PU0 = "gpio160"; + +#define SYSFS_GPIO_DIR "/sys/class/gpio" +#define POLL_TIMEOUT 3000 // 3000 milliseconds = 3 seconds +#define MAX_BUF 64 + +/** Low level driver to control up to 9 K1 GPIO pins. + * @link http://elinux.org/Jetson/GPIO + * @link https://github.com/derekmolloy/boneDeviceTree/tree/master/gpio + */ +class JetsonGPIO +{ + public: + JetsonGPIO(); + ~JetsonGPIO(); + JetsonGPIO(unsigned int name, unsigned int direction, unsigned int initValue); + + //Wrapper functions for private functions + unsigned int ReadPinState(); + void WritePinState(unsigned int value); + void UnitTest(); + + private: + unsigned int name; //NVIDIA pin name (i.e. GPIO_PU0) + unsigned int inputPinValue; //Stored state of input pin + + //Linux specific system calls to get GPIO information + int gpio_export(unsigned int gpio); + int gpio_unexport(unsigned int gpio); + int gpio_set_dir(unsigned int gpio, unsigned int out_flag); + int gpio_set_value(unsigned int gpio, unsigned int value); + int gpio_get_value(unsigned int gpio, unsigned int *value); + int gpio_set_edge(unsigned int gpio, char *edge); + int gpio_fd_open(unsigned int gpio); + int gpio_fd_close(int fd); +}; + +#endif //JETSON_GPIO_H + +/* Copyright Derek Molloy, School of Electronic Engineering, Dublin City University + * www.derekmolloy.ie + * + * Based on Software by RidgeRun + * Copyright (c) 2011, RidgeRun + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the RidgeRun. + * 4. Neither the name of the RidgeRun nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY RIDGERUN ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL RIDGERUN BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */