rpi_gpio 0.1.5 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,233 +1,253 @@
1
- /*
2
- Original code by Ben Croston modified for Ruby by Nick Lowery
3
- (github.com/clockvapor)
4
- Copyright (c) 2014-2015 Nick Lowery
5
-
6
- Copyright (c) 2013-2014 Ben Croston
7
-
8
- Permission is hereby granted, free of charge, to any person obtaining a copy of
9
- this software and associated documentation files (the "Software"), to deal in
10
- the Software without restriction, including without limitation the rights to
11
- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12
- of the Software, and to permit persons to whom the Software is furnished to do
13
- so, subject to the following conditions:
14
-
15
- The above copyright notice and this permission notice shall be included in all
16
- copies or substantial portions of the Software.
17
-
18
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
- SOFTWARE.
25
- */
26
-
27
- #include <stdint.h>
28
- #include <stdlib.h>
29
- #include <fcntl.h>
30
- #include <sys/mman.h>
31
- #include "c_gpio.h"
32
-
33
- #define BCM2708_PERI_BASE 0x20000000
34
- #define GPIO_BASE (BCM2708_PERI_BASE + 0x200000)
35
- #define FSEL_OFFSET 0 // 0x0000
36
- #define SET_OFFSET 7 // 0x001c / 4
37
- #define CLR_OFFSET 10 // 0x0028 / 4
38
- #define PINLEVEL_OFFSET 13 // 0x0034 / 4
39
- #define EVENT_DETECT_OFFSET 16 // 0x0040 / 4
40
- #define RISING_ED_OFFSET 19 // 0x004c / 4
41
- #define FALLING_ED_OFFSET 22 // 0x0058 / 4
42
- #define HIGH_DETECT_OFFSET 25 // 0x0064 / 4
43
- #define LOW_DETECT_OFFSET 28 // 0x0070 / 4
44
- #define PULLUPDN_OFFSET 37 // 0x0094 / 4
45
- #define PULLUPDNCLK_OFFSET 38 // 0x0098 / 4
46
-
47
- #define PAGE_SIZE (4*1024)
48
- #define BLOCK_SIZE (4*1024)
49
-
50
- static volatile uint32_t *gpio_map;
51
-
52
- void short_wait(void)
53
- {
54
- int i;
55
-
56
- for (i=0; i<150; i++) // wait 150 cycles
57
- {
58
- asm volatile("nop");
59
- }
60
- }
61
-
62
- int setup(void)
63
- {
64
- int mem_fd;
65
- uint8_t *gpio_mem;
66
-
67
- if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0)
68
- {
69
- return SETUP_DEVMEM_FAIL;
70
- }
71
-
72
- if ((gpio_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL)
73
- return SETUP_MALLOC_FAIL;
74
-
75
- if ((uint32_t)gpio_mem % PAGE_SIZE)
76
- gpio_mem += PAGE_SIZE - ((uint32_t)gpio_mem % PAGE_SIZE);
77
-
78
- gpio_map = (uint32_t *)mmap( (caddr_t)gpio_mem, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, mem_fd, GPIO_BASE);
79
-
80
- if ((uint32_t)gpio_map < 0)
81
- return SETUP_MMAP_FAIL;
82
-
83
- return SETUP_OK;
84
- }
85
-
86
- void clear_event_detect(int gpio)
87
- {
88
- int offset = EVENT_DETECT_OFFSET + (gpio/32);
89
- int shift = (gpio%32);
90
-
91
- *(gpio_map+offset) |= (1 << shift);
92
- short_wait();
93
- *(gpio_map+offset) = 0;
94
- }
95
-
96
- int eventdetected(int gpio)
97
- {
98
- int offset, value, bit;
99
-
100
- offset = EVENT_DETECT_OFFSET + (gpio/32);
101
- bit = (1 << (gpio%32));
102
- value = *(gpio_map+offset) & bit;
103
- if (value)
104
- {
105
- clear_event_detect(gpio);
106
- }
107
- return value;
108
- }
109
-
110
- void set_rising_event(int gpio, int enable)
111
- {
112
- int offset = RISING_ED_OFFSET + (gpio/32);
113
- int shift = (gpio%32);
114
-
115
- if (enable)
116
- *(gpio_map+offset) |= 1 << shift;
117
- else
118
- *(gpio_map+offset) &= ~(1 << shift);
119
- clear_event_detect(gpio);
120
- }
121
-
122
- void set_falling_event(int gpio, int enable)
123
- {
124
- int offset = FALLING_ED_OFFSET + (gpio/32);
125
- int shift = (gpio%32);
126
-
127
- if (enable)
128
- {
129
- *(gpio_map+offset) |= (1 << shift);
130
- *(gpio_map+offset) = (1 << shift);
131
- } else {
132
- *(gpio_map+offset) &= ~(1 << shift);
133
- }
134
- clear_event_detect(gpio);
135
- }
136
-
137
- void set_high_event(int gpio, int enable)
138
- {
139
- int offset = HIGH_DETECT_OFFSET + (gpio/32);
140
- int shift = (gpio%32);
141
-
142
- if (enable)
143
- {
144
- *(gpio_map+offset) |= (1 << shift);
145
- } else {
146
- *(gpio_map+offset) &= ~(1 << shift);
147
- }
148
- clear_event_detect(gpio);
149
- }
150
-
151
- void set_low_event(int gpio, int enable)
152
- {
153
- int offset = LOW_DETECT_OFFSET + (gpio/32);
154
- int shift = (gpio%32);
155
-
156
- if (enable)
157
- *(gpio_map+offset) |= 1 << shift;
158
- else
159
- *(gpio_map+offset) &= ~(1 << shift);
160
- clear_event_detect(gpio);
161
- }
162
-
163
- void set_pullupdn(int gpio, int pud)
164
- {
165
- int clk_offset = PULLUPDNCLK_OFFSET + (gpio/32);
166
- int shift = (gpio%32);
167
-
168
- if (pud == PUD_DOWN)
169
- *(gpio_map+PULLUPDN_OFFSET) = (*(gpio_map+PULLUPDN_OFFSET)&~3)|PUD_DOWN;
170
- else if (pud == PUD_UP)
171
- *(gpio_map+PULLUPDN_OFFSET) = (*(gpio_map+PULLUPDN_OFFSET)&~3)|PUD_UP;
172
- else // pud == PUD_OFF
173
- *(gpio_map+PULLUPDN_OFFSET) &= ~3;
174
-
175
- short_wait();
176
- *(gpio_map+clk_offset) = 1 << shift;
177
- short_wait();
178
- *(gpio_map+PULLUPDN_OFFSET) &= ~3;
179
- *(gpio_map+clk_offset) = 0;
180
- }
181
-
182
- void setup_gpio(int gpio, int direction, int pud)
183
- {
184
- int offset = FSEL_OFFSET + (gpio/10);
185
- int shift = (gpio%10)*3;
186
-
187
- set_pullupdn(gpio, pud);
188
- if (direction == OUTPUT)
189
- *(gpio_map+offset) = (*(gpio_map+offset) & ~(7<<shift)) | (1<<shift);
190
- else // direction == INPUT
191
- *(gpio_map+offset) = (*(gpio_map+offset) & ~(7<<shift));
192
- }
193
-
194
- // Contribution by Eric Ptak <trouch@trouch.com>
195
- int gpio_function(int gpio)
196
- {
197
- int offset = FSEL_OFFSET + (gpio/10);
198
- int shift = (gpio%10)*3;
199
- int value = *(gpio_map+offset);
200
- value >>= shift;
201
- value &= 7;
202
- return value; // 0=input, 1=output, 4=alt0
203
- }
204
-
205
- void output_gpio(int gpio, int value)
206
- {
207
- int offset, shift;
208
-
209
- if (value) // value == HIGH
210
- offset = SET_OFFSET + (gpio/32);
211
- else // value == LOW
212
- offset = CLR_OFFSET + (gpio/32);
213
-
214
- shift = (gpio%32);
215
-
216
- *(gpio_map+offset) = 1 << shift;
217
- }
218
-
219
- int input_gpio(int gpio)
220
- {
221
- int offset, value, mask;
222
-
223
- offset = PINLEVEL_OFFSET + (gpio/32);
224
- mask = (1 << gpio%32);
225
- value = *(gpio_map+offset) & mask;
226
- return value;
227
- }
228
-
229
- void cleanup(void)
230
- {
231
- // fixme - set all gpios back to input
232
- munmap((caddr_t)gpio_map, BLOCK_SIZE);
233
- }
1
+ /*
2
+ Original code by Ben Croston modified for Ruby by Nick Lowery
3
+ (github.com/clockvapor)
4
+ Copyright (c) 2014-2015 Nick Lowery
5
+
6
+ Copyright (c) 2013-2014 Ben Croston
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
9
+ this software and associated documentation files (the "Software"), to deal in
10
+ the Software without restriction, including without limitation the rights to
11
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12
+ of the Software, and to permit persons to whom the Software is furnished to do
13
+ so, subject to the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be included in all
16
+ copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
+ SOFTWARE.
25
+ */
26
+
27
+ #include <stdio.h>
28
+ #include <stdint.h>
29
+ #include <stdlib.h>
30
+ #include <fcntl.h>
31
+ #include <sys/mman.h>
32
+ #include "c_gpio.h"
33
+
34
+ #define BCM2708_PERI_BASE_DEFAULT 0x20000000
35
+ #define GPIO_BASE_OFFSET 0x200000
36
+ #define FSEL_OFFSET 0 // 0x0000
37
+ #define SET_OFFSET 7 // 0x001c / 4
38
+ #define CLR_OFFSET 10 // 0x0028 / 4
39
+ #define PINLEVEL_OFFSET 13 // 0x0034 / 4
40
+ #define EVENT_DETECT_OFFSET 16 // 0x0040 / 4
41
+ #define RISING_ED_OFFSET 19 // 0x004c / 4
42
+ #define FALLING_ED_OFFSET 22 // 0x0058 / 4
43
+ #define HIGH_DETECT_OFFSET 25 // 0x0064 / 4
44
+ #define LOW_DETECT_OFFSET 28 // 0x0070 / 4
45
+ #define PULLUPDN_OFFSET 37 // 0x0094 / 4
46
+ #define PULLUPDNCLK_OFFSET 38 // 0x0098 / 4
47
+
48
+ #define PAGE_SIZE (4*1024)
49
+ #define BLOCK_SIZE (4*1024)
50
+
51
+ static volatile uint32_t *gpio_map;
52
+
53
+ void short_wait(void)
54
+ {
55
+ int i;
56
+
57
+ for (i=0; i<150; i++) { // wait 150 cycles
58
+ asm volatile("nop");
59
+ }
60
+ }
61
+
62
+ int setup(void)
63
+ {
64
+ int mem_fd;
65
+ uint8_t *gpio_mem;
66
+ uint32_t peri_base = BCM2708_PERI_BASE_DEFAULT;
67
+ uint32_t gpio_base;
68
+ unsigned char buf[4];
69
+ FILE *fp;
70
+
71
+ // get peri base from device tree
72
+ if ((fp = fopen("/proc/device-tree/soc/ranges", "rb")) != NULL) {
73
+ fseek(fp, 4, SEEK_SET);
74
+ if (fread(buf, 1, sizeof buf, fp) == sizeof buf) {
75
+ peri_base = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0;
76
+ }
77
+ fclose(fp);
78
+ }
79
+
80
+ gpio_base = peri_base + GPIO_BASE_OFFSET;
81
+
82
+ // mmap the GPIO memory registers
83
+ if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
84
+ return SETUP_DEVMEM_FAIL;
85
+ }
86
+
87
+ if ((gpio_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) {
88
+ return SETUP_MALLOC_FAIL;
89
+ }
90
+
91
+ if ((uint32_t)gpio_mem % PAGE_SIZE) {
92
+ gpio_mem += PAGE_SIZE - ((uint32_t)gpio_mem % PAGE_SIZE);
93
+ }
94
+
95
+ gpio_map = (uint32_t *) mmap((caddr_t) gpio_mem, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, mem_fd, gpio_base);
96
+
97
+ if ((uint32_t)gpio_map < 0) {
98
+ return SETUP_MMAP_FAIL;
99
+ }
100
+
101
+ return SETUP_OK;
102
+ }
103
+
104
+ void clear_event_detect(int gpio)
105
+ {
106
+ int offset = EVENT_DETECT_OFFSET + (gpio/32);
107
+ int shift = (gpio%32);
108
+
109
+ *(gpio_map+offset) |= (1 << shift);
110
+ short_wait();
111
+ *(gpio_map+offset) = 0;
112
+ }
113
+
114
+ int eventdetected(int gpio)
115
+ {
116
+ int offset, value, bit;
117
+
118
+ offset = EVENT_DETECT_OFFSET + (gpio/32);
119
+ bit = (1 << (gpio%32));
120
+ value = *(gpio_map+offset) & bit;
121
+ if (value) {
122
+ clear_event_detect(gpio);
123
+ }
124
+ return value;
125
+ }
126
+
127
+ void set_rising_event(int gpio, int enable)
128
+ {
129
+ int offset = RISING_ED_OFFSET + (gpio/32);
130
+ int shift = (gpio%32);
131
+
132
+ if (enable) {
133
+ *(gpio_map+offset) |= 1 << shift;
134
+ } else {
135
+ *(gpio_map+offset) &= ~(1 << shift);
136
+ }
137
+ clear_event_detect(gpio);
138
+ }
139
+
140
+ void set_falling_event(int gpio, int enable)
141
+ {
142
+ int offset = FALLING_ED_OFFSET + (gpio/32);
143
+ int shift = (gpio%32);
144
+
145
+ if (enable) {
146
+ *(gpio_map+offset) |= (1 << shift);
147
+ *(gpio_map+offset) = (1 << shift);
148
+ } else {
149
+ *(gpio_map+offset) &= ~(1 << shift);
150
+ }
151
+ clear_event_detect(gpio);
152
+ }
153
+
154
+ void set_high_event(int gpio, int enable)
155
+ {
156
+ int offset = HIGH_DETECT_OFFSET + (gpio/32);
157
+ int shift = (gpio%32);
158
+
159
+ if (enable) {
160
+ *(gpio_map+offset) |= (1 << shift);
161
+ } else {
162
+ *(gpio_map+offset) &= ~(1 << shift);
163
+ }
164
+ clear_event_detect(gpio);
165
+ }
166
+
167
+ void set_low_event(int gpio, int enable)
168
+ {
169
+ int offset = LOW_DETECT_OFFSET + (gpio/32);
170
+ int shift = (gpio%32);
171
+
172
+ if (enable) {
173
+ *(gpio_map+offset) |= 1 << shift;
174
+ } else {
175
+ *(gpio_map+offset) &= ~(1 << shift);
176
+ }
177
+ clear_event_detect(gpio);
178
+ }
179
+
180
+ void set_pullupdn(int gpio, int pud)
181
+ {
182
+ int clk_offset = PULLUPDNCLK_OFFSET + (gpio/32);
183
+ int shift = (gpio%32);
184
+
185
+ if (pud == PUD_DOWN) {
186
+ *(gpio_map+PULLUPDN_OFFSET) = (*(gpio_map+PULLUPDN_OFFSET) & ~3) |
187
+ PUD_DOWN;
188
+ } else if (pud == PUD_UP) {
189
+ *(gpio_map+PULLUPDN_OFFSET) = (*(gpio_map+PULLUPDN_OFFSET) & ~3) | PUD_UP;
190
+ } else { // pud == PUD_OFF
191
+ *(gpio_map+PULLUPDN_OFFSET) &= ~3;
192
+ }
193
+
194
+ short_wait();
195
+ *(gpio_map+clk_offset) = 1 << shift;
196
+ short_wait();
197
+ *(gpio_map+PULLUPDN_OFFSET) &= ~3;
198
+ *(gpio_map+clk_offset) = 0;
199
+ }
200
+
201
+ void setup_gpio(int gpio, int direction, int pud)
202
+ {
203
+ int offset = FSEL_OFFSET + (gpio/10);
204
+ int shift = (gpio%10)*3;
205
+
206
+ set_pullupdn(gpio, pud);
207
+ if (direction == OUTPUT)
208
+ *(gpio_map+offset) = (*(gpio_map+offset) & ~(7<<shift)) | (1<<shift);
209
+ else // direction == INPUT
210
+ *(gpio_map+offset) = (*(gpio_map+offset) & ~(7<<shift));
211
+ }
212
+
213
+ // Contribution by Eric Ptak <trouch@trouch.com>
214
+ int gpio_function(int gpio)
215
+ {
216
+ int offset = FSEL_OFFSET + (gpio/10);
217
+ int shift = (gpio%10)*3;
218
+ int value = *(gpio_map+offset);
219
+ value >>= shift;
220
+ value &= 7;
221
+ return value; // 0=input, 1=output, 4=alt0
222
+ }
223
+
224
+ void output_gpio(int gpio, int value)
225
+ {
226
+ int offset, shift;
227
+
228
+ if (value) { // value == HIGH
229
+ offset = SET_OFFSET + (gpio/32);
230
+ } else { // value == LOW
231
+ offset = CLR_OFFSET + (gpio/32);
232
+ }
233
+
234
+ shift = (gpio%32);
235
+
236
+ *(gpio_map+offset) = 1 << shift;
237
+ }
238
+
239
+ int input_gpio(int gpio)
240
+ {
241
+ int offset, value, mask;
242
+
243
+ offset = PINLEVEL_OFFSET + (gpio/32);
244
+ mask = (1 << gpio%32);
245
+ value = *(gpio_map+offset) & mask;
246
+ return value;
247
+ }
248
+
249
+ void cleanup(void)
250
+ {
251
+ // fixme - set all gpios back to input
252
+ munmap((caddr_t)gpio_map, BLOCK_SIZE);
253
+ }