/* gpio.c D.J.Whale 8/07/2014 * * A very simple interface to the GPIO port on the Raspberry Pi. */ /***** INCLUDES *****/ #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <fcntl.h> #include <sys/mman.h> #include <unistd.h> #include <time.h> #include "gpio.h" /***** CONSTANTS *****/ #define BCM2708_PERI_BASE 0x20000000 //#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */ #define GPIO_BASE_OFFSET 0x200000 #define PAGE_SIZE (4*1024) #define BLOCK_SIZE (4*1024) /***** VARIABLES *****/ static int mem_fd; static void *gpio_map; static volatile unsigned *gpio; const uint8_t gpio_sim=0; /* 0=> not simulated */ /****** MACROS *****/ #define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3)) #define OUT_GPIO(g) *(gpio+((g)/10)) |= (1<<(((g)%10)*3)) #define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3)) #define GPIO_SET *(gpio+7) // sets bits which are 1 ignores bits which are 0 #define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0 #define GPIO_READ(g) ((*(gpio+13)&(1<<g)) != 0) #define GPIO_HIGH(g) GPIO_SET = (1<<(g)) #define GPIO_LOW(g) GPIO_CLR = (1<<(g)) void gpio_init() { uint32_t peri_base = BCM2708_PERI_BASE; /* default if device tree not found */ uint32_t gpio_base; FILE* fp; /* for RPi2, get peri-base from device tree */ if ((fp = fopen("/proc/device-tree/soc/ranges", "rb")) != NULL) { unsigned char buf[4]; fseek(fp, 4, SEEK_SET); if (fread(buf, 1, sizeof(buf), fp) == sizeof(buf)) { peri_base = buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3]; } fclose(fp); } gpio_base = peri_base + GPIO_BASE_OFFSET; /* open /dev/mem */ if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) { printf("can't open /dev/mem \n"); exit(-1); //TODO return a result code } /* mmap GPIO */ gpio_map = mmap( NULL, //Any adddress in our space will do BLOCK_SIZE, //Map length PROT_READ|PROT_WRITE,// Enable reading & writting to mapped memory MAP_SHARED, //Shared with other processes mem_fd, //File to map gpio_base //Offset to GPIO peripheral ); close(mem_fd); //No need to keep mem_fd open after mmap if (gpio_map == MAP_FAILED) { printf("mmap error %d\n", (int)gpio_map);//errno also set! exit(-1); //TODO return a result code } // Always use volatile pointer! gpio = (volatile unsigned *)gpio_map; } void gpio_setin(uint8_t g) { INP_GPIO(g); } void gpio_setout(uint8_t g) { /* always INP_GPIO before OUT_GPIO */ //INP_GPIO(g); #### this causes glitching OUT_GPIO(g); } void gpio_high(uint8_t g) { GPIO_HIGH(g); } void gpio_low(uint8_t g) { GPIO_LOW(g); } void gpio_write(uint8_t g, uint8_t v) { if (v != 0) { GPIO_HIGH(g); } else { GPIO_LOW(g); } } uint8_t gpio_read(uint8_t g) { return GPIO_READ(g); } void gpio_finished(void) { //TODO probably need gpio_finished() to unmmap() the memory region and clean up the peripheral? } /***** END OF FILE *****/