-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathc_gpio.c
executable file
·187 lines (165 loc) · 4.91 KB
/
c_gpio.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/*
* This file is part of RPIO.
*
* Copyright
*
* Copyright (C) 2013 Chris Hager <chris@linuxuser.at>
*
* License
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details at
* <http://www.gnu.org/licenses/lgpl-3.0-standalone.html>
*
* Documentation
*
* http://pythonhosted.org/RPIO
*
*
* c_gpio.c is based on RPi.GPIO by Ben Croston, and provides a Python interface to
* interact with the gpio-related C methods.
*/
#include <stdint.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include "c_gpio.h"
#include "cpuinfo.h"
#include <unistd.h>
//#define BCM2708_PERI_BASE 0x20000000
//#define BCM2709_PERI_BASE 0x3f000000
#define GPIO_BASE (peri_base + 0x200000)
#define OFFSET_FSEL 0 // 0x0000
#define OFFSET_SET 7 // 0x001c / 4
#define OFFSET_CLR 10 // 0x0028 / 4
#define OFFSET_PINLEVEL 13 // 0x0034 / 4
#define OFFSET_PULLUPDN 37 // 0x0094 / 4
#define OFFSET_PULLUPDNCLK 38 // 0x0098 / 4
// Event detection offsets disabled for now
//#define OFFSET_EVENT_DETECT 16 // 0x0040 / 4
//#define OFFSET_RISING_ED 19 // 0x004c / 4
//#define OFFSET_FALLING_ED 22 // 0x0058 / 4
//#define OFFSET_HIGH_DETECT 25 // 0x0064 / 4
//#define OFFSET_LOW_DETECT 28 // 0x0070 / 4
#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)
static volatile uint32_t *gpio_map;
static uint32_t peri_base;
// `short_wait` waits 150 cycles
void
short_wait(void)
{
int i;
for (i=0; i<150; i++) {
asm volatile("nop");
}
}
// `setup` is run when GPIO is imported in Python
int
setup(void)
{
int mem_fd, type;
char revision_hex[1024];
uint8_t *gpio_mem;
if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0)
return SETUP_DEVMEM_FAIL;
if ((gpio_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL)
return SETUP_MALLOC_FAIL;
if ((uint32_t)gpio_mem % PAGE_SIZE)
gpio_mem += PAGE_SIZE - ((uint32_t)gpio_mem % PAGE_SIZE);
// type = get_cpuinfo_revision(revision_hex);
peri_base = get_peri_base();
// if ((type & 0x100) == 0)
// peri_base = BCM2708_PERI_BASE;
// else
// peri_base = BCM2709_PERI_BASE;
gpio_map = (uint32_t *)mmap( (caddr_t)gpio_mem, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, mem_fd, GPIO_BASE);
if ((uint32_t)gpio_map < 0)
return SETUP_MMAP_FAIL;
return SETUP_OK;
}
// Sets a pullup or -down resistor on a GPIO
void
set_pullupdn(int gpio, int pud)
{
int clk_offset = OFFSET_PULLUPDNCLK + (gpio/32);
int shift = (gpio%32);
if (pud == PUD_DOWN)
*(gpio_map+OFFSET_PULLUPDN) = (*(gpio_map+OFFSET_PULLUPDN) & ~3) | PUD_DOWN;
else if (pud == PUD_UP)
*(gpio_map+OFFSET_PULLUPDN) = (*(gpio_map+OFFSET_PULLUPDN) & ~3) | PUD_UP;
else // pud == PUD_OFF
*(gpio_map+OFFSET_PULLUPDN) &= ~3;
short_wait();
*(gpio_map+clk_offset) = 1 << shift;
short_wait();
*(gpio_map+OFFSET_PULLUPDN) &= ~3;
*(gpio_map+clk_offset) = 0;
}
// Sets a GPIO to either output or input (input can have an optional pullup
// or -down resistor).
void
setup_gpio(int gpio, int direction, int pud)
{
int offset = OFFSET_FSEL + (gpio/10);
int shift = (gpio%10)*3;
set_pullupdn(gpio, pud);
if (direction == OUTPUT)
*(gpio_map+offset) = (*(gpio_map+offset) & ~(7<<shift)) | (1<<shift);
else // direction == INPUT
*(gpio_map+offset) = (*(gpio_map+offset) & ~(7<<shift));
}
// Returns the function of a GPIO: 0=input, 1=output, 4=alt0
// Contribution by Eric Ptak <trouch@trouch.com>
int
gpio_function(int gpio)
{
int offset = OFFSET_FSEL + (gpio/10);
int shift = (gpio%10)*3;
int value = *(gpio_map+offset);
value >>= shift;
value &= 7;
return value;
}
// Sets a GPIO output to 1 or 0
void
output_gpio(int gpio, int value)
{
int offset;
if (value) // value == HIGH
offset = OFFSET_SET + (gpio / 32);
else // value == LOW
offset = OFFSET_CLR + (gpio / 32);
*(gpio_map+offset) = 1 << gpio % 32;
}
// Returns the value of a GPIO input (1 or 0)
int
input_gpio(int gpio)
{
int offset, value, mask;
offset = OFFSET_PINLEVEL + (gpio/32);
mask = (1 << gpio%32);
value = *(gpio_map+offset) & mask;
return value;
}
void
cleanup(void)
{
// fixme - set all gpios back to input
munmap((caddr_t)gpio_map, BLOCK_SIZE);
}
/*
int main(int argc, char **argv){
setup();
setup_gpio(18, OUTPUT, PUD_DOWN);
output_gpio(18, atoi(argv[1]));
usleep(100 * 1000000);
cleanup();
}*/