raspi_tests

annotate gpiotest1/test.c @ 1:7cdaa3a0df97

- non-priviledged GPIO by opening /dev/gpiomem - input pin with internal pullup/pulldown resistor
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 03 Mar 2016 04:28:11 +0000
parents fbf9076c1984
children
rev   line source
nuclear@0 1 #include <stdio.h>
nuclear@1 2 #include <string.h>
nuclear@0 3 #include <signal.h>
nuclear@1 4 #include <errno.h>
nuclear@0 5 #include <unistd.h>
nuclear@0 6 #include <fcntl.h>
nuclear@0 7 #include <sys/mman.h>
nuclear@0 8 #include "bcm_host.h"
nuclear@0 9
nuclear@1 10 #define REG_GPIO_BASE 0x200000
nuclear@1 11 #define REG_GPFSEL_BASE 0x200000
nuclear@1 12 #define REG_GPSET_BASE 0x20001c
nuclear@1 13 #define REG_GPCLR_BASE 0x200028
nuclear@1 14 #define REG_GPLEV_BASE 0x200034
nuclear@1 15 #define REG_GPPUD 0x200094
nuclear@1 16 #define REG_GPPUDCLK_BASE 0x200098
nuclear@0 17
nuclear@0 18 #define FSEL_BITS 3
nuclear@0 19 #define FSEL_INPUT 0
nuclear@0 20 #define FSEL_OUTPUT 1
nuclear@0 21
nuclear@0 22 #define FSEL_SHIFT(i) (((i) % 10) * 3)
nuclear@0 23 #define FSEL_MASK(i) (3 << FSEL_SHIFT(i))
nuclear@0 24
nuclear@0 25 #define REG(r) (volatile uint32_t*)((unsigned char*)iomem + (r))
nuclear@0 26
nuclear@0 27 void *iomem;
nuclear@0 28 int quit;
nuclear@0 29
nuclear@0 30 static inline void set_pin_func(int pin, int func);
nuclear@0 31 static inline void set_pin_state(int pin, int s);
nuclear@0 32 static inline int get_pin_state(int pin);
nuclear@1 33 static inline void set_pullup(int pin, int en);
nuclear@1 34 static inline void set_pulldown(int pin, int en);
nuclear@0 35 static void sighandler(int s);
nuclear@0 36
nuclear@0 37 int main(void)
nuclear@0 38 {
nuclear@0 39 int fd;
nuclear@0 40 int i;
nuclear@1 41 uint32_t io_addr, io_size, mmap_size;
nuclear@1 42 void *mmap_ptr;
nuclear@0 43
nuclear@0 44 signal(SIGINT, sighandler);
nuclear@0 45 signal(SIGQUIT, sighandler);
nuclear@0 46 signal(SIGSEGV, sighandler);
nuclear@0 47 signal(SIGILL, sighandler);
nuclear@0 48 signal(SIGFPE, sighandler);
nuclear@0 49
nuclear@0 50 io_addr = bcm_host_get_peripheral_address();
nuclear@0 51 io_size = bcm_host_get_peripheral_size();
nuclear@0 52 printf("I/O registers\n");
nuclear@0 53 printf(" addr: %x\n", io_addr);
nuclear@0 54 printf(" size: %d\n", io_size);
nuclear@0 55
nuclear@1 56 if((fd = open("/dev/gpiomem", O_RDWR | O_SYNC)) >= 0) {
nuclear@1 57 mmap_size = 0xb4; /* last gpio reg addr + 4 */
nuclear@1 58 if((mmap_ptr = mmap(0, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == (void*)-1) {
nuclear@1 59 perror("failed to map I/O registers");
nuclear@1 60 return 1;
nuclear@1 61 }
nuclear@1 62 iomem = ((unsigned char*)mmap_ptr) - REG_GPIO_BASE;
nuclear@1 63 } else if((fd = open("/dev/mem", O_RDWR | O_SYNC)) >= 0) {
nuclear@1 64 mmap_size = io_size;
nuclear@1 65 if((mmap_ptr = mmap(0, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, io_addr)) == (void*)-1) {
nuclear@1 66 perror("failed to map I/O registers");
nuclear@1 67 return 1;
nuclear@1 68 }
nuclear@1 69 iomem = mmap_ptr;
nuclear@1 70 } else {
nuclear@0 71 perror("failed to open /dev/mem");
nuclear@0 72 return 1;
nuclear@0 73 }
nuclear@0 74
nuclear@0 75 /* configure GPIO pins 4 and 17 as outputs */
nuclear@0 76 set_pin_func(4, FSEL_OUTPUT);
nuclear@0 77 set_pin_func(17, FSEL_OUTPUT);
nuclear@1 78 /* configure GPIO pin 22 as input, and enable it's pulldown resistor */
nuclear@1 79 set_pin_func(22, FSEL_INPUT);
nuclear@1 80 set_pulldown(22, 1);
nuclear@0 81
nuclear@0 82 i = 0;
nuclear@0 83 while(!quit) {
nuclear@1 84 if(get_pin_state(22)) {
nuclear@1 85 set_pin_state(4, 1);
nuclear@1 86 set_pin_state(17, 1);
nuclear@1 87 } else {
nuclear@1 88 set_pin_state(4, i & 1);
nuclear@1 89 set_pin_state(17, (~i) & 1);
nuclear@1 90 ++i;
nuclear@1 91 }
nuclear@1 92 usleep(250000);
nuclear@0 93 }
nuclear@0 94
nuclear@0 95 set_pin_state(4, 0);
nuclear@0 96 set_pin_state(17, 0);
nuclear@0 97 set_pin_func(4, FSEL_INPUT);
nuclear@0 98 set_pin_func(17, FSEL_INPUT);
nuclear@1 99 set_pulldown(22, 0);
nuclear@0 100
nuclear@1 101 munmap(mmap_ptr, mmap_size);
nuclear@0 102 close(fd);
nuclear@0 103 return 0;
nuclear@0 104 }
nuclear@0 105
nuclear@0 106 static inline void set_pin_func(int pin, int func)
nuclear@0 107 {
nuclear@0 108 int reg_addr, val;
nuclear@0 109 reg_addr = REG_GPFSEL_BASE + (pin / 10) * 4;
nuclear@0 110 val = *REG(reg_addr);
nuclear@0 111 *REG(reg_addr) = (val & FSEL_MASK(pin)) | (func << FSEL_SHIFT(pin));
nuclear@0 112 }
nuclear@0 113
nuclear@0 114 static inline void set_pin_state(int pin, int s)
nuclear@0 115 {
nuclear@0 116 int reg_addr;
nuclear@0 117 int regidx = pin / 32;
nuclear@0 118 int bit = pin % 32;
nuclear@0 119
nuclear@0 120 if(s) {
nuclear@0 121 reg_addr = REG_GPSET_BASE + regidx * 4;
nuclear@0 122 *REG(reg_addr) |= 1 << bit;
nuclear@0 123 } else {
nuclear@0 124 reg_addr = REG_GPCLR_BASE + regidx * 4;
nuclear@0 125 *REG(reg_addr) |= 1 << bit;
nuclear@0 126 }
nuclear@0 127 }
nuclear@0 128
nuclear@0 129 static inline int get_pin_state(int pin)
nuclear@0 130 {
nuclear@0 131 int reg_addr;
nuclear@0 132 int regidx = pin / 32;
nuclear@0 133 int bit = pin % 32;
nuclear@0 134
nuclear@0 135 reg_addr = REG_GPLEV_BASE + regidx * 4;
nuclear@0 136 return (*REG(reg_addr) >> bit) & 1;
nuclear@0 137 }
nuclear@0 138
nuclear@1 139 #define delay_cycles(x) \
nuclear@1 140 __asm__ __volatile__ ( \
nuclear@1 141 "mov %0, #150\n" \
nuclear@1 142 "1:\n\t" \
nuclear@1 143 "nop\n\t" \
nuclear@1 144 "subs %0, %0, #1\n\t" \
nuclear@1 145 "bne 1b\n\t" \
nuclear@1 146 :: "r"(x))
nuclear@1 147
nuclear@1 148 static inline void set_pull_updown(int pin, int updown)
nuclear@1 149 {
nuclear@1 150 int regidx = pin / 32;
nuclear@1 151 int bit = pin % 32;
nuclear@1 152 int clk_addr = REG_GPPUDCLK_BASE + regidx * 4;
nuclear@1 153
nuclear@1 154 *REG(REG_GPPUD) = updown;
nuclear@1 155 delay_cycles(150);
nuclear@1 156 *REG(clk_addr) = bit;
nuclear@1 157 delay_cycles(150);
nuclear@1 158 *REG(REG_GPPUD) = 0;
nuclear@1 159 *REG(clk_addr) = 0;
nuclear@1 160 }
nuclear@1 161
nuclear@1 162 static inline void set_pullup(int pin, int en)
nuclear@1 163 {
nuclear@1 164 set_pull_updown(pin, en ? 2 : 0);
nuclear@1 165 }
nuclear@1 166
nuclear@1 167 static inline void set_pulldown(int pin, int en)
nuclear@1 168 {
nuclear@1 169 set_pull_updown(pin, en ? 1 : 0);
nuclear@1 170 }
nuclear@1 171
nuclear@0 172 static void sighandler(int s)
nuclear@0 173 {
nuclear@0 174 quit = 1;
nuclear@0 175 }