We all know that the raspi is a small and neat device for controlling our LEDs but sometimes I miss the possibility to add hardware to a “real” bus like a real CPU has. Sure it is possible to imitate a bus what is called bit banging. This way you can control external hardware like LCDs or writing data to external SRAM faster than utilizing SPI. So we were interested how fast the Pi can really switch these pins.
There are some benchmarks out there but I tried to find the real limit. Therefore we implemented the GPIO pin switching in assembler:
#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <fcntl.h> #include <sys/mman.h> #include <errno.h> #include <stdint.h> #include <string.h> #include <unistd.h> static volatile uint32_t *gpio; int main(int argc, char **argv) { int fd; // Obtain handle to physical memory if ((fd = open ("/dev/mem", O_RDWR | O_SYNC) ) < 0) { printf("Unable to open /dev/mem: %s\n", strerror(errno)); return -1; } // map a page of memory to gpio at offset 0x20200000 which is where GPIO goodnessstarts gpio = (uint32_t *)mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0x20200000); if (gpio == 0){ printf("Mmap failed: %s\n", strerror(errno)); return -1; } // set gpio17 as an output // increment the pointer to 0x20200004 // set the value through a little bit twiddling where we only modify the bits 21-23 in the register *(gpio + 1) = (*(gpio + 1) & ~(7 << 21)) | (1 << 21); // Now do a loop as fast as possible in assembler __asm__("loop:\n\t" "mov r1,#1\n\t" //PIN ON "lsl r1,#17\n\t" "str r1,[%0,#28]\n\t" "mov r1,#1\n\t" //PIN OFF "lsl r1,#17\n\t" "str r1,[%0,#40]\n\t" "b loop\n\t" : :"r"((uint32_t)gpio) : "r0", "r1" ); }
Here is the result:
As you can see, this code is able to switch it at 25 MHz and the the curve looks quite good. However, even further optimizations like loop-unrolling does not help. 25 MHz is really the highest frequency you can achieve.
Pingback: Rasky update: choosing how to connect the CPLD to RaspberryPI | Nexlab