347 lines
12 KiB
C
347 lines
12 KiB
C
/*******************************************************************************
|
|
*
|
|
* gpio.c
|
|
*
|
|
* Copyright (c) 2013 Shahrooz Shahparnia
|
|
*
|
|
* Description:
|
|
* gpio is a command-line utility for executing gpio commands with the
|
|
* Broadcom bcm2835. It was developed and tested on a Raspberry Pi single-board
|
|
* computer model B. The utility is based on the bcm2835 C library developed
|
|
* by Mike McCauley of Open System Consultants, http://www.open.com.au/mikem/bcm2835/.
|
|
*
|
|
* Invoking "gpio" results in a read, set of clear of a GPIO.
|
|
* Options include GPIO read/set/clear
|
|
* of a single GPIO pin, enabling or disabling pull up and pull downs as well as
|
|
* resetting all GPIOs to a default input state.
|
|
* The command usage and command-line parameters are described below
|
|
* in the showusage function, which prints the usage if no command-line parameters
|
|
* are included or if there are any command-line parameter errors. Invoking gpio
|
|
* requires root privilege.
|
|
*
|
|
* This file contains the main function as well as functions for displaying
|
|
* usage and for parsing the command line.
|
|
*
|
|
* Open Source Licensing GNU GPLv3
|
|
*
|
|
* Building:
|
|
* After installing bcm2835, you can build this
|
|
* with something like:
|
|
* gcc -o gpio gpio.c -l bcm2835
|
|
* sudo ./gpio
|
|
*
|
|
* Or you can test it before installing with:
|
|
* gcc -o gpio -I ../../src ../../src/bcm2835.c gpio.c
|
|
* sudo ./gpio
|
|
*
|
|
*
|
|
* History:
|
|
* 11/10 VERSION 1.0.0: Original
|
|
*
|
|
* User input parsing (comparse) and showusage\
|
|
* have been adapted from: http://ipsolutionscorp.com/raspberry-pi-spi-utility/
|
|
* mostly to keep consistence with the spincl tool usage.
|
|
*
|
|
* Compile with: gcc -o gpio gpio.c bcm2835.c
|
|
*
|
|
* Examples:
|
|
* Clear pin 5: sudo ./gpio -ib -dc -pn -n5
|
|
* Reset all GPIOs to inputs and disable all pull up/downs: sudo ./gpio -ie
|
|
* Read pin 10: sudo ./gpio -ib -dr -pn -n10
|
|
* Read pin 10 in debug mode with verbose output: sudo ./gpio -ib -dr -pn -n10 -b
|
|
* Read pin 10 and set pin as input with pull down: sudo ./gpio -ib -di -pd -n10
|
|
*
|
|
* Note: Pin numbers match the Raspberry Pie connector pin numbers
|
|
********************************************************************************/
|
|
|
|
#include <bcm2835.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
|
|
#define MODE_READ 0
|
|
#define MODE_SET 1
|
|
#define MODE_CLR 2
|
|
#define MODE_INPUT_READ 3
|
|
|
|
#define PULL_UP 0
|
|
#define PULL_DOWN 1
|
|
#define NO_PULL 2
|
|
|
|
#define GPIO_BEGIN 0
|
|
#define GPIO_END 1
|
|
#define NO_ACTION 2
|
|
|
|
#define NO_PIN 40 // Some big number that's beyond the connector's pin count
|
|
#define DEBUG_OFF 0
|
|
#define DEBUG_ON 1
|
|
|
|
uint8_t init = NO_ACTION;
|
|
uint8_t pull = NO_PULL;
|
|
uint8_t mode = MODE_READ;
|
|
uint8_t pin_number = NO_PIN;
|
|
|
|
uint8_t i, len;
|
|
uint8_t data, pin, debug_mode = DEBUG_OFF;
|
|
|
|
//*******************************************************************************
|
|
// comparse: Parse the command line and return EXIT_SUCCESS or EXIT_FAILURE
|
|
// argc: number of command-line arguments
|
|
// argv: array of command-line argument strings
|
|
//*******************************************************************************
|
|
|
|
void gpio_reset(void);
|
|
|
|
int comparse(int argc, char **argv) {
|
|
int argnum, i, xmitnum;
|
|
|
|
if (argc < 2) { // must have at least program name and len arguments
|
|
// or -ie (GPIO_END) or -ib (GPIO_BEGIN)
|
|
fprintf(stderr, "Insufficient command line arguments\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
argnum = 1;
|
|
while (argnum < argc && argv[argnum][0] == '-') {
|
|
|
|
switch (argv[argnum][1]) {
|
|
|
|
case 'i': // GPIO init
|
|
switch (argv[argnum][2]) {
|
|
case 'b': init = GPIO_BEGIN; break;
|
|
case 'e': init = GPIO_END; break;
|
|
default:
|
|
fprintf(stderr, "%c is not a valid init option\n", argv[argnum][2]);
|
|
return EXIT_FAILURE;
|
|
}
|
|
break;
|
|
|
|
case 'd': // Set/Clear/Read Mode
|
|
switch (argv[argnum][2]) {
|
|
case 'r': mode = MODE_READ; break;
|
|
case 's': mode = MODE_SET; break;
|
|
case 'c': mode = MODE_CLR; break;
|
|
case 'i': mode = MODE_INPUT_READ; break;
|
|
default:
|
|
fprintf(stderr, "%c is not a valid init option\n", argv[argnum][2]);
|
|
return EXIT_FAILURE;
|
|
}
|
|
break;
|
|
|
|
case 'p': // Pull up, down and no pull Mode
|
|
switch (argv[argnum][2]) {
|
|
case 'u': pull = PULL_UP; break;
|
|
case 'd': pull = PULL_DOWN; break;
|
|
case 'n': pull = NO_PULL; break;
|
|
default:
|
|
fprintf(stderr, "%c is not a valid init option\n", argv[argnum][2]);
|
|
return EXIT_FAILURE;
|
|
}
|
|
break;
|
|
|
|
case 'n': // pin number
|
|
pin_number = atoi(argv[argnum]+2);
|
|
break;
|
|
|
|
case 'b': // debug mode
|
|
debug_mode = DEBUG_ON;
|
|
break;
|
|
|
|
default:
|
|
fprintf(stderr, "%c is not a valid option\n", argv[argnum][1]);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
argnum++; // advance the argument number
|
|
|
|
}
|
|
|
|
if (argnum == argc && init != NO_ACTION) // no further arguments are needed
|
|
return EXIT_SUCCESS;
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
//*******************************************************************************
|
|
// showusage: Print the usage statement and return errcode.
|
|
//*******************************************************************************
|
|
|
|
int showusage(int errcode) {
|
|
printf("gpio \n");
|
|
printf("Usage: \n");
|
|
printf(" gpio [options]\n");
|
|
printf("\n");
|
|
printf(" Invoking gpio to set or reset a GPIO, enable disable pull up or pull down. Initialize or release a GPIO.\n");
|
|
printf("\n");
|
|
printf(" The following are the options, which must be a single letter\n");
|
|
printf(" preceded by a '-' and followed by another character.\n");
|
|
printf(" -ix where x is the GPIO init option, b[egin] or e[nd]\n");
|
|
printf(" The begin option must be executed before any transfer can happen.\n");
|
|
printf(" The end option will return the GPIO to inputs and turn off all pull up and pull downs.\n");
|
|
printf(" It may be included with a transfer.\n");
|
|
printf(" -dx where x is 'c' for clear, 's' is for set, 'r' for read and 'i' for read and set as input.\n");
|
|
printf(" -px where x is the GPIO pull up or down option. 'u' for pull up, 'd' for pull down and 'n' for none.\n");
|
|
printf(" -nx where x is the pin number.\n");
|
|
printf("\n");
|
|
return errcode;
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
|
|
printf("Running ... \n");
|
|
|
|
// parse the command line
|
|
if (comparse(argc, argv) == EXIT_FAILURE) return showusage (EXIT_FAILURE);
|
|
|
|
if (!bcm2835_init()) return 1;
|
|
|
|
// GPIO begin if specified
|
|
if (init == GPIO_BEGIN) ;
|
|
|
|
|
|
// If len is 0, no need to continue, but do GPIO end if specified
|
|
// if (len == 0) {
|
|
// if (init == GPIO_END) ;
|
|
// printf("Zero length ... error!\n");
|
|
// return EXIT_SUCCESS;
|
|
// }
|
|
switch (pin_number) {
|
|
case 3:
|
|
pin = RPI_V2_GPIO_P1_03;
|
|
break;
|
|
case 5:
|
|
pin = RPI_V2_GPIO_P1_05;
|
|
break;
|
|
case 7:
|
|
pin = RPI_V2_GPIO_P1_07;
|
|
break;
|
|
case 26:
|
|
pin = RPI_V2_GPIO_P1_26;
|
|
break;
|
|
case 24:
|
|
pin = RPI_V2_GPIO_P1_24;
|
|
break;
|
|
case 21:
|
|
pin = RPI_V2_GPIO_P1_21;
|
|
break;
|
|
case 19:
|
|
pin = RPI_V2_GPIO_P1_19;
|
|
break;
|
|
case 23:
|
|
pin = RPI_V2_GPIO_P1_23;
|
|
break;
|
|
case 10:
|
|
pin = RPI_V2_GPIO_P1_10;
|
|
break;
|
|
case 11:
|
|
pin = RPI_V2_GPIO_P1_11;
|
|
break;
|
|
case 12:
|
|
pin = RPI_V2_GPIO_P1_12;
|
|
break;
|
|
case 13:
|
|
pin = RPI_V2_GPIO_P1_13;
|
|
break;
|
|
case 15:
|
|
pin = RPI_V2_GPIO_P1_15;
|
|
break;
|
|
case 16:
|
|
pin = RPI_V2_GPIO_P1_16;
|
|
break;
|
|
case 18:
|
|
pin = RPI_V2_GPIO_P1_18;
|
|
break;
|
|
case 22:
|
|
pin = RPI_V2_GPIO_P1_22;
|
|
break;
|
|
default:
|
|
pin = NO_PIN;
|
|
}
|
|
|
|
switch (pull) {
|
|
case PULL_UP:
|
|
bcm2835_gpio_set_pud(pin, BCM2835_GPIO_PUD_UP);
|
|
break;
|
|
case PULL_DOWN:
|
|
bcm2835_gpio_set_pud(pin, BCM2835_GPIO_PUD_DOWN);
|
|
break;
|
|
case NO_PULL:
|
|
bcm2835_gpio_set_pud(pin, BCM2835_GPIO_PUD_OFF);
|
|
break;
|
|
default:
|
|
bcm2835_gpio_set_pud(pin, BCM2835_GPIO_PUD_OFF);
|
|
}
|
|
|
|
switch (mode) {
|
|
case MODE_READ:
|
|
data = bcm2835_gpio_lev(pin);
|
|
printf("Reading pin: %d\n", data);
|
|
break;
|
|
case MODE_INPUT_READ:
|
|
bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_INPT);
|
|
data = bcm2835_gpio_lev(pin);
|
|
printf("Reading pin: %d\n", data);
|
|
break;
|
|
case MODE_SET:
|
|
bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_OUTP);
|
|
bcm2835_gpio_set(pin);
|
|
break;
|
|
case MODE_CLR:
|
|
bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_OUTP);
|
|
bcm2835_gpio_clr(pin);
|
|
break;
|
|
default:
|
|
printf("Wrong mode ...!\n");
|
|
}
|
|
|
|
if (debug_mode == DEBUG_ON) {
|
|
printf("Init %d\n", init);
|
|
printf("Mode %d\n", mode);
|
|
printf("Pull %d\n", pull);
|
|
printf("Pin Number %d\n", pin_number);
|
|
printf("Pin %d\n", pin);
|
|
}
|
|
|
|
if (init == GPIO_END) gpio_reset();
|
|
bcm2835_close();
|
|
printf("... done!\n");
|
|
return 0;
|
|
}
|
|
|
|
void gpio_reset(void) {
|
|
bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_03, BCM2835_GPIO_PUD_OFF);
|
|
bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_05, BCM2835_GPIO_PUD_OFF);
|
|
bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_07, BCM2835_GPIO_PUD_OFF);
|
|
bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_26, BCM2835_GPIO_PUD_OFF);
|
|
bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_24, BCM2835_GPIO_PUD_OFF);
|
|
bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_21, BCM2835_GPIO_PUD_OFF);
|
|
bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_19, BCM2835_GPIO_PUD_OFF);
|
|
bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_23, BCM2835_GPIO_PUD_OFF);
|
|
bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_10, BCM2835_GPIO_PUD_OFF);
|
|
bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_11, BCM2835_GPIO_PUD_OFF);
|
|
bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_12, BCM2835_GPIO_PUD_OFF);
|
|
bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_13, BCM2835_GPIO_PUD_OFF);
|
|
bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_15, BCM2835_GPIO_PUD_OFF);
|
|
bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_16, BCM2835_GPIO_PUD_OFF);
|
|
bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_18, BCM2835_GPIO_PUD_OFF);
|
|
bcm2835_gpio_set_pud(RPI_V2_GPIO_P1_22, BCM2835_GPIO_PUD_OFF);
|
|
|
|
bcm2835_gpio_fsel(RPI_V2_GPIO_P1_03, BCM2835_GPIO_FSEL_INPT);
|
|
bcm2835_gpio_fsel(RPI_V2_GPIO_P1_05, BCM2835_GPIO_FSEL_INPT);
|
|
bcm2835_gpio_fsel(RPI_V2_GPIO_P1_07, BCM2835_GPIO_FSEL_INPT);
|
|
bcm2835_gpio_fsel(RPI_V2_GPIO_P1_26, BCM2835_GPIO_FSEL_INPT);
|
|
bcm2835_gpio_fsel(RPI_V2_GPIO_P1_24, BCM2835_GPIO_FSEL_INPT);
|
|
bcm2835_gpio_fsel(RPI_V2_GPIO_P1_21, BCM2835_GPIO_FSEL_INPT);
|
|
bcm2835_gpio_fsel(RPI_V2_GPIO_P1_19, BCM2835_GPIO_FSEL_INPT);
|
|
bcm2835_gpio_fsel(RPI_V2_GPIO_P1_23, BCM2835_GPIO_FSEL_INPT);
|
|
bcm2835_gpio_fsel(RPI_V2_GPIO_P1_10, BCM2835_GPIO_FSEL_INPT);
|
|
bcm2835_gpio_fsel(RPI_V2_GPIO_P1_11, BCM2835_GPIO_FSEL_INPT);
|
|
bcm2835_gpio_fsel(RPI_V2_GPIO_P1_12, BCM2835_GPIO_FSEL_INPT);
|
|
bcm2835_gpio_fsel(RPI_V2_GPIO_P1_13, BCM2835_GPIO_FSEL_INPT);
|
|
bcm2835_gpio_fsel(RPI_V2_GPIO_P1_15, BCM2835_GPIO_FSEL_INPT);
|
|
bcm2835_gpio_fsel(RPI_V2_GPIO_P1_16, BCM2835_GPIO_FSEL_INPT);
|
|
bcm2835_gpio_fsel(RPI_V2_GPIO_P1_18, BCM2835_GPIO_FSEL_INPT);
|
|
bcm2835_gpio_fsel(RPI_V2_GPIO_P1_22, BCM2835_GPIO_FSEL_INPT);
|
|
}
|