summaryrefslogtreecommitdiffstats
path: root/python/native/gpio.c
diff options
context:
space:
mode:
Diffstat (limited to 'python/native/gpio.c')
-rw-r--r--python/native/gpio.c329
1 files changed, 329 insertions, 0 deletions
diff --git a/python/native/gpio.c b/python/native/gpio.c
new file mode 100644
index 0000000..3950b16
--- /dev/null
+++ b/python/native/gpio.c
@@ -0,0 +1,329 @@
1/*
2Copyright (c) 2012 Ben Croston / 2012-2013 Eric PTAK
3
4Permission is hereby granted, free of charge, to any person obtaining a copy of
5this software and associated documentation files (the "Software"), to deal in
6the Software without restriction, including without limitation the rights to
7use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8of the Software, and to permit persons to whom the Software is furnished to do
9so, subject to the following conditions:
10
11The above copyright notice and this permission notice shall be included in all
12copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20SOFTWARE.
21*/
22
23#include <stdint.h>
24#include <stdlib.h>
25#include <string.h>
26#include <fcntl.h>
27#include <sys/mman.h>
28#include <time.h>
29#include <pthread.h>
30#include "gpio.h"
31
32#define BCM2708_PERI_BASE 0x20000000
33#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000)
34#define FSEL_OFFSET 0 // 0x0000
35#define SET_OFFSET 7 // 0x001c / 4
36#define CLR_OFFSET 10 // 0x0028 / 4
37#define PINLEVEL_OFFSET 13 // 0x0034 / 4
38#define EVENT_DETECT_OFFSET 16 // 0x0040 / 4
39#define RISING_ED_OFFSET 19 // 0x004c / 4
40#define FALLING_ED_OFFSET 22 // 0x0058 / 4
41#define HIGH_DETECT_OFFSET 25 // 0x0064 / 4
42#define LOW_DETECT_OFFSET 28 // 0x0070 / 4
43#define PULLUPDN_OFFSET 37 // 0x0094 / 4
44#define PULLUPDNCLK_OFFSET 38 // 0x0098 / 4
45
46#define PAGE_SIZE (4*1024)
47#define BLOCK_SIZE (4*1024)
48
49static volatile uint32_t *gpio_map;
50
51struct tspair {
52 struct timespec up;
53 struct timespec down;
54};
55
56static struct pulse gpio_pulses[GPIO_COUNT];
57static struct tspair gpio_tspairs[GPIO_COUNT];
58static pthread_t *gpio_threads[GPIO_COUNT];
59
60void short_wait(void)
61{
62 int i;
63
64 for (i=0; i<150; i++) // wait 150 cycles
65 {
66 asm volatile("nop");
67 }
68}
69
70int setup(void)
71{
72 int mem_fd;
73 uint8_t *gpio_mem;
74
75 if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0)
76 {
77 return SETUP_DEVMEM_FAIL;
78 }
79
80 if ((gpio_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL)
81 return SETUP_MALLOC_FAIL;
82
83 if ((uint32_t)gpio_mem % PAGE_SIZE)
84 gpio_mem += PAGE_SIZE - ((uint32_t)gpio_mem % PAGE_SIZE);
85
86 gpio_map = (uint32_t *)mmap( (caddr_t)gpio_mem, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, mem_fd, GPIO_BASE);
87
88 if ((uint32_t)gpio_map < 0)
89 return SETUP_MMAP_FAIL;
90
91 return SETUP_OK;
92}
93
94void set_pullupdn(int gpio, int pud)
95{
96 int clk_offset = PULLUPDNCLK_OFFSET + (gpio/32);
97 int shift = (gpio%32);
98
99 if (pud == PUD_DOWN)
100 *(gpio_map+PULLUPDN_OFFSET) = (*(gpio_map+PULLUPDN_OFFSET) & ~3) | PUD_DOWN;
101 else if (pud == PUD_UP)
102 *(gpio_map+PULLUPDN_OFFSET) = (*(gpio_map+PULLUPDN_OFFSET) & ~3) | PUD_UP;
103 else // pud == PUD_OFF
104 *(gpio_map+PULLUPDN_OFFSET) &= ~3;
105
106 short_wait();
107 *(gpio_map+clk_offset) = 1 << shift;
108 short_wait();
109 *(gpio_map+PULLUPDN_OFFSET) &= ~3;
110 *(gpio_map+clk_offset) = 0;
111}
112
113//updated Eric PTAK - trouch.com
114void set_function(int gpio, int function, int pud)
115{
116 if (function == PWM) {
117 function = OUT;
118 enablePWM(gpio);
119 }
120 else {
121 disablePWM(gpio);
122 }
123
124 int offset = FSEL_OFFSET + (gpio/10);
125 int shift = (gpio%10)*3;
126
127 set_pullupdn(gpio, pud);
128 *(gpio_map+offset) = (*(gpio_map+offset) & ~(7<<shift)) | (function<<shift);
129}
130
131//added Eric PTAK - trouch.com
132int get_function(int gpio)
133{
134 int offset = FSEL_OFFSET + (gpio/10);
135 int shift = (gpio%10)*3;
136 int value = *(gpio_map+offset);
137 value >>= shift;
138 value &= 7;
139 if ((value == OUT) && isPWMEnabled(gpio)) {
140 value = PWM;
141 }
142 return value; // 0=input, 1=output, 4=alt0
143}
144
145//updated Eric PTAK - trouch.com
146int input(int gpio)
147{
148 int offset, value, mask;
149
150 offset = PINLEVEL_OFFSET + (gpio/32);
151 mask = (1 << gpio%32);
152 value = *(gpio_map+offset) & mask;
153 return value;
154}
155
156void output(int gpio, int value)
157{
158 int offset, shift;
159
160 if (value) // value == HIGH
161 offset = SET_OFFSET + (gpio/32);
162 else // value == LOW
163 offset = CLR_OFFSET + (gpio/32);
164
165 shift = (gpio%32);
166
167 *(gpio_map+offset) = 1 << shift;
168}
169
170//added Eric PTAK - trouch.com
171void outputSequence(int gpio, int period, char* sequence) {
172 int i, value;
173 struct timespec ts;
174 ts.tv_sec = period/1000;
175 ts.tv_nsec = (period%1000) * 1000000;
176
177 for (i=0; sequence[i] != '\0'; i++) {
178 if (sequence[i] == '1') {
179 value = 1;
180 }
181 else {
182 value = 0;
183 }
184 output(gpio, value);
185 nanosleep(&ts, NULL);
186 }
187}
188
189void resetPWM(int gpio) {
190 gpio_pulses[gpio].type = 0;
191 gpio_pulses[gpio].value = 0;
192
193 gpio_tspairs[gpio].up.tv_sec = 0;
194 gpio_tspairs[gpio].up.tv_nsec = 0;
195 gpio_tspairs[gpio].down.tv_sec = 0;
196 gpio_tspairs[gpio].down.tv_nsec = 0;
197}
198
199//added Eric PTAK - trouch.com
200void pulseTS(int gpio, struct timespec *up, struct timespec *down) {
201 if ((up->tv_sec > 0) || (up->tv_nsec > 0)) {
202 output(gpio, 1);
203 nanosleep(up, NULL);
204 }
205
206 if ((down->tv_sec > 0) || (down->tv_nsec > 0)) {
207 output(gpio, 0);
208 nanosleep(down, NULL);
209 }
210}
211
212//added Eric PTAK - trouch.com
213void pulseOrSaveTS(int gpio, struct timespec *up, struct timespec *down) {
214 if (gpio_threads[gpio] != NULL) {
215 memcpy(&gpio_tspairs[gpio].up, up, sizeof(struct timespec));
216 memcpy(&gpio_tspairs[gpio].down, down, sizeof(struct timespec));
217 }
218 else {
219 pulseTS(gpio, up, down);
220 }
221}
222
223//added Eric PTAK - trouch.com
224void pulseMilli(int gpio, int up, int down) {
225 struct timespec tsUP, tsDOWN;
226
227 tsUP.tv_sec = up/1000;
228 tsUP.tv_nsec = (up%1000) * 1000000;
229
230 tsDOWN.tv_sec = down/1000;
231 tsDOWN.tv_nsec = (down%1000) * 1000000;
232 pulseOrSaveTS(gpio, &tsUP, &tsDOWN);
233}
234
235//added Eric PTAK - trouch.com
236void pulseMilliRatio(int gpio, int width, float ratio) {
237 int up = ratio*width;
238 int down = width - up;
239 pulseMilli(gpio, up, down);
240}
241
242//added Eric PTAK - trouch.com
243void pulseMicro(int gpio, int up, int down) {
244 struct timespec tsUP, tsDOWN;
245
246 tsUP.tv_sec = 0;
247 tsUP.tv_nsec = up * 1000;
248
249 tsDOWN.tv_sec = 0;
250 tsDOWN.tv_nsec = down * 1000;
251 pulseOrSaveTS(gpio, &tsUP, &tsDOWN);
252}
253
254//added Eric PTAK - trouch.com
255void pulseMicroRatio(int gpio, int width, float ratio) {
256 int up = ratio*width;
257 int down = width - up;
258 pulseMicro(gpio, up, down);
259}
260
261//added Eric PTAK - trouch.com
262void pulseAngle(int gpio, float angle) {
263 gpio_pulses[gpio].type = ANGLE;
264 gpio_pulses[gpio].value = angle;
265 int up = 1520 + (angle*400)/45;
266 int down = 20000-up;
267 pulseMicro(gpio, up, down);
268}
269
270//added Eric PTAK - trouch.com
271void pulseRatio(int gpio, float ratio) {
272 gpio_pulses[gpio].type = RATIO;
273 gpio_pulses[gpio].value = ratio;
274 int up = ratio * 20000;
275 int down = 20000 - up;
276 pulseMicro(gpio, up, down);
277}
278
279struct pulse* getPulse(int gpio) {
280 return &gpio_pulses[gpio];
281}
282
283//added Eric PTAK - trouch.com
284void* pwmLoop(void* data) {
285 int gpio = (int)data;
286
287 while (1) {
288 pulseTS(gpio, &gpio_tspairs[gpio].up, &gpio_tspairs[gpio].down);
289 }
290}
291
292//added Eric PTAK - trouch.com
293void enablePWM(int gpio) {
294 pthread_t *thread = gpio_threads[gpio];
295 if (thread != NULL) {
296 return;
297 }
298
299 resetPWM(gpio);
300
301 thread = (pthread_t*) malloc(sizeof(pthread_t));
302 pthread_create(thread, NULL, pwmLoop, (void*)gpio);
303 gpio_threads[gpio] = thread;
304}
305
306//added Eric PTAK - trouch.com
307void disablePWM(int gpio) {
308 pthread_t *thread = gpio_threads[gpio];
309 if (thread == NULL) {
310 return;
311 }
312
313 pthread_cancel(*thread);
314 gpio_threads[gpio] = NULL;
315 output(gpio, 0);
316 resetPWM(gpio);
317}
318
319//added Eric PTAK - trouch.com
320int isPWMEnabled(int gpio) {
321 return gpio_threads[gpio] != NULL;
322}
323
324
325void cleanup(void)
326{
327 // fixme - set all gpios back to input
328 munmap((caddr_t)gpio_map, BLOCK_SIZE);
329}