X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=wiringPi%2FwiringPi.c;h=7c899ea5c276316e4f4c0d2b78bb31815557369b;hb=170dce5f1939a3629bbc2329c5557cbaa0bc278f;hp=9655db25d705a292dc08608f12d54c3fa8d64f8b;hpb=be04c1bd52fbc787eb741a2a87fcebe40f571a0d;p=wiringPi.git diff --git a/wiringPi/wiringPi.c b/wiringPi/wiringPi.c index 9655db2..7c899ea 100644 --- a/wiringPi/wiringPi.c +++ b/wiringPi/wiringPi.c @@ -1,7 +1,7 @@ /* * wiringPi: - * Arduino compatable (ish) Wiring library for the Raspberry Pi - * Copyright (c) 2012 Gordon Henderson + * Arduino look-a-like Wiring library for the Raspberry Pi + * Copyright (c) 2012-2015 Gordon Henderson * Additional code for pwmSetClock by Chris Hall * * Thanks to code samples from Gert Jan van Loo and the @@ -51,11 +51,9 @@ // Added in the 2 UART pins // Change maxPins to numPins to more accurately reflect purpose -// Pad drive current fiddling - -#undef DEBUG_PADS #include +#include #include #include #include @@ -68,44 +66,61 @@ #include #include #include -#include #include #include +#include -#include "wiringPi.h" - -// Function stubs - -void (*pinMode) (int pin, int mode) ; -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) ; +#include "softPwm.h" +#include "softTone.h" +#include "wiringPi.h" #ifndef TRUE #define TRUE (1==1) #define FALSE (1==2) #endif +// Environment Variables + +#define ENV_DEBUG "WIRINGPI_DEBUG" +#define ENV_CODES "WIRINGPI_CODES" + + +// Mask for the bottom 64 pins which belong to the Raspberry Pi +// The others are available for the other devices + +#define PI_GPIO_MASK (0xFFFFFFC0) + +struct wiringPiNodeStruct *wiringPiNodes = NULL ; + // BCM Magic #define BCM_PASSWORD 0x5A000000 +// The BCM2835 has 54 GPIO pins. +// BCM2835 data sheet, Page 90 onwards. +// There are 6 control registers, each control the functions of a block +// of 10 pins. +// Each control register has 10 sets of 3 bits per GPIO pin - the ALT values +// +// 000 = GPIO Pin X is an input +// 001 = GPIO Pin X is an output +// 100 = GPIO Pin X takes alternate function 0 +// 101 = GPIO Pin X takes alternate function 1 +// 110 = GPIO Pin X takes alternate function 2 +// 111 = GPIO Pin X takes alternate function 3 +// 011 = GPIO Pin X takes alternate function 4 +// 010 = GPIO Pin X takes alternate function 5 +// +// So the 3 bits for port X are: +// X / 10 + ((X % 10) * 3) + // Port function select bits #define FSEL_INPT 0b000 #define FSEL_OUTP 0b001 #define FSEL_ALT0 0b100 -#define FSEL_ALT0 0b100 #define FSEL_ALT1 0b101 #define FSEL_ALT2 0b110 #define FSEL_ALT3 0b111 @@ -113,20 +128,24 @@ void (*pwmSetClock) (int divisor) ; #define FSEL_ALT5 0b010 // Access from ARM Running Linux -// Take from Gert/Doms code. Some of this is not in the manual +// Taken from Gert/Doms code. Some of this is not in the manual // that I can find )-: +// +// Updates in September 2015 - all now static variables (and apologies for the caps) +// due to the Pi v2 and the new /dev/gpiomem interface -#define BCM2708_PERI_BASE 0x20000000 -#define GPIO_PADS (BCM2708_PERI_BASE + 0x100000) -#define CLOCK_BASE (BCM2708_PERI_BASE + 0x101000) -#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) -#define GPIO_TIMER (BCM2708_PERI_BASE + 0x00B000) -#define GPIO_PWM (BCM2708_PERI_BASE + 0x20C000) +static volatile unsigned int RASPBERRY_PI_PERI_BASE ; +static volatile unsigned int GPIO_PADS ; +static volatile unsigned int GPIO_CLOCK_BASE ; +static volatile unsigned int GPIO_BASE ; +static volatile unsigned int GPIO_TIMER ; +static volatile unsigned int GPIO_PWM ; #define PAGE_SIZE (4*1024) #define BLOCK_SIZE (4*1024) // PWM +// Word offsets into the PWM control region #define PWM_CONTROL 0 #define PWM_STATUS 1 @@ -135,17 +154,11 @@ void (*pwmSetClock) (int divisor) ; #define PWM1_RANGE 8 #define PWM1_DATA 9 +// Clock regsiter offsets + #define PWMCLK_CNTL 40 #define PWMCLK_DIV 41 -#define PWM1_MS_MODE 0x8000 // Run in MS mode -#define PWM1_USEFIFO 0x2000 // Data from FIFO -#define PWM1_REVPOLAR 0x1000 // Reverse polarity -#define PWM1_OFFSTATE 0x0800 // Ouput Off state -#define PWM1_REPEATFF 0x0400 // Repeat last value if FIFO empty -#define PWM1_SERIAL 0x0200 // Run in serial mode -#define PWM1_ENABLE 0x0100 // Channel Enable - #define PWM0_MS_MODE 0x0080 // Run in MS mode #define PWM0_USEFIFO 0x0020 // Data from FIFO #define PWM0_REVPOLAR 0x0010 // Reverse polarity @@ -154,7 +167,16 @@ void (*pwmSetClock) (int divisor) ; #define PWM0_SERIAL 0x0002 // Run in serial mode #define PWM0_ENABLE 0x0001 // Channel Enable +#define PWM1_MS_MODE 0x8000 // Run in MS mode +#define PWM1_USEFIFO 0x2000 // Data from FIFO +#define PWM1_REVPOLAR 0x1000 // Reverse polarity +#define PWM1_OFFSTATE 0x0800 // Ouput Off state +#define PWM1_REPEATFF 0x0400 // Repeat last value if FIFO empty +#define PWM1_SERIAL 0x0200 // Run in serial mode +#define PWM1_ENABLE 0x0100 // Channel Enable + // Timer +// Word offsets #define TIMER_LOAD (0x400 >> 2) #define TIMER_VALUE (0x404 >> 2) @@ -172,43 +194,75 @@ static volatile uint32_t *gpio ; static volatile uint32_t *pwm ; static volatile uint32_t *clk ; static volatile uint32_t *pads ; + +#ifdef USE_TIMER static volatile uint32_t *timer ; static volatile uint32_t *timerIrqRaw ; +#endif + + +// Data for use with the boardId functions. +// The order of entries here to correspond with the PI_MODEL_X +// and PI_VERSION_X defines in wiringPi.h +// Only intended for the gpio command - use at your own risk! + +static int piModel2 = FALSE ; + +const char *piModelNames [7] = +{ + "Unknown", + "Model A", + "Model B", + "Model B+", + "Compute Module", + "Model A+", + "Model 2", // Quad Core +} ; + +const char *piRevisionNames [5] = +{ + "Unknown", + "1", + "1.1", + "1.2", + "2", +} ; + +const char *piMakerNames [5] = +{ + "Unknown", + "Egoman", + "Sony", + "Qusda", + "MBest", +} ; + // Time for easy calculations -static unsigned long long epoch ; +static uint64_t epochMilli, epochMicro ; // Misc static int wiringPiMode = WPI_MODE_UNINITIALISED ; +static volatile int pinPass = -1 ; +static pthread_mutex_t pinMutex ; -// Debugging +// Debugging & Return codes -int wiringPiDebug = FALSE ; - -// The BCM2835 has 54 GPIO pins. -// BCM2835 data sheet, Page 90 onwards. -// There are 6 control registers, each control the functions of a block -// of 10 pins. -// Each control register has 10 sets of 3 bits per GPIO pin: -// -// 000 = GPIO Pin X is an input -// 001 = GPIO Pin X is an output -// 100 = GPIO Pin X takes alternate function 0 -// 101 = GPIO Pin X takes alternate function 1 -// 110 = GPIO Pin X takes alternate function 2 -// 111 = GPIO Pin X takes alternate function 3 -// 011 = GPIO Pin X takes alternate function 4 -// 010 = GPIO Pin X takes alternate function 5 -// -// So the 3 bits for port X are: -// X / 10 + ((X % 10) * 3) +int wiringPiDebug = FALSE ; +int wiringPiReturnCodes = FALSE ; // sysFds: // Map a file descriptor from the /sys/class/gpio/gpioX/value -static int sysFds [64] ; +static int sysFds [64] = +{ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +} ; // ISR Data @@ -221,17 +275,19 @@ static void (*isrFunctions [64])(void) ; // pinToGpio: // Take a Wiring pin (0 through X) and re-map it to the BCM_GPIO pin -// Cope for 2 different board revieions here +// Cope for 3 different board revisions here. static int *pinToGpio ; +// Revision 1, 1.1: + static int pinToGpioR1 [64] = { - 17, 18, 21, 22, 23, 24, 25, 4, // From the Original Wiki - GPIO 0 through 7 - 0, 1, // I2C - SDA0, SCL0 - 8, 7, // SPI - CE1, CE0 - 10, 9, 11, // SPI - MOSI, MISO, SCLK - 14, 15, // UART - Tx, Rx + 17, 18, 21, 22, 23, 24, 25, 4, // From the Original Wiki - GPIO 0 through 7: wpi 0 - 7 + 0, 1, // I2C - SDA1, SCL1 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 // Padding: @@ -240,6 +296,8 @@ static int pinToGpioR1 [64] = -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 63 } ; +// Revision 2: + static int pinToGpioR2 [64] = { 17, 18, 27, 22, 23, 24, 25, 4, // From the Original Wiki - GPIO 0 through 7: wpi 0 - 7 @@ -247,18 +305,93 @@ static int pinToGpioR2 [64] = 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 + 28, 29, 30, 31, // Rev 2: New GPIOs 8 though 11 wpi 17 - 20 + 5, 6, 13, 19, 26, // B+ wpi 21, 22, 23, 24, 25 + 12, 16, 20, 21, // B+ wpi 26, 27, 28, 29 + 0, 1, // B+ wpi 30, 31 // Padding: - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 31 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 63 } ; +// physToGpio: +// Take a physical pin (1 through 26) and re-map it to the BCM_GPIO pin +// Cope for 2 different board revisions here. +// Also add in the P5 connector, so the P5 pins are 3,4,5,6, so 53,54,55,56 + +static int *physToGpio ; + +static int physToGpioR1 [64] = +{ + -1, // 0 + -1, -1, // 1, 2 + 0, -1, + 1, -1, + 4, 14, + -1, 15, + 17, 18, + 21, -1, + 22, 23, + -1, 24, + 10, -1, + 9, 25, + 11, 8, + -1, 7, // 25, 26 + + -1, -1, -1, -1, -1, // ... 31 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 63 +} ; + +static int physToGpioR2 [64] = +{ + -1, // 0 + -1, -1, // 1, 2 + 2, -1, + 3, -1, + 4, 14, + -1, 15, + 17, 18, + 27, -1, + 22, 23, + -1, 24, + 10, -1, + 9, 25, + 11, 8, + -1, 7, // 25, 26 + +// B+ + + 0, 1, + 5, -1, + 6, 12, + 13, -1, + 19, 16, + 26, 20, + -1, 21, + +// the P5 connector on the Rev 2 boards: + + -1, -1, + -1, -1, + -1, -1, + -1, -1, + -1, -1, + 28, 29, + 30, 31, + -1, -1, + -1, -1, + -1, -1, + -1, -1, +} ; + // gpioToGPFSEL: -// Map a BCM_GPIO pin to it's control port. (GPFSEL 0-5) +// Map a BCM_GPIO pin to it's Function Selection +// control port. (GPFSEL 0-5) +// Groups of 10 - 3 bits per Function - 30 bits per port static uint8_t gpioToGPFSEL [] = { @@ -293,7 +426,6 @@ static uint8_t gpioToGPSET [] = 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 @@ -325,7 +457,7 @@ static uint8_t gpioToEDS [] = } ; // gpioToREN -// (Word) offset to the Rising edgde ENable register +// (Word) offset to the Rising edge ENable register static uint8_t gpioToREN [] = { @@ -344,11 +476,14 @@ static uint8_t gpioToFEN [] = #endif -// gpioToPUDCLK -// (Word) offset to the Pull Up Down Clock regsiter +// GPPUD: +// GPIO Pin pull up/down register #define GPPUD 37 +// gpioToPUDCLK +// (Word) offset to the Pull Up Down Clock regsiter + static uint8_t gpioToPUDCLK [] = { 38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38, @@ -371,6 +506,10 @@ static uint8_t gpioToPwmALT [] = 0, 0, 0, 0, 0, 0, 0, 0, // 56 -> 63 } ; + +// gpioToPwmPort +// The port value to put a GPIO pin into PWM mode + static uint8_t gpioToPwmPort [] = { 0, 0, 0, 0, 0, 0, 0, 0, // 0 -> 7 @@ -384,6 +523,55 @@ static uint8_t gpioToPwmPort [] = } ; +// gpioToGpClkALT: +// ALT value to put a GPIO pin into GP Clock mode. +// On the Pi we can really only use BCM_GPIO_4 and BCM_GPIO_21 +// for clocks 0 and 1 respectively, however I'll include the full +// list for completeness - maybe one day... + +#define GPIO_CLOCK_SOURCE 1 + +// gpioToGpClkALT0: + +static uint8_t gpioToGpClkALT0 [] = +{ + 0, 0, 0, 0, FSEL_ALT0, FSEL_ALT0, FSEL_ALT0, 0, // 0 -> 7 + 0, 0, 0, 0, 0, 0, 0, 0, // 8 -> 15 + 0, 0, 0, 0, FSEL_ALT5, FSEL_ALT5, 0, 0, // 16 -> 23 + 0, 0, 0, 0, 0, 0, 0, 0, // 24 -> 31 + FSEL_ALT0, 0, FSEL_ALT0, 0, 0, 0, 0, 0, // 32 -> 39 + 0, 0, FSEL_ALT0, FSEL_ALT0, FSEL_ALT0, 0, 0, 0, // 40 -> 47 + 0, 0, 0, 0, 0, 0, 0, 0, // 48 -> 55 + 0, 0, 0, 0, 0, 0, 0, 0, // 56 -> 63 +} ; + +// gpioToClk: +// (word) Offsets to the clock Control and Divisor register + +static uint8_t gpioToClkCon [] = +{ + -1, -1, -1, -1, 28, 30, 32, -1, // 0 -> 7 + -1, -1, -1, -1, -1, -1, -1, -1, // 8 -> 15 + -1, -1, -1, -1, 28, 30, -1, -1, // 16 -> 23 + -1, -1, -1, -1, -1, -1, -1, -1, // 24 -> 31 + 28, -1, 28, -1, -1, -1, -1, -1, // 32 -> 39 + -1, -1, 28, 30, 28, -1, -1, -1, // 40 -> 47 + -1, -1, -1, -1, -1, -1, -1, -1, // 48 -> 55 + -1, -1, -1, -1, -1, -1, -1, -1, // 56 -> 63 +} ; + +static uint8_t gpioToClkDiv [] = +{ + -1, -1, -1, -1, 29, 31, 33, -1, // 0 -> 7 + -1, -1, -1, -1, -1, -1, -1, -1, // 8 -> 15 + -1, -1, -1, -1, 29, 31, -1, -1, // 16 -> 23 + -1, -1, -1, -1, -1, -1, -1, -1, // 24 -> 31 + 29, -1, 29, -1, -1, -1, -1, -1, // 32 -> 39 + -1, -1, 29, 31, 29, -1, -1, -1, // 40 -> 47 + -1, -1, -1, -1, -1, -1, -1, -1, // 48 -> 55 + -1, -1, -1, -1, -1, -1, -1, -1, // 56 -> 63 +} ; + /* * Functions @@ -392,44 +580,75 @@ static uint8_t gpioToPwmPort [] = /* - * 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!) + * wiringPiFailure: + * Fail. Or not. ********************************************************************************* */ -int wpiPinToGpio (int wpiPin) +int wiringPiFailure (int fatal, const char *message, ...) { - return pinToGpio [wpiPin & 63] ; + va_list argp ; + char buffer [1024] ; + + if (!fatal && wiringPiReturnCodes) + return -1 ; + + va_start (argp, message) ; + vsnprintf (buffer, 1023, message, argp) ; + va_end (argp) ; + + fprintf (stderr, "%s", buffer) ; + exit (EXIT_FAILURE) ; + + return 0 ; } /* * 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 )-: + * Revision 1 really means the early Model B's. + * Revision 2 is everything else - it covers the B, B+ and CM. + * ... and the Pi 2 - which is a B+ ++ ... + * * 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 + * 0001 - Not used + * 0002 - Model B, Rev 1, 256MB, Egoman + * 0003 - Model B, Rev 1.1, 256MB, Egoman, Fuses/D14 removed. + * 0004 - Model B, Rev 2, 256MB, Sony + * 0005 - Model B, Rev 2, 256MB, Qisda + * 0006 - Model B, Rev 2, 256MB, Egoman + * 0007 - Model A, Rev 2, 256MB, Egoman + * 0008 - Model A, Rev 2, 256MB, Sony + * 0009 - Model A, Rev 2, 256MB, Qisda + * 000d - Model B, Rev 2, 512MB, Egoman + * 000e - Model B, Rev 2, 512MB, Sony + * 000f - Model B, Rev 2, 512MB, Qisda + * 0010 - Model B+, Rev 1.2, 512MB, Sony + * 0011 - Pi CM, Rev 1.2, 512MB, Sony + * 0012 - Model A+ Rev 1.2, 256MB, Sony + * 0014 - Pi CM, Rev 1.1, 512MB, Sony (Actual Revision might be different) + * 0015 - Model A+ Rev 1.1, 256MB, Sony + * + * For the Pi 2: + * 0010 - Model 2, Rev 1.1, Quad Core, 1GB, Sony * * A small thorn is the olde style overvolting - that will add in * 1000000 * + * The Pi compute module has an revision of 0011 - since we only check the + * last digit, then it's 1, therefore it'll default to not 2 or 3 for a + * Rev 1, so will appear as a Rev 2. This is fine for the most part, but + * we'll properly detect the Compute Module later and adjust accordingly. + * And the next rev of the CN is 0014 ... + * ********************************************************************************* */ -static void piBoardRevOops (char *why) +static void piBoardRevOops (const char *why) { fprintf (stderr, "piBoardRev: Unable to determine board revision from /proc/cpuinfo\n") ; fprintf (stderr, " -> %s\n", why) ; @@ -442,16 +661,45 @@ int piBoardRev (void) { FILE *cpuFd ; char line [120] ; - char *c, lastChar ; + char *c ; static int boardRev = -1 ; -// No point checking twice... - - if (boardRev != -1) + if (boardRev != -1) // No point checking twice return boardRev ; if ((cpuFd = fopen ("/proc/cpuinfo", "r")) == NULL) - return -1 ; + piBoardRevOops ("Unable to open /proc/cpuinfo") ; + +// Start by looking for the Architecture, then we can look for a B2 revision.... + + while (fgets (line, 120, cpuFd) != NULL) + if (strncmp (line, "Hardware", 8) == 0) + break ; + + if (strncmp (line, "Hardware", 8) != 0) + piBoardRevOops ("No \"Hardware\" line") ; + + if (wiringPiDebug) + printf ("piboardRev: Hardware: %s\n", line) ; + +// See if it's BCM2708 or BCM2709 + + if (strstr (line, "BCM2709") != NULL) + piModel2 = TRUE ; + else if (strstr (line, "BCM2708") == NULL) + { + fprintf (stderr, "Unable to determine hardware version. I see: %s,\n", line) ; + fprintf (stderr, " - expecting BCM2708 or BCM2709.\n") ; + fprintf (stderr, "If this is a genuine Raspberry Pi then please report this\n") ; + fprintf (stderr, "to projects@drogon.net. If this is not a Raspberry Pi then you\n") ; + fprintf (stderr, "are on your own as wiringPi is designed to support the\n") ; + fprintf (stderr, "Raspberry Pi ONLY.\n") ; + exit (EXIT_FAILURE) ; + } + +// Now do the rest of it as before + + rewind (cpuFd) ; while (fgets (line, 120, cpuFd) != NULL) if (strncmp (line, "Revision", 8) == 0) @@ -459,14 +707,19 @@ int piBoardRev (void) fclose (cpuFd) ; - if (line == NULL) + if (strncmp (line, "Revision", 8) != 0) piBoardRevOops ("No \"Revision\" line") ; - line [strlen (line) - 1] = 0 ; // Chomp LF +// Chomp trailing CR/NL + + for (c = &line [strlen (line) - 1] ; (*c == '\n') || (*c == '\r') ; --c) + *c = 0 ; if (wiringPiDebug) printf ("piboardRev: Revision string: %s\n", line) ; +// Scan to first digit + for (c = line ; *c ; ++c) if (isdigit (*c)) break ; @@ -474,22 +727,31 @@ int piBoardRev (void) if (!isdigit (*c)) piBoardRevOops ("No numeric revision string") ; +// Make sure its long enough + + if (strlen (c) < 4) + piBoardRevOops ("Bogus \"Revision\" line (too small)") ; + // If you have overvolted the Pi, then it appears that the revision // has 100000 added to it! +// The actual condition for it being set is: +// (force_turbo || current_limit_override || temp_limit>85) && over_voltage>0 if (wiringPiDebug) if (strlen (c) != 4) - printf ("piboardRev: This Pi has/is overvolted!\n") ; + printf ("piboardRev: This Pi has/is (force_turbo || current_limit_override || temp_limit>85) && over_voltage>0\n") ; - lastChar = line [strlen (line) - 1] ; +// Isolate last 4 characters: + + c = c + strlen (c) - 4 ; if (wiringPiDebug) - printf ("piboardRev: lastChar is: '%c' (%d, 0x%02X)\n", lastChar, lastChar, lastChar) ; + printf ("piboardRev: last4Chars are: \"%s\"\n", c) ; - /**/ if ((lastChar == '2') || (lastChar == '3')) + if ( (strcmp (c, "0002") == 0) || (strcmp (c, "0003") == 0)) boardRev = 1 ; else - boardRev = 2 ; + boardRev = 2 ; // Covers everything else from the B revision 2 to the B+, the Pi v2 and CM's. if (wiringPiDebug) printf ("piBoardRev: Returning revision: %d\n", boardRev) ; @@ -498,147 +760,262 @@ int piBoardRev (void) } - /* - * pinMode: - * Sets the mode of a pin to be input, output or PWM output + * piBoardId: + * Do more digging into the board revision string as above, but return + * as much details as we can. + * This is undocumented and really only intended for the GPIO command. + * Use at your own risk! + * + * for Pi v2: + * [USER:8] [NEW:1] [MEMSIZE:3] [MANUFACTURER:4] [PROCESSOR:4] [TYPE:8] [REV:4] + * NEW 23: will be 1 for the new scheme, 0 for the old scheme + * MEMSIZE 20: 0=256M 1=512M 2=1G + * MANUFACTURER 16: 0=SONY 1=EGOMAN 2=EMBEST + * PROCESSOR 12: 0=2835 1=2836 + * TYPE 04: 0=MODELA 1=MODELB 2=MODELA+ 3=MODELB+ 4=Pi2 MODEL B 5=ALPHA 6=CM + * REV 00: 0=REV0 1=REV1 2=REV2 ********************************************************************************* */ -void pinModeGpio (int pin, int mode) +void piBoardId (int *model, int *rev, int *mem, int *maker, int *overVolted) { -// register int barrier ; + FILE *cpuFd ; + char line [120] ; + char *c ; - int fSel, shift, alt ; +// Will deal with the properly later on - for now, lets just get it going... +// unsigned int modelNum ; - pin &= 63 ; + (void)piBoardRev () ; // Call this first to make sure all's OK. Don't care about the result. - fSel = gpioToGPFSEL [pin] ; - shift = gpioToShift [pin] ; + if ((cpuFd = fopen ("/proc/cpuinfo", "r")) == NULL) + piBoardRevOops ("Unable to open /proc/cpuinfo") ; - /**/ if (mode == INPUT) - *(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) ; // Sets bits to zero = input - else if (mode == OUTPUT) - *(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) | (1 << shift) ; - else if (mode == PWM_OUTPUT) - { - if ((alt = gpioToPwmALT [pin]) == 0) // Not a PWM pin - return ; + while (fgets (line, 120, cpuFd) != NULL) + if (strncmp (line, "Revision", 8) == 0) + break ; -// Set pin to PWM mode + fclose (cpuFd) ; + + if (strncmp (line, "Revision", 8) != 0) + piBoardRevOops ("No \"Revision\" line") ; - *(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) | (alt << shift) ; +// Chomp trailing CR/NL - delayMicroseconds (110) ; // See comments in pwmSetClockWPi - *(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) | (alt << shift) ; + for (c = &line [strlen (line) - 1] ; (*c == '\n') || (*c == '\r') ; --c) + *c = 0 ; + + if (wiringPiDebug) + printf ("piboardId: Revision string: %s\n", line) ; -// Page 107 of the BCM Peripherals manual talks about the GPIO clocks, -// but I'm assuming (hoping!) that this applies to other clocks too. + if (piModel2) + { - *(pwm + PWM_CONTROL) = 0 ; // Stop PWM +// Scan to the colon - *(clk + PWMCLK_CNTL) = BCM_PASSWORD | 0x01 ; // Stop PWM Clock - delayMicroseconds (110) ; // See comments in pwmSetClockWPi + for (c = line ; *c ; ++c) + if (*c == ':') + break ; - while ((*(clk + PWMCLK_CNTL) & 0x80) != 0) // Wait for clock to be !BUSY - delayMicroseconds (1) ; + if (*c != ':') + piBoardRevOops ("Bogus \"Revision\" line (no colon)") ; - *(clk + PWMCLK_DIV) = BCM_PASSWORD | (32 << 12) ; // set pwm div to 32 (19.2/32 = 600KHz) - *(clk + PWMCLK_CNTL) = BCM_PASSWORD | 0x11 ; // enable clk +// modelNum = (unsigned int)strtol (++c, NULL, 16) ; // Hex number with no leading 0x + + *model = PI_MODEL_2 ; + *rev = PI_VERSION_1_1 ; + *mem = 1024 ; + *maker = PI_MAKER_SONY ; + } + else + { - delayMicroseconds (110) ; // See comments in pwmSetClockWPi +// Scan to first digit -// Default range register of 1024 + for (c = line ; *c ; ++c) + if (isdigit (*c)) + break ; - *(pwm + PWM0_RANGE) = 1024 ; delayMicroseconds (10) ; - *(pwm + PWM1_RANGE) = 1024 ; delayMicroseconds (10) ; - *(pwm + PWM0_DATA) = 0 ; delayMicroseconds (10) ; - *(pwm + PWM1_DATA) = 0 ; delayMicroseconds (10) ; +// Make sure its long enough -// Enable PWMs in balanced mode (default) + if (strlen (c) < 4) + piBoardRevOops ("Bogus \"Revision\" line (not long enough)") ; - *(pwm + PWM_CONTROL) = PWM0_ENABLE | PWM1_ENABLE ; +// If longer than 4, we'll assume it's been overvolted - delay (100) ; + *overVolted = strlen (c) > 4 ; + +// Extract last 4 characters: + + c = c + strlen (c) - 4 ; + +// Fill out the replys as appropriate + + /**/ if (strcmp (c, "0002") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1 ; *mem = 256 ; *maker = PI_MAKER_EGOMAN ; } + else if (strcmp (c, "0003") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1_1 ; *mem = 256 ; *maker = PI_MAKER_EGOMAN ; } + else if (strcmp (c, "0004") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_2 ; *mem = 256 ; *maker = PI_MAKER_SONY ; } + else if (strcmp (c, "0005") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_2 ; *mem = 256 ; *maker = PI_MAKER_QISDA ; } + else if (strcmp (c, "0006") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_2 ; *mem = 256 ; *maker = PI_MAKER_EGOMAN ; } + else if (strcmp (c, "0007") == 0) { *model = PI_MODEL_A ; *rev = PI_VERSION_2 ; *mem = 256 ; *maker = PI_MAKER_EGOMAN ; } + else if (strcmp (c, "0008") == 0) { *model = PI_MODEL_A ; *rev = PI_VERSION_2 ; *mem = 256 ; *maker = PI_MAKER_SONY ; ; } + else if (strcmp (c, "0009") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_2 ; *mem = 256 ; *maker = PI_MAKER_QISDA ; } + else if (strcmp (c, "000d") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_2 ; *mem = 512 ; *maker = PI_MAKER_EGOMAN ; } + else if (strcmp (c, "000e") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_2 ; *mem = 512 ; *maker = PI_MAKER_SONY ; } + else if (strcmp (c, "000f") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_2 ; *mem = 512 ; *maker = PI_MAKER_EGOMAN ; } + else if (strcmp (c, "0010") == 0) { *model = PI_MODEL_BP ; *rev = PI_VERSION_1_2 ; *mem = 512 ; *maker = PI_MAKER_SONY ; } + else if (strcmp (c, "0011") == 0) { *model = PI_MODEL_CM ; *rev = PI_VERSION_1_2 ; *mem = 512 ; *maker = PI_MAKER_SONY ; } + else if (strcmp (c, "0012") == 0) { *model = PI_MODEL_AP ; *rev = PI_VERSION_1_2 ; *mem = 256 ; *maker = PI_MAKER_SONY ; } + else if (strcmp (c, "0013") == 0) { *model = PI_MODEL_BP ; *rev = PI_VERSION_1_2 ; *mem = 512 ; *maker = PI_MAKER_MBEST ; } + else if (strcmp (c, "0014") == 0) { *model = PI_MODEL_CM ; *rev = PI_VERSION_1_2 ; *mem = 512 ; *maker = PI_MAKER_SONY ; } + else if (strcmp (c, "0015") == 0) { *model = PI_MODEL_AP ; *rev = PI_VERSION_1_1 ; *mem = 256 ; *maker = PI_MAKER_SONY ; } + else { *model = 0 ; *rev = 0 ; *mem = 0 ; *maker = 0 ; } } +} + -// 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 -// not quite gotten to the bottom of why this happens -// The down-side is that the pull up/downs are rememberd in the SoC between -// power cycles, so it's going to be a good idea to explicitly set them in -// any new code. -// -// pullUpDnControl (pin, PUD_OFF) ; - -} +/* + * wpiPinToGpio: + * Translate a wiringPi Pin number to native GPIO pin number. + * Provided for external support. + ********************************************************************************* + */ -void pinModeWPi (int pin, int mode) +int wpiPinToGpio (int wpiPin) { - pinModeGpio (pinToGpio [pin & 63], mode) ; + return pinToGpio [wpiPin & 63] ; } -void pinModeSys (int pin, int mode) + +/* + * physPinToGpio: + * Translate a physical Pin number to native GPIO pin number. + * Provided for external support. + ********************************************************************************* + */ + +int physPinToGpio (int physPin) { - return ; + return physToGpio [physPin & 63] ; } /* - * pwmControl: - * Allow the user to control some of the PWM functions + * setPadDrive: + * Set the PAD driver value ********************************************************************************* */ -void pwmSetModeWPi (int mode) +void setPadDrive (int group, int value) { - if (mode == PWM_MODE_MS) - *(pwm + PWM_CONTROL) = PWM0_ENABLE | PWM1_ENABLE | PWM0_MS_MODE | PWM1_MS_MODE ; - else - *(pwm + PWM_CONTROL) = PWM0_ENABLE | PWM1_ENABLE ; + uint32_t wrVal ; + + if ((wiringPiMode == WPI_MODE_PINS) || (wiringPiMode == WPI_MODE_PHYS) || (wiringPiMode == WPI_MODE_GPIO)) + { + if ((group < 0) || (group > 2)) + return ; + + wrVal = BCM_PASSWORD | 0x18 | (value & 7) ; + *(pads + group + 11) = wrVal ; + + if (wiringPiDebug) + { + printf ("setPadDrive: Group: %d, value: %d (%08X)\n", group, value, wrVal) ; + printf ("Read : %08X\n", *(pads + group + 11)) ; + } + } } -void pwmSetModeSys (int mode) + +/* + * getAlt: + * Returns the ALT bits for a given port. Only really of-use + * for the gpio readall command (I think) + ********************************************************************************* + */ + +int getAlt (int pin) { - return ; + int fSel, shift, alt ; + + pin &= 63 ; + + /**/ if (wiringPiMode == WPI_MODE_PINS) + pin = pinToGpio [pin] ; + else if (wiringPiMode == WPI_MODE_PHYS) + pin = physToGpio [pin] ; + else if (wiringPiMode != WPI_MODE_GPIO) + return 0 ; + + fSel = gpioToGPFSEL [pin] ; + shift = gpioToShift [pin] ; + + alt = (*(gpio + fSel) >> shift) & 7 ; + + return alt ; } -void pwmSetRangeWPi (unsigned int range) +/* + * pwmSetMode: + * Select the native "balanced" mode, or standard mark:space mode + ********************************************************************************* + */ + +void pwmSetMode (int mode) { - *(pwm + PWM0_RANGE) = range ; delayMicroseconds (10) ; - *(pwm + PWM1_RANGE) = range ; delayMicroseconds (10) ; + if ((wiringPiMode == WPI_MODE_PINS) || (wiringPiMode == WPI_MODE_PHYS) || (wiringPiMode == WPI_MODE_GPIO)) + { + if (mode == PWM_MODE_MS) + *(pwm + PWM_CONTROL) = PWM0_ENABLE | PWM1_ENABLE | PWM0_MS_MODE | PWM1_MS_MODE ; + else + *(pwm + PWM_CONTROL) = PWM0_ENABLE | PWM1_ENABLE ; + } } -void pwmSetRangeSys (unsigned int range) + +/* + * pwmSetRange: + * Set the PWM range register. We set both range registers to the same + * value. If you want different in your own code, then write your own. + ********************************************************************************* + */ + +void pwmSetRange (unsigned int range) { - return ; + if ((wiringPiMode == WPI_MODE_PINS) || (wiringPiMode == WPI_MODE_PHYS) || (wiringPiMode == WPI_MODE_GPIO)) + { + *(pwm + PWM0_RANGE) = range ; delayMicroseconds (10) ; + *(pwm + PWM1_RANGE) = range ; delayMicroseconds (10) ; + } } + /* - * pwmSetClockWPi: + * pwmSetClock: * Set/Change the PWM clock. Originally my code, but changed * (for the better!) by Chris Hall, * after further study of the manual and testing with a 'scope ********************************************************************************* */ -void pwmSetClockWPi (int divisor) +void pwmSetClock (int divisor) { - unsigned int pwm_control ; + uint32_t pwm_control ; divisor &= 4095 ; - if (wiringPiDebug) - printf ("Setting to: %d. Current: 0x%08X\n", divisor, *(clk + PWMCLK_DIV)) ; + if ((wiringPiMode == WPI_MODE_PINS) || (wiringPiMode == WPI_MODE_PHYS) || (wiringPiMode == WPI_MODE_GPIO)) + { + if (wiringPiDebug) + printf ("Setting to: %d. Current: 0x%08X\n", divisor, *(clk + PWMCLK_DIV)) ; - pwm_control = *(pwm + PWM_CONTROL) ; // preserve PWM_CONTROL + 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 + *(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 @@ -646,24 +1023,125 @@ void pwmSetClockWPi (int divisor) // 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 + *(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) ; + while ((*(clk + PWMCLK_CNTL) & 0x80) != 0) // Wait for clock to be !BUSY + delayMicroseconds (1) ; - *(clk + PWMCLK_DIV) = BCM_PASSWORD | (divisor << 12) ; + *(clk + PWMCLK_DIV) = BCM_PASSWORD | (divisor << 12) ; - *(clk + PWMCLK_CNTL) = BCM_PASSWORD | 0x11 ; // Start PWM clock - *(pwm + PWM_CONTROL) = pwm_control ; // restore PWM_CONTROL + *(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)) ; + if (wiringPiDebug) + printf ("Set to: %d. Now : 0x%08X\n", divisor, *(clk + PWMCLK_DIV)) ; + } } -void pwmSetClockSys (int divisor) -{ - return ; + +/* + * gpioClockSet: + * Set the freuency on a GPIO clock pin + ********************************************************************************* + */ + +void gpioClockSet (int pin, int freq) +{ + int divi, divr, divf ; + + pin &= 63 ; + + /**/ if (wiringPiMode == WPI_MODE_PINS) + pin = pinToGpio [pin] ; + else if (wiringPiMode == WPI_MODE_PHYS) + pin = physToGpio [pin] ; + else if (wiringPiMode != WPI_MODE_GPIO) + return ; + + divi = 19200000 / freq ; + divr = 19200000 % freq ; + divf = (int)((double)divr * 4096.0 / 19200000.0) ; + + if (divi > 4095) + divi = 4095 ; + + *(clk + gpioToClkCon [pin]) = BCM_PASSWORD | GPIO_CLOCK_SOURCE ; // Stop GPIO Clock + while ((*(clk + gpioToClkCon [pin]) & 0x80) != 0) // ... and wait + ; + + *(clk + gpioToClkDiv [pin]) = BCM_PASSWORD | (divi << 12) | divf ; // Set dividers + *(clk + gpioToClkCon [pin]) = BCM_PASSWORD | 0x10 | GPIO_CLOCK_SOURCE ; // Start Clock +} + + +/* + * wiringPiFindNode: + * Locate our device node + ********************************************************************************* + */ + +struct wiringPiNodeStruct *wiringPiFindNode (int pin) +{ + struct wiringPiNodeStruct *node = wiringPiNodes ; + + while (node != NULL) + if ((pin >= node->pinBase) && (pin <= node->pinMax)) + return node ; + else + node = node->next ; + + return NULL ; +} + + +/* + * wiringPiNewNode: + * Create a new GPIO node into the wiringPi handling system + ********************************************************************************* + */ + +static void pinModeDummy (struct wiringPiNodeStruct *node, int pin, int mode) { return ; } +static void pullUpDnControlDummy (struct wiringPiNodeStruct *node, int pin, int pud) { return ; } +static int digitalReadDummy (struct wiringPiNodeStruct *node, int pin) { return LOW ; } +static void digitalWriteDummy (struct wiringPiNodeStruct *node, int pin, int value) { return ; } +static void pwmWriteDummy (struct wiringPiNodeStruct *node, int pin, int value) { return ; } +static int analogReadDummy (struct wiringPiNodeStruct *node, int pin) { return 0 ; } +static void analogWriteDummy (struct wiringPiNodeStruct *node, int pin, int value) { return ; } + +struct wiringPiNodeStruct *wiringPiNewNode (int pinBase, int numPins) +{ + int pin ; + struct wiringPiNodeStruct *node ; + +// Minimum pin base is 64 + + if (pinBase < 64) + (void)wiringPiFailure (WPI_FATAL, "wiringPiNewNode: pinBase of %d is < 64\n", pinBase) ; + +// Check all pins in-case there is overlap: + + for (pin = pinBase ; pin < (pinBase + numPins) ; ++pin) + if (wiringPiFindNode (pin) != NULL) + (void)wiringPiFailure (WPI_FATAL, "wiringPiNewNode: Pin %d overlaps with existing definition\n", pin) ; + + node = (struct wiringPiNodeStruct *)calloc (sizeof (struct wiringPiNodeStruct), 1) ; // calloc zeros + if (node == NULL) + (void)wiringPiFailure (WPI_FATAL, "wiringPiNewNode: Unable to allocate memory: %s\n", strerror (errno)) ; + + node->pinBase = pinBase ; + node->pinMax = pinBase + numPins - 1 ; + node->pinMode = pinModeDummy ; + node->pullUpDnControl = pullUpDnControlDummy ; + node->digitalRead = digitalReadDummy ; + node->digitalWrite = digitalWriteDummy ; + node->pwmWrite = pwmWriteDummy ; + node->analogRead = analogReadDummy ; + node->analogWrite = analogWriteDummy ; + node->next = wiringPiNodes ; + wiringPiNodes = node ; + + return node ; } @@ -683,87 +1161,233 @@ void pinEnableED01Pi (int pin) #endif +/* + ********************************************************************************* + * Core Functions + ********************************************************************************* + */ /* - * digitalWrite: - * Set an output bit + * pinModeAlt: + * This is an un-documented special to let you set any pin to any mode ********************************************************************************* */ -void digitalWriteWPi (int pin, int value) +void pinModeAlt (int pin, int mode) { - pin = pinToGpio [pin & 63] ; + int fSel, shift ; - if (value == LOW) - *(gpio + gpioToGPCLR [pin]) = 1 << (pin & 31) ; - else - *(gpio + gpioToGPSET [pin]) = 1 << (pin & 31) ; + if ((pin & PI_GPIO_MASK) == 0) // On-board pin + { + /**/ if (wiringPiMode == WPI_MODE_PINS) + pin = pinToGpio [pin] ; + else if (wiringPiMode == WPI_MODE_PHYS) + pin = physToGpio [pin] ; + else if (wiringPiMode != WPI_MODE_GPIO) + return ; + + fSel = gpioToGPFSEL [pin] ; + shift = gpioToShift [pin] ; + + *(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) | ((mode & 0x7) << shift) ; + } } -void digitalWriteGpio (int pin, int value) + +/* + * pinMode: + * Sets the mode of a pin to be input, output or PWM output + ********************************************************************************* + */ + +void pinMode (int pin, int mode) { - pin &= 63 ; + int fSel, shift, alt ; + struct wiringPiNodeStruct *node = wiringPiNodes ; + int origPin = pin ; + + if ((pin & PI_GPIO_MASK) == 0) // On-board pin + { + /**/ if (wiringPiMode == WPI_MODE_PINS) + pin = pinToGpio [pin] ; + else if (wiringPiMode == WPI_MODE_PHYS) + pin = physToGpio [pin] ; + else if (wiringPiMode != WPI_MODE_GPIO) + return ; + + softPwmStop (origPin) ; + softToneStop (origPin) ; + + fSel = gpioToGPFSEL [pin] ; + shift = gpioToShift [pin] ; + + /**/ if (mode == INPUT) + *(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) ; // Sets bits to zero = input + else if (mode == OUTPUT) + *(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) | (1 << shift) ; + else if (mode == SOFT_PWM_OUTPUT) + softPwmCreate (origPin, 0, 100) ; + else if (mode == SOFT_TONE_OUTPUT) + softToneCreate (origPin) ; + else if (mode == PWM_TONE_OUTPUT) + { + pinMode (origPin, PWM_OUTPUT) ; // Call myself to enable PWM mode + pwmSetMode (PWM_MODE_MS) ; + } + else if (mode == PWM_OUTPUT) + { + if ((alt = gpioToPwmALT [pin]) == 0) // Not a hardware capable PWM pin + return ; + +// Set pin to PWM mode + + *(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) | (alt << shift) ; + delayMicroseconds (110) ; // See comments in pwmSetClockWPi + + pwmSetMode (PWM_MODE_BAL) ; // Pi default mode + pwmSetRange (1024) ; // Default range of 1024 + pwmSetClock (32) ; // 19.2 / 32 = 600KHz - Also starts the PWM + } + else if (mode == GPIO_CLOCK) + { + if ((alt = gpioToGpClkALT0 [pin]) == 0) // Not a GPIO_CLOCK pin + return ; + +// Set pin to GPIO_CLOCK mode and set the clock frequency to 100KHz - if (value == LOW) - *(gpio + gpioToGPCLR [pin]) = 1 << (pin & 31) ; + *(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) | (alt << shift) ; + delayMicroseconds (110) ; + gpioClockSet (pin, 100000) ; + } + } else - *(gpio + gpioToGPSET [pin]) = 1 << (pin & 31) ; + { + if ((node = wiringPiFindNode (pin)) != NULL) + node->pinMode (node, pin, mode) ; + return ; + } } -void digitalWriteSys (int pin, int value) + +/* + * pullUpDownCtrl: + * Control the internal pull-up/down resistors on a GPIO pin + * The Arduino only has pull-ups and these are enabled by writing 1 + * to a port when in input mode - this paradigm doesn't quite apply + * here though. + ********************************************************************************* + */ + +void pullUpDnControl (int pin, int pud) { - pin &= 63 ; + struct wiringPiNodeStruct *node = wiringPiNodes ; - if (sysFds [pin] != -1) + if ((pin & PI_GPIO_MASK) == 0) // On-Board Pin { - if (value == LOW) - write (sysFds [pin], "0\n", 2) ; - else - write (sysFds [pin], "1\n", 2) ; + /**/ if (wiringPiMode == WPI_MODE_PINS) + pin = pinToGpio [pin] ; + else if (wiringPiMode == WPI_MODE_PHYS) + pin = physToGpio [pin] ; + else if (wiringPiMode != WPI_MODE_GPIO) + return ; + + *(gpio + GPPUD) = pud & 3 ; delayMicroseconds (5) ; + *(gpio + gpioToPUDCLK [pin]) = 1 << (pin & 31) ; delayMicroseconds (5) ; + + *(gpio + GPPUD) = 0 ; delayMicroseconds (5) ; + *(gpio + gpioToPUDCLK [pin]) = 0 ; delayMicroseconds (5) ; + } + else // Extension module + { + if ((node = wiringPiFindNode (pin)) != NULL) + node->pullUpDnControl (node, pin, pud) ; + return ; } } /* - * 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 + * digitalRead: + * Read the value of a given Pin, returning HIGH or LOW ********************************************************************************* */ -void digitalWriteByteGpio (int value) +int digitalRead (int pin) { - uint32_t pinSet = 0 ; - uint32_t pinClr = 0 ; - int mask = 1 ; - int pin ; + char c ; + struct wiringPiNodeStruct *node = wiringPiNodes ; - for (pin = 0 ; pin < 8 ; ++pin) + if ((pin & PI_GPIO_MASK) == 0) // On-Board Pin { - if ((value & mask) == 0) - pinClr |= (1 << pinToGpio [pin]) ; - else - pinSet |= (1 << pinToGpio [pin]) ; + /**/ if (wiringPiMode == WPI_MODE_GPIO_SYS) // Sys mode + { + if (sysFds [pin] == -1) + return LOW ; - mask <<= 1 ; + lseek (sysFds [pin], 0L, SEEK_SET) ; + read (sysFds [pin], &c, 1) ; + return (c == '0') ? LOW : HIGH ; + } + else if (wiringPiMode == WPI_MODE_PINS) + pin = pinToGpio [pin] ; + else if (wiringPiMode == WPI_MODE_PHYS) + pin = physToGpio [pin] ; + else if (wiringPiMode != WPI_MODE_GPIO) + return LOW ; + + if ((*(gpio + gpioToGPLEV [pin]) & (1 << (pin & 31))) != 0) + return HIGH ; + else + return LOW ; + } + else + { + if ((node = wiringPiFindNode (pin)) == NULL) + return LOW ; + return node->digitalRead (node, pin) ; } - - *(gpio + gpioToGPCLR [0]) = pinClr ; - *(gpio + gpioToGPSET [0]) = pinSet ; } -void digitalWriteByteSys (int value) + +/* + * digitalWrite: + * Set an output bit + ********************************************************************************* + */ + +void digitalWrite (int pin, int value) { - int mask = 1 ; - int pin ; + struct wiringPiNodeStruct *node = wiringPiNodes ; - for (pin = 0 ; pin < 8 ; ++pin) + if ((pin & PI_GPIO_MASK) == 0) // On-Board Pin { - digitalWriteSys (pinToGpio [pin], value & mask) ; - mask <<= 1 ; + /**/ if (wiringPiMode == WPI_MODE_GPIO_SYS) // Sys mode + { + if (sysFds [pin] != -1) + { + if (value == LOW) + write (sysFds [pin], "0\n", 2) ; + else + write (sysFds [pin], "1\n", 2) ; + } + return ; + } + else if (wiringPiMode == WPI_MODE_PINS) + pin = pinToGpio [pin] ; + else if (wiringPiMode == WPI_MODE_PHYS) + pin = physToGpio [pin] ; + else if (wiringPiMode != WPI_MODE_GPIO) + return ; + + if (value == LOW) + *(gpio + gpioToGPCLR [pin]) = 1 << (pin & 31) ; + else + *(gpio + gpioToGPSET [pin]) = 1 << (pin & 31) ; + } + else + { + if ((node = wiringPiFindNode (pin)) != NULL) + node->digitalWrite (node, pin, value) ; } } @@ -774,135 +1398,138 @@ void digitalWriteByteSys (int value) ********************************************************************************* */ -void pwmWriteGpio (int pin, int value) +void pwmWrite (int pin, int value) { - int port ; + struct wiringPiNodeStruct *node = wiringPiNodes ; - pin = pin & 63 ; - port = gpioToPwmPort [pin] ; + if ((pin & PI_GPIO_MASK) == 0) // On-Board Pin + { + /**/ if (wiringPiMode == WPI_MODE_PINS) + pin = pinToGpio [pin] ; + else if (wiringPiMode == WPI_MODE_PHYS) + pin = physToGpio [pin] ; + else if (wiringPiMode != WPI_MODE_GPIO) + return ; - *(pwm + port) = value ; + *(pwm + gpioToPwmPort [pin]) = value ; + } + else + { + if ((node = wiringPiFindNode (pin)) != NULL) + node->pwmWrite (node, pin, value) ; + } } -void pwmWriteWPi (int pin, int value) -{ - pwmWriteGpio (pinToGpio [pin & 63], value) ; -} -void pwmWriteSys (int pin, int value) +/* + * analogRead: + * Read the analog value of a given Pin. + * There is no on-board Pi analog hardware, + * so this needs to go to a new node. + ********************************************************************************* + */ + +int analogRead (int pin) { - return ; + struct wiringPiNodeStruct *node = wiringPiNodes ; + + if ((node = wiringPiFindNode (pin)) == NULL) + return 0 ; + else + return node->analogRead (node, pin) ; } /* - * setPadDrive: - * Set the PAD driver value + * analogWrite: + * Write the analog value to the given Pin. + * There is no on-board Pi analog hardware, + * so this needs to go to a new node. ********************************************************************************* */ -void setPadDriveWPi (int group, int value) +void analogWrite (int pin, int value) { - uint32_t wrVal ; + struct wiringPiNodeStruct *node = wiringPiNodes ; - if ((group < 0) || (group > 2)) + if ((node = wiringPiFindNode (pin)) == NULL) return ; - 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 -} - -void setPadDriveGpio (int group, int value) -{ - setPadDriveWPi (group, value) ; -} - -void setPadDriveSys (int group, int value) -{ - return ; + node->analogWrite (node, pin, value) ; } /* - * digitalRead: - * Read the value of a given Pin, returning HIGH or LOW + * pwmToneWrite: + * Pi Specific. + * Output the given frequency on the Pi's PWM pin ********************************************************************************* */ -int digitalReadWPi (int pin) +void pwmToneWrite (int pin, int freq) { - pin = pinToGpio [pin & 63] ; + int range ; - if ((*(gpio + gpioToGPLEV [pin]) & (1 << (pin & 31))) != 0) - return HIGH ; + if (freq == 0) + pwmWrite (pin, 0) ; // Off else - return LOW ; -} - -int digitalReadGpio (int pin) -{ - pin &= 63 ; - - if ((*(gpio + gpioToGPLEV [pin]) & (1 << (pin & 31))) != 0) - return HIGH ; - else - return LOW ; + { + range = 600000 / freq ; + pwmSetRange (range) ; + pwmWrite (pin, freq / 2) ; + } } -int digitalReadSys (int pin) -{ - char c ; - - pin &= 63 ; - - if (sysFds [pin] == -1) - return 0 ; - - lseek (sysFds [pin], 0L, SEEK_SET) ; - read (sysFds [pin], &c, 1) ; - return (c == '0') ? 0 : 1 ; -} /* - * pullUpDownCtrl: - * Control the internal pull-up/down resistors on a GPIO pin - * The Arduino only has pull-ups and these are enabled by writing 1 - * to a port when in input mode - this paradigm doesn't quite apply - * here though. + * digitalWriteByte: + * Pi Specific + * 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 pullUpDnControlGpio (int pin, int pud) +void digitalWriteByte (int value) { - pin &= 63 ; - pud &= 3 ; + uint32_t pinSet = 0 ; + uint32_t pinClr = 0 ; + int mask = 1 ; + int pin ; - *(gpio + GPPUD) = pud ; delayMicroseconds (5) ; - *(gpio + gpioToPUDCLK [pin]) = 1 << (pin & 31) ; delayMicroseconds (5) ; - - *(gpio + GPPUD) = 0 ; delayMicroseconds (5) ; - *(gpio + gpioToPUDCLK [pin]) = 0 ; delayMicroseconds (5) ; -} + /**/ if (wiringPiMode == WPI_MODE_GPIO_SYS) + { + for (pin = 0 ; pin < 8 ; ++pin) + { + digitalWrite (pin, value & mask) ; + mask <<= 1 ; + } + return ; + } + else + { + for (pin = 0 ; pin < 8 ; ++pin) + { + if ((value & mask) == 0) + pinClr |= (1 << pinToGpio [pin]) ; + else + pinSet |= (1 << pinToGpio [pin]) ; -void pullUpDnControlWPi (int pin, int pud) -{ - pullUpDnControlGpio (pinToGpio [pin & 63], pud) ; -} + mask <<= 1 ; + } -void pullUpDnControlSys (int pin, int pud) -{ - return ; + *(gpio + gpioToGPCLR [0]) = pinClr ; + *(gpio + gpioToGPSET [0]) = pinSet ; + } } /* * waitForInterrupt: + * Pi Specific. * Wait for Interrupt on a GPIO pin. * This is actually done via the /sys/class/gpio interface regardless of * the wiringPi access mode in-use. Maybe sometime it might get a better @@ -910,24 +1537,19 @@ void pullUpDnControlSys (int pin, int pud) ********************************************************************************* */ -int waitForInterruptSys (int pin, int mS) +int waitForInterrupt (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 + /**/ if (wiringPiMode == WPI_MODE_PINS) + pin = pinToGpio [pin] ; + else if (wiringPiMode == WPI_MODE_PHYS) + pin = physToGpio [pin] ; - lseek (fd, 0, SEEK_SET) ; + if ((fd = sysFds [pin]) == -1) + return -2 ; // Setup poll structure @@ -936,17 +1558,16 @@ int waitForInterruptSys (int pin, int mS) // Wait for it ... - return poll (&polls, 1, mS) ; -} + x = poll (&polls, 1, mS) ; -int waitForInterruptWPi (int pin, int mS) -{ - return waitForInterruptSys (pinToGpio [pin & 63], mS) ; -} +// Do a dummy read to clear the interrupt +// A one character read appars to be enough. +// Followed by a seek to reset it. -int waitForInterruptGpio (int pin, int mS) -{ - return waitForInterruptSys (pin, mS) ; + (void)read (fd, &c, 1) ; + lseek (fd, 0, SEEK_SET) ; + + return x ; } @@ -960,12 +1581,15 @@ int waitForInterruptGpio (int pin, int mS) static void *interruptHandler (void *arg) { - int myPin = *(int *)arg ; + int myPin ; (void)piHiPri (55) ; // Only effective if we run as root + myPin = pinPass ; + pinPass = -1 ; + for (;;) - if (waitForInterruptSys (myPin, -1) > 0) + if (waitForInterrupt (myPin, -1) > 0) isrFunctions [myPin] () ; return NULL ; @@ -974,6 +1598,7 @@ static void *interruptHandler (void *arg) /* * wiringPiISR: + * Pi Specific. * Take the details and create an interrupt handler that will do a call- * back to the user supplied function. ********************************************************************************* @@ -982,20 +1607,25 @@ static void *interruptHandler (void *arg) int wiringPiISR (int pin, int mode, void (*function)(void)) { pthread_t threadId ; + const char *modeS ; char fName [64] ; - char *modeS ; char pinS [8] ; pid_t pid ; + int count, i ; + char c ; + int bcmGpioPin ; - pin &= 63 ; + if ((pin < 0) || (pin > 63)) + return wiringPiFailure (WPI_FATAL, "wiringPiISR: pin must be 0-63 (%d)\n", pin) ; - if (wiringPiMode == WPI_MODE_UNINITIALISED) - { - fprintf (stderr, "wiringPiISR: wiringPi has not been initialised. Unable to continue.\n") ; - exit (EXIT_FAILURE) ; - } + /**/ if (wiringPiMode == WPI_MODE_UNINITIALISED) + return wiringPiFailure (WPI_FATAL, "wiringPiISR: wiringPi has not been initialised. Unable to continue.\n") ; else if (wiringPiMode == WPI_MODE_PINS) - pin = pinToGpio [pin] ; + bcmGpioPin = pinToGpio [pin] ; + else if (wiringPiMode == WPI_MODE_PHYS) + bcmGpioPin = physToGpio [pin] ; + else + bcmGpioPin = pin ; // Now export the pin and set the right edge // We're going to use the gpio program to do this, so it assumes @@ -1012,40 +1642,79 @@ int wiringPiISR (int pin, int mode, void (*function)(void)) else modeS = "both" ; - sprintf (pinS, "%d", pin) ; + sprintf (pinS, "%d", bcmGpioPin) ; if ((pid = fork ()) < 0) // Fail - return pid ; + return wiringPiFailure (WPI_FATAL, "wiringPiISR: fork failed: %s\n", strerror (errno)) ; if (pid == 0) // Child, exec { - execl ("/usr/local/bin/gpio", "gpio", "edge", pinS, modeS, (char *)NULL) ; - return -1 ; // Failure ... + /**/ if (access ("/usr/local/bin/gpio", X_OK) == 0) + { + execl ("/usr/local/bin/gpio", "gpio", "edge", pinS, modeS, (char *)NULL) ; + return wiringPiFailure (WPI_FATAL, "wiringPiISR: execl failed: %s\n", strerror (errno)) ; + } + else if (access ("/usr/bin/gpio", X_OK) == 0) + { + execl ("/usr/bin/gpio", "gpio", "edge", pinS, modeS, (char *)NULL) ; + return wiringPiFailure (WPI_FATAL, "wiringPiISR: execl failed: %s\n", strerror (errno)) ; + } + else + return wiringPiFailure (WPI_FATAL, "wiringPiISR: Can't find gpio program\n") ; } 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. +// Now pre-open the /sys/class node - but it may already be open if +// we are in Sys mode... - sprintf (fName, "/sys/class/gpio/gpio%d/value", pin) ; - if ((sysFds [pin] = open (fName, O_RDWR)) < 0) - return -1 ; + if (sysFds [bcmGpioPin] == -1) + { + sprintf (fName, "/sys/class/gpio/gpio%d/value", bcmGpioPin) ; + if ((sysFds [bcmGpioPin] = open (fName, O_RDWR)) < 0) + return wiringPiFailure (WPI_FATAL, "wiringPiISR: unable to open %s: %s\n", fName, strerror (errno)) ; + } - isrFunctions [pin] = function ; +// Clear any initial pending interrupt + + ioctl (sysFds [bcmGpioPin], FIONREAD, &count) ; + for (i = 0 ; i < count ; ++i) + read (sysFds [bcmGpioPin], &c, 1) ; - pthread_create (&threadId, NULL, interruptHandler, &pin) ; + isrFunctions [pin] = function ; - delay (1) ; + pthread_mutex_lock (&pinMutex) ; + pinPass = pin ; + pthread_create (&threadId, NULL, interruptHandler, NULL) ; + while (pinPass != -1) + delay (1) ; + pthread_mutex_unlock (&pinMutex) ; return 0 ; } +/* + * initialiseEpoch: + * Initialise our start-of-time variable to be the current unix + * time in milliseconds and microseconds. + ********************************************************************************* + */ + +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: - * Wait for some number of milli seconds + * Wait for some number of milliseconds ********************************************************************************* */ @@ -1078,28 +1747,8 @@ void delay (unsigned int howLong) ********************************************************************************* */ -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) { -#ifdef HARD_TIMER - volatile unsigned int dummy ; - - *(timer + TIMER_LOAD) = howLong ; - *(timer + TIMER_IRQ_CLR) = 0 ; - - dummy = *timerIrqRaw ; - while (dummy == 0) - dummy = *timerIrqRaw ; -#else struct timeval tNow, tLong, tEnd ; gettimeofday (&tNow, NULL) ; @@ -1109,12 +1758,13 @@ void delayMicrosecondsHard (unsigned int howLong) while (timercmp (&tNow, &tEnd, <)) gettimeofday (&tNow, NULL) ; -#endif } -void delayMicrosecondsWPi (unsigned int howLong) +void delayMicroseconds (unsigned int howLong) { struct timespec sleeper ; + unsigned int uSecs = howLong % 1000000 ; + unsigned int wSecs = howLong / 1000000 ; /**/ if (howLong == 0) return ; @@ -1122,8 +1772,8 @@ void delayMicrosecondsWPi (unsigned int howLong) delayMicrosecondsHard (howLong) ; else { - sleeper.tv_sec = 0 ; - sleeper.tv_nsec = (long)(howLong * 1000) ; + sleeper.tv_sec = wSecs ; + sleeper.tv_nsec = (long)(uSecs * 1000L) ; nanosleep (&sleeper, NULL) ; } } @@ -1138,13 +1788,30 @@ void delayMicrosecondsWPi (unsigned int howLong) 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) ; + + return (uint32_t)(now - epochMilli) ; +} - t1 = (tv.tv_sec * 1000000 + tv.tv_usec) / 1000 ; - return (uint32_t)(t1 - epoch) ; +/* + * 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)(now - epochMicro) ; } @@ -1154,138 +1821,106 @@ unsigned int millis (void) * * Default setup: Initialises the system into wiringPi Pin mode and uses the * memory mapped hardware directly. + * + * Changed now to revert to "gpio" mode if we're running on a Compute Module. ********************************************************************************* */ int wiringPiSetup (void) { - int fd ; - int boardRev ; - //uint8_t *gpioMem, *pwmMem, *clkMem, *padsMem, *timerMem ; - struct timeval tv ; - - if (geteuid () != 0) - { - fprintf (stderr, "wiringPi:\n Must be root to call wiringPiSetup().\n (Did you forget sudo?)\n") ; - exit (EXIT_FAILURE) ; - } + int fd ; + int boardRev ; + int model, rev, mem, maker, overVolted ; - if (getenv ("WIRINGPI_DEBUG") != NULL) - { - printf ("wiringPi: Debug mode enabled\n") ; + if (getenv (ENV_DEBUG) != NULL) wiringPiDebug = TRUE ; - } + + if (getenv (ENV_CODES) != NULL) + wiringPiReturnCodes = TRUE ; if (wiringPiDebug) printf ("wiringPi: wiringPiSetup called\n") ; - pinMode = pinModeWPi ; - pullUpDnControl = pullUpDnControlWPi ; - digitalWrite = digitalWriteWPi ; - digitalWriteByte = digitalWriteByteGpio ; // Same code - pwmWrite = pwmWriteWPi ; - setPadDrive = setPadDriveWPi ; - digitalRead = digitalReadWPi ; - waitForInterrupt = waitForInterruptWPi ; - delayMicroseconds = delayMicrosecondsWPi ; - pwmSetMode = pwmSetModeWPi ; - pwmSetRange = pwmSetRangeWPi ; - pwmSetClock = pwmSetClockWPi ; - boardRev = piBoardRev () ; - if (boardRev == 1) - pinToGpio = pinToGpioR1 ; + /**/ if (boardRev == 1) // A, B, Rev 1, 1.1 + { + pinToGpio = pinToGpioR1 ; + physToGpio = physToGpioR1 ; + } + else // A, B, Rev 2, B+, CM, Pi2 + { + pinToGpio = pinToGpioR2 ; + physToGpio = physToGpioR2 ; + } + + if (piModel2) + RASPBERRY_PI_PERI_BASE = 0x3F000000 ; else - pinToGpio = pinToGpioR2 ; + RASPBERRY_PI_PERI_BASE = 0x20000000 ; -// Open the master /dev/memory device +// Open the master /dev/ memory control device - if ((fd = open ("/dev/mem", O_RDWR | O_SYNC) ) < 0) +// See if /dev/gpiomem exists and we can open it... + + if ((fd = open ("/dev/gpiomem", O_RDWR | O_SYNC | O_CLOEXEC) ) >= 0) + RASPBERRY_PI_PERI_BASE = 0 ; + +// ... otherwise fall back to the original /dev/mem which requires root level access + + else { - if (wiringPiDebug) - { - int serr = errno ; - fprintf (stderr, "wiringPiSetup: Unable to open /dev/mem: %s\n", strerror (errno)) ; - errno = serr ; - } - return -1 ; + +// This check is here because people are too stupid to check for themselves or read +// error messages. + + if (geteuid () != 0) + (void)wiringPiFailure (WPI_FATAL, "wiringPiSetup: Must be root. (Did you forget sudo?)\n") ; + + if ((fd = open ("/dev/mem", O_RDWR | O_SYNC | O_CLOEXEC) ) < 0) + return wiringPiFailure (WPI_ALMOST, "wiringPiSetup: Unable to open /dev/mem: %s\n", strerror (errno)) ; } -// GPIO: +// Set the offsets into the memory interface. + + GPIO_PADS = RASPBERRY_PI_PERI_BASE + 0x00100000 ; + GPIO_CLOCK_BASE = RASPBERRY_PI_PERI_BASE + 0x00101000 ; + GPIO_BASE = RASPBERRY_PI_PERI_BASE + 0x00200000 ; + GPIO_TIMER = RASPBERRY_PI_PERI_BASE + 0x0000B000 ; + GPIO_PWM = RASPBERRY_PI_PERI_BASE + 0x0020C000 ; + +// Map the individual hardware components + +// GPIO: gpio = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_BASE) ; if ((int32_t)gpio == -1) - { - if (wiringPiDebug) - { - int serr = errno ; - fprintf (stderr, "wiringPiSetup: mmap failed: %s\n", strerror (errno)) ; - errno = serr ; - } - return -1 ; - } + return wiringPiFailure (WPI_ALMOST, "wiringPiSetup: mmap (GPIO) failed: %s\n", strerror (errno)) ; -// PWM +// PWM pwm = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_PWM) ; if ((int32_t)pwm == -1) - { - if (wiringPiDebug) - { - int serr = errno ; - fprintf (stderr, "wiringPiSetup: mmap failed (pwm): %s\n", strerror (errno)) ; - errno = serr ; - } - return -1 ; - } + return wiringPiFailure (WPI_ALMOST, "wiringPiSetup: mmap (PWM) failed: %s\n", strerror (errno)) ; -// Clock control (needed for PWM) +// Clock control (needed for PWM) - clk = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, CLOCK_BASE) ; + clk = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_CLOCK_BASE) ; if ((int32_t)clk == -1) - { - if (wiringPiDebug) - { - int serr = errno ; - fprintf (stderr, "wiringPiSetup: mmap failed (clk): %s\n", strerror (errno)) ; - errno = serr ; - } - return -1 ; - } + return wiringPiFailure (WPI_ALMOST, "wiringPiSetup: mmap (CLOCK) failed: %s\n", strerror (errno)) ; -// The drive pads +// The drive pads pads = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_PADS) ; if ((int32_t)pads == -1) - { - 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 + return wiringPiFailure (WPI_ALMOST, "wiringPiSetup: mmap (PADS) failed: %s\n", strerror (errno)) ; -// The system timer +#ifdef USE_TIMER +// The system timer timer = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_TIMER) ; if ((int32_t)timer == -1) - { - if (wiringPiDebug) - { - int serr = errno ; - fprintf (stderr, "wiringPiSetup: mmap failed (timer): %s\n", strerror (errno)) ; - errno = serr ; - } - return -1 ; - } + return wiringPiFailure (WPI_ALMOST, "wiringPiSetup: mmap (TIMER) failed: %s\n", strerror (errno)) ; // Set the timer to free-running, 1MHz. // 0xF9 is 249, the timer divide is base clock / (divide+1) @@ -1294,13 +1929,17 @@ int wiringPiSetup (void) *(timer + TIMER_CONTROL) = 0x0000280 ; *(timer + TIMER_PRE_DIV) = 0x00000F9 ; timerIrqRaw = timer + TIMER_IRQ_RAW ; +#endif -// Initialise our epoch for millis() + initialiseEpoch () ; - gettimeofday (&tv, NULL) ; - epoch = (tv.tv_sec * 1000000 + tv.tv_usec) / 1000 ; +// If we're running on a compute module, then wiringPi pin numbers don't really many anything... - wiringPiMode = WPI_MODE_PINS ; + piBoardId (&model, &rev, &mem, &maker, &overVolted) ; + if (model == PI_MODEL_CM) + wiringPiMode = WPI_MODE_GPIO ; + else + wiringPiMode = WPI_MODE_PINS ; return 0 ; } @@ -1317,39 +1956,39 @@ int wiringPiSetup (void) int wiringPiSetupGpio (void) { - int x ; - - 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 ; + (void)wiringPiSetup () ; if (wiringPiDebug) printf ("wiringPi: wiringPiSetupGpio called\n") ; - pinMode = pinModeGpio ; - 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 ; } +/* + * wiringPiSetupPhys: + * Must be called once at the start of your program execution. + * + * Phys setup: Initialises the system into Physical Pin mode and uses the + * memory mapped hardware directly. + ********************************************************************************* + */ + +int wiringPiSetupPhys (void) +{ + (void)wiringPiSetup () ; + + if (wiringPiDebug) + printf ("wiringPi: wiringPiSetupPhys called\n") ; + + wiringPiMode = WPI_MODE_PHYS ; + + return 0 ; +} + + /* * wiringPiSetupSys: * Must be called once at the start of your program execution. @@ -1363,34 +2002,29 @@ int wiringPiSetupSys (void) { int boardRev ; int pin ; - struct timeval tv ; char fName [128] ; - if (getenv ("WIRINGPI_DEBUG") != NULL) + if (getenv (ENV_DEBUG) != NULL) wiringPiDebug = TRUE ; + if (getenv (ENV_CODES) != NULL) + wiringPiReturnCodes = TRUE ; + if (wiringPiDebug) printf ("wiringPi: wiringPiSetupSys called\n") ; - pinMode = pinModeSys ; - 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 ; + { + pinToGpio = pinToGpioR1 ; + physToGpio = physToGpioR1 ; + } else - pinToGpio = pinToGpioR2 ; + { + pinToGpio = pinToGpioR2 ; + physToGpio = physToGpioR2 ; + } // Open and scan the directory, looking for exported GPIOs, and pre-open // the 'value' interface to speed things up for later @@ -1401,10 +2035,7 @@ int wiringPiSetupSys (void) sysFds [pin] = open (fName, O_RDWR) ; } -// Initialise the epoch for mills() ... - - gettimeofday (&tv, NULL) ; - epoch = (tv.tv_sec * 1000000 + tv.tv_usec) / 1000 ; + initialiseEpoch () ; wiringPiMode = WPI_MODE_GPIO_SYS ;