Although WiringPi
is discontinued, there was an unofficial patch.
(Open-source is hard to kill, others will continue it.)
Tested, and GPIO
worked great on my RaspberryPi4
after applying that.
Patch:
diff -ruN wiringPi/wiringPi.c wiringPi/wiringPi.c
--- wiringPi/wiringPi.c
+++ wiringPi/wiringPi.c
@@ -215,6 +215,7 @@ volatile unsigned int *_wiringPiTimerIrqRaw ;
#define GPIO_PERI_BASE_OLD 0x20000000
#define GPIO_PERI_BASE_NEW 0x3F000000
+#define GPIO_PERI_BASE_RP4 0xFE000000
static volatile unsigned int piGpioBase = 0 ;
@@ -547,6 +548,10 @@ static uint8_t gpioToPUDCLK [] =
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,
} ;
+#define PULLUPDN_OFFSET_2711_0 57
+#define PULLUPDN_OFFSET_2711_1 58
+#define PULLUPDN_OFFSET_2711_2 59
+#define PULLUPDN_OFFSET_2711_3 60
// gpioToPwmALT
// the ALT value to put a GPIO pin into PWM mode
@@ -814,7 +819,7 @@ int piGpioLayout (void)
for (c = &line [strlen (line) - 1] ; (*c == '\n') || (*c == '\r') ; --c)
*c = 0 ;
-
+
if (wiringPiDebug)
printf ("piGpioLayout: Revision string: %s\n", line) ;
@@ -883,7 +888,7 @@ int piBoardRev (void)
* So the distinction between boards that I can see is:
*
* 0000 - Error
- * 0001 - Not used
+ * 0001 - Not used
*
* Original Pi boards:
* 0002 - Model B, Rev 1, 256MB, Egoman
@@ -955,6 +960,30 @@ void piBoardId (int *model, int *rev, int *mem, int *maker, int *warranty)
if ((cpuFd = fopen ("/proc/cpuinfo", "r")) == NULL)
piGpioLayoutOops ("Unable to open /proc/cpuinfo") ;
+ char buffer[12] ;
+ const char *ranges_file = "/proc/device-tree/soc/ranges" ;
+ int info_fd = open(ranges_file, O_RDONLY) ;
+
+ if (info_fd < 0) {
+ fprintf(stderr, "cannot open: %s", ranges_file) ;
+ exit (EXIT_FAILURE) ;
+ }
+
+ ssize_t n = read(info_fd, buffer, sizeof(buffer)) ;
+ close(info_fd) ;
+
+ if (n < 8) {
+ fprintf(stderr, "cannot read base address: %s", ranges_file) ;
+ exit (EXIT_FAILURE) ;
+ }
+
+ uint32_t gpio_base = (buffer[4] << 24) + (buffer[5] << 16) + (buffer[6] << 8) + (buffer[7] << 0) ;
+
+ if (!gpio_base)
+ {
+ gpio_base = (buffer[8] << 24) + (buffer[9] << 16) + (buffer[10] << 8) + (buffer[11] << 0) ;
+ }
+
while (fgets (line, 120, cpuFd) != NULL)
if (strncmp (line, "Revision", 8) == 0)
break ;
@@ -968,7 +997,7 @@ void piBoardId (int *model, int *rev, int *mem, int *maker, int *warranty)
for (c = &line [strlen (line) - 1] ; (*c == '\n') || (*c == '\r') ; --c)
*c = 0 ;
-
+
if (wiringPiDebug)
printf ("piBoardId: Revision string: %s\n", line) ;
@@ -1007,7 +1036,7 @@ void piBoardId (int *model, int *rev, int *mem, int *maker, int *warranty)
bMfg = (revision & (0x0F << 16)) >> 16 ;
bMem = (revision & (0x07 << 20)) >> 20 ;
bWarranty = (revision & (0x03 << 24)) != 0 ;
-
+
*model = bType ;
*rev = bRev ;
*mem = bMem ;
@@ -1034,7 +1063,7 @@ void piBoardId (int *model, int *rev, int *mem, int *maker, int *warranty)
// If longer than 4, we'll assume it's been overvolted
*warranty = strlen (c) > 4 ;
-
+
// Extract last 4 characters:
c = c + strlen (c) - 4 ;
@@ -1073,8 +1102,11 @@ void piBoardId (int *model, int *rev, int *mem, int *maker, int *warranty)
else { *model = 0 ; *rev = 0 ; *mem = 0 ; *maker = 0 ; }
}
+ if (gpio_base == GPIO_PERI_BASE_RP4) {
+ *model = PI_MODEL_4;
+ }
}
-
+
/*
@@ -1205,6 +1237,10 @@ void pwmSetRange (unsigned int range)
void pwmSetClock (int divisor)
{
uint32_t pwm_control ;
+
+ if(piGpioBase == GPIO_PERI_BASE_RP4) {
+ divisor = 540*divisor/192;
+ }
divisor &= 4095 ;
if ((wiringPiMode == WPI_MODE_PINS) || (wiringPiMode == WPI_MODE_PHYS) || (wiringPiMode == WPI_MODE_GPIO))
@@ -1260,7 +1296,7 @@ void gpioClockSet (int pin, int freq)
pin = physToGpio [pin] ;
else if (wiringPiMode != WPI_MODE_GPIO)
return ;
-
+
divi = 19200000 / freq ;
divr = 19200000 % freq ;
divf = (int)((double)divr * 4096.0 / 19200000.0) ;
@@ -1504,11 +1540,31 @@ void pullUpDnControl (int pin, int pud)
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) ;
+ // Check GPIO register
+ int is2711 = *(gpio + PULLUPDN_OFFSET_2711_3) != 0x6770696f;
+ if(is2711) {
+ // Pi 4 Pull-up/down method
+ int pullreg = PULLUPDN_OFFSET_2711_0 + (pin >> 4);
+ int pullshift = (pin & 0xf) << 1;
+ unsigned int pullbits;
+ unsigned int pull = 0; // Turn PUD off by default
+ if (pud == PUD_UP) {
+ pull = 1;
+ } else if (pud == PUD_DOWN) {
+ pull = 2;
+ }
+ pullbits = *(gpio + pullreg);
+ pullbits &= ~(3 << pullshift);
+ pullbits |= (pull << pullshift);
+ *(gpio + pullreg) = pullbits;
+ } else {
+ // Legacy Pull-up/down method
+ *(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
{
@@ -1680,7 +1736,7 @@ void pwmWrite (int pin, int value)
/*
* analogRead:
- * Read the analog value of a given Pin.
+ * 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.
*********************************************************************************
@@ -1699,7 +1755,7 @@ int analogRead (int pin)
/*
* analogWrite:
- * Write the analog value to the given Pin.
+ * 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.
*********************************************************************************
@@ -1748,7 +1804,7 @@ void pwmToneWrite (int pin, int freq)
* 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
+ * 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
* Reading is just bit fiddling.
* These are wiringPi pin numbers 0..7, or BCM_GPIO pin numbers
@@ -1804,7 +1860,7 @@ unsigned int digitalReadByte (void)
data = (data << 1) | x ;
}
}
- else
+ else
{
raw = *(gpio + gpioToGPLEV [0]) ; // First bank for these pins
for (pin = 0 ; pin < 8 ; ++pin)
@@ -1861,7 +1917,7 @@ unsigned int digitalReadByte2 (void)
data = (data << 1) | x ;
}
}
- else
+ else
data = ((*(gpio + gpioToGPLEV [0])) >> 20) & 0xFF ; // First bank for these pins
return data ;
@@ -2265,6 +2321,9 @@ int wiringPiSetup (void)
case PI_MODEL_ZERO: case PI_MODEL_ZERO_W:
piGpioBase = GPIO_PERI_BASE_OLD ;
break ;
+ case PI_MODEL_4:
+ piGpioBase = GPIO_PERI_BASE_RP4 ;
+ break ;
default:
piGpioBase = GPIO_PERI_BASE_NEW ;
@@ -2273,7 +2332,7 @@ int wiringPiSetup (void)
// Open the master /dev/ memory control device
// Device strategy: December 2016:
-// Try /dev/mem. If that fails, then
+// Try /dev/mem. If that fails, then
// try /dev/gpiomem. If that fails then game over.
if ((fd = open ("/dev/mem", O_RDWR | O_SYNC | O_CLOEXEC)) < 0)
@@ -2311,13 +2370,13 @@ int wiringPiSetup (void)
pwm = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_PWM) ;
if (pwm == MAP_FAILED)
return wiringPiFailure (WPI_ALMOST, "wiringPiSetup: mmap (PWM) failed: %s\n", strerror (errno)) ;
-
+
// Clock control (needed for PWM)
clk = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_CLOCK_BASE) ;
if (clk == MAP_FAILED)
return wiringPiFailure (WPI_ALMOST, "wiringPiSetup: mmap (CLOCK) failed: %s\n", strerror (errno)) ;
-
+
// The drive pads
pads = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_PADS) ;
@@ -2437,7 +2496,7 @@ int wiringPiSetupSys (void)
// Open and scan the directory, looking for exported GPIOs, and pre-open
// the 'value' interface to speed things up for later
-
+
for (pin = 0 ; pin < 64 ; ++pin)
{
sprintf (fName, "/sys/class/gpio/gpio%d/value", pin) ;
diff -ruN wiringPi/wiringPi.h wiringPi/wiringPi.h
--- wiringPi/wiringPi.h
+++ wiringPi/wiringPi.h
@@ -100,6 +100,7 @@
#define PI_MODEL_CM3 10
#define PI_MODEL_ZERO_W 12
#define PI_MODEL_3P 13
+#define PI_MODEL_4 14
#define PI_VERSION_1 0
#define PI_VERSION_1_1 1
Note that the patch should be executed inside of Wiring-Pi root (outside of it's wiringPi
sub-directory).
Also, this is a copy of my other answer on StackOverflow.com, and is not related to https://github.com/WiringPi/WiringPi (although, they are free to apply this, too).