1 /*
2 minimal_gpio.c
3 2019-07-03
4 Public Domain
5
6 Original Site: http://abyz.me.uk/rpi/pigpio/examples.html
7
8 */
9
10 #include <stdio.h>
11 #include <unistd.h>
12 #include <stdint.h>
13 #include <string.h>
14 #include <fcntl.h>
15 #include <sys/mman.h>
16 #include <sys/stat.h>
17 #include <sys/types.h>
18
19 static volatile uint32_t piPeriphBase = 0x20000000;
20
21 static volatile int pi_is_2711 = 0;
22
23 #define SYST_BASE (piPeriphBase + 0x003000)
24 #define DMA_BASE (piPeriphBase + 0x007000)
25 #define CLK_BASE (piPeriphBase + 0x101000)
26 #define GPIO_BASE (piPeriphBase + 0x200000)
27 #define UART0_BASE (piPeriphBase + 0x201000)
28 #define PCM_BASE (piPeriphBase + 0x203000)
29 #define SPI0_BASE (piPeriphBase + 0x204000)
30 #define I2C0_BASE (piPeriphBase + 0x205000)
31 #define PWM_BASE (piPeriphBase + 0x20C000)
32 #define BSCS_BASE (piPeriphBase + 0x214000)
33 #define UART1_BASE (piPeriphBase + 0x215000)
34 #define I2C1_BASE (piPeriphBase + 0x804000)
35 #define I2C2_BASE (piPeriphBase + 0x805000)
36 #define DMA15_BASE (piPeriphBase + 0xE05000)
37
38 #define DMA_LEN 0x1000 /* allow access to all channels */
39 #define CLK_LEN 0xA8
40 #define GPIO_LEN 0xF4
41 #define SYST_LEN 0x1C
42 #define PCM_LEN 0x24
43 #define PWM_LEN 0x28
44 #define I2C_LEN 0x1C
45 #define BSCS_LEN 0x40
46
47 #define GPSET0 7
48 #define GPSET1 8
49
50 #define GPCLR0 10
51 #define GPCLR1 11
52
53 #define GPLEV0 13
54 #define GPLEV1 14
55
56 #define GPPUD 37
57 #define GPPUDCLK0 38
58 #define GPPUDCLK1 39
59
60 /* BCM2711 has different pulls */
61
62 #define GPPUPPDN0 57
63 #define GPPUPPDN1 58
64 #define GPPUPPDN2 59
65 #define GPPUPPDN3 60
66
67 #define SYST_CS 0
68 #define SYST_CLO 1
69 #define SYST_CHI 2
70
71 static volatile uint32_t *gpioReg = MAP_FAILED;
72 static volatile uint32_t *systReg = MAP_FAILED;
73 static volatile uint32_t *bscsReg = MAP_FAILED;
74
75 #define PI_BANK (gpio>>5)
76 #define PI_BIT (1<<(gpio&0x1F))
77
78 /* gpio modes. */
79
80 #define PI_INPUT 0
81 #define PI_OUTPUT 1
82 #define PI_ALT0 4
83 #define PI_ALT1 5
84 #define PI_ALT2 6
85 #define PI_ALT3 7
86 #define PI_ALT4 3
87 #define PI_ALT5 2
88
gpioSetMode(unsigned gpio,unsigned mode)89 void gpioSetMode(unsigned gpio, unsigned mode)
90 {
91 int reg, shift;
92
93 reg = gpio/10;
94 shift = (gpio%10) * 3;
95
96 gpioReg[reg] = (gpioReg[reg] & ~(7<<shift)) | (mode<<shift);
97 }
98
gpioGetMode(unsigned gpio)99 int gpioGetMode(unsigned gpio)
100 {
101 int reg, shift;
102
103 reg = gpio/10;
104 shift = (gpio%10) * 3;
105
106 return (*(gpioReg + reg) >> shift) & 7;
107 }
108
109 /* Values for pull-ups/downs off, pull-down and pull-up. */
110
111 #define PI_PUD_OFF 0
112 #define PI_PUD_DOWN 1
113 #define PI_PUD_UP 2
114
gpioSetPullUpDown(unsigned gpio,unsigned pud)115 void gpioSetPullUpDown(unsigned gpio, unsigned pud)
116 {
117 int shift = (gpio & 0xf) << 1;
118 uint32_t bits;
119 uint32_t pull = 0;
120
121 if (pi_is_2711)
122 {
123 switch (pud)
124 {
125 case PI_PUD_OFF: pull = 0; break;
126 case PI_PUD_UP: pull = 1; break;
127 case PI_PUD_DOWN: pull = 2; break;
128 }
129
130 bits = *(gpioReg + GPPUPPDN0 + (gpio>>4));
131 bits &= ~(3 << shift);
132 bits |= (pull << shift);
133 *(gpioReg + GPPUPPDN0 + (gpio>>4)) = bits;
134 }
135 else
136 {
137 *(gpioReg + GPPUD) = pud;
138
139 usleep(20);
140
141 *(gpioReg + GPPUDCLK0 + PI_BANK) = PI_BIT;
142
143 usleep(20);
144
145 *(gpioReg + GPPUD) = 0;
146
147 *(gpioReg + GPPUDCLK0 + PI_BANK) = 0;
148 }
149 }
150
gpioRead(unsigned gpio)151 int gpioRead(unsigned gpio)
152 {
153 if ((*(gpioReg + GPLEV0 + PI_BANK) & PI_BIT) != 0) return 1;
154 else return 0;
155 }
156
gpioWrite(unsigned gpio,unsigned level)157 void gpioWrite(unsigned gpio, unsigned level)
158 {
159 if (level == 0) *(gpioReg + GPCLR0 + PI_BANK) = PI_BIT;
160 else *(gpioReg + GPSET0 + PI_BANK) = PI_BIT;
161 }
162
gpioTrigger(unsigned gpio,unsigned pulseLen,unsigned level)163 void gpioTrigger(unsigned gpio, unsigned pulseLen, unsigned level)
164 {
165 if (level == 0) *(gpioReg + GPCLR0 + PI_BANK) = PI_BIT;
166 else *(gpioReg + GPSET0 + PI_BANK) = PI_BIT;
167
168 usleep(pulseLen);
169
170 if (level != 0) *(gpioReg + GPCLR0 + PI_BANK) = PI_BIT;
171 else *(gpioReg + GPSET0 + PI_BANK) = PI_BIT;
172 }
173
174 /* Bit (1<<x) will be set if gpio x is high. */
175
gpioReadBank1(void)176 uint32_t gpioReadBank1(void) { return (*(gpioReg + GPLEV0)); }
gpioReadBank2(void)177 uint32_t gpioReadBank2(void) { return (*(gpioReg + GPLEV1)); }
178
179 /* To clear gpio x bit or in (1<<x). */
180
gpioClearBank1(uint32_t bits)181 void gpioClearBank1(uint32_t bits) { *(gpioReg + GPCLR0) = bits; }
gpioClearBank2(uint32_t bits)182 void gpioClearBank2(uint32_t bits) { *(gpioReg + GPCLR1) = bits; }
183
184 /* To set gpio x bit or in (1<<x). */
185
gpioSetBank1(uint32_t bits)186 void gpioSetBank1(uint32_t bits) { *(gpioReg + GPSET0) = bits; }
gpioSetBank2(uint32_t bits)187 void gpioSetBank2(uint32_t bits) { *(gpioReg + GPSET1) = bits; }
188
gpioHardwareRevision(void)189 unsigned gpioHardwareRevision(void)
190 {
191 static unsigned rev = 0;
192
193 FILE *filp;
194 char buf[512];
195 char term;
196 int chars=4; /* number of chars in revision string */
197
198 filp = fopen ("/proc/cpuinfo", "r");
199
200 if (filp != NULL)
201 {
202 while (fgets(buf, sizeof(buf), filp) != NULL)
203 {
204 if (!strncasecmp("revision", buf, 8))
205 {
206 if (sscanf(buf+strlen(buf)-(chars+1),
207 "%x%c", &rev, &term) == 2)
208 {
209 if (term != '\n') rev = 0;
210 else rev &= 0xFFFFFF; /* mask out warranty bit */
211 }
212 }
213 }
214
215 fclose(filp);
216 }
217
218 filp = fopen("/proc/device-tree/soc/ranges" , "rb");
219
220 if (filp != NULL)
221 {
222 if (fread(buf, 1, sizeof(buf), filp) >= 8)
223 {
224 piPeriphBase = buf[4]<<24 | buf[5]<<16 | buf[6]<<8 | buf[7];
225 if (!piPeriphBase)
226 piPeriphBase = buf[8]<<24 | buf[9]<<16 | buf[10]<<8 | buf[11];
227
228 if (piPeriphBase == 0xFE000000) pi_is_2711 = 1;
229 }
230 fclose(filp);
231 }
232
233 return rev;
234 }
235
236 /* Returns the number of microseconds after system boot. Wraps around
237 after 1 hour 11 minutes 35 seconds.
238 */
239
gpioTick(void)240 uint32_t gpioTick(void) { return systReg[SYST_CLO]; }
241
242
243 /* Map in registers. */
244
initMapMem(int fd,uint32_t addr,uint32_t len)245 static uint32_t * initMapMem(int fd, uint32_t addr, uint32_t len)
246 {
247 return (uint32_t *) mmap(0, len,
248 PROT_READ|PROT_WRITE|PROT_EXEC,
249 MAP_SHARED|MAP_LOCKED,
250 fd, addr);
251 }
252
gpioInitialise(void)253 int gpioInitialise(void)
254 {
255 int fd;
256
257 gpioHardwareRevision(); /* sets rev and peripherals base address */
258
259 fd = open("/dev/mem", O_RDWR | O_SYNC) ;
260
261 if (fd < 0)
262 {
263 fprintf(stderr,
264 "This program needs root privileges. Try using sudo\n");
265 return -1;
266 }
267
268 gpioReg = initMapMem(fd, GPIO_BASE, GPIO_LEN);
269 systReg = initMapMem(fd, SYST_BASE, SYST_LEN);
270 bscsReg = initMapMem(fd, BSCS_BASE, BSCS_LEN);
271
272 close(fd);
273
274 if ((gpioReg == MAP_FAILED) ||
275 (systReg == MAP_FAILED) ||
276 (bscsReg == MAP_FAILED))
277 {
278 fprintf(stderr,
279 "Bad, mmap failed\n");
280 return -1;
281 }
282 return 0;
283 }
284