* wiringPi:
* Arduino compatable (ish) Wiring library for the Raspberry Pi
* Copyright (c) 2012 Gordon Henderson
+ * Additional code for pwmSetClock by Chris Hall <chris@kchall.plus.com>
*
* Thanks to code samples from Gert Jan van Loo and the
* BCM2835 ARM Peripherals manual, however it's missing
// Added in the 2 UART pins
// Change maxPins to numPins to more accurately reflect purpose
-// Pad drive current fiddling
-
-#undef DEBUG_PADS
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <fcntl.h>
+#include <pthread.h>
#include <sys/time.h>
#include <sys/mman.h>
-#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/ioctl.h>
#include "wiringPi.h"
// Function stubs
void (*pinMode) (int pin, int mode) ;
+int (*getAlt) (int pin) ;
void (*pullUpDnControl) (int pin, int pud) ;
void (*digitalWrite) (int pin, int value) ;
+void (*digitalWriteByte) (int value) ;
void (*pwmWrite) (int pin, int value) ;
void (*setPadDrive) (int group, int value) ;
int (*digitalRead) (int pin) ;
int (*waitForInterrupt) (int pin, int mS) ;
-void (*delayMicroseconds) (unsigned int howLong) ;
void (*pwmSetMode) (int mode) ;
void (*pwmSetRange) (unsigned int range) ;
+void (*pwmSetClock) (int divisor) ;
#ifndef TRUE
static volatile uint32_t *clk ;
static volatile uint32_t *pads ;
static volatile uint32_t *timer ;
-
static volatile uint32_t *timerIrqRaw ;
-// Raspberry Pi board revision
+// Time for easy calculations
+
+static uint64_t epochMilli, epochMicro ;
+
+// Misc
-static int boardRevision = -1 ;
+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.
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!
static int pinToGpioR2 [64] =
{
- 17, 18, 27, 22, 23, 24, 25, 4, // From the Original Wiki - GPIO 0 through 7
- 2, 3, // I2C - SDA0, SCL0
- 8, 7, // SPI - CE1, CE0
- 10, 9, 11, // SPI - MOSI, MISO, SCLK
- 14, 15, // UART - Tx, Rx
- 28, 29, 30, 31, // New GPIOs 8 though 11
+ 17, 18, 27, 22, 23, 24, 25, 4, // From the Original Wiki - GPIO 0 through 7: wpi 0 - 7
+ 2, 3, // I2C - SDA0, SCL0 wpi 8 - 9
+ 8, 7, // SPI - CE1, CE0 wpi 10 - 11
+ 10, 9, 11, // SPI - MOSI, MISO, SCLK wpi 12 - 14
+ 14, 15, // UART - Tx, Rx wpi 15 - 16
+ 28, 29, 30, 31, // New GPIOs 8 though 11 wpi 17 - 20
// Padding:
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 63
} ;
+
// gpioToGPFSEL:
// Map a BCM_GPIO pin to it's control port. (GPFSEL 0-5)
5,5,5,5,5,5,5,5,5,5,
} ;
+
// gpioToShift
// Define the shift up for the 3 bits per pin in each GPFSEL port
0,3,6,9,12,15,18,21,24,27,
} ;
+
// gpioToGPSET:
// (Word) offset to the GPIO Set registers for each GPIO pin
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
} ;
+
// gpioToGPCLR:
// (Word) offset to the GPIO Clear registers for each GPIO pin
11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
} ;
+
// gpioToGPLEV:
// (Word) offset to the GPIO Input level registers for each GPIO pin
14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,
} ;
+
#ifdef notYetReady
// gpioToEDS
// (Word) offset to the Event Detect Status
} ;
#endif
+
// gpioToPUDCLK
// (Word) offset to the Pull Up Down Clock regsiter
39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,
} ;
+
// gpioToPwmALT
// the ALT value to put a GPIO pin into PWM mode
} ;
-// Time for easy calculations
+/*
+ * Functions
+ *********************************************************************************
+ */
+
+
+/*
+ * wpiPinToGpio:
+ * Translate a wiringPi Pin number to native GPIO pin number.
+ * (We don't use this here, prefering to just do the lookup directly,
+ * but it's been requested!)
+ *********************************************************************************
+ */
+
+int wpiPinToGpio (int wpiPin)
+{
+ return pinToGpio [wpiPin & 63] ;
+}
+
+
+/*
+ * piBoardRev:
+ * Return a number representing the hardware revision of the board.
+ * Revision is currently 1 or 2. -1 is returned on error.
+ *
+ * Much confusion here )-:
+ * Seems there are some boards with 0000 in them (mistake in manufacture)
+ * and some board with 0005 in them (another mistake in manufacture?)
+ * So the distinction between boards that I can see is:
+ * 0000 - Error
+ * 0001 - Not used
+ * 0002 - Rev 1
+ * 0003 - Rev 1
+ * 0004 - Rev 2
+ * 0005 - Rev 2 (but error)
+ * 0006 - Rev 2
+ * 000f - Rev 2 + 512MB
+ *
+ * A small thorn is the olde style overvolting - that will add in
+ * 1000000
+ *
+ *********************************************************************************
+ */
+
+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 ;
+ char line [120] ;
+ char *c, lastChar ;
+ static int boardRev = -1 ;
+
+// No point checking twice...
+
+ if (boardRev != -1)
+ return boardRev ;
+
+ if ((cpuFd = fopen ("/proc/cpuinfo", "r")) == NULL)
+ return -1 ;
+
+ while (fgets (line, 120, cpuFd) != NULL)
+ if (strncmp (line, "Revision", 8) == 0)
+ break ;
+
+ fclose (cpuFd) ;
+
+ if (line == NULL)
+ 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))
+ piBoardRevOops ("No numeric revision string") ;
+
+// If you have overvolted the Pi, then it appears that the revision
+// has 100000 added to it!
-static unsigned long long epoch ;
+ if (wiringPiDebug)
+ if (strlen (c) != 4)
+ printf ("piboardRev: This Pi has/is overvolted!\n") ;
+
+ 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 ;
+
+ if (wiringPiDebug)
+ printf ("piBoardRev: Returning revision: %d\n", boardRev) ;
+
+ return boardRev ;
+}
-//////////////////////////////////////////////////////////////////////////////////
/*
void pinModeGpio (int pin, int mode)
{
- static int pwmRunning = FALSE ;
+// register int barrier ;
+
int fSel, shift, alt ;
pin &= 63 ;
*(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) | (alt << shift) ;
-// We didn't initialise the PWM hardware at setup time - because it's possible that
-// something else is using the PWM - e.g. the Audio systems! So if we use PWM
-// here, then we're assuming that nothing else is, otherwise things are going
-// to sound a bit funny...
+ delayMicroseconds (110) ; // See comments in pwmSetClockWPi
+ *(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) | (alt << shift) ;
- if (!pwmRunning)
- {
+// Page 107 of the BCM Peripherals manual talks about the GPIO clocks,
+// but I'm assuming (hoping!) that this applies to other clocks too.
- *(pwm + PWM_CONTROL) = 0 ; // Stop PWM
- delayMicroseconds (10) ;
-
-// Gert/Doms Values
- *(clk + PWMCLK_DIV) = BCM_PASSWORD | (32<<12) ; // set pwm div to 32 (19.2/32 = 600KHz)
- *(clk + PWMCLK_CNTL) = BCM_PASSWORD | 0x11 ; // Source=osc and enable
+ *(pwm + PWM_CONTROL) = 0 ; // Stop PWM
- delayMicroseconds (10) ;
+ *(clk + PWMCLK_CNTL) = BCM_PASSWORD | 0x01 ; // Stop PWM Clock
+ delayMicroseconds (110) ; // See comments in pwmSetClockWPi
- *(pwm + PWM0_RANGE) = 0x400 ; delayMicroseconds (10) ;
- *(pwm + PWM1_RANGE) = 0x400 ; delayMicroseconds (10) ;
+ while ((*(clk + PWMCLK_CNTL) & 0x80) != 0) // Wait for clock to be !BUSY
+ delayMicroseconds (1) ;
-// Enable PWMs
+ *(clk + PWMCLK_DIV) = BCM_PASSWORD | (32 << 12) ; // set pwm div to 32 (19.2/32 = 600KHz)
+ *(clk + PWMCLK_CNTL) = BCM_PASSWORD | 0x11 ; // enable clk
- *(pwm + PWM0_DATA) = 512 ;
- *(pwm + PWM1_DATA) = 512 ;
+ delayMicroseconds (110) ; // See comments in pwmSetClockWPi
-// Balanced mode (default)
+// Default range register of 1024
- *(pwm + PWM_CONTROL) = PWM0_ENABLE | PWM1_ENABLE ;
+ *(pwm + PWM0_RANGE) = 1024 ; delayMicroseconds (10) ;
+ *(pwm + PWM1_RANGE) = 1024 ; delayMicroseconds (10) ;
+ *(pwm + PWM0_DATA) = 0 ; delayMicroseconds (10) ;
+ *(pwm + PWM1_DATA) = 0 ; delayMicroseconds (10) ;
- pwmRunning = TRUE ;
- }
+// Enable PWMs in balanced mode (default)
+
+ *(pwm + PWM_CONTROL) = PWM0_ENABLE | PWM1_ENABLE ;
+ delay (100) ;
}
+
// When we change mode of any pin, we remove the pull up/downs
// Or we used to... Hm. Commented out now because for some wieird reason,
// it seems to block subsequent attempts to set the pull up/downs and I've
}
+/*
+ * getAlt:
+ * Returns the ALT bits for a given port. Only really of-use
+ * for the gpio readall command (I think)
+ *********************************************************************************
+ */
+
+int getAltGpio (int pin)
+{
+ int fSel, shift, alt ;
+
+ pin &= 63 ;
+
+ fSel = gpioToGPFSEL [pin] ;
+ shift = gpioToShift [pin] ;
+
+ alt = (*(gpio + fSel) >> shift) & 7 ;
+
+ return alt ;
+}
+
+int getAltWPi (int pin)
+{
+ return getAltGpio (pinToGpio [pin & 63]) ;
+}
+
+int getAltSys (int pin)
+{
+ return 0 ;
+}
+
+
/*
* pwmControl:
* Allow the user to control some of the PWM functions
return ;
}
+/*
+ * pwmSetClockWPi:
+ * Set/Change the PWM clock. Originally my code, but changed
+ * (for the better!) by Chris Hall, <chris@kchall.plus.com>
+ * after further study of the manual and testing with a 'scope
+ *********************************************************************************
+ */
+
+void pwmSetClockWPi (int divisor)
+{
+ uint32_t pwm_control ;
+ divisor &= 4095 ;
+
+ if (wiringPiDebug)
+ printf ("Setting to: %d. Current: 0x%08X\n", divisor, *(clk + PWMCLK_DIV)) ;
+
+ pwm_control = *(pwm + PWM_CONTROL) ; // preserve PWM_CONTROL
+
+// We need to stop PWM prior to stopping PWM clock in MS mode otherwise BUSY
+// stays high.
+
+ *(pwm + PWM_CONTROL) = 0 ; // Stop PWM
+
+// Stop PWM clock before changing divisor. The delay after this does need to
+// this big (95uS occasionally fails, 100uS OK), it's almost as though the BUSY
+// flag is not working properly in balanced mode. Without the delay when DIV is
+// adjusted the clock sometimes switches to very slow, once slow further DIV
+// adjustments do nothing and it's difficult to get out of this mode.
+
+ *(clk + PWMCLK_CNTL) = BCM_PASSWORD | 0x01 ; // Stop PWM Clock
+ delayMicroseconds (110) ; // prevents clock going sloooow
+
+ while ((*(clk + PWMCLK_CNTL) & 0x80) != 0) // Wait for clock to be !BUSY
+ delayMicroseconds (1) ;
+
+ *(clk + PWMCLK_DIV) = BCM_PASSWORD | (divisor << 12) ;
+
+ *(clk + PWMCLK_CNTL) = BCM_PASSWORD | 0x11 ; // Start PWM clock
+ *(pwm + PWM_CONTROL) = pwm_control ; // restore PWM_CONTROL
+
+ if (wiringPiDebug)
+ printf ("Set to: %d. Now : 0x%08X\n", divisor, *(clk + PWMCLK_DIV)) ;
+}
+
+void pwmSetClockSys (int divisor)
+{
+ return ;
+}
+
#ifdef notYetReady
/*
/*
- * pwnWrite:
+ * digitalWriteByte:
+ * Write an 8-bit byte to the first 8 GPIO pins - try to do it as
+ * fast as possible.
+ * However it still needs 2 operations to set the bits, so any external
+ * hardware must not rely on seeing a change as there will be a change
+ * to set the outputs bits to zero, then another change to set the 1's
+ *********************************************************************************
+ */
+
+void digitalWriteByteGpio (int value)
+{
+ uint32_t pinSet = 0 ;
+ uint32_t pinClr = 0 ;
+ int mask = 1 ;
+ int pin ;
+
+ for (pin = 0 ; pin < 8 ; ++pin)
+ {
+ if ((value & mask) == 0)
+ pinClr |= (1 << pinToGpio [pin]) ;
+ else
+ pinSet |= (1 << pinToGpio [pin]) ;
+
+ mask <<= 1 ;
+ }
+
+ *(gpio + gpioToGPCLR [0]) = pinClr ;
+ *(gpio + gpioToGPSET [0]) = pinSet ;
+}
+
+void digitalWriteByteSys (int value)
+{
+ int mask = 1 ;
+ int pin ;
+
+ for (pin = 0 ; pin < 8 ; ++pin)
+ {
+ digitalWriteSys (pinToGpio [pin], value & mask) ;
+ mask <<= 1 ;
+ }
+}
+
+
+/*
+ * pwmWrite:
* Set an output PWM value
*********************************************************************************
*/
wrVal = BCM_PASSWORD | 0x18 | (value & 7) ;
*(pads + group + 11) = wrVal ;
-#ifdef DEBUG_PADS
- printf ("setPadDrive: Group: %d, value: %d (%08X)\n", group, value, wrVal) ;
- printf ("Read : %08X\n", *(pads + group + 11)) ;
-#endif
+ if (wiringPiDebug)
+ {
+ printf ("setPadDrive: Group: %d, value: %d (%08X)\n", group, value, wrVal) ;
+ printf ("Read : %08X\n", *(pads + group + 11)) ;
+ }
}
void setPadDriveGpio (int group, int value)
int waitForInterruptSys (int pin, int mS)
{
int fd, x ;
- char buf [8] ;
+ uint8_t c ;
struct pollfd polls ;
if ((fd = sysFds [pin & 63]) == -1)
return -2 ;
-// Do a dummy read
-
- x = read (fd, buf, 6) ;
- if (x < 0)
- return x ;
-
-// And seek
-
- lseek (fd, 0, SEEK_SET) ;
-
// Setup poll structure
polls.fd = fd ;
// Wait for it ...
- return poll (&polls, 1, mS) ;
+ x = poll (&polls, 1, mS) ;
+
+// Do a dummy read to clear the interrupt
+// A one character read appars to be enough.
+
+ (void)read (fd, &c, 1) ;
+
+ return x ;
}
int waitForInterruptWPi (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 ;
+ int count, i ;
+ uint8_t c ;
+
+ 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 are in Sys mode, 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 ;
+
+// Clear any initial pending interrupt
+
+ ioctl (sysFds [pin], FIONREAD, &count) ;
+ for (i = 0 ; i < count ; ++i)
+ read (sysFds [pin], &c, 1) ;
+
+ isrFunctions [pin] = function ;
+
+ pthread_create (&threadId, NULL, interruptHandler, &pin) ;
+
+ delay (1) ;
+
+ return 0 ;
+}
+
+
+/*
+ * initialiseEpoch:
+ * Initialise our start-of-time variable to be the current unix
+ * time in milliseconds.
+ *********************************************************************************
+ */
+
+static void initialiseEpoch (void)
+{
+ struct timeval tv ;
+ gettimeofday (&tv, NULL) ;
+ epochMilli = (uint64_t)tv.tv_sec * (uint64_t)1000 + (uint64_t)(tv.tv_usec / 1000) ;
+ epochMicro = (uint64_t)tv.tv_sec * (uint64_t)1000000 + (uint64_t)(tv.tv_usec) ;
+}
/*
* delay:
* somewhat sub-optimal in that it uses 100% CPU, something not an issue
* in a microcontroller, but under a multi-tasking, multi-user OS, it's
* wastefull, however we've no real choice )-:
+ *
+ * Plan B: It seems all might not be well with that plan, so changing it
+ * to use gettimeofday () and poll on that instead...
*********************************************************************************
*/
-void delayMicrosecondsSys (unsigned int howLong)
-{
- struct timespec sleeper, dummy ;
-
- sleeper.tv_sec = 0 ;
- sleeper.tv_nsec = (long)(howLong * 1000) ;
-
- nanosleep (&sleeper, &dummy) ;
-}
-
void delayMicrosecondsHard (unsigned int howLong)
{
- *(timer + TIMER_LOAD) = howLong ;
- *(timer + TIMER_IRQ_CLR) = 0 ;
+ struct timeval tNow, tLong, tEnd ;
- while (*timerIrqRaw == 0)
- ;
+ gettimeofday (&tNow, NULL) ;
+ tLong.tv_sec = howLong / 1000000 ;
+ tLong.tv_usec = howLong % 1000000 ;
+ timeradd (&tNow, &tLong, &tEnd) ;
+
+ while (timercmp (&tNow, &tEnd, <))
+ gettimeofday (&tNow, NULL) ;
}
-void delayMicrosecondsWPi (unsigned int howLong)
+void delayMicroseconds (unsigned int howLong)
{
- struct timespec sleeper, dummy ;
+ struct timespec sleeper ;
/**/ if (howLong == 0)
return ;
{
sleeper.tv_sec = 0 ;
sleeper.tv_nsec = (long)(howLong * 1000) ;
- nanosleep (&sleeper, &dummy) ;
+ nanosleep (&sleeper, NULL) ;
}
}
unsigned int millis (void)
{
struct timeval tv ;
- unsigned long long t1 ;
+ uint64_t now ;
gettimeofday (&tv, NULL) ;
+ now = (uint64_t)tv.tv_sec * (uint64_t)1000 + (uint64_t)(tv.tv_usec / 1000) ;
- t1 = (tv.tv_sec * 1000000 + tv.tv_usec) / 1000 ;
+ return (uint32_t)(now - epochMilli) ;
+}
+
+
+/*
+ * micros:
+ * Return a number of microseconds as an unsigned int.
+ *********************************************************************************
+ */
+
+unsigned int micros (void)
+{
+ struct timeval tv ;
+ uint64_t now ;
+
+ gettimeofday (&tv, NULL) ;
+ now = (uint64_t)tv.tv_sec * (uint64_t)1000000 + (uint64_t)tv.tv_usec ;
- return (uint32_t)(t1 - epoch) ;
+ return (uint32_t)(now - epochMicro) ;
}
int wiringPiSetup (void)
{
int fd ;
- FILE *cpuFd ;
- char line [80] ;
- char *c ;
- int revision = -1 ;
- uint8_t *gpioMem, *pwmMem, *clkMem, *padsMem, *timerMem ;
- struct timeval tv ;
+ int boardRev ;
+
+ if (geteuid () != 0)
+ {
+ fprintf (stderr, "wiringPi:\n Must be root to call wiringPiSetup().\n (Did you forget sudo?)\n") ;
+ exit (EXIT_FAILURE) ;
+ }
if (getenv ("WIRINGPI_DEBUG") != NULL)
+ {
+ printf ("wiringPi: Debug mode enabled\n") ;
wiringPiDebug = TRUE ;
+ }
if (wiringPiDebug)
- printf ("wiringPiSetup called\n") ;
+ printf ("wiringPi: wiringPiSetup called\n") ;
pinMode = pinModeWPi ;
+ getAlt = getAltWPi ;
pullUpDnControl = pullUpDnControlWPi ;
digitalWrite = digitalWriteWPi ;
+ digitalWriteByte = digitalWriteByteGpio ; // Same code
pwmWrite = pwmWriteWPi ;
setPadDrive = setPadDriveWPi ;
digitalRead = digitalReadWPi ;
waitForInterrupt = waitForInterruptWPi ;
- delayMicroseconds = delayMicrosecondsWPi ;
pwmSetMode = pwmSetModeWPi ;
pwmSetRange = pwmSetRangeWPi ;
+ pwmSetClock = pwmSetClockWPi ;
-// Find board revision
+ boardRev = piBoardRev () ;
- if ((cpuFd = fopen ("/proc/cpuinfo", "r")) == NULL)
- {
- fprintf (stderr, "wiringPiSetup: Unable to open /proc/cpuinfo: %s\n", strerror (errno)) ;
- return -1 ;
- }
-
- while (fgets (line, 80, cpuFd) != NULL)
- if (strncmp (line, "Revision", 8) == 0)
- for (c = line ; *c ; ++c)
- {
- if (!isdigit (*c))
- continue ;
- revision = atoi (c) ;
- break ;
- }
-
- fclose (cpuFd) ;
- if (revision == -1)
- {
- fprintf (stderr, "wiringPiSetup: Unable to determine board revision\n") ;
- errno = 0 ;
- return -1 ;
- }
-
- /**/ if ((revision == 2) || (revision == 3))
- boardRevision = 1 ;
- else if ((revision == 4) || (revision == 5) || (revision == 6))
- boardRevision = 2 ;
- else
- {
- fprintf (stderr, "wiringPiSetup: Unable to determine board revision: %d\n", revision) ;
- errno = 0 ;
- return -1 ;
- }
-
-
- if (boardRevision == 1)
+ if (boardRev == 1)
pinToGpio = pinToGpioR1 ;
else
pinToGpio = pinToGpioR2 ;
- if (wiringPiDebug)
- printf ("Revision: %d, board revision: %d\n", revision, boardRevision) ;
-
// Open the master /dev/memory device
if ((fd = open ("/dev/mem", O_RDWR | O_SYNC) ) < 0)
{
- fprintf (stderr, "wiringPiSetup: Unable to open /dev/mem: %s\n", strerror (errno)) ;
+ if (wiringPiDebug)
+ {
+ int serr = errno ;
+ fprintf (stderr, "wiringPiSetup: Unable to open /dev/mem: %s\n", strerror (errno)) ;
+ errno = serr ;
+ }
return -1 ;
}
// GPIO:
-// Allocate 2 pages - 1 ...
-
- if ((gpioMem = malloc (BLOCK_SIZE + (PAGE_SIZE-1))) == NULL)
+ gpio = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_BASE) ;
+ if ((int32_t)gpio == -1)
{
- fprintf (stderr, "wiringPiSetup: malloc failed: %s\n", strerror (errno)) ;
- return -1 ;
- }
-
-// ... presumably to make sure we can round it up to a whole page size
-
- if (((uint32_t)gpioMem % PAGE_SIZE) != 0)
- gpioMem += PAGE_SIZE - ((uint32_t)gpioMem % PAGE_SIZE) ;
-
- gpio = (uint32_t *)mmap((caddr_t)gpioMem, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, fd, GPIO_BASE) ;
-
- if ((int32_t)gpio < 0)
- {
- fprintf (stderr, "wiringPiSetup: mmap failed: %s\n", strerror (errno)) ;
+ if (wiringPiDebug)
+ {
+ int serr = errno ;
+ fprintf (stderr, "wiringPiSetup: mmap failed: %s\n", strerror (errno)) ;
+ errno = serr ;
+ }
return -1 ;
}
// PWM
- if ((pwmMem = malloc (BLOCK_SIZE + (PAGE_SIZE-1))) == NULL)
- {
- fprintf (stderr, "wiringPiSetup: pwmMem malloc failed: %s\n", strerror (errno)) ;
- return -1 ;
- }
-
- if (((uint32_t)pwmMem % PAGE_SIZE) != 0)
- pwmMem += PAGE_SIZE - ((uint32_t)pwmMem % PAGE_SIZE) ;
-
- pwm = (uint32_t *)mmap(pwmMem, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, fd, GPIO_PWM) ;
-
- if ((int32_t)pwm < 0)
+ pwm = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_PWM) ;
+ if ((int32_t)pwm == -1)
{
- fprintf (stderr, "wiringPiSetup: mmap failed (pwm): %s\n", strerror (errno)) ;
+ if (wiringPiDebug)
+ {
+ int serr = errno ;
+ fprintf (stderr, "wiringPiSetup: mmap failed (pwm): %s\n", strerror (errno)) ;
+ errno = serr ;
+ }
return -1 ;
}
// Clock control (needed for PWM)
- if ((clkMem = malloc (BLOCK_SIZE + (PAGE_SIZE-1))) == NULL)
+ clk = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, CLOCK_BASE) ;
+ if ((int32_t)clk == -1)
{
- fprintf (stderr, "wiringPiSetup: clkMem malloc failed: %s\n", strerror (errno)) ;
- return -1 ;
- }
-
- if (((uint32_t)clkMem % PAGE_SIZE) != 0)
- clkMem += PAGE_SIZE - ((uint32_t)clkMem % PAGE_SIZE) ;
-
- clk = (uint32_t *)mmap(clkMem, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, fd, CLOCK_BASE) ;
-
- if ((int32_t)clk < 0)
- {
- fprintf (stderr, "wiringPiSetup: mmap failed (clk): %s\n", strerror (errno)) ;
+ if (wiringPiDebug)
+ {
+ int serr = errno ;
+ fprintf (stderr, "wiringPiSetup: mmap failed (clk): %s\n", strerror (errno)) ;
+ errno = serr ;
+ }
return -1 ;
}
// The drive pads
- if ((padsMem = malloc (BLOCK_SIZE + (PAGE_SIZE-1))) == NULL)
- {
- fprintf (stderr, "wiringPiSetup: padsMem malloc failed: %s\n", strerror (errno)) ;
- return -1 ;
- }
-
- if (((uint32_t)padsMem % PAGE_SIZE) != 0)
- padsMem += PAGE_SIZE - ((uint32_t)padsMem % PAGE_SIZE) ;
-
- pads = (uint32_t *)mmap(padsMem, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, fd, GPIO_PADS) ;
-
- if ((int32_t)pads < 0)
+ pads = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_PADS) ;
+ if ((int32_t)pads == -1)
{
- fprintf (stderr, "wiringPiSetup: mmap failed (pads): %s\n", strerror (errno)) ;
+ if (wiringPiDebug)
+ {
+ int serr = errno ;
+ fprintf (stderr, "wiringPiSetup: mmap failed (pads): %s\n", strerror (errno)) ;
+ errno = serr ;
+ }
return -1 ;
}
-#ifdef DEBUG_PADS
- printf ("Checking pads @ 0x%08X\n", (unsigned int)pads) ;
- printf (" -> %08X %08X %08X\n", *(pads + 11), *(pads + 12), *(pads + 13)) ;
-#endif
-
// The system timer
- if ((timerMem = malloc (BLOCK_SIZE + (PAGE_SIZE-1))) == NULL)
+ timer = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_TIMER) ;
+ if ((int32_t)timer == -1)
{
- fprintf (stderr, "wiringPiSetup: timerMem malloc failed: %s\n", strerror (errno)) ;
- return -1 ;
- }
-
- if (((uint32_t)timerMem % PAGE_SIZE) != 0)
- timerMem += PAGE_SIZE - ((uint32_t)timerMem % PAGE_SIZE) ;
-
- timer = (uint32_t *)mmap(timerMem, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, fd, GPIO_TIMER) ;
-
- if ((int32_t)timer < 0)
- {
- fprintf (stderr, "wiringPiSetup: mmap failed (timer): %s\n", strerror (errno)) ;
+ if (wiringPiDebug)
+ {
+ int serr = errno ;
+ fprintf (stderr, "wiringPiSetup: mmap failed (timer): %s\n", strerror (errno)) ;
+ errno = serr ;
+ }
return -1 ;
}
*(timer + TIMER_PRE_DIV) = 0x00000F9 ;
timerIrqRaw = timer + TIMER_IRQ_RAW ;
-// Initialise our epoch for millis()
+ initialiseEpoch () ;
- gettimeofday (&tv, NULL) ;
- epoch = (tv.tv_sec * 1000000 + tv.tv_usec) / 1000 ;
+ wiringPiMode = WPI_MODE_PINS ;
return 0 ;
}
{
int x ;
- if (wiringPiDebug)
- printf ("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 ;
+ getAlt = getAltGpio ;
pullUpDnControl = pullUpDnControlGpio ;
digitalWrite = digitalWriteGpio ;
+ digitalWriteByte = digitalWriteByteGpio ;
pwmWrite = pwmWriteGpio ;
setPadDrive = setPadDriveGpio ;
digitalRead = digitalReadGpio ;
waitForInterrupt = waitForInterruptGpio ;
- delayMicroseconds = delayMicrosecondsWPi ; // Same
pwmSetMode = pwmSetModeWPi ;
pwmSetRange = pwmSetRangeWPi ;
+ pwmSetClock = pwmSetClockWPi ;
+
+ wiringPiMode = WPI_MODE_GPIO ;
return 0 ;
}
int wiringPiSetupSys (void)
{
+ int boardRev ;
int pin ;
- struct timeval tv ;
char fName [128] ;
+ if (getenv ("WIRINGPI_DEBUG") != NULL)
+ wiringPiDebug = TRUE ;
+
if (wiringPiDebug)
- printf ("wiringPiSetupSys called\n") ;
+ printf ("wiringPi: wiringPiSetupSys called\n") ;
pinMode = pinModeSys ;
+ getAlt = getAltSys ;
pullUpDnControl = pullUpDnControlSys ;
digitalWrite = digitalWriteSys ;
+ digitalWriteByte = digitalWriteByteSys ;
pwmWrite = pwmWriteSys ;
setPadDrive = setPadDriveSys ;
digitalRead = digitalReadSys ;
waitForInterrupt = waitForInterruptSys ;
- delayMicroseconds = delayMicrosecondsSys ;
pwmSetMode = pwmSetModeSys ;
pwmSetRange = pwmSetRangeSys ;
+ pwmSetClock = pwmSetClockSys ;
+ 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
sysFds [pin] = open (fName, O_RDWR) ;
}
-// Initialise the epoch for mills() ...
+ initialiseEpoch () ;
- gettimeofday (&tv, NULL) ;
- epoch = (tv.tv_sec * 1000000 + tv.tv_usec) / 1000 ;
+ wiringPiMode = WPI_MODE_GPIO_SYS ;
return 0 ;
}