X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=wiringPi%2FwiringPi.c;h=7c899ea5c276316e4f4c0d2b78bb31815557369b;hb=170dce5f1939a3629bbc2329c5557cbaa0bc278f;hp=e7ae3863c7ca0fe6f5b66e08a833293965d9325b;hpb=df45388f6431f7baba31ac1e8e242d89828637a0;p=wiringPi.git diff --git a/wiringPi/wiringPi.c b/wiringPi/wiringPi.c index e7ae386..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 @@ -130,13 +130,16 @@ struct wiringPiNodeStruct *wiringPiNodes = NULL ; // Access from ARM Running Linux // 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 + 0x00100000) -#define CLOCK_BASE (BCM2708_PERI_BASE + 0x00101000) -#define GPIO_BASE (BCM2708_PERI_BASE + 0x00200000) -#define GPIO_TIMER (BCM2708_PERI_BASE + 0x0000B000) -#define GPIO_PWM (BCM2708_PERI_BASE + 0x0020C000) +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) @@ -203,13 +206,17 @@ static volatile uint32_t *timerIrqRaw ; // and PI_VERSION_X defines in wiringPi.h // Only intended for the gpio command - use at your own risk! -const char *piModelNames [5] = +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] = @@ -221,12 +228,13 @@ const char *piRevisionNames [5] = "2", } ; -const char *piMakerNames [4] = +const char *piMakerNames [5] = { "Unknown", "Egoman", "Sony", "Qusda", + "MBest", } ; @@ -602,6 +610,7 @@ int wiringPiFailure (int fatal, const char *message, ...) * * 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) * So the distinction between boards that I can see is: @@ -620,6 +629,12 @@ int wiringPiFailure (int fatal, const char *message, ...) * 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 @@ -628,6 +643,7 @@ int wiringPiFailure (int fatal, const char *message, ...) * 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 ... * ********************************************************************************* */ @@ -654,6 +670,37 @@ int piBoardRev (void) if ((cpuFd = fopen ("/proc/cpuinfo", "r")) == NULL) 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) break ; @@ -687,10 +734,12 @@ int piBoardRev (void) // 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") ; // Isolate last 4 characters: @@ -702,7 +751,7 @@ int piBoardRev (void) 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) ; @@ -717,6 +766,15 @@ int piBoardRev (void) * 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 ********************************************************************************* */ @@ -726,6 +784,9 @@ void piBoardId (int *model, int *rev, int *mem, int *maker, int *overVolted) char line [120] ; char *c ; +// Will deal with the properly later on - for now, lets just get it going... +// unsigned int modelNum ; + (void)piBoardRev () ; // Call this first to make sure all's OK. Don't care about the result. if ((cpuFd = fopen ("/proc/cpuinfo", "r")) == NULL) @@ -748,41 +809,68 @@ void piBoardId (int *model, int *rev, int *mem, int *maker, int *overVolted) if (wiringPiDebug) printf ("piboardId: Revision string: %s\n", line) ; + if (piModel2) + { + +// Scan to the colon + + for (c = line ; *c ; ++c) + if (*c == ':') + break ; + + if (*c != ':') + piBoardRevOops ("Bogus \"Revision\" line (no colon)") ; + +// 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 + { + // Scan to first digit - for (c = line ; *c ; ++c) - if (isdigit (*c)) - break ; + for (c = line ; *c ; ++c) + if (isdigit (*c)) + break ; // Make sure its long enough - if (strlen (c) < 4) - piBoardRevOops ("Bogus \"Revision\" line") ; + if (strlen (c) < 4) + piBoardRevOops ("Bogus \"Revision\" line (not long enough)") ; // If longer than 4, we'll assume it's been overvolted - *overVolted = strlen (c) > 4 ; + *overVolted = strlen (c) > 4 ; // Extract last 4 characters: - c = c + strlen (c) - 4 ; + 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 { *model = 0 ; *rev = 0 ; *mem = 0 ; *maker = 0 ; } + /**/ 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 ; } + } } @@ -1474,8 +1562,10 @@ int waitForInterrupt (int pin, int mS) // Do a dummy read to clear the interrupt // A one character read appars to be enough. +// Followed by a seek to reset it. (void)read (fd, &c, 1) ; + lseek (fd, 0, SEEK_SET) ; return x ; } @@ -1748,9 +1838,6 @@ int wiringPiSetup (void) if (getenv (ENV_CODES) != NULL) wiringPiReturnCodes = TRUE ; - if (geteuid () != 0) - (void)wiringPiFailure (WPI_FATAL, "wiringPiSetup: Must be root. (Did you forget sudo?)\n") ; - if (wiringPiDebug) printf ("wiringPi: wiringPiSetup called\n") ; @@ -1761,43 +1848,75 @@ int wiringPiSetup (void) pinToGpio = pinToGpioR1 ; physToGpio = physToGpioR1 ; } - else // A, B, Rev 2, B+, CM + else // A, B, Rev 2, B+, CM, Pi2 { pinToGpio = pinToGpioR2 ; physToGpio = physToGpioR2 ; } -// Open the master /dev/memory device + if (piModel2) + RASPBERRY_PI_PERI_BASE = 0x3F000000 ; + else + RASPBERRY_PI_PERI_BASE = 0x20000000 ; + +// Open the master /dev/ memory control device + +// See if /dev/gpiomem exists and we can open it... - 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)) ; + if ((fd = open ("/dev/gpiomem", O_RDWR | O_SYNC | O_CLOEXEC) ) >= 0) + RASPBERRY_PI_PERI_BASE = 0 ; -// GPIO: +// ... otherwise fall back to the original /dev/mem which requires root level access + + else + { + +// 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)) ; + } + +// 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) 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) 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) 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) return wiringPiFailure (WPI_ALMOST, "wiringPiSetup: mmap (PADS) failed: %s\n", strerror (errno)) ; #ifdef USE_TIMER -// The system 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)