rpi_gpio 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,36 +1,36 @@
1
- PATH
2
- remote: .
3
- specs:
4
- rpi_gpio (0.2.0)
5
-
6
- GEM
7
- remote: https://rubygems.org/
8
- specs:
9
- diff-lcs (1.2.5)
10
- rake (10.4.2)
11
- rake-compiler (0.9.5)
12
- rake
13
- rspec (3.3.0)
14
- rspec-core (~> 3.3.0)
15
- rspec-expectations (~> 3.3.0)
16
- rspec-mocks (~> 3.3.0)
17
- rspec-core (3.3.2)
18
- rspec-support (~> 3.3.0)
19
- rspec-expectations (3.3.1)
20
- diff-lcs (>= 1.2.0, < 2.0)
21
- rspec-support (~> 3.3.0)
22
- rspec-mocks (3.3.2)
23
- diff-lcs (>= 1.2.0, < 2.0)
24
- rspec-support (~> 3.3.0)
25
- rspec-support (3.3.0)
26
-
27
- PLATFORMS
28
- ruby
29
-
30
- DEPENDENCIES
31
- rake-compiler
32
- rpi_gpio!
33
- rspec
34
-
35
- BUNDLED WITH
36
- 1.10.6
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ rpi_gpio (0.3.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ diff-lcs (1.2.5)
10
+ rake (11.2.2)
11
+ rake-compiler (1.0.1)
12
+ rake
13
+ rspec (3.5.0)
14
+ rspec-core (~> 3.5.0)
15
+ rspec-expectations (~> 3.5.0)
16
+ rspec-mocks (~> 3.5.0)
17
+ rspec-core (3.5.1)
18
+ rspec-support (~> 3.5.0)
19
+ rspec-expectations (3.5.0)
20
+ diff-lcs (>= 1.2.0, < 2.0)
21
+ rspec-support (~> 3.5.0)
22
+ rspec-mocks (3.5.0)
23
+ diff-lcs (>= 1.2.0, < 2.0)
24
+ rspec-support (~> 3.5.0)
25
+ rspec-support (3.5.0)
26
+
27
+ PLATFORMS
28
+ ruby
29
+
30
+ DEPENDENCIES
31
+ rake-compiler
32
+ rpi_gpio!
33
+ rspec
34
+
35
+ BUNDLED WITH
36
+ 1.10.6
data/README.md CHANGED
@@ -1,137 +1,138 @@
1
- # rpi_gpio v0.2.0
2
-
3
- Ruby conversion of [RPi.GPIO Python module](https://pypi.python.org/pypi/RPi.GPIO)
4
-
5
- ## Features
6
-
7
- Manipulate your Raspberry Pi's GPIO pins from Ruby!
8
-
9
- - Boolean input/output
10
- - Software-driven PWM (written in C for speed)
11
-
12
- Up-to-date with RPi.GPIO Python module version 0.5.11, so it works on all Raspberry Pi models!
13
-
14
- ## Sample Usage
15
-
16
- I aimed to make the gem's usage exactly the same as its Python counterpart -- only with a few semantic differences to utilize Ruby's readability. If anything is confusing, you can always check [here](http://sourceforge.net/p/raspberry-gpio-python/wiki/Examples/) for the original Python module's documentation.
17
-
18
- #### Download the gem
19
-
20
- The easiest way to download the gem is to use [Bundler](http://bundler.io/) with a Gemfile. In your Gemfile, include the line
21
- ```
22
- gem 'rpi_gpio'
23
- ```
24
- Then you can run `bundle install` to automatically download and compile the gem for your system. To include the gem in a Ruby file, use the line `require 'rpi_gpio'`.
25
-
26
- #### Pin numbering
27
-
28
- Before you can do anything with the GPIO pins, you need to specify how you want to number them.
29
- ```
30
- RPi::GPIO.set_numbering :board
31
- # or
32
- RPi::GPIO.set_numbering :bcm
33
- ````
34
- `:board` numbering refers to the physical pin numbers on the Pi, whereas `:bcm` numbering refers to the Broadcom SOC channel numbering. Note that `:bcm` numbering differs between Pi models, while `:board` numbering does not.
35
-
36
- #### Input
37
-
38
- To receive input from a GPIO pin, you must first initialize it as an input pin:
39
- ```
40
- RPi::GPIO.setup PIN_NUM, as: :input
41
- ```
42
- The pin number will differ based on your selected numbering system and which pin you want to use.
43
-
44
- Now you can use the calls
45
- ```
46
- RPi::GPIO.high? PIN_NUM
47
- RPi::GPIO.low? PIN_NUM
48
- ```
49
- to receive either `true` or `false`.
50
-
51
- You can use the additional hash argument `:pull` to apply a pull-up or pull-down resistor to the input pin like so:
52
- ```
53
- RPi::GPIO.setup PIN_NUM, as: :input, pull: :down
54
- # or
55
- RPi::GPIO.setup PIN_NUM, as: :input, pull: :up
56
- # or (not necessary; :off is the default value)
57
- RPi::GPIO.setup PIN_NUM, as: :input, pull: :off
58
- ```
59
-
60
- #### Output
61
-
62
- To send output to a GPIO pin, you must first initialize it as an output pin:
63
- ```
64
- RPi::GPIO.setup PIN_NUM, as: :output
65
- ```
66
- Now you can use the calls
67
- ```
68
- RPi::GPIO.set_high PIN_NUM
69
- RPi::GPIO.set_low PIN_NUM
70
- ```
71
- to set the pin either high or low.
72
-
73
- #### PWM (pulse-width modulation)
74
-
75
- Pulse-width modulation is a useful tool for controlling things like LED brightness or motor speed. To utilize PWM, first create a PWM object for an [output pin](#output).
76
- ```ruby
77
- pwm = RPi::GPIO::PWM.new(PIN_NUM, PWM_FREQ)
78
- ```
79
- The `PWM_FREQ` is a value in hertz that specifies the amount of pulse cycles per second.
80
-
81
- Now you can call the following method to start PWM:
82
- ```
83
- pwm.start DUTY_CYCLE
84
- ```
85
- `DUTY_CYCLE` is a value from `0.0` to `100.0` indicating the percent of the time that the signal will be high.
86
-
87
- Once running, you can get/set the PWM duty cycle with
88
- ```
89
- pwm.duty_cycle # get
90
- pwm.duty_cycle = NEW_DUTY_CYCLE # set
91
- ```
92
- get/set the PWM frequency with
93
- ```
94
- pwm.frequency # get
95
- pwm.frequency = NEW_FREQUENCY # set
96
- ```
97
- and get the PWM GPIO number with
98
- ```ruby
99
- pwm.gpio
100
- ```
101
- Note that this number corresponds to `:bcm` numbering of the GPIO pins, so it will be different than pin number you used if you created the PWM with `:board` numbering.
102
-
103
- To stop PWM, use
104
- ```
105
- pwm.stop
106
- ```
107
-
108
- To check if a PWM object is currently running, use
109
- ```ruby
110
- pwm.running?
111
- ```
112
-
113
- #### Cleaning up
114
-
115
- After your program is finished using the GPIO pins, it's a good idea to release them so other programs can use them later. Simply call
116
- ```
117
- RPi::GPIO.clean_up PIN_NUM
118
- ```
119
- to release a specific pin, or
120
- ```
121
- RPi::GPIO.clean_up
122
- ```
123
- to release all allocated pins.
124
-
125
- Alternatively, you can call
126
- ```ruby
127
- RPi::GPIO.reset
128
- ```
129
- to clean up all pins and to also reset the selected numbering mode.
130
-
131
- ## Credits
132
-
133
- Original Python code by Ben Croston modified for Ruby by Nick Lowery
134
-
135
- Copyright (c) 2014-2015 [Nick Lowery](https://github.com/ClockVapor)
136
-
137
- View LICENSE for full license.
1
+ # rpi_gpio v0.3.0
2
+
3
+ Ruby conversion of [RPi.GPIO Python module](https://pypi.python.org/pypi/RPi.GPIO)
4
+
5
+ ## Features
6
+
7
+ Manipulate your Raspberry Pi's GPIO pins from Ruby!
8
+
9
+ - Boolean input/output
10
+ - Software-driven PWM (written in C for speed)
11
+
12
+ Up-to-date with RPi.GPIO Python module version 0.6.2, so it works on all Raspberry Pi models!
13
+
14
+ ## Sample Usage
15
+
16
+ I aimed to make the gem's usage exactly the same as its Python counterpart -- only with a few semantic differences to utilize Ruby's readability. If anything is confusing, you can always check [here](http://sourceforge.net/p/raspberry-gpio-python/wiki/Examples/) for the original Python module's documentation.
17
+
18
+ #### Download the gem
19
+
20
+ The easiest way to download the gem is to use [Bundler](http://bundler.io/) with a Gemfile. In your Gemfile, include the line
21
+ ```ruby
22
+ gem 'rpi_gpio'
23
+ ```
24
+ Then you can run `bundle install` to automatically download and compile the gem for your system. To include the gem in a Ruby file, use the line `require 'rpi_gpio'`.
25
+
26
+ #### Pin numbering
27
+
28
+ Before you can do anything with the GPIO pins, you need to specify how you want to number them.
29
+ ```ruby
30
+ RPi::GPIO.set_numbering :board
31
+ # or
32
+ RPi::GPIO.set_numbering :bcm
33
+ ````
34
+ `:board` numbering refers to the physical pin numbers on the Pi, whereas `:bcm` numbering refers to the Broadcom SOC channel numbering. Note that `:bcm` numbering differs between Pi models, while `:board` numbering does not.
35
+
36
+ #### Input
37
+
38
+ To receive input from a GPIO pin, you must first initialize it as an input pin:
39
+ ```ruby
40
+ RPi::GPIO.setup PIN_NUM, :as => :input
41
+ ```
42
+ The pin number will differ based on your selected numbering system and which pin you want to use.
43
+
44
+ Now you can use the calls
45
+ ```ruby
46
+ RPi::GPIO.high? PIN_NUM
47
+ RPi::GPIO.low? PIN_NUM
48
+ ```
49
+ to receive either `true` or `false`.
50
+
51
+ You can use the additional hash argument `:pull` to apply a pull-up or pull-down resistor to the input pin like so:
52
+ ```ruby
53
+ RPi::GPIO.setup PIN_NUM, :as => :input, :pull => :down
54
+ # or
55
+ RPi::GPIO.setup PIN_NUM, :as => :input, :pull => :up
56
+ # or (not necessary; :off is the default value)
57
+ RPi::GPIO.setup PIN_NUM, :as => :input, :pull => :off
58
+ ```
59
+
60
+ #### Output
61
+
62
+ To send output to a GPIO pin, you must first initialize it as an output pin:
63
+ ```ruby
64
+ RPi::GPIO.setup PIN_NUM, :as => :output
65
+ ```
66
+ Now you can use the calls
67
+ ```ruby
68
+ RPi::GPIO.set_high PIN_NUM
69
+ RPi::GPIO.set_low PIN_NUM
70
+ ```
71
+ to set the pin either high or low.
72
+
73
+ #### PWM (pulse-width modulation)
74
+
75
+ Pulse-width modulation is a useful tool for controlling things like LED brightness or motor speed. To utilize PWM, first create a PWM object for an [output pin](#output).
76
+ ```ruby
77
+ pwm = RPi::GPIO::PWM.new(PIN_NUM, PWM_FREQ)
78
+ ```
79
+ The `PWM_FREQ` is a value in hertz that specifies the amount of pulse cycles per second.
80
+
81
+ Now you can call the following method to start PWM:
82
+ ```ruby
83
+ pwm.start DUTY_CYCLE
84
+ ```
85
+ `DUTY_CYCLE` is a value from `0.0` to `100.0` indicating the percent of the time that the signal will be high.
86
+
87
+ Once running, you can get/set the PWM duty cycle with
88
+ ```ruby
89
+ pwm.duty_cycle # get
90
+ pwm.duty_cycle = NEW_DUTY_CYCLE # set
91
+ ```
92
+ get/set the PWM frequency with
93
+ ```ruby
94
+ pwm.frequency # get
95
+ pwm.frequency = NEW_FREQUENCY # set
96
+ ```
97
+ and get the PWM GPIO number with
98
+ ```ruby
99
+ pwm.gpio
100
+ ```
101
+ Note that this number corresponds to `:bcm` numbering of the GPIO pins, so it will be different than pin number you used if you created the PWM with `:board` numbering.
102
+
103
+ To stop PWM, use
104
+ ```ruby
105
+ pwm.stop
106
+ ```
107
+
108
+ To check if a PWM object is currently running, use
109
+ ```ruby
110
+ pwm.running?
111
+ ```
112
+
113
+ #### Cleaning up
114
+
115
+ After your program is finished using the GPIO pins, it's a good idea to release them so other programs can use them later. Simply call
116
+ ```ruby
117
+ RPi::GPIO.clean_up PIN_NUM
118
+ ```
119
+ to release a specific pin, or
120
+ ```ruby
121
+ RPi::GPIO.clean_up
122
+ ```
123
+ to release all allocated pins.
124
+
125
+ Alternatively, you can call
126
+ ```ruby
127
+ RPi::GPIO.reset
128
+ ```
129
+ to clean up all pins and to also reset the selected numbering mode.
130
+
131
+ ## Credits
132
+
133
+ Original Python code by Ben Croston modified for Ruby by Nick Lowery
134
+
135
+ Copyright (c) 2014-2015 [Nick Lowery](https://github.com/ClockVapor)
136
+
137
+ View LICENSE for full license.
138
+
@@ -1,253 +1,292 @@
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
- }
1
+ /*
2
+ Original code by Ben Croston modified for Ruby by Nick Lowery
3
+ (github.com/clockvapor)
4
+ Copyright (c) 2014-2016 Nick Lowery
5
+
6
+ Copyright (c) 2013-2015 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 <string.h>
33
+ #include "c_gpio.h"
34
+
35
+ #define BCM2708_PERI_BASE_DEFAULT 0x20000000
36
+ #define BCM2709_PERI_BASE_DEFAULT 0x3f000000
37
+ #define GPIO_BASE_OFFSET 0x200000
38
+ #define FSEL_OFFSET 0 // 0x0000
39
+ #define SET_OFFSET 7 // 0x001c / 4
40
+ #define CLR_OFFSET 10 // 0x0028 / 4
41
+ #define PINLEVEL_OFFSET 13 // 0x0034 / 4
42
+ #define EVENT_DETECT_OFFSET 16 // 0x0040 / 4
43
+ #define RISING_ED_OFFSET 19 // 0x004c / 4
44
+ #define FALLING_ED_OFFSET 22 // 0x0058 / 4
45
+ #define HIGH_DETECT_OFFSET 25 // 0x0064 / 4
46
+ #define LOW_DETECT_OFFSET 28 // 0x0070 / 4
47
+ #define PULLUPDN_OFFSET 37 // 0x0094 / 4
48
+ #define PULLUPDNCLK_OFFSET 38 // 0x0098 / 4
49
+
50
+ #define PAGE_SIZE (4*1024)
51
+ #define BLOCK_SIZE (4*1024)
52
+
53
+ static volatile uint32_t *gpio_map;
54
+
55
+ void short_wait(void)
56
+ {
57
+ int i;
58
+
59
+ for (i=0; i<150; i++) { // wait 150 cycles
60
+ asm volatile("nop");
61
+ }
62
+ }
63
+
64
+ int setup(void)
65
+ {
66
+ int mem_fd;
67
+ uint8_t *gpio_mem;
68
+ uint32_t peri_base;
69
+ uint32_t gpio_base;
70
+ unsigned char buf[4];
71
+ FILE *fp;
72
+ char buffer[1024];
73
+ char hardware[1024];
74
+ int found = 0;
75
+
76
+ // try /dev/gpiomem first - this does not require root privs
77
+ if ((mem_fd = open("/dev/gpiomem", O_RDWR|O_SYNC)) > 0)
78
+ {
79
+ gpio_map = (uint32_t *)mmap(NULL, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, 0);
80
+ if ((uint32_t)gpio_map < 0) {
81
+ return SETUP_MMAP_FAIL;
82
+ } else {
83
+ return SETUP_OK;
84
+ }
85
+ }
86
+
87
+ // revert to /dev/mem method - requires root
88
+
89
+ // determine peri_base
90
+ if ((fp = fopen("/proc/device-tree/soc/ranges", "rb")) != NULL) {
91
+ // get peri base from device tree
92
+ fseek(fp, 4, SEEK_SET);
93
+ if (fread(buf, 1, sizeof buf, fp) == sizeof buf) {
94
+ peri_base = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0;
95
+ }
96
+ fclose(fp);
97
+ } else {
98
+ // guess peri base based on /proc/cpuinfo hardware field
99
+ if ((fp = fopen("/proc/cpuinfo", "r")) == NULL)
100
+ return SETUP_CPUINFO_FAIL;
101
+
102
+ while(!feof(fp) && !found) {
103
+ fgets(buffer, sizeof(buffer), fp);
104
+ sscanf(buffer, "Hardware : %s", hardware);
105
+ if (strcmp(hardware, "BCM2708") == 0 || strcmp(hardware, "BCM2835") == 0) {
106
+ // pi 1 hardware
107
+ peri_base = BCM2708_PERI_BASE_DEFAULT;
108
+ found = 1;
109
+ } else if (strcmp(hardware, "BCM2709") == 0 || strcmp(hardware, "BCM2836") == 0) {
110
+ // pi 2 hardware
111
+ peri_base = BCM2709_PERI_BASE_DEFAULT;
112
+ found = 1;
113
+ }
114
+ }
115
+ fclose(fp);
116
+ if (!found)
117
+ return SETUP_NOT_RPI_FAIL;
118
+ }
119
+
120
+ gpio_base = peri_base + GPIO_BASE_OFFSET;
121
+
122
+ // mmap the GPIO memory registers
123
+ if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
124
+ return SETUP_DEVMEM_FAIL;
125
+ }
126
+
127
+ if ((gpio_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) {
128
+ return SETUP_MALLOC_FAIL;
129
+ }
130
+
131
+ if ((uint32_t)gpio_mem % PAGE_SIZE) {
132
+ gpio_mem += PAGE_SIZE - ((uint32_t) gpio_mem % PAGE_SIZE);
133
+ }
134
+
135
+ gpio_map = (uint32_t *) mmap((void *) gpio_mem, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, mem_fd, gpio_base);
136
+
137
+ if ((uint32_t) gpio_map < 0) {
138
+ return SETUP_MMAP_FAIL;
139
+ }
140
+
141
+ return SETUP_OK;
142
+ }
143
+
144
+ void clear_event_detect(int gpio)
145
+ {
146
+ int offset = EVENT_DETECT_OFFSET + (gpio/32);
147
+ int shift = (gpio%32);
148
+
149
+ *(gpio_map+offset) |= (1 << shift);
150
+ short_wait();
151
+ *(gpio_map+offset) = 0;
152
+ }
153
+
154
+ int eventdetected(int gpio)
155
+ {
156
+ int offset, value, bit;
157
+
158
+ offset = EVENT_DETECT_OFFSET + (gpio/32);
159
+ bit = (1 << (gpio%32));
160
+ value = *(gpio_map+offset) & bit;
161
+ if (value) {
162
+ clear_event_detect(gpio);
163
+ }
164
+ return value;
165
+ }
166
+
167
+ void set_rising_event(int gpio, int enable)
168
+ {
169
+ int offset = RISING_ED_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_falling_event(int gpio, int enable)
181
+ {
182
+ int offset = FALLING_ED_OFFSET + (gpio/32);
183
+ int shift = (gpio%32);
184
+
185
+ if (enable) {
186
+ *(gpio_map+offset) |= (1 << shift);
187
+ *(gpio_map+offset) = (1 << shift);
188
+ } else {
189
+ *(gpio_map+offset) &= ~(1 << shift);
190
+ }
191
+ clear_event_detect(gpio);
192
+ }
193
+
194
+ void set_high_event(int gpio, int enable)
195
+ {
196
+ int offset = HIGH_DETECT_OFFSET + (gpio/32);
197
+ int shift = (gpio%32);
198
+
199
+ if (enable) {
200
+ *(gpio_map+offset) |= (1 << shift);
201
+ } else {
202
+ *(gpio_map+offset) &= ~(1 << shift);
203
+ }
204
+ clear_event_detect(gpio);
205
+ }
206
+
207
+ void set_low_event(int gpio, int enable)
208
+ {
209
+ int offset = LOW_DETECT_OFFSET + (gpio/32);
210
+ int shift = (gpio%32);
211
+
212
+ if (enable) {
213
+ *(gpio_map+offset) |= 1 << shift;
214
+ } else {
215
+ *(gpio_map+offset) &= ~(1 << shift);
216
+ }
217
+ clear_event_detect(gpio);
218
+ }
219
+
220
+ void set_pullupdn(int gpio, int pud)
221
+ {
222
+ int clk_offset = PULLUPDNCLK_OFFSET + (gpio/32);
223
+ int shift = (gpio%32);
224
+
225
+ if (pud == PUD_DOWN) {
226
+ *(gpio_map+PULLUPDN_OFFSET) = (*(gpio_map+PULLUPDN_OFFSET) & ~3) |
227
+ PUD_DOWN;
228
+ } else if (pud == PUD_UP) {
229
+ *(gpio_map+PULLUPDN_OFFSET) = (*(gpio_map+PULLUPDN_OFFSET) & ~3) | PUD_UP;
230
+ } else { // pud == PUD_OFF
231
+ *(gpio_map+PULLUPDN_OFFSET) &= ~3;
232
+ }
233
+
234
+ short_wait();
235
+ *(gpio_map+clk_offset) = 1 << shift;
236
+ short_wait();
237
+ *(gpio_map+PULLUPDN_OFFSET) &= ~3;
238
+ *(gpio_map+clk_offset) = 0;
239
+ }
240
+
241
+ void setup_gpio(int gpio, int direction, int pud)
242
+ {
243
+ int offset = FSEL_OFFSET + (gpio/10);
244
+ int shift = (gpio%10)*3;
245
+
246
+ set_pullupdn(gpio, pud);
247
+ if (direction == OUTPUT)
248
+ *(gpio_map+offset) = (*(gpio_map+offset) & ~(7<<shift)) | (1<<shift);
249
+ else // direction == INPUT
250
+ *(gpio_map+offset) = (*(gpio_map+offset) & ~(7<<shift));
251
+ }
252
+
253
+ // Contribution by Eric Ptak <trouch@trouch.com>
254
+ int gpio_function(int gpio)
255
+ {
256
+ int offset = FSEL_OFFSET + (gpio/10);
257
+ int shift = (gpio%10)*3;
258
+ int value = *(gpio_map+offset);
259
+ value >>= shift;
260
+ value &= 7;
261
+ return value; // 0=input, 1=output, 4=alt0
262
+ }
263
+
264
+ void output_gpio(int gpio, int value)
265
+ {
266
+ int offset, shift;
267
+
268
+ if (value) { // value == HIGH
269
+ offset = SET_OFFSET + (gpio/32);
270
+ } else { // value == LOW
271
+ offset = CLR_OFFSET + (gpio/32);
272
+ }
273
+
274
+ shift = (gpio%32);
275
+
276
+ *(gpio_map+offset) = 1 << shift;
277
+ }
278
+
279
+ int input_gpio(int gpio)
280
+ {
281
+ int offset, value, mask;
282
+
283
+ offset = PINLEVEL_OFFSET + (gpio/32);
284
+ mask = (1 << gpio%32);
285
+ value = *(gpio_map+offset) & mask;
286
+ return value;
287
+ }
288
+
289
+ void cleanup(void)
290
+ {
291
+ munmap((void *) gpio_map, BLOCK_SIZE);
292
+ }