-
Notifications
You must be signed in to change notification settings - Fork 51
/
gpio_rpi.c
163 lines (118 loc) · 3.31 KB
/
gpio_rpi.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
/* gpio.c D.J.Whale 8/07/2014
*
* gpiomem fix Achronite, Jan 2019
*
* A very simple interface to the GPIO port on the Raspberry Pi.
*/
/***** INCLUDES *****/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <time.h>
#include "gpio.h"
/***** CONSTANTS *****/
#define BCM2708_PERI_BASE 0x20000000
//#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */
#define GPIO_BASE_OFFSET 0x200000
#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)
/***** VARIABLES *****/
static int mem_fd;
static void *gpio_map;
static volatile unsigned *gpio;
const uint8_t gpio_sim=0; /* 0=> not simulated */
/****** MACROS *****/
#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
#define OUT_GPIO(g) *(gpio+((g)/10)) |= (1<<(((g)%10)*3))
#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
#define GPIO_SET *(gpio+7) // sets bits which are 1 ignores bits which are 0
#define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0
#define GPIO_READ(g) ((*(gpio+13)&(1<<g)) != 0)
#define GPIO_HIGH(g) GPIO_SET = (1<<(g))
#define GPIO_LOW(g) GPIO_CLR = (1<<(g))
void gpio_init()
{
uint32_t peri_base = BCM2708_PERI_BASE; /* default if device tree not found */
uint32_t gpio_base;
FILE* fp;
/* for RPi2, get peri-base from device tree */
if ((fp = fopen("/proc/device-tree/soc/ranges", "rb")) != NULL)
{
unsigned char buf[4];
fseek(fp, 4, SEEK_SET);
if (fread(buf, 1, sizeof(buf), fp) == sizeof(buf))
{
peri_base = buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3];
}
fclose(fp);
}
gpio_base = peri_base + GPIO_BASE_OFFSET;
/* open /dev/mem */
/* PTG: changed to use gpiomem first to avoid root */
if ((mem_fd = open("/dev/gpiomem", O_RDWR|O_SYNC) ) < 0)
{
if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0)
{
printf("can't open /dev/gpiomem or /dev/mem\n");
exit(-1); //TODO return a result code
}
}
/* mmap GPIO */
gpio_map = mmap(
NULL, //Any adddress in our space will do
BLOCK_SIZE, //Map length
PROT_READ|PROT_WRITE,// Enable reading & writting to mapped memory
MAP_SHARED, //Shared with other processes
mem_fd, //File to map
gpio_base //Offset to GPIO peripheral
);
close(mem_fd); //No need to keep mem_fd open after mmap
if (gpio_map == MAP_FAILED)
{
printf("mmap error %d\n", (int)gpio_map);//errno also set!
exit(-1); //TODO return a result code
}
// Always use volatile pointer!
gpio = (volatile unsigned *)gpio_map;
}
void gpio_setin(uint8_t g)
{
INP_GPIO(g);
}
void gpio_setout(uint8_t g)
{
/* always INP_GPIO before OUT_GPIO */
//INP_GPIO(g); #### this causes glitching
OUT_GPIO(g);
}
void gpio_high(uint8_t g)
{
GPIO_HIGH(g);
}
void gpio_low(uint8_t g)
{
GPIO_LOW(g);
}
void gpio_write(uint8_t g, uint8_t v)
{
if (v != 0)
{
GPIO_HIGH(g);
}
else
{
GPIO_LOW(g);
}
}
uint8_t gpio_read(uint8_t g)
{
return GPIO_READ(g);
}
void gpio_finished(void)
{
//TODO probably need gpio_finished() to unmmap() the memory region and clean up the peripheral?
}
/***** END OF FILE *****/