Hi, folks,
I have been trying to bit bang an interface on the GPIO pins. I looked at a bunch of the tutorials on the web and managed to build something that worked. However, the speed seems to be a bit slower than I would expect.
My scope shows that I am running at about 2.95MHz (It also roughly matches the result from here–http://chiragnagpal.com/examples.html of 2.78MHz). That seems slow–I would have expected closer to 25MHz–so I think I’m an order of magnitude off somewhere The assembly code seems to be as expected, so my question is:
What is slowing things down?
Since the assembly is basically ldr/str in a chain, something must be stalling the pipeline, but I don’t know what.
Suggestions would be appreciated.
I’m running Debian Jessie Linux arm 4.1.6-ti-r11 #1 SMP PREEMPT Tue Aug 18 21:36:11 UTC 2015 armv7l GNU/Linux
Thanks.
The assembly code looks optimal at 4 instructions per toggle (I’m using clang):
`
.loc 2 80 2 @ gpi.c:80:2
ldr r1, [sp, #28]
str r0, [r1]
.loc 2 81 9 @ gpi.c:81:9
ldr r1, [sp, #32]
str r0, [r1]
.loc 2 82 2 @ gpi.c:82:2
ldr r1, [sp, #28]
str r0, [r1]
.loc 2 83 9 @ gpi.c:83:9
ldr r1, [sp, #32]
str r0, [r1]
`
The C Code I used to toggle the pin P9_23 (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;
}
//*(uint32_t volatile )(bbGPIOMap[3] + GPIO_SETDATAOUT) = (uint32_t)1 << 14;
//(uint32_t volatile *)(bbGPIOMap[3] + GPIO_CLEARDATAOUT) = (uint32_t)1 << 14;
close(fd);
return 0;
}
`