From 13bbba7a2275f19d597909ecd80a074ae34c94f6 Mon Sep 17 00:00:00 2001 From: Gordon Henderson Date: Mon, 14 Jan 2013 11:31:56 +0000 Subject: [PATCH] Lots of changes here. Added new I2C test code, a new serialTest program, and developed the new ISR - Interrupt Service Routine handler - much easier than the old waitForInterrupt code! Minor tweaks to the gpio program to recognise the environment variable WIRINGPI_DEBUG too, and removed the printing of the errors from the main wiringPi setup routines (and added some new ones!) --- INSTALL | 36 +++++++ examples/Makefile | 12 ++- examples/isr.c | 99 ++++++++++++++++++ examples/okLed.c | 1 + examples/serialTest.c | 57 ++++++++++ examples/wfi.c | 31 +++--- gpio/Makefile | 2 +- gpio/gpio.1 | 13 ++- gpio/gpio.c | 24 ++++- wiringPi/Makefile | 20 ++-- wiringPi/wiringPi.c | 231 ++++++++++++++++++++++++++++++++--------- wiringPi/wiringPi.h | 37 ++++--- wiringPi/wiringPiI2C.c | 122 ++++++++++++++++++++++ wiringPi/wiringPiI2C.h | 41 ++++++++ wiringPi/wiringPiISR.c | 109 +++++++++++++++++++ 15 files changed, 744 insertions(+), 91 deletions(-) create mode 100644 INSTALL create mode 100644 examples/isr.c create mode 100644 examples/serialTest.c create mode 100644 wiringPi/wiringPiI2C.c create mode 100644 wiringPi/wiringPiI2C.h create mode 100644 wiringPi/wiringPiISR.c diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..8e0c43c --- /dev/null +++ b/INSTALL @@ -0,0 +1,36 @@ + +How to install wiringPi +======================= + +The easiest way is to use the supplied 'build' script: + + ./build + +that should do a complete install or upgrade of wiringPi for you. + +That will install a dynamic library. + +Some distributions do not have /usr/local/lib in the default LD_LIBRARY_PATH. To +fix this, you need to edit /etc/ld.so.conf and add in a single line: + + /usr/local/lib + +then run the ldconfig command. + + sudo ldconfig + +If you want to install a static library, you may need to do this manually: + + cd wiringPi + make static + sudo make install-static + + +To un-install wiringPi: + + ./build uninstall + +Gordon Henderson + +projects@drogon.net +https://projects.drogon.net/ diff --git a/examples/Makefile b/examples/Makefile index 738d36c..3607fc8 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -35,10 +35,10 @@ LDLIBS = -lwiringPi # Should not alter anything below this line ############################################################################### -SRC = test1.c test2.c speed.c lcd.c wfi.c \ +SRC = test1.c test2.c speed.c lcd.c wfi.c isr.c \ piface.c gertboard.c nes.c \ pwm.c tone.c servo.c \ - delayTest.c serialRead.c okLed.c + delayTest.c serialRead.c serialTest.c okLed.c OBJ = $(SRC:.c=.o) @@ -69,6 +69,10 @@ wfi: wfi.o @echo [link] @$(CC) -o $@ wfi.o $(LDFLAGS) $(LDLIBS) +isr: isr.o + @echo [link] + @$(CC) -o $@ isr.o $(LDFLAGS) $(LDLIBS) + piface: piface.o @echo [link] @$(CC) -o $@ piface.o $(LDFLAGS) $(LDLIBS) -lpthread @@ -93,6 +97,10 @@ serialRead: serialRead.o @echo [link] @$(CC) -o $@ serialRead.o $(LDFLAGS) $(LDLIBS) +serialTest: serialTest.o + @echo [link] + @$(CC) -o $@ serialTest.o $(LDFLAGS) $(LDLIBS) + okLed: okLed.o @echo [link] @$(CC) -o $@ okLed.o $(LDFLAGS) $(LDLIBS) diff --git a/examples/isr.c b/examples/isr.c new file mode 100644 index 0000000..2bef54a --- /dev/null +++ b/examples/isr.c @@ -0,0 +1,99 @@ +/* + * isr.c: + * Wait for Interrupt test program - ISR method + * + * How to test: + * Use the SoC's pull-up and pull down resistors that are avalable + * on input pins. So compile & run this program (via sudo), then + * in another terminal: + * gpio mode 0 up + * gpio mode 0 down + * at which point it should trigger an interrupt. Toggle the pin + * up/down to generate more interrupts to test. + * + * Copyright (c) 2013 Gordon Henderson. + *********************************************************************** + * This file is part of wiringPi: + * https://projects.drogon.net/raspberry-pi/wiringpi/ + * + * wiringPi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * wiringPi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with wiringPi. If not, see . + *********************************************************************** + */ + +#include +#include +#include +#include +#include + + +// What GPIO input are we using? +// This is a wiringPi pin number + +#define BUTTON_PIN 0 + +// globalCounter: +// Global variable to count interrupts +// Should be declared volatile to make sure the compiler doesn't cache it. + +static volatile int globalCounter = 0 ; + + +/* + * myInterrupt: + ********************************************************************************* + */ + +void myInterrupt (void) +{ + ++globalCounter ; +} + + +/* + ********************************************************************************* + * main + ********************************************************************************* + */ + +int main (void) +{ + int myCounter = 0 ; + + if (wiringPiSetup () < 0) + { + fprintf (stderr, "Unable to setup wiringPi: %s\n", strerror (errno)) ; + return 1 ; + } + + if (wiringPiISR (BUTTON_PIN, INT_EDGE_FALLING, &myInterrupt) < 0) + { + fprintf (stderr, "Unable to setup ISR: %s\n", strerror (errno)) ; + return 1 ; + } + + + for (;;) + { + printf ("Waiting ... ") ; fflush (stdout) ; + + while (myCounter == globalCounter) + delay (100) ; + + printf (" Done. counter: %5d\n", globalCounter) ; + myCounter = globalCounter ; + } + + return 0 ; +} diff --git a/examples/okLed.c b/examples/okLed.c index 3bf21e2..02f0b22 100644 --- a/examples/okLed.c +++ b/examples/okLed.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include diff --git a/examples/serialTest.c b/examples/serialTest.c new file mode 100644 index 0000000..85a1a66 --- /dev/null +++ b/examples/serialTest.c @@ -0,0 +1,57 @@ +/* + * serialTest.c: + * Very simple program to test the serial port. Expects + * the port to be looped back to itself + * + */ + +#include +#include +#include + +#include +#include + +int main () +{ + int fd ; + int count ; + unsigned int nextTime ; + + if ((fd = serialOpen ("/dev/ttyAMA0", 115200)) < 0) + { + fprintf (stderr, "Unable to open serial device: %s\n", strerror (errno)) ; + return 1 ; + } + + if (wiringPiSetup () == -1) + { + fprintf (stdout, "Unable to start wiringPi: %s\n", strerror (errno)) ; + return 1 ; + } + + nextTime = millis () + 300 ; + + for (count = 0 ; count < 256 ; ) + { + if (millis () > nextTime) + { + printf ("\nOut: %3d: ", count) ; + fflush (stdout) ; + serialPutchar (fd, count) ; + nextTime += 300 ; + ++count ; + } + + delay (3) ; + + while (serialDataAvail (fd)) + { + printf (" -> %3d", serialGetchar (fd)) ; + fflush (stdout) ; + } + } + + printf ("\n") ; + return 0 ; +} diff --git a/examples/wfi.c b/examples/wfi.c index 9efcc2c..6bb6892 100644 --- a/examples/wfi.c +++ b/examples/wfi.c @@ -2,7 +2,17 @@ * wfi.c: * Wait for Interrupt test program * - * Copyright (c) 2012 Gordon Henderson. + * This program demonstrates the use of the waitForInterrupt() + * function in wiringPi. It listens to a button input on + * BCM_GPIO pin 17 (wiringPi pin 0) + * + * The biggest issue with this method is that it really only works + * well in Sys mode. + * + * Jan 2013: This way of doing things is sort of deprecated now, see + * the wiringPiISR() function instead and the isr.c test program here. + * + * Copyright (c) 2012-2013 Gordon Henderson. *********************************************************************** * This file is part of wiringPi: * https://projects.drogon.net/raspberry-pi/wiringpi/ @@ -33,9 +43,8 @@ #define COUNT_KEY 0 // What BCM_GPIO input are we using? -// GPIO 0 is one of the I2C pins with an on-board pull-up -#define BUTTON_PIN 0 +#define BUTTON_PIN 17 // Debounce time in mS @@ -63,13 +72,11 @@ PI_THREAD (waitForIt) int debounceTime = 0 ; (void)piHiPri (10) ; // Set this thread to be high priority - digitalWrite (18, 1) ; for (;;) { if (waitForInterrupt (BUTTON_PIN, -1) > 0) // Got it { - // Bouncing? if (millis () < debounceTime) @@ -80,7 +87,6 @@ PI_THREAD (waitForIt) // We have a valid one - digitalWrite (17, state) ; state ^= 1 ; piLock (COUNT_KEY) ; @@ -89,7 +95,7 @@ PI_THREAD (waitForIt) // Wait for key to be released - while (digitalRead (0) == LOW) + while (digitalRead (BUTTON_PIN) == LOW) delay (1) ; debounceTime = millis () + DEBOUNCE_TIME ; @@ -108,11 +114,9 @@ void setup (void) { // Use the gpio program to initialise the hardware -// (This is the crude, but effective bit) +// (This is the crude, but effective) - system ("gpio edge 0 falling") ; - system ("gpio export 17 out") ; - system ("gpio export 18 out") ; + system ("gpio edge 17 falling") ; // Setup wiringPi @@ -120,9 +124,8 @@ void setup (void) // Fire off our interrupt handler - piThreadCreate (waitForIt) ; + piThreadCreate (waitForIt) ; - digitalWrite (17, 0) ; } @@ -147,7 +150,7 @@ int main (void) piLock (COUNT_KEY) ; myCounter = globalCounter ; piUnlock (COUNT_KEY) ; - delay (5000) ; + delay (500) ; } printf (" Done. myCounter: %5d\n", myCounter) ; diff --git a/gpio/Makefile b/gpio/Makefile index 5693c44..729a86b 100644 --- a/gpio/Makefile +++ b/gpio/Makefile @@ -30,7 +30,7 @@ INCLUDE = -I/usr/local/include CFLAGS = $(DEBUG) -Wall $(INCLUDE) -Winline -pipe LDFLAGS = -L/usr/local/lib -LIBS = -lwiringPi +LIBS = -lwiringPi -lpthread # May not need to alter anything below this line ############################################################################### diff --git a/gpio/gpio.1 b/gpio/gpio.1 index c39e5dc..a83cf9f 100644 --- a/gpio/gpio.1 +++ b/gpio/gpio.1 @@ -57,6 +57,9 @@ converters on the Gertboard. It's designed for simple testing and diagnostic purposes, but can be used in shell scripts for general if somewhat slow control of the GPIO pins. +It can also control the IO's on the PiFace IO board and load the SPI and I2C +kernel modules if required. + Additionally, it can be used to set the exports in the \fI/sys/class/gpio\fR system directory to allow subsequent programs to use the \fR/sys/class/gpio\fR interface without needing to be run as root. @@ -70,6 +73,8 @@ Output the current version including the board revision of the Raspberry Pi. .TP .B \-g Use the BCM_GPIO pins numbers rather than wiringPi pin numbers. +\fINOTE:\fR The BCM_GPIO pin numbers are always used with the +export and edge commands. .TP .B \-p @@ -183,7 +188,7 @@ SPI digital to analogue converter. The board jumpers need to be in-place to do this operation. -.SH "WiringPi vs. GPIO Pin numbering" +.SH "WiringPi vs. BCM_GPIO Pin numbering" .PP .TS @@ -213,6 +218,12 @@ _ 20 - 31 .TE +Note that "r1" and "r2" above refers to the board revision. Normally +wiringPi detects the correct board revision with use for it's own +numbering scheme, but if you are using a Revision 2 board with some +of the pins which change numbers between revisions you will need +to alter your software. + .SH FILES .TP 2.2i diff --git a/gpio/gpio.c b/gpio/gpio.c index 52fcb6f..7b84abd 100644 --- a/gpio/gpio.c +++ b/gpio/gpio.c @@ -35,12 +35,14 @@ #include #include +extern int wiringPiDebug ; + #ifndef TRUE # define TRUE (1==1) # define FALSE (1==2) #endif -#define VERSION "1.5" +#define VERSION "1.6" static int wpMode ; @@ -127,7 +129,7 @@ static int moduleLoaded (char *modName) static void _doLoadUsage (char *argv []) { - fprintf (stderr, "Usage: %s load \n", argv [0]) ; + fprintf (stderr, "Usage: %s load [bufferSize in KB for spi]\n", argv [0]) ; exit (1) ; } @@ -136,16 +138,24 @@ static void doLoad (int argc, char *argv []) char *module1, *module2 ; char cmd [80] ; char *file1, *file2 ; + char spiBuf [32] ; - if (argc != 3) + if (argc < 3) _doLoadUsage (argv) ; + spiBuf [0] = 0 ; + /**/ if (strcasecmp (argv [2], "spi") == 0) { module1 = "spidev" ; module2 = "spi_bcm2708" ; file1 = "/dev/spidev0.0" ; file2 = "/dev/spidev0.1" ; + if (argc == 4) + sprintf (spiBuf, " bufsize=%d", atoi (argv [3]) * 1024) ; + else if (argc > 4) + _doLoadUsage (argv) ; + } else if (strcasecmp (argv [2], "i2c") == 0) { @@ -159,7 +169,7 @@ static void doLoad (int argc, char *argv []) if (!moduleLoaded (module1)) { - sprintf (cmd, "modprobe %s", module1) ; + sprintf (cmd, "modprobe %s%s", module1, spiBuf) ; system (cmd) ; } @@ -848,6 +858,12 @@ int main (int argc, char *argv []) { int i ; + if (getenv ("WIRINGPI_DEBUG") != NULL) + { + printf ("gpio: wiringPi debug mode enabled\n") ; + wiringPiDebug = TRUE ; + } + if (argc == 1) { fprintf (stderr, "%s\n", usage) ; diff --git a/wiringPi/Makefile b/wiringPi/Makefile index e18a654..62e9d9b 100644 --- a/wiringPi/Makefile +++ b/wiringPi/Makefile @@ -1,4 +1,4 @@ -# +# ; # Makefile: # wiringPi - Wiring Compatable library for the Raspberry Pi # @@ -45,13 +45,15 @@ LIBS = SRC = wiringPi.c wiringPiFace.c wiringSerial.c wiringShift.c \ gertboard.c \ piNes.c \ - lcd.c piHiPri.c piThread.c wiringPiSPI.c \ + lcd.c piHiPri.c piThread.c \ + wiringPiSPI.c wiringPiI2C.c \ softPwm.c softServo.c softTone.c OBJ = $(SRC:.c=.o) -all: $(STATIC) $(DYNAMIC) -#all: $(DYNAMIC) +all: $(DYNAMIC) + +static: $(STATIC) $(STATIC): $(OBJ) @echo "[Link (Static)]" @@ -77,7 +79,7 @@ tags: $(SRC) @ctags $(SRC) .PHONEY: install -install: $(TARGET) +install: $(DYNAMIC) @echo "[Install]" @install -m 0755 -d $(DESTDIR)$(PREFIX)/lib @install -m 0755 -d $(DESTDIR)$(PREFIX)/include @@ -91,12 +93,17 @@ install: $(TARGET) @install -m 0644 softTone.h $(DESTDIR)$(PREFIX)/include @install -m 0644 lcd.h $(DESTDIR)$(PREFIX)/include @install -m 0644 wiringPiSPI.h $(DESTDIR)$(PREFIX)/include - @install -m 0755 libwiringPi.a $(DESTDIR)$(PREFIX)/lib + @install -m 0644 wiringPiI2C.h $(DESTDIR)$(PREFIX)/include @install -m 0755 libwiringPi.so.$(VERSION) $(DESTDIR)$(PREFIX)/lib @ln -sf $(DESTDIR)$(PREFIX)/lib/libwiringPi.so.$(VERSION) $(DESTDIR)/lib/libwiringPi.so @ln -sf $(DESTDIR)$(PREFIX)/lib/libwiringPi.so.$(VERSION) $(DESTDIR)/lib/libwiringPi.so.1 @ldconfig +.PHONEY: install-static +install-static: $(STATIC) + @echo "[Install Static]" + @install -m 0755 libwiringPi.a $(DESTDIR)$(PREFIX)/lib + .PHONEY: uninstall uninstall: @echo "[UnInstall]" @@ -110,6 +117,7 @@ uninstall: @rm -f $(DESTDIR)$(PREFIX)/include/softTone.h @rm -f $(DESTDIR)$(PREFIX)/include/lcd.h @rm -f $(DESTDIR)$(PREFIX)/include/wiringPiSPI.h + @rm -f $(DESTDIR)$(PREFIX)/include/wiringPiI2C.h @rm -f $(DESTDIR)$(PREFIX)/lib/libwiringPi.* @ldconfig diff --git a/wiringPi/wiringPi.c b/wiringPi/wiringPi.c index df4d969..cfb6705 100644 --- a/wiringPi/wiringPi.c +++ b/wiringPi/wiringPi.c @@ -65,10 +65,12 @@ #include #include #include +#include #include #include #include #include +#include #include "wiringPi.h" @@ -173,9 +175,17 @@ static volatile uint32_t *pads ; static volatile uint32_t *timer ; static volatile uint32_t *timerIrqRaw ; +// Time for easy calculations + +static unsigned long long epoch ; + +// Misc + +static int wiringPiMode = WPI_MODE_UNINITIALISED ; + // Debugging -static int wiringPiDebug = FALSE ; +int wiringPiDebug = FALSE ; // The BCM2835 has 54 GPIO pins. // BCM2835 data sheet, Page 90 onwards. @@ -200,6 +210,11 @@ static int wiringPiDebug = FALSE ; static int sysFds [64] ; +// ISR Data + +static void (*isrFunctions [64])(void) ; + + // Doing it the Arduino way with lookup tables... // Yes, it's probably more innefficient than all the bit-twidling, but it // does tend to make it all a bit clearer. At least to me! @@ -370,10 +385,6 @@ static uint8_t gpioToPwmPort [] = } ; -// Time for easy calculations - -static unsigned long long epoch ; - /* * Functions ********************************************************************************* @@ -418,6 +429,15 @@ int wpiPinToGpio (int wpiPin) ********************************************************************************* */ +static void piBoardRevOops (char *why) +{ + fprintf (stderr, "piBoardRev: Unable to determine board revision from /proc/cpuinfo\n") ; + fprintf (stderr, " -> %s\n", why) ; + fprintf (stderr, " -> You may want to check:\n") ; + fprintf (stderr, " -> http://www.raspberrypi.org/phpBB3/viewtopic.php?p=184410#p184410\n") ; + exit (EXIT_FAILURE) ; +} + int piBoardRev (void) { FILE *cpuFd ; @@ -440,24 +460,19 @@ int piBoardRev (void) fclose (cpuFd) ; if (line == NULL) - { - fprintf (stderr, "piBoardRev: Unable to determine board revision from /proc/cpuinfo\n") ; - fprintf (stderr, " (No \"Revision\" line)\n") ; - errno = 0 ; - return -1 ; - } + piBoardRevOops ("No \"Revision\" line") ; + + line [strlen (line) - 1] = 0 ; // Chomp LF + if (wiringPiDebug) + printf ("piboardRev: Revision string: %s\n", line) ; + for (c = line ; *c ; ++c) if (isdigit (*c)) break ; if (!isdigit (*c)) - { - fprintf (stderr, "piBoardRev: Unable to determine board revision from /proc/cpuinfo\n") ; - fprintf (stderr, " (No numeric revision string in: \"%s\"\n", line) ; - errno = 0 ; - return -1 ; - } + piBoardRevOops ("No numeric revision string") ; // If you have overvolted the Pi, then it appears that the revision // has 100000 added to it! @@ -466,26 +481,18 @@ int piBoardRev (void) if (strlen (c) != 4) printf ("piboardRev: This Pi has/is overvolted!\n") ; - lastChar = c [strlen (c) - 2] ; + lastChar = line [strlen (line) - 1] ; + + if (wiringPiDebug) + printf ("piboardRev: lastChar is: '%c' (%d, 0x%02X)\n", lastChar, lastChar, lastChar) ; /**/ if ((lastChar == '2') || (lastChar == '3')) boardRev = 1 ; else boardRev = 2 ; -#ifdef DO_WE_CARE_ABOUT_THIS_NOW - else - { - fprintf (stderr, "WARNING: wiringPi: Unable to determine board revision from \"%d\"\n", r) ; - fprintf (stderr, " -> You may want to check:\n") ; - fprintf (stderr, " -> http://www.raspberrypi.org/phpBB3/viewtopic.php?p=184410#p184410\n") ; - fprintf (stderr, " -> Assuming a Rev 1 board\n") ; - boardRev = 1 ; - } -#endif - if (wiringPiDebug) - printf ("piboardRev: Revision string: %s, board revision: %d\n", c, boardRev) ; + printf ("piBoardRev: Returning revision: %d\n", boardRev) ; return boardRev ; } @@ -741,11 +748,11 @@ void digitalWriteByteGpio (int value) else pinSet |= (1 << pinToGpio [pin]) ; - *(gpio + gpioToGPCLR [0]) = pinClr ; - *(gpio + gpioToGPSET [0]) = pinSet ; - mask <<= 1 ; } + + *(gpio + gpioToGPCLR [0]) = pinClr ; + *(gpio + gpioToGPSET [0]) = pinSet ; } void digitalWriteByteSys (int value) @@ -943,6 +950,99 @@ int waitForInterruptGpio (int pin, int mS) } +/* + * interruptHandler: + * This is a thread and gets started to wait for the interrupt we're + * hoping to catch. It will call the user-function when the interrupt + * fires. + ********************************************************************************* + */ + +static void *interruptHandler (void *arg) +{ + int myPin = *(int *)arg ; + + (void)piHiPri (55) ; // Only effective if we run as root + + for (;;) + if (waitForInterruptSys (myPin, -1) > 0) + isrFunctions [myPin] () ; + + return NULL ; +} + + +/* + * wiringPiISR: + * Take the details and create an interrupt handler that will do a call- + * back to the user supplied function. + ********************************************************************************* + */ + +int wiringPiISR (int pin, int mode, void (*function)(void)) +{ + pthread_t threadId ; + char fName [64] ; + char *modeS ; + char pinS [8] ; + pid_t pid ; + + pin &= 63 ; + + if (wiringPiMode == WPI_MODE_UNINITIALISED) + { + fprintf (stderr, "wiringPiISR: wiringPi has not been initialised. Unable to continue.\n") ; + exit (EXIT_FAILURE) ; + } + else if (wiringPiMode == WPI_MODE_PINS) + pin = pinToGpio [pin] ; + +// Now export the pin and set the right edge +// We're going to use the gpio program to do this, so it assumes +// a full installation of wiringPi. It's a bit 'clunky', but it +// is a way that will work when we're running in "Sys" mode, as +// a non-root user. (without sudo) + + if (mode != INT_EDGE_SETUP) + { + /**/ if (mode == INT_EDGE_FALLING) + modeS = "falling" ; + else if (mode == INT_EDGE_RISING) + modeS = "rising" ; + else + modeS = "both" ; + + sprintf (pinS, "%d", pin) ; + + if ((pid = fork ()) < 0) // Fail + return pid ; + + if (pid == 0) // Child, exec + { + execl ("/usr/local/bin/gpio", "gpio", "edge", pinS, modeS, (char *)NULL) ; + return -1 ; // Failure ... + } + else // Parent, wait + wait (NULL) ; + } + +// Now pre-open the /sys/class node - it may already be open if +// we had set it up earlier, but this will do no harm. + + sprintf (fName, "/sys/class/gpio/gpio%d/value", pin) ; + if ((sysFds [pin] = open (fName, O_RDWR)) < 0) + return -1 ; + + isrFunctions [pin] = function ; + + pthread_create (&threadId, NULL, interruptHandler, &pin) ; + + delay (1) ; + + return 0 ; +} + + /* * delay: * Wait for some number of milli seconds @@ -1064,8 +1164,17 @@ int wiringPiSetup (void) uint8_t *gpioMem, *pwmMem, *clkMem, *padsMem, *timerMem ; struct timeval tv ; + if (geteuid () != 0) + { + fprintf (stderr, "Must be root to call wiringPiSetup(). (Did you forget sudo?)\n") ; + exit (EXIT_FAILURE) ; + } + if (getenv ("WIRINGPI_DEBUG") != NULL) + { + printf ("wiringPi: Debug mode enabled\n") ; wiringPiDebug = TRUE ; + } if (wiringPiDebug) printf ("wiringPi: wiringPiSetup called\n") ; @@ -1083,8 +1192,7 @@ int wiringPiSetup (void) pwmSetRange = pwmSetRangeWPi ; pwmSetClock = pwmSetClockWPi ; - if ((boardRev = piBoardRev ()) < 0) - return -1 ; + boardRev = piBoardRev () ; if (boardRev == 1) pinToGpio = pinToGpioR1 ; @@ -1105,7 +1213,8 @@ int wiringPiSetup (void) if ((gpioMem = malloc (BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) { - fprintf (stderr, "wiringPiSetup: malloc failed: %s\n", strerror (errno)) ; + if (wiringPiDebug) + fprintf (stderr, "wiringPiSetup: malloc failed: %s\n", strerror (errno)) ; return -1 ; } @@ -1118,7 +1227,8 @@ int wiringPiSetup (void) if ((int32_t)gpio < 0) { - fprintf (stderr, "wiringPiSetup: mmap failed: %s\n", strerror (errno)) ; + if (wiringPiDebug) + fprintf (stderr, "wiringPiSetup: mmap failed: %s\n", strerror (errno)) ; return -1 ; } @@ -1126,7 +1236,8 @@ int wiringPiSetup (void) if ((pwmMem = malloc (BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) { - fprintf (stderr, "wiringPiSetup: pwmMem malloc failed: %s\n", strerror (errno)) ; + if (wiringPiDebug) + fprintf (stderr, "wiringPiSetup: pwmMem malloc failed: %s\n", strerror (errno)) ; return -1 ; } @@ -1137,7 +1248,8 @@ int wiringPiSetup (void) if ((int32_t)pwm < 0) { - fprintf (stderr, "wiringPiSetup: mmap failed (pwm): %s\n", strerror (errno)) ; + if (wiringPiDebug) + fprintf (stderr, "wiringPiSetup: mmap failed (pwm): %s\n", strerror (errno)) ; return -1 ; } @@ -1145,7 +1257,8 @@ int wiringPiSetup (void) if ((clkMem = malloc (BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) { - fprintf (stderr, "wiringPiSetup: clkMem malloc failed: %s\n", strerror (errno)) ; + if (wiringPiDebug) + fprintf (stderr, "wiringPiSetup: clkMem malloc failed: %s\n", strerror (errno)) ; return -1 ; } @@ -1156,7 +1269,8 @@ int wiringPiSetup (void) if ((int32_t)clk < 0) { - fprintf (stderr, "wiringPiSetup: mmap failed (clk): %s\n", strerror (errno)) ; + if (wiringPiDebug) + fprintf (stderr, "wiringPiSetup: mmap failed (clk): %s\n", strerror (errno)) ; return -1 ; } @@ -1164,7 +1278,8 @@ int wiringPiSetup (void) if ((padsMem = malloc (BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) { - fprintf (stderr, "wiringPiSetup: padsMem malloc failed: %s\n", strerror (errno)) ; + if (wiringPiDebug) + fprintf (stderr, "wiringPiSetup: padsMem malloc failed: %s\n", strerror (errno)) ; return -1 ; } @@ -1175,7 +1290,8 @@ int wiringPiSetup (void) if ((int32_t)pads < 0) { - fprintf (stderr, "wiringPiSetup: mmap failed (pads): %s\n", strerror (errno)) ; + if (wiringPiDebug) + fprintf (stderr, "wiringPiSetup: mmap failed (pads): %s\n", strerror (errno)) ; return -1 ; } @@ -1188,7 +1304,8 @@ int wiringPiSetup (void) if ((timerMem = malloc (BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) { - fprintf (stderr, "wiringPiSetup: timerMem malloc failed: %s\n", strerror (errno)) ; + if (wiringPiDebug) + fprintf (stderr, "wiringPiSetup: timerMem malloc failed: %s\n", strerror (errno)) ; return -1 ; } @@ -1199,7 +1316,8 @@ int wiringPiSetup (void) if ((int32_t)timer < 0) { - fprintf (stderr, "wiringPiSetup: mmap failed (timer): %s\n", strerror (errno)) ; + if (wiringPiDebug) + fprintf (stderr, "wiringPiSetup: mmap failed (timer): %s\n", strerror (errno)) ; return -1 ; } @@ -1216,6 +1334,8 @@ int wiringPiSetup (void) gettimeofday (&tv, NULL) ; epoch = (tv.tv_sec * 1000000 + tv.tv_usec) / 1000 ; + wiringPiMode = WPI_MODE_PINS ; + return 0 ; } @@ -1233,12 +1353,18 @@ int wiringPiSetupGpio (void) { int x ; - if (wiringPiDebug) - printf ("wiringPi: wiringPiSetupGpio called\n") ; + if (geteuid () != 0) + { + fprintf (stderr, "Must be root to call wiringPiSetupGpio(). (Did you forget sudo?)\n") ; + exit (EXIT_FAILURE) ; + } if ((x = wiringPiSetup ()) < 0) return x ; + if (wiringPiDebug) + printf ("wiringPi: wiringPiSetupGpio called\n") ; + pinMode = pinModeGpio ; pullUpDnControl = pullUpDnControlGpio ; digitalWrite = digitalWriteGpio ; @@ -1252,6 +1378,8 @@ int wiringPiSetupGpio (void) pwmSetRange = pwmSetRangeWPi ; pwmSetClock = pwmSetClockWPi ; + wiringPiMode = WPI_MODE_GPIO ; + return 0 ; } @@ -1272,6 +1400,9 @@ int wiringPiSetupSys (void) struct timeval tv ; char fName [128] ; + if (getenv ("WIRINGPI_DEBUG") != NULL) + wiringPiDebug = TRUE ; + if (wiringPiDebug) printf ("wiringPi: wiringPiSetupSys called\n") ; @@ -1288,15 +1419,13 @@ int wiringPiSetupSys (void) pwmSetRange = pwmSetRangeSys ; pwmSetClock = pwmSetClockSys ; - if ((boardRev = piBoardRev ()) < 0) - return -1 ; + boardRev = piBoardRev () ; if (boardRev == 1) pinToGpio = pinToGpioR1 ; else pinToGpio = pinToGpioR2 ; - // Open and scan the directory, looking for exported GPIOs, and pre-open // the 'value' interface to speed things up for later @@ -1311,5 +1440,7 @@ int wiringPiSetupSys (void) gettimeofday (&tv, NULL) ; epoch = (tv.tv_sec * 1000000 + tv.tv_usec) / 1000 ; + wiringPiMode = WPI_MODE_GPIO_SYS ; + return 0 ; } diff --git a/wiringPi/wiringPi.h b/wiringPi/wiringPi.h index 6a7278e..424e3bc 100644 --- a/wiringPi/wiringPi.h +++ b/wiringPi/wiringPi.h @@ -23,32 +23,44 @@ // Handy defines +// Deprecated #define NUM_PINS 17 #define WPI_MODE_PINS 0 #define WPI_MODE_GPIO 1 #define WPI_MODE_GPIO_SYS 2 #define WPI_MODE_PIFACE 3 +#define WPI_MODE_UNINITIALISED -1 -#define INPUT 0 -#define OUTPUT 1 -#define PWM_OUTPUT 2 +#define INPUT 0 +#define OUTPUT 1 +#define PWM_OUTPUT 2 -#define LOW 0 -#define HIGH 1 +#define LOW 0 +#define HIGH 1 -#define PUD_OFF 0 -#define PUD_DOWN 1 -#define PUD_UP 2 +#define PUD_OFF 0 +#define PUD_DOWN 1 +#define PUD_UP 2 // PWM -#define PWM_MODE_MS 0 -#define PWM_MODE_BAL 1 +#define PWM_MODE_MS 0 +#define PWM_MODE_BAL 1 + +// Interrupt levels + +#define INT_EDGE_SETUP 0 +#define INT_EDGE_FALLING 1 +#define INT_EDGE_RISING 2 + +// Threads + +#define PI_THREAD(X) void *X (void *dummy) // Function prototypes -// c++ wrappers thanks to a commend by Nick Lott +// c++ wrappers thanks to a comment by Nick Lott // (and others on the Raspberry Pi forums) #ifdef __cplusplus @@ -82,11 +94,10 @@ extern void (*pwmSetClock) (int divisor) ; // Interrupts extern int (*waitForInterrupt) (int pin, int mS) ; +extern int wiringPiISR (int pin, int mode, void (*function)(void)) ; // Threads -#define PI_THREAD(X) void *X (void *dummy) - extern int piThreadCreate (void *(*fn)(void *)) ; extern void piLock (int key) ; extern void piUnlock (int key) ; diff --git a/wiringPi/wiringPiI2C.c b/wiringPi/wiringPiI2C.c new file mode 100644 index 0000000..93fe1d3 --- /dev/null +++ b/wiringPi/wiringPiI2C.c @@ -0,0 +1,122 @@ +/* + * wiringPiI2C.c: + * Simplified I2C access routines + * Copyright (c) 2013 Gordon Henderson + *********************************************************************** + * This file is part of wiringPi: + * https://projects.drogon.net/raspberry-pi/wiringpi/ + * + * wiringPi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * wiringPi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with wiringPi. + * If not, see . + *********************************************************************** + */ + +#include +#include +#include +#include +#include + +#include "wiringPi.h" +#include "wiringPiI2C.h" + + +/* + * wiringPiI2CRead: + * Simple device read + ********************************************************************************* + */ + +int wiringPiI2CRead (int fd) +{ + return i2c_smbus_read_byte (fd) ; +} + + +/* + * wiringPiI2CReadReg8: wiringPiI2CReadReg16: + * Read an 8 or 16-bit value from a regsiter on the device + ********************************************************************************* + */ + +int wiringPiI2CReadReg8 (int fd, int reg) +{ + return i2c_smbus_read_byte_data (fd, reg) ; +} + +int wiringPiI2CReadReg16 (int fd, int reg) +{ + return i2c_smbus_read_word_data (fd, reg) ; +} + + +/* + * wiringPiI2CWrite: + * Simple device write + ********************************************************************************* + */ + +int wiringPiI2CWrite (int fd, int data) +{ + return i2c_smbus_write_byte (fd, data) ; +} + + +/* + * wiringPiI2CWriteReg8: wiringPiI2CWriteReg16: + * Write an 8 or 16-bit value to the given register + ********************************************************************************* + */ + +int wiringPiI2CWriteReg8 (int fd, int reg, int data) +{ + return i2c_smbus_write_byte_data (fd, reg, data) ; +} + +int wiringPiI2CWriteReg16 (int fd, int reg, int data) +{ + return i2c_smbus_write_word_data (fd, reg, data) ; +} + + +/* + * wiringPiI2CSetup: + * Open the I2C device, and regsiter the target device + ********************************************************************************* + */ + +int wiringPiI2CSetup (int devId) +{ + int rev, fd ; + char *device ; + + if ((rev = piBoardRev ()) < 0) + { + fprintf (stderr, "wiringPiI2CSetup: Unable to determine Pi board revision\n") ; + exit (1) ; + } + + if (rev == 1) + device = "/dev/i2c-0" ; + else + device = "/dev/i2c-1" ; + + if ((fd = open (device, O_RDWR)) < 0) + return -1 ; + + if (ioctl (fd, I2C_SLAVE, devId) < 0) + return -1 ; + + return fd ; +} diff --git a/wiringPi/wiringPiI2C.h b/wiringPi/wiringPiI2C.h new file mode 100644 index 0000000..6710ff4 --- /dev/null +++ b/wiringPi/wiringPiI2C.h @@ -0,0 +1,41 @@ +/* + * wiringPiI2C.h: + * Simplified I2C access routines + * Copyright (c) 2013 Gordon Henderson + *********************************************************************** + * This file is part of wiringPi: + * https://projects.drogon.net/raspberry-pi/wiringpi/ + * + * wiringPi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * wiringPi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with wiringPi. + * If not, see . + *********************************************************************** + */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int wiringPiI2CRead (int fd) ; +extern int wiringPiI2CReadReg8 (int fd, int reg) ; +extern int wiringPiI2CReadReg16 (int fd, int reg) ; + +extern int wiringPiI2CWrite (int fd, int data) ; +extern int wiringPiI2CWriteReg8 (int fd, int reg, int data) ; +extern int wiringPiI2CWriteReg16 (int fd, int reg, int data) ; + +int wiringPiI2CSetup (int devId) ; + +#ifdef __cplusplus +} +#endif diff --git a/wiringPi/wiringPiISR.c b/wiringPi/wiringPiISR.c new file mode 100644 index 0000000..9e847cc --- /dev/null +++ b/wiringPi/wiringPiISR.c @@ -0,0 +1,109 @@ +/* + * wiringPiISR.c: + * Simplified Interrupt Service Routine handling + * Copyright (c) 2013 Gordon Henderson + *********************************************************************** + * This file is part of wiringPi: + * https://projects.drogon.net/raspberry-pi/wiringpi/ + * + * wiringPi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * wiringPi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with wiringPi. + * If not, see . + *********************************************************************** + */ + +#include +#include +#include + +#include "wiringPi.h" + + + +static void (*isrFunctions [64])(void) ; +static int isrFds [64] ; + +/* + * interruptHandler: + * This is a thread and gets started to wait for the interrupt we're + * hoping to catch. It will call the user-function when the interrupt + * fires. + ********************************************************************************* + */ + +static void *interruptHandler (void *arg) +{ + int pin = *(int *)arg ; + + (void)piHiPri (55) ; + + for (;;) + { + if (waitForInterrupt (pin, -1) > 0) + isrFunctions [pin] () ; + } + + return NULL ; +} + +/* + * wiringPiISR: + * Take the details and create an interrupt handler that will do a call- + * back to the user supplied function. + ********************************************************************************* + */ + +int wiringPiISR (int pin, int mode, void (*function)(void)) +{ + pthread_t threadId ; + char command [64] ; + + pin &= 63 ; + + if (wiringPiMode == WPI_MODE_UNINITIALISED) + { + fprintf (stderr, "wiringPiISR: wiringPi has not been initialised. Unable to continue.\n") ; + exit (EXIT_FAILURE) ; + } + else if (wiringPiMode == WPI_MODE_PINS) + pin = pinToGpio [pin] ; + + + isrFunctions [pin] = function ; + +// Now export the pin and set the right edge + + if (mode != INT_EDGE_SETUP) + { + /**/ if (mode == INT_EDGE_FALLING) + modes = "falling" ; + else if (mode == INT_EDGE_RISING) + modes = "rising" ; + else + modes = "both" ; + + sprintf (command, "/usr/local/bin/gpio edge %d %s", pin, modes) ; + system (command) ; + } + + sprintf (fName, "/sys/class/gpio/gpio%d/value", pin) ; + if ((isrFds [pin] = open (fName, O_RDWR)) < 0) + return -1 ; + + { + fprintf ("std + + pthread_create (&threadId, NULL, interruptHandler, &pin) ; +} + + -- 2.30.2