4

I can't seem to set the pull-up resistor mode on the PI4 with most methods I try. I have tried: C# (the new System.Device.Gpio interface), WiringPi (using a C# abstraction), and wiringPi command line interface. Setting the pin mode to input or output always works, just not changing the pull up mode. If I use an example python script, the mode does change, so the hardware is likely not broken.

Steps to reproduce:

root@raspberrypi:/home/pi# gpio -g mode 24 in
root@raspberrypi:/home/pi# gpio -g mode 24 up
root@raspberrypi:/home/pi# gpio -g read 24 
0 
root@raspberrypi:/home/pi# 

There's nothing connected to BCM Pin 24, so the result should be 1. Same result with WiringPi 2.50 and 2.52. Same result on other pins.

Edit: Update after some time has passed

WiringPi is deprecated, but there's an unofficial release here that works on the Pi4. Just use that one (particularly helpful are still the command line options)

System.Device.GPIO nuget for C# has been updated too. It seamlessly supports the Pi4/400 now as well.

4 Answers 4

3

I can confirm that result with version 2.52 of wiringPi, setting the pulls does not work on the Pi4B.

wiringPi is now deprecated.

http://wiringpi.com/wiringpi-deprecated/

You could contact the author but do not expect a response.

6
  • Yes, I've seen that. What confuses me is that also the new .NET interface doesn't work, and I don't think that one uses wiringpi internally.
    – PMF
    Oct 6, 2019 at 15:53
  • I have no idea what .NET uses internally. Presumably it has not been updated for the Pi4B either (the Pi4B has a new GPIO design with a different way of setting the pulls).
    – joan
    Oct 6, 2019 at 15:57
  • Good hint. Luckily, the .NET code is open source: github.com/dotnet/iot It has several Driver modules, the default one is called RaspberryPi3Driver (sic!). There's one for libgpiod, but that one explicitly does not support setting the pulls. You don't by chance know what would need to be changed here: github.com/dotnet/iot/blob/master/src/System.Device.Gpio/System/… do you ;-) ...?
    – PMF
    Oct 6, 2019 at 17:10
  • You need to change setInputPullMode to recognise it is running on a BCM2711 and then use updated code to set the pulls. This shows how I do it in pigpio. github.com/joan2937/pigpio/blob/master/pigpio.c#L8785
    – joan
    Oct 6, 2019 at 17:38
  • That's a start. Will take me some time to investigate this, though.
    – PMF
    Oct 6, 2019 at 17:53
1

I have run into the very same issue, setting pull-up with latest wiringPI (2.52) on the 4B+ does not work. I solved it by using 'raspi-gpio' utility ( https://github.com/RPi-Distro/raspi-gpio ) to just activate the pull-ups via commandline, which worked fine with my 4B+ Just be aware that raspi-gpio do use 'BCM' numbering. So in your case for GPIO.24 you need to use '13'; the raspi-gpio line would be 'raspi-gpio set 13 pu'

hope that helps

1

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).

0

While working on the next version of Pi4J, Robert Savage found a solution by using the unofficial version of WiringPi that be found on GitHub in WiringPi > WiringPi.

Remove the existing WiringPi installation, clone the GitHub project and build it like this:

echo "--------------------------------------------"
echo "Uninstalling any existing WiringPi versions "
echo "--------------------------------------------"
sudo apt-get remove wiringpi -y
sudo apt-get --force-yes --yes install git-core gcc make
echo "--------------------------------------------"
echo "Cloning latest WiringPi sources from repo   "
echo "--------------------------------------------"
cd /opt/pi4j
git clone https://github.com/WiringPi/WiringPi --branch master --single-branch wiringpi
cd /opt/pi4j/wiringpi
echo "--------------------------------------------"
echo "Building and installing WiringPi library"
echo "--------------------------------------------"
sudo ./build uninstall
sudo ./build clean
sudo ./build

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.