raspi_tests

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