BeagleBone Black GPIO access via mmap is slow

Hi, folks,

I’ve been poking around to get GPIO to work via /dev/mem and mmap. After finally pushing a lot of things around, I finally managed to pull the various flavors of tutorials together into something I now understand (mostly).

However, what I don’t understand is that when I put my scope on the pin, I see it toggle at 2.95MHz. That seems slow. This is the same frequency as here: http://chiragnagpal.com/examples.html

The question is: Why?

I could understand if it was something like 30MHz, but 3MHz seems off by an order of magnitude. And when something seems off in embedded programming, it’s usually a bug waiting to bite you when you least need it.

I’m on a BeagleBoard Black with Debian Jessie Linux arm 4.1.6-ti-r11 #1 SMP PREEMPT Tue Aug 18 21:36:11 UTC 2015 armv7l GNU/Linux

Any suggestions? Given that the assembly seems to be spot on, something appears to be stalling the pipeline.

Is the core being throttled? Is the peripheral bus at some strange frequency? Is the memory mapping hardware inserting cycles? I’m completely at a loss.

Thanks for any advice.

The assembly looks exactly optimal with a ldr/str sequence at maximum density (I’m using clang):

`

.loc 2 83 9 @ gpi.c:83:9
ldr r1, [sp, #32]
str r0, [r1]
.loc 2 84 2 @ gpi.c:84:2
ldr r1, [sp, #28]
str r0, [r1]
.loc 2 85 9 @ gpi.c:85:9
ldr r1, [sp, #32]
str r0, [r1]
.loc 2 86 2 @ gpi.c:86:2
ldr r1, [sp, #28]
str r0, [r1]

`

And here’s the C code I used to generate the pulse train on P9 Pin23 (GPIO1[17])

`

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <unistd.h>
#include <assert.h>

#define GPIO_OE 0x134
#define GPIO_SETDATAOUT 0x194
#define GPIO_CLEARDATAOUT 0x190

// Hunt these addresses down from ls -al /sys/devices/platform/ocp | grep gpio
// You can also pull them from the TI manual (spruh73l.pdf)
#define GPIO0_BASE 0x44E07000
#define GPIO1_BASE 0x4804C000
#define GPIO2_BASE 0x481AC000
#define GPIO3_BASE 0x481AE000

#define GPIO_SIZE 0x00001000

#define PIN_17 ((uint32_t)1<<17)

uint32_t ui32Base[] = {GPIO0_BASE, GPIO1_BASE, GPIO2_BASE, GPIO3_BASE};
uint8_t volatile * bbGPIOMap[] = {0, 0, 0, 0};

int main(int argc, char *argv[])
{
unsigned int ui;

uint32_t volatile * gpio_oe_addr = NULL;
uint32_t volatile * gpio_setdataout_addr = NULL;
uint32_t volatile * gpio_cleardataout_addr = NULL;

int fd = open("/dev/mem", O_RDWR);

for(ui=0; ui<4; ++ui) {
bbGPIOMap[ui] = mmap(0, GPIO_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, ui32Base[ui]);
assert(bbGPIOMap[ui] != MAP_FAILED);
}

gpio_oe_addr = (uint32_t volatile *)(bbGPIOMap[1] + GPIO_OE);
gpio_setdataout_addr = (uint32_t volatile *)(bbGPIOMap[1] + GPIO_SETDATAOUT);
gpio_cleardataout_addr = (uint32_t volatile *)(bbGPIOMap[1] + GPIO_CLEARDATAOUT);

*gpio_oe_addr = *gpio_oe_addr & ~PIN_17;

while(1) {
*gpio_setdataout_addr = PIN_17;
*gpio_cleardataout_addr = PIN_17;
*gpio_setdataout_addr = PIN_17;
*gpio_cleardataout_addr = PIN_17;
*gpio_setdataout_addr = PIN_17;
*gpio_cleardataout_addr = PIN_17;
*gpio_setdataout_addr = PIN_17;
*gpio_cleardataout_addr = PIN_17;
*gpio_setdataout_addr = PIN_17;
*gpio_cleardataout_addr = PIN_17;
*gpio_setdataout_addr = PIN_17;
*gpio_cleardataout_addr = PIN_17;
*gpio_setdataout_addr = PIN_17;
*gpio_cleardataout_addr = PIN_17;
*gpio_setdataout_addr = PIN_17;
*gpio_cleardataout_addr = PIN_17;
*gpio_setdataout_addr = PIN_17;
*gpio_cleardataout_addr = PIN_17;
*gpio_setdataout_addr = PIN_17;
*gpio_cleardataout_addr = PIN_17;
*gpio_setdataout_addr = PIN_17;
*gpio_cleardataout_addr = PIN_17;
*gpio_setdataout_addr = PIN_17;
*gpio_cleardataout_addr = PIN_17;
*gpio_setdataout_addr = PIN_17;
*gpio_cleardataout_addr = PIN_17;
*gpio_setdataout_addr = PIN_17;
*gpio_cleardataout_addr = PIN_17;
*gpio_setdataout_addr = PIN_17;
*gpio_cleardataout_addr = PIN_17;
*gpio_setdataout_addr = PIN_17;
*gpio_cleardataout_addr = PIN_17;
}

close(fd);
return 0;
}

`