8

What is the RPi GPIO Pin output current?

I assume it's more than 10mA since it can drive LEDs without any problem but what is the spec?

JeeShen Lee
  • 1,405
  • 2
  • 10
  • 10

4 Answers4

6

After reset it's 8mA. You can program it up to 16mA though

John La Rooy
  • 11,947
  • 9
  • 47
  • 75
2

To program the PADS registers to alter the output current, the following shows the pertinent code:

#define BCM2708_PERI_BASE        0x20000000
#define GPIO_BASE                (BCM2708_PERI_BASE + 0x200000) /* GPIO   */
#define PADS_BASE                (BCM2708_PERI_BASE + 0x100000) /* PADS   */

#define PADS0   *(pads+11)
#define PADS1   *(pads+12)
#define PADS2   *(pads+13)

// I/O access - Reqires maping.
volatile unsigned *pads;

Then from your code, after mmap'ing the pads (see here) pointer you should be able to set the pads registers like so,

PADS0 = (0xFFFFFFF8 & PADS0) | 7; // Sets GPIO 0-27 to 16mA
PADS1 = (0xFFFFFFF8 & PADS1) | 4; // Sets GPIO 28-45 to 10mA
PADS2 = (0xFFFFFFF8 & PADS2);     // Sets GPIO 46-53 to 2mA
Dog Ears
  • 2,027
  • 6
  • 19
  • 28
1

If you can bear some of my old C code, here is an example of performing the mapping in C

#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <limits.h>
#include <unistd.h>
#include <time.h>
#include <signal.h>
#include <termios.h>
#include <ctype.h>

#define FALSE                    (0)
#define TRUE                     (!FALSE)
#define NULL_FD                  ((int)0)
#define MAP_NAME_LEN             (20)
#define NO_MASK                  (UINT_MAX)

#define BCM2708_PERI_BASE        0x20000000
#define GPIO_BASE                (BCM2708_PERI_BASE + 0x200000) /* GPIO   */
#define PADS_BASE                (BCM2708_PERI_BASE + 0x100000) /* PADS   */

#define PADS0                    (11 * 4)
#define PADS1                    (12 * 4)
#define PADS2                    (13 * 4)

#define PADS_CURRENT_MASK        (0x00000007)

typedef struct raw_memory {
    void *accessor;             // Base location for memory access
    unsigned int offset;        // Offset into base for the starting point
    unsigned int length;
    char name[MAP_NAME_LEN + 1];
} raw_memory;

int memFile = NULL_FD;
raw_memory rawMemPads= {MAP_FAILED, 0, 0, "PADS"};


void RegWrite(raw_memory *base, unsigned int address, unsigned int mask, unsigned int value);
unsigned int RegRead(raw_memory *base, unsigned int address);
BOOL MapMemory(raw_memory *base, int device, unsigned int startAddress, size_t size);
void UnmapMemory(raw_memory *base);

void RegWrite(raw_memory *base, unsigned int address, unsigned int mask, unsigned int value) {
    if (base->accessor == MAP_FAILED) {
        printf("RegWrite failed due to an unmapped base (%s)!\n", base->name);
    } else if (address >= base->length) {
        printf("RegWrite failed due to address out of bounds (%s, 0x%08X)!\n", base->name, address);
    } else {
        if (mask != NO_MASK) {
            unsigned int read = RegRead(base, address);
            value &= mask;
            value |= (~mask) & read;
        }
        *((unsigned int *)(base->accessor + base->offset + address)) = value;
    }
}

BOOL MapMemory(raw_memory *base, int device, unsigned int startAddress, size_t size) {
    // Unmap first if already allocated
    if (base->accessor != MAP_FAILED) {
        UnmapMemory(base);
    }
    // Align start address to the page size (we can only map page aligned blocks)
    base->offset = (unsigned int)(startAddress / getpagesize()) * getpagesize();
    // Compute the necessary size to cover the alignment
    base->length = (unsigned int)size;
    size += (size_t)(startAddress - base->offset);
    // Map the memory from the device to a local address
    base->accessor = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, device, base->offset);
    if (base->accessor == MAP_FAILED) {
        return FALSE;
    } else {
        // Calculate the offset needed by read / write functions to get startAddress as 0
        base->offset = startAddress - base->offset;
        return TRUE;
    }
}

void UnmapMemory(raw_memory *base) {
    if (base->accessor != MAP_FAILED) {
        munmap(base->accessor, base->offset + base->length);
        base->accessor = MAP_FAILED;
    } else {
    }
}

int main(void) {
    // Enable raw memory access
    if (memFile == NULL_FD) memFile = open("/dev/mem", O_RDWR | O_SYNC); 
    if (memFile == NULL_FD) {
        printf("Failed to open /dev/mem (are we root?) !\n");
        return 1;
    }

    // Map GPIO memory
    if (!MapMemory(&rawMemPads, memFile, PADS_BASE, 1024)) {
        printf("Failed to map GPIO device memory !\n");
        return 2;
    }

    // Actual work here
    RegWrite(&rawMem, PADS0, PADS_CURRENT_MASK, 7); // Sets GPIO 0-27 to 16mA
    RegWrite(&rawMem, PADS1, PADS_CURRENT_MASK, 4); // Sets GPIO 28-45 to 10mA
    RegWrite(&rawMem, PADS2, PADS_CURRENT_MASK, 0); // Sets GPIO 46-53 to 2mA

    // Any other code here
    //

    // Unmap the GPIO memory
    if (rawMemPads.accessor != MAP_FAILED) {
        UnmapMemory(&rawMemPads);
    }

    // Disable raw memory access
    if (memFile != NULL_FD) {
        close(memFile);
        memFile = NULL_FD;
    }

    return 0;
}

Excuse the length, it is a long bit of setup so that the main bit of code for doing masked writes is short, also it allows for out-of-alignment pages, which is not really an issue here (I had this problem previously with a different embedded register map). Note that you will need to run the binary as root or the mapping will fail as permission denied to /dev/mem

PiBorg
  • 1,497
  • 10
  • 11
  • Does not compile, rawMem is not declared in main(). Also "BOOL" is not a valid datatype but is fixed with including <stdbool.h> and changing it to lowercase "bool". – timonsku Jun 15 '16 at 12:42
0

I know this thread is ancient (but not closed!) however it was really helpful to me so I am contributing what might be a useful update.

Using pigpio you can set the GPIO pin current via "PAD strength" for a group (PAD) of pins. Using the interactive pigs tool. To set PAD0 (GPIOs 0-27) to 16mA (see pigs "pads" cmd:

pigs pads 0 16

You can also use the native C, pigpiod pipe interface, C pigpiod or Python gpiod (pgpiod is a daemon that serves up a socket interface to pigpio). Before you use pigs or any of the other pigpio d socket-based bindings, make sure you do

sudo pigpiod

I tested it and it on RPi 4B (32 bit Raspbian) and I was able to drive a 13 mA load.

jxb
  • 1