pikeyd165 – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* bcm2835.c |
2 | // C and C++ support for Broadcom BCM 2835 as used in Raspberry Pi |
||
3 | // http://elinux.org/RPi_Low-level_peripherals |
||
4 | // http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf |
||
5 | // |
||
6 | // Author: Mike McCauley |
||
7 | // Copyright (C) 2011-2013 Mike McCauley |
||
8 | // $Id: bcm2835.c,v 1.28 2020/01/11 05:07:13 mikem Exp mikem $ |
||
9 | */ |
||
10 | |||
11 | // Needed to compile with gcc -std=c99, as reported by John Blaiklock. |
||
12 | #define _POSIX_C_SOURCE 200809L |
||
13 | |||
14 | #include <stdlib.h> |
||
15 | #include <stdio.h> |
||
16 | #include <errno.h> |
||
17 | #include <fcntl.h> |
||
18 | #include <sys/mman.h> |
||
19 | #include <string.h> |
||
20 | #include <time.h> |
||
21 | #include <unistd.h> |
||
22 | #include <sys/types.h> |
||
23 | |||
24 | #define BCK2835_LIBRARY_BUILD |
||
25 | #include "bcm2835.h" |
||
26 | |||
27 | /* This define enables a little test program (by default a blinking output on pin RPI_GPIO_PIN_11) |
||
28 | // You can do some safe, non-destructive testing on any platform with: |
||
29 | // gcc bcm2835.c -D BCM2835_TEST |
||
30 | // ./a.out |
||
31 | */ |
||
32 | /*#define BCM2835_TEST*/ |
||
33 | |||
34 | /* Uncommenting this define compiles alternative I2C code for the version 1 RPi |
||
35 | // The P1 header I2C pins are connected to SDA0 and SCL0 on V1. |
||
36 | // By default I2C code is generated for the V2 RPi which has SDA1 and SCL1 connected. |
||
37 | */ |
||
38 | /* #define I2C_V1*/ |
||
39 | |||
40 | /* Physical address and size of the peripherals block |
||
41 | // May be overridden on RPi2 |
||
42 | */ |
||
43 | off_t bcm2835_peripherals_base = BCM2835_PERI_BASE; |
||
44 | size_t bcm2835_peripherals_size = BCM2835_PERI_SIZE; |
||
45 | |||
46 | /* Virtual memory address of the mapped peripherals block |
||
47 | */ |
||
48 | uint32_t *bcm2835_peripherals = (uint32_t *)MAP_FAILED; |
||
49 | |||
50 | /* And the register bases within the peripherals block |
||
51 | */ |
||
52 | volatile uint32_t *bcm2835_gpio = (uint32_t *)MAP_FAILED; |
||
53 | volatile uint32_t *bcm2835_pwm = (uint32_t *)MAP_FAILED; |
||
54 | volatile uint32_t *bcm2835_clk = (uint32_t *)MAP_FAILED; |
||
55 | volatile uint32_t *bcm2835_pads = (uint32_t *)MAP_FAILED; |
||
56 | volatile uint32_t *bcm2835_spi0 = (uint32_t *)MAP_FAILED; |
||
57 | volatile uint32_t *bcm2835_bsc0 = (uint32_t *)MAP_FAILED; |
||
58 | volatile uint32_t *bcm2835_bsc1 = (uint32_t *)MAP_FAILED; |
||
59 | volatile uint32_t *bcm2835_st = (uint32_t *)MAP_FAILED; |
||
60 | volatile uint32_t *bcm2835_aux = (uint32_t *)MAP_FAILED; |
||
61 | volatile uint32_t *bcm2835_spi1 = (uint32_t *)MAP_FAILED; |
||
62 | /* BEB*/ |
||
63 | volatile uint32_t *bcm2835_smi = (uint32_t *)MAP_FAILED; |
||
64 | |||
65 | |||
66 | |||
67 | /* This variable allows us to test on hardware other than RPi. |
||
68 | // It prevents access to the kernel memory, and does not do any peripheral access |
||
69 | // Instead it prints out what it _would_ do if debug were 0 |
||
70 | */ |
||
71 | static uint8_t debug = 0; |
||
72 | |||
73 | /* RPI 4 has different pullup registers - we need to know if we have that type */ |
||
74 | |||
75 | static uint8_t pud_type_rpi4 = 0; |
||
76 | |||
77 | /* RPI 4 has different pullup operation - make backwards compat */ |
||
78 | |||
79 | static uint8_t pud_compat_setting = BCM2835_GPIO_PUD_OFF; |
||
80 | |||
81 | /* I2C The time needed to transmit one byte. In microseconds. |
||
82 | */ |
||
83 | static int i2c_byte_wait_us = 0; |
||
84 | |||
85 | /* SPI bit order. BCM2835 SPI0 only supports MSBFIRST, so we instead |
||
86 | * have a software based bit reversal, based on a contribution by Damiano Benedetti |
||
87 | */ |
||
88 | static uint8_t bcm2835_spi_bit_order = BCM2835_SPI_BIT_ORDER_MSBFIRST; |
||
89 | static uint8_t bcm2835_byte_reverse_table[] = |
||
90 | { |
||
91 | 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, |
||
92 | 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, |
||
93 | 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, |
||
94 | 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, |
||
95 | 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, |
||
96 | 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, |
||
97 | 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, |
||
98 | 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, |
||
99 | 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, |
||
100 | 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, |
||
101 | 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, |
||
102 | 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, |
||
103 | 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, |
||
104 | 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, |
||
105 | 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, |
||
106 | 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, |
||
107 | 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, |
||
108 | 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, |
||
109 | 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, |
||
110 | 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, |
||
111 | 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, |
||
112 | 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, |
||
113 | 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, |
||
114 | 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, |
||
115 | 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, |
||
116 | 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, |
||
117 | 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, |
||
118 | 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, |
||
119 | 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, |
||
120 | 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, |
||
121 | 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, |
||
122 | 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff |
||
123 | }; |
||
124 | |||
125 | static uint8_t bcm2835_correct_order(uint8_t b) |
||
126 | { |
||
127 | if (bcm2835_spi_bit_order == BCM2835_SPI_BIT_ORDER_LSBFIRST) |
||
128 | return bcm2835_byte_reverse_table[b]; |
||
129 | else |
||
130 | return b; |
||
131 | } |
||
132 | |||
133 | #ifdef BCM2835_HAVE_LIBCAP |
||
134 | #include <sys/capability.h> |
||
135 | static int bcm2835_has_capability(cap_value_t capability) |
||
136 | { |
||
137 | int ok = 0; |
||
138 | cap_t cap = cap_get_proc(); |
||
139 | if (cap) |
||
140 | { |
||
141 | cap_flag_value_t value; |
||
142 | if (cap_get_flag(cap,capability,CAP_EFFECTIVE,&value) == 0 && value == CAP_SET) |
||
143 | ok = 1; |
||
144 | cap_free(cap); |
||
145 | } |
||
146 | return ok; |
||
147 | } |
||
148 | #endif |
||
149 | |||
150 | /* |
||
151 | // Low level register access functions |
||
152 | */ |
||
153 | |||
154 | /* Function to return the pointers to the hardware register bases */ |
||
155 | uint32_t* bcm2835_regbase(uint8_t regbase) |
||
156 | { |
||
157 | switch (regbase) |
||
158 | { |
||
159 | case BCM2835_REGBASE_ST: |
||
160 | return (uint32_t *)bcm2835_st; |
||
161 | case BCM2835_REGBASE_GPIO: |
||
162 | return (uint32_t *)bcm2835_gpio; |
||
163 | case BCM2835_REGBASE_PWM: |
||
164 | return (uint32_t *)bcm2835_pwm; |
||
165 | case BCM2835_REGBASE_CLK: |
||
166 | return (uint32_t *)bcm2835_clk; |
||
167 | case BCM2835_REGBASE_PADS: |
||
168 | return (uint32_t *)bcm2835_pads; |
||
169 | case BCM2835_REGBASE_SPI0: |
||
170 | return (uint32_t *)bcm2835_spi0; |
||
171 | case BCM2835_REGBASE_BSC0: |
||
172 | return (uint32_t *)bcm2835_bsc0; |
||
173 | case BCM2835_REGBASE_BSC1: |
||
174 | return (uint32_t *)bcm2835_st; |
||
175 | case BCM2835_REGBASE_AUX: |
||
176 | return (uint32_t *)bcm2835_aux; |
||
177 | case BCM2835_REGBASE_SPI1: |
||
178 | return (uint32_t *)bcm2835_spi1; |
||
179 | /* BEB */ |
||
180 | case BCM2835_REGBASE_SMI: |
||
181 | return (uint32_t *)bcm2835_smi; |
||
182 | |||
183 | |||
184 | } |
||
185 | return (uint32_t *)MAP_FAILED; |
||
186 | } |
||
187 | |||
188 | void bcm2835_set_debug(uint8_t d) |
||
189 | { |
||
190 | debug = d; |
||
191 | } |
||
192 | |||
193 | unsigned int bcm2835_version(void) |
||
194 | { |
||
195 | return BCM2835_VERSION; |
||
196 | } |
||
197 | |||
198 | /* Read with memory barriers from peripheral |
||
199 | * |
||
200 | */ |
||
201 | uint32_t bcm2835_peri_read(volatile uint32_t* paddr) |
||
202 | { |
||
203 | uint32_t ret; |
||
204 | if (debug) |
||
205 | { |
||
206 | printf("bcm2835_peri_read paddr %p\n", (void *) paddr); |
||
207 | return 0; |
||
208 | } |
||
209 | else |
||
210 | { |
||
211 | __sync_synchronize(); |
||
212 | ret = *paddr; |
||
213 | __sync_synchronize(); |
||
214 | return ret; |
||
215 | } |
||
216 | } |
||
217 | |||
218 | /* read from peripheral without the read barrier |
||
219 | * This can only be used if more reads to THE SAME peripheral |
||
220 | * will follow. The sequence must terminate with memory barrier |
||
221 | * before any read or write to another peripheral can occur. |
||
222 | * The MB can be explicit, or one of the barrier read/write calls. |
||
223 | */ |
||
224 | uint32_t bcm2835_peri_read_nb(volatile uint32_t* paddr) |
||
225 | { |
||
226 | if (debug) |
||
227 | { |
||
228 | printf("bcm2835_peri_read_nb paddr %p\n", paddr); |
||
229 | return 0; |
||
230 | } |
||
231 | else |
||
232 | { |
||
233 | return *paddr; |
||
234 | } |
||
235 | } |
||
236 | |||
237 | /* Write with memory barriers to peripheral |
||
238 | */ |
||
239 | |||
240 | void bcm2835_peri_write(volatile uint32_t* paddr, uint32_t value) |
||
241 | { |
||
242 | if (debug) |
||
243 | { |
||
244 | printf("bcm2835_peri_write paddr %p, value %08X\n", paddr, value); |
||
245 | } |
||
246 | else |
||
247 | { |
||
248 | __sync_synchronize(); |
||
249 | *paddr = value; |
||
250 | __sync_synchronize(); |
||
251 | } |
||
252 | } |
||
253 | |||
254 | /* write to peripheral without the write barrier */ |
||
255 | void bcm2835_peri_write_nb(volatile uint32_t* paddr, uint32_t value) |
||
256 | { |
||
257 | if (debug) |
||
258 | { |
||
259 | printf("bcm2835_peri_write_nb paddr %p, value %08X\n", |
||
260 | paddr, value); |
||
261 | } |
||
262 | else |
||
263 | { |
||
264 | *paddr = value; |
||
265 | } |
||
266 | } |
||
267 | |||
268 | /* Set/clear only the bits in value covered by the mask |
||
269 | * This is not atomic - can be interrupted. |
||
270 | */ |
||
271 | void bcm2835_peri_set_bits(volatile uint32_t* paddr, uint32_t value, uint32_t mask) |
||
272 | { |
||
273 | uint32_t v = bcm2835_peri_read(paddr); |
||
274 | v = (v & ~mask) | (value & mask); |
||
275 | bcm2835_peri_write(paddr, v); |
||
276 | } |
||
277 | |||
278 | /* |
||
279 | // Low level convenience functions |
||
280 | */ |
||
281 | |||
282 | /* Function select |
||
283 | // pin is a BCM2835 GPIO pin number NOT RPi pin number |
||
284 | // There are 6 control registers, each control the functions of a block |
||
285 | // of 10 pins. |
||
286 | // Each control register has 10 sets of 3 bits per GPIO pin: |
||
287 | // |
||
288 | // 000 = GPIO Pin X is an input |
||
289 | // 001 = GPIO Pin X is an output |
||
290 | // 100 = GPIO Pin X takes alternate function 0 |
||
291 | // 101 = GPIO Pin X takes alternate function 1 |
||
292 | // 110 = GPIO Pin X takes alternate function 2 |
||
293 | // 111 = GPIO Pin X takes alternate function 3 |
||
294 | // 011 = GPIO Pin X takes alternate function 4 |
||
295 | // 010 = GPIO Pin X takes alternate function 5 |
||
296 | // |
||
297 | // So the 3 bits for port X are: |
||
298 | // X / 10 + ((X % 10) * 3) |
||
299 | */ |
||
300 | void bcm2835_gpio_fsel(uint8_t pin, uint8_t mode) |
||
301 | { |
||
302 | /* Function selects are 10 pins per 32 bit word, 3 bits per pin */ |
||
303 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPFSEL0/4 + (pin/10); |
||
304 | uint8_t shift = (pin % 10) * 3; |
||
305 | uint32_t mask = BCM2835_GPIO_FSEL_MASK << shift; |
||
306 | uint32_t value = mode << shift; |
||
307 | bcm2835_peri_set_bits(paddr, value, mask); |
||
308 | } |
||
309 | |||
310 | /* Set output pin */ |
||
311 | void bcm2835_gpio_set(uint8_t pin) |
||
312 | { |
||
313 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPSET0/4 + pin/32; |
||
314 | uint8_t shift = pin % 32; |
||
315 | bcm2835_peri_write(paddr, 1 << shift); |
||
316 | } |
||
317 | |||
318 | /* Clear output pin */ |
||
319 | void bcm2835_gpio_clr(uint8_t pin) |
||
320 | { |
||
321 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPCLR0/4 + pin/32; |
||
322 | uint8_t shift = pin % 32; |
||
323 | bcm2835_peri_write(paddr, 1 << shift); |
||
324 | } |
||
325 | |||
326 | /* Set all output pins in the mask */ |
||
327 | void bcm2835_gpio_set_multi(uint32_t mask) |
||
328 | { |
||
329 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPSET0/4; |
||
330 | bcm2835_peri_write(paddr, mask); |
||
331 | } |
||
332 | |||
333 | /* Clear all output pins in the mask */ |
||
334 | void bcm2835_gpio_clr_multi(uint32_t mask) |
||
335 | { |
||
336 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPCLR0/4; |
||
337 | bcm2835_peri_write(paddr, mask); |
||
338 | } |
||
339 | |||
340 | /* Read input pin */ |
||
341 | uint8_t bcm2835_gpio_lev(uint8_t pin) |
||
342 | { |
||
343 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPLEV0/4 + pin/32; |
||
344 | uint8_t shift = pin % 32; |
||
345 | uint32_t value = bcm2835_peri_read(paddr); |
||
346 | return (value & (1 << shift)) ? HIGH : LOW; |
||
347 | } |
||
348 | |||
349 | /* See if an event detection bit is set |
||
350 | // Sigh cant support interrupts yet |
||
351 | */ |
||
352 | uint8_t bcm2835_gpio_eds(uint8_t pin) |
||
353 | { |
||
354 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPEDS0/4 + pin/32; |
||
355 | uint8_t shift = pin % 32; |
||
356 | uint32_t value = bcm2835_peri_read(paddr); |
||
357 | return (value & (1 << shift)) ? HIGH : LOW; |
||
358 | } |
||
359 | |||
360 | uint32_t bcm2835_gpio_eds_multi(uint32_t mask) |
||
361 | { |
||
362 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPEDS0/4; |
||
363 | uint32_t value = bcm2835_peri_read(paddr); |
||
364 | return (value & mask); |
||
365 | } |
||
366 | |||
367 | /* Write a 1 to clear the bit in EDS */ |
||
368 | void bcm2835_gpio_set_eds(uint8_t pin) |
||
369 | { |
||
370 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPEDS0/4 + pin/32; |
||
371 | uint8_t shift = pin % 32; |
||
372 | uint32_t value = 1 << shift; |
||
373 | bcm2835_peri_write(paddr, value); |
||
374 | } |
||
375 | |||
376 | void bcm2835_gpio_set_eds_multi(uint32_t mask) |
||
377 | { |
||
378 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPEDS0/4; |
||
379 | bcm2835_peri_write(paddr, mask); |
||
380 | } |
||
381 | |||
382 | /* Rising edge detect enable */ |
||
383 | void bcm2835_gpio_ren(uint8_t pin) |
||
384 | { |
||
385 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPREN0/4 + pin/32; |
||
386 | uint8_t shift = pin % 32; |
||
387 | uint32_t value = 1 << shift; |
||
388 | bcm2835_peri_set_bits(paddr, value, value); |
||
389 | } |
||
390 | void bcm2835_gpio_clr_ren(uint8_t pin) |
||
391 | { |
||
392 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPREN0/4 + pin/32; |
||
393 | uint8_t shift = pin % 32; |
||
394 | uint32_t value = 1 << shift; |
||
395 | bcm2835_peri_set_bits(paddr, 0, value); |
||
396 | } |
||
397 | |||
398 | /* Falling edge detect enable */ |
||
399 | void bcm2835_gpio_fen(uint8_t pin) |
||
400 | { |
||
401 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPFEN0/4 + pin/32; |
||
402 | uint8_t shift = pin % 32; |
||
403 | uint32_t value = 1 << shift; |
||
404 | bcm2835_peri_set_bits(paddr, value, value); |
||
405 | } |
||
406 | void bcm2835_gpio_clr_fen(uint8_t pin) |
||
407 | { |
||
408 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPFEN0/4 + pin/32; |
||
409 | uint8_t shift = pin % 32; |
||
410 | uint32_t value = 1 << shift; |
||
411 | bcm2835_peri_set_bits(paddr, 0, value); |
||
412 | } |
||
413 | |||
414 | /* High detect enable */ |
||
415 | void bcm2835_gpio_hen(uint8_t pin) |
||
416 | { |
||
417 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPHEN0/4 + pin/32; |
||
418 | uint8_t shift = pin % 32; |
||
419 | uint32_t value = 1 << shift; |
||
420 | bcm2835_peri_set_bits(paddr, value, value); |
||
421 | } |
||
422 | void bcm2835_gpio_clr_hen(uint8_t pin) |
||
423 | { |
||
424 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPHEN0/4 + pin/32; |
||
425 | uint8_t shift = pin % 32; |
||
426 | uint32_t value = 1 << shift; |
||
427 | bcm2835_peri_set_bits(paddr, 0, value); |
||
428 | } |
||
429 | |||
430 | /* Low detect enable */ |
||
431 | void bcm2835_gpio_len(uint8_t pin) |
||
432 | { |
||
433 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPLEN0/4 + pin/32; |
||
434 | uint8_t shift = pin % 32; |
||
435 | uint32_t value = 1 << shift; |
||
436 | bcm2835_peri_set_bits(paddr, value, value); |
||
437 | } |
||
438 | void bcm2835_gpio_clr_len(uint8_t pin) |
||
439 | { |
||
440 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPLEN0/4 + pin/32; |
||
441 | uint8_t shift = pin % 32; |
||
442 | uint32_t value = 1 << shift; |
||
443 | bcm2835_peri_set_bits(paddr, 0, value); |
||
444 | } |
||
445 | |||
446 | /* Async rising edge detect enable */ |
||
447 | void bcm2835_gpio_aren(uint8_t pin) |
||
448 | { |
||
449 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPAREN0/4 + pin/32; |
||
450 | uint8_t shift = pin % 32; |
||
451 | uint32_t value = 1 << shift; |
||
452 | bcm2835_peri_set_bits(paddr, value, value); |
||
453 | } |
||
454 | void bcm2835_gpio_clr_aren(uint8_t pin) |
||
455 | { |
||
456 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPAREN0/4 + pin/32; |
||
457 | uint8_t shift = pin % 32; |
||
458 | uint32_t value = 1 << shift; |
||
459 | bcm2835_peri_set_bits(paddr, 0, value); |
||
460 | } |
||
461 | |||
462 | /* Async falling edge detect enable */ |
||
463 | void bcm2835_gpio_afen(uint8_t pin) |
||
464 | { |
||
465 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPAFEN0/4 + pin/32; |
||
466 | uint8_t shift = pin % 32; |
||
467 | uint32_t value = 1 << shift; |
||
468 | bcm2835_peri_set_bits(paddr, value, value); |
||
469 | } |
||
470 | void bcm2835_gpio_clr_afen(uint8_t pin) |
||
471 | { |
||
472 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPAFEN0/4 + pin/32; |
||
473 | uint8_t shift = pin % 32; |
||
474 | uint32_t value = 1 << shift; |
||
475 | bcm2835_peri_set_bits(paddr, 0, value); |
||
476 | } |
||
477 | |||
478 | /* Set pullup/down */ |
||
479 | void bcm2835_gpio_pud(uint8_t pud) |
||
480 | { |
||
481 | if( pud_type_rpi4 ) |
||
482 | { |
||
483 | pud_compat_setting = pud; |
||
484 | } |
||
485 | else { |
||
486 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPPUD/4; |
||
487 | bcm2835_peri_write(paddr, pud); |
||
488 | } |
||
489 | } |
||
490 | |||
491 | /* Pullup/down clock |
||
492 | // Clocks the value of pud into the GPIO pin |
||
493 | */ |
||
494 | void bcm2835_gpio_pudclk(uint8_t pin, uint8_t on) |
||
495 | { |
||
496 | if( pud_type_rpi4 ) |
||
497 | { |
||
498 | if( on ) |
||
499 | bcm2835_gpio_set_pud( pin, pud_compat_setting); |
||
500 | } |
||
501 | else |
||
502 | { |
||
503 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPPUDCLK0/4 + pin/32; |
||
504 | uint8_t shift = pin % 32; |
||
505 | bcm2835_peri_write(paddr, (on ? 1 : 0) << shift); |
||
506 | } |
||
507 | } |
||
508 | |||
509 | /* Read GPIO pad behaviour for groups of GPIOs */ |
||
510 | uint32_t bcm2835_gpio_pad(uint8_t group) |
||
511 | { |
||
512 | if (bcm2835_pads == MAP_FAILED) |
||
513 | return 0; |
||
514 | |||
515 | volatile uint32_t* paddr = bcm2835_pads + BCM2835_PADS_GPIO_0_27/4 + group; |
||
516 | return bcm2835_peri_read(paddr); |
||
517 | } |
||
518 | |||
519 | /* Set GPIO pad behaviour for groups of GPIOs |
||
520 | // powerup value for all pads is |
||
521 | // BCM2835_PAD_SLEW_RATE_UNLIMITED | BCM2835_PAD_HYSTERESIS_ENABLED | BCM2835_PAD_DRIVE_8mA |
||
522 | */ |
||
523 | void bcm2835_gpio_set_pad(uint8_t group, uint32_t control) |
||
524 | { |
||
525 | if (bcm2835_pads == MAP_FAILED) |
||
526 | return; |
||
527 | |||
528 | volatile uint32_t* paddr = bcm2835_pads + BCM2835_PADS_GPIO_0_27/4 + group; |
||
529 | bcm2835_peri_write(paddr, control | BCM2835_PAD_PASSWRD); |
||
530 | } |
||
531 | |||
532 | /* Some convenient arduino-like functions |
||
533 | // milliseconds |
||
534 | */ |
||
535 | void bcm2835_delay(unsigned int millis) |
||
536 | { |
||
537 | struct timespec sleeper; |
||
538 | |||
539 | sleeper.tv_sec = (time_t)(millis / 1000); |
||
540 | sleeper.tv_nsec = (long)(millis % 1000) * 1000000; |
||
541 | nanosleep(&sleeper, NULL); |
||
542 | } |
||
543 | |||
544 | /* microseconds */ |
||
545 | void bcm2835_delayMicroseconds(uint64_t micros) |
||
546 | { |
||
547 | struct timespec t1; |
||
548 | uint64_t start; |
||
549 | |||
550 | if (debug) |
||
551 | { |
||
552 | /* Cant access sytem timers in debug mode */ |
||
553 | printf("bcm2835_delayMicroseconds %lld\n", (long long int) micros); |
||
554 | return; |
||
555 | } |
||
556 | |||
557 | /* Calling nanosleep() takes at least 100-200 us, so use it for |
||
558 | // long waits and use a busy wait on the System Timer for the rest. |
||
559 | */ |
||
560 | start = bcm2835_st_read(); |
||
561 | |||
562 | /* Not allowed to access timer registers (result is not as precise)*/ |
||
563 | if (start==0) |
||
564 | { |
||
565 | t1.tv_sec = 0; |
||
566 | t1.tv_nsec = 1000 * (long)(micros); |
||
567 | nanosleep(&t1, NULL); |
||
568 | return; |
||
569 | } |
||
570 | |||
571 | if (micros > 450) |
||
572 | { |
||
573 | t1.tv_sec = 0; |
||
574 | t1.tv_nsec = 1000 * (long)(micros - 200); |
||
575 | nanosleep(&t1, NULL); |
||
576 | } |
||
577 | |||
578 | bcm2835_st_delay(start, micros); |
||
579 | } |
||
580 | |||
581 | /* |
||
582 | // Higher level convenience functions |
||
583 | */ |
||
584 | |||
585 | /* Set the state of an output */ |
||
586 | void bcm2835_gpio_write(uint8_t pin, uint8_t on) |
||
587 | { |
||
588 | if (on) |
||
589 | bcm2835_gpio_set(pin); |
||
590 | else |
||
591 | bcm2835_gpio_clr(pin); |
||
592 | } |
||
593 | |||
594 | /* Set the state of a all 32 outputs in the mask to on or off */ |
||
595 | void bcm2835_gpio_write_multi(uint32_t mask, uint8_t on) |
||
596 | { |
||
597 | if (on) |
||
598 | bcm2835_gpio_set_multi(mask); |
||
599 | else |
||
600 | bcm2835_gpio_clr_multi(mask); |
||
601 | } |
||
602 | |||
603 | /* Set the state of a all 32 outputs in the mask to the values in value */ |
||
604 | void bcm2835_gpio_write_mask(uint32_t value, uint32_t mask) |
||
605 | { |
||
606 | bcm2835_gpio_set_multi(value & mask); |
||
607 | bcm2835_gpio_clr_multi((~value) & mask); |
||
608 | } |
||
609 | |||
610 | /* Set the pullup/down resistor for a pin |
||
611 | // |
||
612 | // The GPIO Pull-up/down Clock Registers control the actuation of internal pull-downs on |
||
613 | // the respective GPIO pins. These registers must be used in conjunction with the GPPUD |
||
614 | // register to effect GPIO Pull-up/down changes. The following sequence of events is |
||
615 | // required: |
||
616 | // 1. Write to GPPUD to set the required control signal (i.e. Pull-up or Pull-Down or neither |
||
617 | // to remove the current Pull-up/down) |
||
618 | // 2. Wait 150 cycles ? this provides the required set-up time for the control signal |
||
619 | // 3. Write to GPPUDCLK0/1 to clock the control signal into the GPIO pads you wish to |
||
620 | // modify ? NOTE only the pads which receive a clock will be modified, all others will |
||
621 | // retain their previous state. |
||
622 | // 4. Wait 150 cycles ? this provides the required hold time for the control signal |
||
623 | // 5. Write to GPPUD to remove the control signal |
||
624 | // 6. Write to GPPUDCLK0/1 to remove the clock |
||
625 | // |
||
626 | // RPi has P1-03 and P1-05 with 1k8 pullup resistor |
||
627 | // |
||
628 | // RPI 4 uses a different PUD method - no clock |
||
629 | |||
630 | */ |
||
631 | void bcm2835_gpio_set_pud(uint8_t pin, uint8_t pud) |
||
632 | { |
||
633 | if( pud_type_rpi4 ) |
||
634 | { |
||
635 | int shiftbits = (pin & 0xf) << 1; |
||
636 | uint32_t bits; |
||
637 | uint32_t pull; |
||
638 | |||
639 | switch (pud) |
||
640 | { |
||
641 | case BCM2835_GPIO_PUD_OFF: pull = 0; break; |
||
642 | case BCM2835_GPIO_PUD_UP: pull = 1; break; |
||
643 | case BCM2835_GPIO_PUD_DOWN: pull = 2; break; |
||
644 | default: return; |
||
645 | } |
||
646 | |||
647 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPPUPPDN0/4 + (pin >> 4); |
||
648 | |||
649 | bits = bcm2835_peri_read_nb( paddr ); |
||
650 | bits &= ~(3 << shiftbits); |
||
651 | bits |= (pull << shiftbits); |
||
652 | |||
653 | bcm2835_peri_write_nb( paddr, bits ); |
||
654 | |||
655 | } else |
||
656 | { |
||
657 | bcm2835_gpio_pud(pud); |
||
658 | delayMicroseconds(10); |
||
659 | bcm2835_gpio_pudclk(pin, 1); |
||
660 | delayMicroseconds(10); |
||
661 | bcm2835_gpio_pud(BCM2835_GPIO_PUD_OFF); |
||
662 | bcm2835_gpio_pudclk(pin, 0); |
||
663 | } |
||
664 | |||
665 | } |
||
666 | |||
667 | |||
668 | uint8_t bcm2835_gpio_get_pud(uint8_t pin) |
||
669 | { |
||
670 | uint8_t ret = BCM2835_GPIO_PUD_ERROR; |
||
671 | |||
672 | if( pud_type_rpi4 ) |
||
673 | { |
||
674 | uint32_t bits; |
||
675 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPPUPPDN0/4 + (pin >> 4); |
||
676 | bits = (bcm2835_peri_read_nb( paddr ) >> ((pin & 0xf)<<1)) & 0x3; |
||
677 | |||
678 | switch (bits) |
||
679 | { |
||
680 | case 0: ret = BCM2835_GPIO_PUD_OFF; break; |
||
681 | case 1: ret = BCM2835_GPIO_PUD_UP; break; |
||
682 | case 2: ret = BCM2835_GPIO_PUD_DOWN; break; |
||
683 | default: ret = BCM2835_GPIO_PUD_ERROR; |
||
684 | } |
||
685 | } |
||
686 | |||
687 | return ret; |
||
688 | } |
||
689 | |||
690 | static void bcm2835_aux_spi_reset(void) |
||
691 | { |
||
692 | volatile uint32_t* cntl0 = bcm2835_spi1 + BCM2835_AUX_SPI_CNTL0/4; |
||
693 | volatile uint32_t* cntl1 = bcm2835_spi1 + BCM2835_AUX_SPI_CNTL1/4; |
||
694 | |||
695 | bcm2835_peri_write(cntl1, 0); |
||
696 | bcm2835_peri_write(cntl0, BCM2835_AUX_SPI_CNTL0_CLEARFIFO); |
||
697 | } |
||
698 | |||
699 | int bcm2835_spi_begin(void) |
||
700 | { |
||
701 | volatile uint32_t* paddr; |
||
702 | |||
703 | if (bcm2835_spi0 == MAP_FAILED) |
||
704 | return 0; /* bcm2835_init() failed, or not root */ |
||
705 | |||
706 | /* Set the SPI0 pins to the Alt 0 function to enable SPI0 access on them */ |
||
707 | bcm2835_gpio_fsel(RPI_GPIO_P1_26, BCM2835_GPIO_FSEL_ALT0); /* CE1 */ |
||
708 | bcm2835_gpio_fsel(RPI_GPIO_P1_24, BCM2835_GPIO_FSEL_ALT0); /* CE0 */ |
||
709 | bcm2835_gpio_fsel(RPI_GPIO_P1_21, BCM2835_GPIO_FSEL_ALT0); /* MISO */ |
||
710 | bcm2835_gpio_fsel(RPI_GPIO_P1_19, BCM2835_GPIO_FSEL_ALT0); /* MOSI */ |
||
711 | bcm2835_gpio_fsel(RPI_GPIO_P1_23, BCM2835_GPIO_FSEL_ALT0); /* CLK */ |
||
712 | |||
713 | /* Set the SPI CS register to the some sensible defaults */ |
||
714 | paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; |
||
715 | bcm2835_peri_write(paddr, 0); /* All 0s */ |
||
716 | |||
717 | /* Clear TX and RX fifos */ |
||
718 | bcm2835_peri_write_nb(paddr, BCM2835_SPI0_CS_CLEAR); |
||
719 | |||
720 | return 1; // OK |
||
721 | } |
||
722 | |||
723 | void bcm2835_spi_end(void) |
||
724 | { |
||
725 | /* Set all the SPI0 pins back to input */ |
||
726 | bcm2835_gpio_fsel(RPI_GPIO_P1_26, BCM2835_GPIO_FSEL_INPT); /* CE1 */ |
||
727 | bcm2835_gpio_fsel(RPI_GPIO_P1_24, BCM2835_GPIO_FSEL_INPT); /* CE0 */ |
||
728 | bcm2835_gpio_fsel(RPI_GPIO_P1_21, BCM2835_GPIO_FSEL_INPT); /* MISO */ |
||
729 | bcm2835_gpio_fsel(RPI_GPIO_P1_19, BCM2835_GPIO_FSEL_INPT); /* MOSI */ |
||
730 | bcm2835_gpio_fsel(RPI_GPIO_P1_23, BCM2835_GPIO_FSEL_INPT); /* CLK */ |
||
731 | } |
||
732 | |||
733 | void bcm2835_spi_setBitOrder(uint8_t order) |
||
734 | { |
||
735 | bcm2835_spi_bit_order = order; |
||
736 | } |
||
737 | |||
738 | /* defaults to 0, which means a divider of 65536. |
||
739 | // The divisor must be a power of 2. Odd numbers |
||
740 | // rounded down. The maximum SPI clock rate is |
||
741 | // of the APB clock |
||
742 | */ |
||
743 | void bcm2835_spi_setClockDivider(uint16_t divider) |
||
744 | { |
||
745 | volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CLK/4; |
||
746 | bcm2835_peri_write(paddr, divider); |
||
747 | } |
||
748 | |||
749 | void bcm2835_spi_set_speed_hz(uint32_t speed_hz) |
||
750 | { |
||
751 | uint16_t divider = (uint16_t) ((uint32_t) BCM2835_CORE_CLK_HZ / speed_hz); |
||
752 | divider &= 0xFFFE; |
||
753 | bcm2835_spi_setClockDivider(divider); |
||
754 | } |
||
755 | |||
756 | void bcm2835_spi_setDataMode(uint8_t mode) |
||
757 | { |
||
758 | volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; |
||
759 | /* Mask in the CPO and CPHA bits of CS */ |
||
760 | bcm2835_peri_set_bits(paddr, mode << 2, BCM2835_SPI0_CS_CPOL | BCM2835_SPI0_CS_CPHA); |
||
761 | } |
||
762 | |||
763 | /* Writes (and reads) a single byte to SPI */ |
||
764 | uint8_t bcm2835_spi_transfer(uint8_t value) |
||
765 | { |
||
766 | volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; |
||
767 | volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4; |
||
768 | uint32_t ret; |
||
769 | |||
770 | /* This is Polled transfer as per section 10.6.1 |
||
771 | // BUG ALERT: what happens if we get interupted in this section, and someone else |
||
772 | // accesses a different peripheral? |
||
773 | // Clear TX and RX fifos |
||
774 | */ |
||
775 | bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR); |
||
776 | |||
777 | /* Set TA = 1 */ |
||
778 | bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA); |
||
779 | |||
780 | /* Maybe wait for TXD */ |
||
781 | while (!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD)) |
||
782 | ; |
||
783 | |||
784 | /* Write to FIFO, no barrier */ |
||
785 | bcm2835_peri_write_nb(fifo, bcm2835_correct_order(value)); |
||
786 | |||
787 | /* Wait for DONE to be set */ |
||
788 | while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE)) |
||
789 | ; |
||
790 | |||
791 | /* Read any byte that was sent back by the slave while we sere sending to it */ |
||
792 | ret = bcm2835_correct_order(bcm2835_peri_read_nb(fifo)); |
||
793 | |||
794 | /* Set TA = 0, and also set the barrier */ |
||
795 | bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA); |
||
796 | |||
797 | return ret; |
||
798 | } |
||
799 | |||
800 | /* Writes (and reads) an number of bytes to SPI */ |
||
801 | void bcm2835_spi_transfernb(char* tbuf, char* rbuf, uint32_t len) |
||
802 | { |
||
803 | volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; |
||
804 | volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4; |
||
805 | uint32_t TXCnt=0; |
||
806 | uint32_t RXCnt=0; |
||
807 | |||
808 | /* This is Polled transfer as per section 10.6.1 |
||
809 | // BUG ALERT: what happens if we get interupted in this section, and someone else |
||
810 | // accesses a different peripheral? |
||
811 | */ |
||
812 | |||
813 | /* Clear TX and RX fifos */ |
||
814 | bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR); |
||
815 | |||
816 | /* Set TA = 1 */ |
||
817 | bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA); |
||
818 | |||
819 | /* Use the FIFO's to reduce the interbyte times */ |
||
820 | while((TXCnt < len)||(RXCnt < len)) |
||
821 | { |
||
822 | /* TX fifo not full, so add some more bytes */ |
||
823 | while(((bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD))&&(TXCnt < len )) |
||
824 | { |
||
825 | bcm2835_peri_write_nb(fifo, bcm2835_correct_order(tbuf[TXCnt])); |
||
826 | TXCnt++; |
||
827 | } |
||
828 | /* Rx fifo not empty, so get the next received bytes */ |
||
829 | while(((bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD))&&( RXCnt < len )) |
||
830 | { |
||
831 | rbuf[RXCnt] = bcm2835_correct_order(bcm2835_peri_read_nb(fifo)); |
||
832 | RXCnt++; |
||
833 | } |
||
834 | } |
||
835 | /* Wait for DONE to be set */ |
||
836 | while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE)) |
||
837 | ; |
||
838 | |||
839 | /* Set TA = 0, and also set the barrier */ |
||
840 | bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA); |
||
841 | } |
||
842 | |||
843 | /* Writes an number of bytes to SPI */ |
||
844 | void bcm2835_spi_writenb(const char* tbuf, uint32_t len) |
||
845 | { |
||
846 | volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; |
||
847 | volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4; |
||
848 | uint32_t i; |
||
849 | |||
850 | /* This is Polled transfer as per section 10.6.1 |
||
851 | // BUG ALERT: what happens if we get interupted in this section, and someone else |
||
852 | // accesses a different peripheral? |
||
853 | // Answer: an ISR is required to issue the required memory barriers. |
||
854 | */ |
||
855 | |||
856 | /* Clear TX and RX fifos */ |
||
857 | bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR); |
||
858 | |||
859 | /* Set TA = 1 */ |
||
860 | bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA); |
||
861 | |||
862 | for (i = 0; i < len; i++) |
||
863 | { |
||
864 | /* Maybe wait for TXD */ |
||
865 | while (!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD)) |
||
866 | ; |
||
867 | |||
868 | /* Write to FIFO, no barrier */ |
||
869 | bcm2835_peri_write_nb(fifo, bcm2835_correct_order(tbuf[i])); |
||
870 | |||
871 | /* Read from FIFO to prevent stalling */ |
||
872 | while (bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD) |
||
873 | (void) bcm2835_peri_read_nb(fifo); |
||
874 | } |
||
875 | |||
876 | /* Wait for DONE to be set */ |
||
877 | while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE)) { |
||
878 | while (bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD) |
||
879 | (void) bcm2835_peri_read_nb(fifo); |
||
880 | }; |
||
881 | |||
882 | /* Set TA = 0, and also set the barrier */ |
||
883 | bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA); |
||
884 | } |
||
885 | |||
886 | /* Writes (and reads) an number of bytes to SPI |
||
887 | // Read bytes are copied over onto the transmit buffer |
||
888 | */ |
||
889 | void bcm2835_spi_transfern(char* buf, uint32_t len) |
||
890 | { |
||
891 | bcm2835_spi_transfernb(buf, buf, len); |
||
892 | } |
||
893 | |||
894 | void bcm2835_spi_chipSelect(uint8_t cs) |
||
895 | { |
||
896 | volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; |
||
897 | /* Mask in the CS bits of CS */ |
||
898 | bcm2835_peri_set_bits(paddr, cs, BCM2835_SPI0_CS_CS); |
||
899 | } |
||
900 | |||
901 | void bcm2835_spi_setChipSelectPolarity(uint8_t cs, uint8_t active) |
||
902 | { |
||
903 | volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; |
||
904 | uint8_t shift = 21 + cs; |
||
905 | /* Mask in the appropriate CSPOLn bit */ |
||
906 | bcm2835_peri_set_bits(paddr, active << shift, 1 << shift); |
||
907 | } |
||
908 | |||
909 | void bcm2835_spi_write(uint16_t data) |
||
910 | { |
||
911 | #if 0 |
||
912 | char buf[2]; |
||
913 | |||
914 | buf[0] = data >> 8; |
||
915 | buf[1] = data & 0xFF; |
||
916 | |||
917 | bcm2835_spi_transfern(buf, 2); |
||
918 | #else |
||
919 | volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; |
||
920 | volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4; |
||
921 | |||
922 | /* Clear TX and RX fifos */ |
||
923 | bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR); |
||
924 | |||
925 | /* Set TA = 1 */ |
||
926 | bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA); |
||
927 | |||
928 | /* Maybe wait for TXD */ |
||
929 | while (!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD)) |
||
930 | ; |
||
931 | |||
932 | /* Write to FIFO */ |
||
933 | bcm2835_peri_write_nb(fifo, (uint32_t) data >> 8); |
||
934 | bcm2835_peri_write_nb(fifo, data & 0xFF); |
||
935 | |||
936 | |||
937 | /* Wait for DONE to be set */ |
||
938 | while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE)) |
||
939 | ; |
||
940 | |||
941 | /* Set TA = 0, and also set the barrier */ |
||
942 | bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA); |
||
943 | #endif |
||
944 | } |
||
945 | |||
946 | int bcm2835_aux_spi_begin(void) |
||
947 | { |
||
948 | volatile uint32_t* enable = bcm2835_aux + BCM2835_AUX_ENABLE/4; |
||
949 | volatile uint32_t* cntl0 = bcm2835_spi1 + BCM2835_AUX_SPI_CNTL0/4; |
||
950 | volatile uint32_t* cntl1 = bcm2835_spi1 + BCM2835_AUX_SPI_CNTL1/4; |
||
951 | |||
952 | if (bcm2835_spi1 == MAP_FAILED) |
||
953 | return 0; /* bcm2835_init() failed, or not root */ |
||
954 | |||
955 | /* Set the SPI pins to the Alt 4 function to enable SPI1 access on them */ |
||
956 | bcm2835_gpio_fsel(RPI_V2_GPIO_P1_36, BCM2835_GPIO_FSEL_ALT4); /* SPI1_CE2_N */ |
||
957 | bcm2835_gpio_fsel(RPI_V2_GPIO_P1_35, BCM2835_GPIO_FSEL_ALT4); /* SPI1_MISO */ |
||
958 | bcm2835_gpio_fsel(RPI_V2_GPIO_P1_38, BCM2835_GPIO_FSEL_ALT4); /* SPI1_MOSI */ |
||
959 | bcm2835_gpio_fsel(RPI_V2_GPIO_P1_40, BCM2835_GPIO_FSEL_ALT4); /* SPI1_SCLK */ |
||
960 | |||
961 | bcm2835_aux_spi_setClockDivider(bcm2835_aux_spi_CalcClockDivider(1000000)); // Default 1MHz SPI |
||
962 | |||
963 | bcm2835_peri_write(enable, BCM2835_AUX_ENABLE_SPI0); |
||
964 | bcm2835_peri_write(cntl1, 0); |
||
965 | bcm2835_peri_write(cntl0, BCM2835_AUX_SPI_CNTL0_CLEARFIFO); |
||
966 | |||
967 | return 1; /* OK */ |
||
968 | } |
||
969 | |||
970 | void bcm2835_aux_spi_end(void) |
||
971 | { |
||
972 | /* Set all the SPI1 pins back to input */ |
||
973 | bcm2835_gpio_fsel(RPI_V2_GPIO_P1_36, BCM2835_GPIO_FSEL_INPT); /* SPI1_CE2_N */ |
||
974 | bcm2835_gpio_fsel(RPI_V2_GPIO_P1_35, BCM2835_GPIO_FSEL_INPT); /* SPI1_MISO */ |
||
975 | bcm2835_gpio_fsel(RPI_V2_GPIO_P1_38, BCM2835_GPIO_FSEL_INPT); /* SPI1_MOSI */ |
||
976 | bcm2835_gpio_fsel(RPI_V2_GPIO_P1_40, BCM2835_GPIO_FSEL_INPT); /* SPI1_SCLK */ |
||
977 | } |
||
978 | |||
979 | #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) |
||
980 | |||
981 | uint16_t bcm2835_aux_spi_CalcClockDivider(uint32_t speed_hz) |
||
982 | { |
||
983 | uint16_t divider; |
||
984 | |||
985 | if (speed_hz < (uint32_t) BCM2835_AUX_SPI_CLOCK_MIN) { |
||
986 | speed_hz = (uint32_t) BCM2835_AUX_SPI_CLOCK_MIN; |
||
987 | } else if (speed_hz > (uint32_t) BCM2835_AUX_SPI_CLOCK_MAX) { |
||
988 | speed_hz = (uint32_t) BCM2835_AUX_SPI_CLOCK_MAX; |
||
989 | } |
||
990 | |||
991 | divider = (uint16_t) DIV_ROUND_UP(BCM2835_CORE_CLK_HZ, 2 * speed_hz) - 1; |
||
992 | |||
993 | if (divider > (uint16_t) BCM2835_AUX_SPI_CNTL0_SPEED_MAX) { |
||
994 | return (uint16_t) BCM2835_AUX_SPI_CNTL0_SPEED_MAX; |
||
995 | } |
||
996 | |||
997 | return divider; |
||
998 | } |
||
999 | |||
1000 | static uint32_t spi1_speed; |
||
1001 | |||
1002 | void bcm2835_aux_spi_setClockDivider(uint16_t divider) |
||
1003 | { |
||
1004 | spi1_speed = (uint32_t) divider; |
||
1005 | } |
||
1006 | |||
1007 | void bcm2835_aux_spi_write(uint16_t data) |
||
1008 | { |
||
1009 | volatile uint32_t* cntl0 = bcm2835_spi1 + BCM2835_AUX_SPI_CNTL0/4; |
||
1010 | volatile uint32_t* cntl1 = bcm2835_spi1 + BCM2835_AUX_SPI_CNTL1/4; |
||
1011 | volatile uint32_t* stat = bcm2835_spi1 + BCM2835_AUX_SPI_STAT/4; |
||
1012 | volatile uint32_t* io = bcm2835_spi1 + BCM2835_AUX_SPI_IO/4; |
||
1013 | |||
1014 | uint32_t _cntl0 = (spi1_speed << BCM2835_AUX_SPI_CNTL0_SPEED_SHIFT); |
||
1015 | _cntl0 |= BCM2835_AUX_SPI_CNTL0_CS2_N; |
||
1016 | _cntl0 |= BCM2835_AUX_SPI_CNTL0_ENABLE; |
||
1017 | _cntl0 |= BCM2835_AUX_SPI_CNTL0_MSBF_OUT; |
||
1018 | _cntl0 |= 16; // Shift length |
||
1019 | |||
1020 | bcm2835_peri_write(cntl0, _cntl0); |
||
1021 | bcm2835_peri_write(cntl1, BCM2835_AUX_SPI_CNTL1_MSBF_IN); |
||
1022 | |||
1023 | while (bcm2835_peri_read(stat) & BCM2835_AUX_SPI_STAT_TX_FULL) |
||
1024 | ; |
||
1025 | |||
1026 | bcm2835_peri_write(io, (uint32_t) data << 16); |
||
1027 | } |
||
1028 | |||
1029 | void bcm2835_aux_spi_writenb(const char *tbuf, uint32_t len) { |
||
1030 | volatile uint32_t* cntl0 = bcm2835_spi1 + BCM2835_AUX_SPI_CNTL0/4; |
||
1031 | volatile uint32_t* cntl1 = bcm2835_spi1 + BCM2835_AUX_SPI_CNTL1/4; |
||
1032 | volatile uint32_t* stat = bcm2835_spi1 + BCM2835_AUX_SPI_STAT/4; |
||
1033 | volatile uint32_t* txhold = bcm2835_spi1 + BCM2835_AUX_SPI_TXHOLD/4; |
||
1034 | volatile uint32_t* io = bcm2835_spi1 + BCM2835_AUX_SPI_IO/4; |
||
1035 | |||
1036 | char *tx = (char *) tbuf; |
||
1037 | uint32_t tx_len = len; |
||
1038 | uint32_t count; |
||
1039 | uint32_t data; |
||
1040 | uint32_t i; |
||
1041 | uint8_t byte; |
||
1042 | |||
1043 | uint32_t _cntl0 = (spi1_speed << BCM2835_AUX_SPI_CNTL0_SPEED_SHIFT); |
||
1044 | _cntl0 |= BCM2835_AUX_SPI_CNTL0_CS2_N; |
||
1045 | _cntl0 |= BCM2835_AUX_SPI_CNTL0_ENABLE; |
||
1046 | _cntl0 |= BCM2835_AUX_SPI_CNTL0_MSBF_OUT; |
||
1047 | _cntl0 |= BCM2835_AUX_SPI_CNTL0_VAR_WIDTH; |
||
1048 | |||
1049 | bcm2835_peri_write(cntl0, _cntl0); |
||
1050 | bcm2835_peri_write(cntl1, BCM2835_AUX_SPI_CNTL1_MSBF_IN); |
||
1051 | |||
1052 | while (tx_len > 0) { |
||
1053 | |||
1054 | while (bcm2835_peri_read(stat) & BCM2835_AUX_SPI_STAT_TX_FULL) |
||
1055 | ; |
||
1056 | |||
1057 | count = MIN(tx_len, 3); |
||
1058 | data = 0; |
||
1059 | |||
1060 | for (i = 0; i < count; i++) { |
||
1061 | byte = (tx != NULL) ? (uint8_t) *tx++ : (uint8_t) 0; |
||
1062 | data |= byte << (8 * (2 - i)); |
||
1063 | } |
||
1064 | |||
1065 | data |= (count * 8) << 24; |
||
1066 | tx_len -= count; |
||
1067 | |||
1068 | if (tx_len != 0) { |
||
1069 | bcm2835_peri_write(txhold, data); |
||
1070 | } else { |
||
1071 | bcm2835_peri_write(io, data); |
||
1072 | } |
||
1073 | |||
1074 | while (bcm2835_peri_read(stat) & BCM2835_AUX_SPI_STAT_BUSY) |
||
1075 | ; |
||
1076 | |||
1077 | (void) bcm2835_peri_read(io); |
||
1078 | } |
||
1079 | } |
||
1080 | |||
1081 | void bcm2835_aux_spi_transfernb(const char *tbuf, char *rbuf, uint32_t len) { |
||
1082 | volatile uint32_t* cntl0 = bcm2835_spi1 + BCM2835_AUX_SPI_CNTL0/4; |
||
1083 | volatile uint32_t* cntl1 = bcm2835_spi1 + BCM2835_AUX_SPI_CNTL1/4; |
||
1084 | volatile uint32_t* stat = bcm2835_spi1 + BCM2835_AUX_SPI_STAT/4; |
||
1085 | volatile uint32_t* txhold = bcm2835_spi1 + BCM2835_AUX_SPI_TXHOLD/4; |
||
1086 | volatile uint32_t* io = bcm2835_spi1 + BCM2835_AUX_SPI_IO/4; |
||
1087 | |||
1088 | char *tx = (char *)tbuf; |
||
1089 | char *rx = (char *)rbuf; |
||
1090 | uint32_t tx_len = len; |
||
1091 | uint32_t rx_len = len; |
||
1092 | uint32_t count; |
||
1093 | uint32_t data; |
||
1094 | uint32_t i; |
||
1095 | uint8_t byte; |
||
1096 | |||
1097 | uint32_t _cntl0 = (spi1_speed << BCM2835_AUX_SPI_CNTL0_SPEED_SHIFT); |
||
1098 | _cntl0 |= BCM2835_AUX_SPI_CNTL0_CS2_N; |
||
1099 | _cntl0 |= BCM2835_AUX_SPI_CNTL0_ENABLE; |
||
1100 | _cntl0 |= BCM2835_AUX_SPI_CNTL0_MSBF_OUT; |
||
1101 | _cntl0 |= BCM2835_AUX_SPI_CNTL0_VAR_WIDTH; |
||
1102 | |||
1103 | bcm2835_peri_write(cntl0, _cntl0); |
||
1104 | bcm2835_peri_write(cntl1, BCM2835_AUX_SPI_CNTL1_MSBF_IN); |
||
1105 | |||
1106 | while ((tx_len > 0) || (rx_len > 0)) { |
||
1107 | |||
1108 | while (!(bcm2835_peri_read(stat) & BCM2835_AUX_SPI_STAT_TX_FULL) && (tx_len > 0)) { |
||
1109 | count = MIN(tx_len, 3); |
||
1110 | data = 0; |
||
1111 | |||
1112 | for (i = 0; i < count; i++) { |
||
1113 | byte = (tx != NULL) ? (uint8_t) *tx++ : (uint8_t) 0; |
||
1114 | data |= byte << (8 * (2 - i)); |
||
1115 | } |
||
1116 | |||
1117 | data |= (count * 8) << 24; |
||
1118 | tx_len -= count; |
||
1119 | |||
1120 | if (tx_len != 0) { |
||
1121 | bcm2835_peri_write(txhold, data); |
||
1122 | } else { |
||
1123 | bcm2835_peri_write(io, data); |
||
1124 | } |
||
1125 | |||
1126 | } |
||
1127 | |||
1128 | while (!(bcm2835_peri_read(stat) & BCM2835_AUX_SPI_STAT_RX_EMPTY) && (rx_len > 0)) { |
||
1129 | count = MIN(rx_len, 3); |
||
1130 | data = bcm2835_peri_read(io); |
||
1131 | |||
1132 | if (rbuf != NULL) { |
||
1133 | switch (count) { |
||
1134 | case 3: |
||
1135 | *rx++ = (char)((data >> 16) & 0xFF); |
||
1136 | /*@fallthrough@*/ |
||
1137 | /* no break */ |
||
1138 | case 2: |
||
1139 | *rx++ = (char)((data >> 8) & 0xFF); |
||
1140 | /*@fallthrough@*/ |
||
1141 | /* no break */ |
||
1142 | case 1: |
||
1143 | *rx++ = (char)((data >> 0) & 0xFF); |
||
1144 | } |
||
1145 | } |
||
1146 | |||
1147 | rx_len -= count; |
||
1148 | } |
||
1149 | |||
1150 | while (!(bcm2835_peri_read(stat) & BCM2835_AUX_SPI_STAT_BUSY) && (rx_len > 0)) { |
||
1151 | count = MIN(rx_len, 3); |
||
1152 | data = bcm2835_peri_read(io); |
||
1153 | |||
1154 | if (rbuf != NULL) { |
||
1155 | switch (count) { |
||
1156 | case 3: |
||
1157 | *rx++ = (char)((data >> 16) & 0xFF); |
||
1158 | /*@fallthrough@*/ |
||
1159 | /* no break */ |
||
1160 | case 2: |
||
1161 | *rx++ = (char)((data >> 8) & 0xFF); |
||
1162 | /*@fallthrough@*/ |
||
1163 | /* no break */ |
||
1164 | case 1: |
||
1165 | *rx++ = (char)((data >> 0) & 0xFF); |
||
1166 | } |
||
1167 | } |
||
1168 | |||
1169 | rx_len -= count; |
||
1170 | } |
||
1171 | } |
||
1172 | } |
||
1173 | |||
1174 | void bcm2835_aux_spi_transfern(char *buf, uint32_t len) { |
||
1175 | bcm2835_aux_spi_transfernb(buf, buf, len); |
||
1176 | } |
||
1177 | |||
1178 | /* Writes (and reads) a single byte to AUX SPI */ |
||
1179 | uint8_t bcm2835_aux_spi_transfer(uint8_t value) |
||
1180 | { |
||
1181 | volatile uint32_t* cntl0 = bcm2835_spi1 + BCM2835_AUX_SPI_CNTL0/4; |
||
1182 | volatile uint32_t* cntl1 = bcm2835_spi1 + BCM2835_AUX_SPI_CNTL1/4; |
||
1183 | volatile uint32_t* stat = bcm2835_spi1 + BCM2835_AUX_SPI_STAT/4; |
||
1184 | volatile uint32_t* io = bcm2835_spi1 + BCM2835_AUX_SPI_IO/4; |
||
1185 | |||
1186 | uint32_t data; |
||
1187 | |||
1188 | uint32_t _cntl0 = (spi1_speed << BCM2835_AUX_SPI_CNTL0_SPEED_SHIFT); |
||
1189 | _cntl0 |= BCM2835_AUX_SPI_CNTL0_CS2_N; |
||
1190 | _cntl0 |= BCM2835_AUX_SPI_CNTL0_ENABLE; |
||
1191 | _cntl0 |= BCM2835_AUX_SPI_CNTL0_MSBF_OUT; |
||
1192 | _cntl0 |= BCM2835_AUX_SPI_CNTL0_CPHA_IN; |
||
1193 | _cntl0 |= 8; // Shift length. |
||
1194 | |||
1195 | uint32_t _cntl1 = BCM2835_AUX_SPI_CNTL1_MSBF_IN; |
||
1196 | |||
1197 | bcm2835_peri_write(cntl1, _cntl1); |
||
1198 | bcm2835_peri_write(cntl0, _cntl0); |
||
1199 | |||
1200 | bcm2835_peri_write(io, (uint32_t) bcm2835_correct_order(value) << 24); |
||
1201 | |||
1202 | while (bcm2835_peri_read(stat) & BCM2835_AUX_SPI_STAT_BUSY) |
||
1203 | ; |
||
1204 | |||
1205 | data = bcm2835_correct_order(bcm2835_peri_read(io) & 0xff); |
||
1206 | |||
1207 | bcm2835_aux_spi_reset(); |
||
1208 | |||
1209 | return data; |
||
1210 | } |
||
1211 | |||
1212 | |||
1213 | int bcm2835_i2c_begin(void) |
||
1214 | { |
||
1215 | uint16_t cdiv; |
||
1216 | |||
1217 | if ( bcm2835_bsc0 == MAP_FAILED |
||
1218 | || bcm2835_bsc1 == MAP_FAILED) |
||
1219 | return 0; /* bcm2835_init() failed, or not root */ |
||
1220 | |||
1221 | #ifdef I2C_V1 |
||
1222 | volatile uint32_t* paddr = bcm2835_bsc0 + BCM2835_BSC_DIV/4; |
||
1223 | /* Set the I2C/BSC0 pins to the Alt 0 function to enable I2C access on them */ |
||
1224 | bcm2835_gpio_fsel(RPI_GPIO_P1_03, BCM2835_GPIO_FSEL_ALT0); /* SDA */ |
||
1225 | bcm2835_gpio_fsel(RPI_GPIO_P1_05, BCM2835_GPIO_FSEL_ALT0); /* SCL */ |
||
1226 | #else |
||
1227 | volatile uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_DIV/4; |
||
1228 | /* Set the I2C/BSC1 pins to the Alt 0 function to enable I2C access on them */ |
||
1229 | bcm2835_gpio_fsel(RPI_V2_GPIO_P1_03, BCM2835_GPIO_FSEL_ALT0); /* SDA */ |
||
1230 | bcm2835_gpio_fsel(RPI_V2_GPIO_P1_05, BCM2835_GPIO_FSEL_ALT0); /* SCL */ |
||
1231 | #endif |
||
1232 | |||
1233 | /* Read the clock divider register */ |
||
1234 | cdiv = bcm2835_peri_read(paddr); |
||
1235 | /* Calculate time for transmitting one byte |
||
1236 | // 1000000 = micros seconds in a second |
||
1237 | // 9 = Clocks per byte : 8 bits + ACK |
||
1238 | */ |
||
1239 | i2c_byte_wait_us = ((float)cdiv / BCM2835_CORE_CLK_HZ) * 1000000 * 9; |
||
1240 | |||
1241 | return 1; |
||
1242 | } |
||
1243 | |||
1244 | void bcm2835_i2c_end(void) |
||
1245 | { |
||
1246 | #ifdef I2C_V1 |
||
1247 | /* Set all the I2C/BSC0 pins back to input */ |
||
1248 | bcm2835_gpio_fsel(RPI_GPIO_P1_03, BCM2835_GPIO_FSEL_INPT); /* SDA */ |
||
1249 | bcm2835_gpio_fsel(RPI_GPIO_P1_05, BCM2835_GPIO_FSEL_INPT); /* SCL */ |
||
1250 | #else |
||
1251 | /* Set all the I2C/BSC1 pins back to input */ |
||
1252 | bcm2835_gpio_fsel(RPI_V2_GPIO_P1_03, BCM2835_GPIO_FSEL_INPT); /* SDA */ |
||
1253 | bcm2835_gpio_fsel(RPI_V2_GPIO_P1_05, BCM2835_GPIO_FSEL_INPT); /* SCL */ |
||
1254 | #endif |
||
1255 | } |
||
1256 | |||
1257 | void bcm2835_i2c_setSlaveAddress(uint8_t addr) |
||
1258 | { |
||
1259 | /* Set I2C Device Address */ |
||
1260 | #ifdef I2C_V1 |
||
1261 | volatile uint32_t* paddr = bcm2835_bsc0 + BCM2835_BSC_A/4; |
||
1262 | #else |
||
1263 | volatile uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_A/4; |
||
1264 | #endif |
||
1265 | bcm2835_peri_write(paddr, addr); |
||
1266 | } |
||
1267 | |||
1268 | /* defaults to 0x5dc, should result in a 166.666 kHz I2C clock frequency. |
||
1269 | // The divisor must be a power of 2. Odd numbers |
||
1270 | // rounded down. |
||
1271 | */ |
||
1272 | void bcm2835_i2c_setClockDivider(uint16_t divider) |
||
1273 | { |
||
1274 | #ifdef I2C_V1 |
||
1275 | volatile uint32_t* paddr = bcm2835_bsc0 + BCM2835_BSC_DIV/4; |
||
1276 | #else |
||
1277 | volatile uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_DIV/4; |
||
1278 | #endif |
||
1279 | bcm2835_peri_write(paddr, divider); |
||
1280 | /* Calculate time for transmitting one byte |
||
1281 | // 1000000 = micros seconds in a second |
||
1282 | // 9 = Clocks per byte : 8 bits + ACK |
||
1283 | */ |
||
1284 | i2c_byte_wait_us = ((float)divider / BCM2835_CORE_CLK_HZ) * 1000000 * 9; |
||
1285 | } |
||
1286 | |||
1287 | /* set I2C clock divider by means of a baudrate number */ |
||
1288 | void bcm2835_i2c_set_baudrate(uint32_t baudrate) |
||
1289 | { |
||
1290 | uint32_t divider; |
||
1291 | /* use 0xFFFE mask to limit a max value and round down any odd number */ |
||
1292 | divider = (BCM2835_CORE_CLK_HZ / baudrate) & 0xFFFE; |
||
1293 | bcm2835_i2c_setClockDivider( (uint16_t)divider ); |
||
1294 | } |
||
1295 | |||
1296 | /* Writes an number of bytes to I2C */ |
||
1297 | uint8_t bcm2835_i2c_write(const char * buf, uint32_t len) |
||
1298 | { |
||
1299 | #ifdef I2C_V1 |
||
1300 | volatile uint32_t* dlen = bcm2835_bsc0 + BCM2835_BSC_DLEN/4; |
||
1301 | volatile uint32_t* fifo = bcm2835_bsc0 + BCM2835_BSC_FIFO/4; |
||
1302 | volatile uint32_t* status = bcm2835_bsc0 + BCM2835_BSC_S/4; |
||
1303 | volatile uint32_t* control = bcm2835_bsc0 + BCM2835_BSC_C/4; |
||
1304 | #else |
||
1305 | volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4; |
||
1306 | volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4; |
||
1307 | volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4; |
||
1308 | volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4; |
||
1309 | #endif |
||
1310 | |||
1311 | uint32_t remaining = len; |
||
1312 | uint32_t i = 0; |
||
1313 | uint8_t reason = BCM2835_I2C_REASON_OK; |
||
1314 | |||
1315 | /* Clear FIFO */ |
||
1316 | bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1 , BCM2835_BSC_C_CLEAR_1 ); |
||
1317 | /* Clear Status */ |
||
1318 | bcm2835_peri_write(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE); |
||
1319 | /* Set Data Length */ |
||
1320 | bcm2835_peri_write(dlen, len); |
||
1321 | /* pre populate FIFO with max buffer */ |
||
1322 | while( remaining && ( i < BCM2835_BSC_FIFO_SIZE ) ) |
||
1323 | { |
||
1324 | bcm2835_peri_write_nb(fifo, buf[i]); |
||
1325 | i++; |
||
1326 | remaining--; |
||
1327 | } |
||
1328 | |||
1329 | /* Enable device and start transfer */ |
||
1330 | bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST); |
||
1331 | |||
1332 | /* Transfer is over when BCM2835_BSC_S_DONE */ |
||
1333 | while(!(bcm2835_peri_read(status) & BCM2835_BSC_S_DONE )) |
||
1334 | { |
||
1335 | while ( remaining && (bcm2835_peri_read(status) & BCM2835_BSC_S_TXD )) |
||
1336 | { |
||
1337 | /* Write to FIFO */ |
||
1338 | bcm2835_peri_write(fifo, buf[i]); |
||
1339 | i++; |
||
1340 | remaining--; |
||
1341 | } |
||
1342 | } |
||
1343 | |||
1344 | /* Received a NACK */ |
||
1345 | if (bcm2835_peri_read(status) & BCM2835_BSC_S_ERR) |
||
1346 | { |
||
1347 | reason = BCM2835_I2C_REASON_ERROR_NACK; |
||
1348 | } |
||
1349 | |||
1350 | /* Received Clock Stretch Timeout */ |
||
1351 | else if (bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT) |
||
1352 | { |
||
1353 | reason = BCM2835_I2C_REASON_ERROR_CLKT; |
||
1354 | } |
||
1355 | |||
1356 | /* Not all data is sent */ |
||
1357 | else if (remaining) |
||
1358 | { |
||
1359 | reason = BCM2835_I2C_REASON_ERROR_DATA; |
||
1360 | } |
||
1361 | |||
1362 | bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE , BCM2835_BSC_S_DONE); |
||
1363 | |||
1364 | return reason; |
||
1365 | } |
||
1366 | |||
1367 | /* Read an number of bytes from I2C */ |
||
1368 | uint8_t bcm2835_i2c_read(char* buf, uint32_t len) |
||
1369 | { |
||
1370 | #ifdef I2C_V1 |
||
1371 | volatile uint32_t* dlen = bcm2835_bsc0 + BCM2835_BSC_DLEN/4; |
||
1372 | volatile uint32_t* fifo = bcm2835_bsc0 + BCM2835_BSC_FIFO/4; |
||
1373 | volatile uint32_t* status = bcm2835_bsc0 + BCM2835_BSC_S/4; |
||
1374 | volatile uint32_t* control = bcm2835_bsc0 + BCM2835_BSC_C/4; |
||
1375 | #else |
||
1376 | volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4; |
||
1377 | volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4; |
||
1378 | volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4; |
||
1379 | volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4; |
||
1380 | #endif |
||
1381 | |||
1382 | uint32_t remaining = len; |
||
1383 | uint32_t i = 0; |
||
1384 | uint8_t reason = BCM2835_I2C_REASON_OK; |
||
1385 | |||
1386 | /* Clear FIFO */ |
||
1387 | bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1 , BCM2835_BSC_C_CLEAR_1 ); |
||
1388 | /* Clear Status */ |
||
1389 | bcm2835_peri_write_nb(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE); |
||
1390 | /* Set Data Length */ |
||
1391 | bcm2835_peri_write_nb(dlen, len); |
||
1392 | /* Start read */ |
||
1393 | bcm2835_peri_write_nb(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST | BCM2835_BSC_C_READ); |
||
1394 | |||
1395 | /* wait for transfer to complete */ |
||
1396 | while (!(bcm2835_peri_read_nb(status) & BCM2835_BSC_S_DONE)) |
||
1397 | { |
||
1398 | /* we must empty the FIFO as it is populated and not use any delay */ |
||
1399 | while (remaining && bcm2835_peri_read_nb(status) & BCM2835_BSC_S_RXD) |
||
1400 | { |
||
1401 | /* Read from FIFO, no barrier */ |
||
1402 | buf[i] = bcm2835_peri_read_nb(fifo); |
||
1403 | i++; |
||
1404 | remaining--; |
||
1405 | } |
||
1406 | } |
||
1407 | |||
1408 | /* transfer has finished - grab any remaining stuff in FIFO */ |
||
1409 | while (remaining && (bcm2835_peri_read_nb(status) & BCM2835_BSC_S_RXD)) |
||
1410 | { |
||
1411 | /* Read from FIFO, no barrier */ |
||
1412 | buf[i] = bcm2835_peri_read_nb(fifo); |
||
1413 | i++; |
||
1414 | remaining--; |
||
1415 | } |
||
1416 | |||
1417 | /* Received a NACK */ |
||
1418 | if (bcm2835_peri_read(status) & BCM2835_BSC_S_ERR) |
||
1419 | { |
||
1420 | reason = BCM2835_I2C_REASON_ERROR_NACK; |
||
1421 | } |
||
1422 | |||
1423 | /* Received Clock Stretch Timeout */ |
||
1424 | else if (bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT) |
||
1425 | { |
||
1426 | reason = BCM2835_I2C_REASON_ERROR_CLKT; |
||
1427 | } |
||
1428 | |||
1429 | /* Not all data is received */ |
||
1430 | else if (remaining) |
||
1431 | { |
||
1432 | reason = BCM2835_I2C_REASON_ERROR_DATA; |
||
1433 | } |
||
1434 | |||
1435 | bcm2835_peri_set_bits(status, BCM2835_BSC_S_DONE , BCM2835_BSC_S_DONE); |
||
1436 | |||
1437 | return reason; |
||
1438 | } |
||
1439 | |||
1440 | /* Read an number of bytes from I2C sending a repeated start after writing |
||
1441 | // the required register. Only works if your device supports this mode |
||
1442 | */ |
||
1443 | uint8_t bcm2835_i2c_read_register_rs(char* regaddr, char* buf, uint32_t len) |
||
1444 | { |
||
1445 | #ifdef I2C_V1 |
||
1446 | volatile uint32_t* dlen = bcm2835_bsc0 + BCM2835_BSC_DLEN/4; |
||
1447 | volatile uint32_t* fifo = bcm2835_bsc0 + BCM2835_BSC_FIFO/4; |
||
1448 | volatile uint32_t* status = bcm2835_bsc0 + BCM2835_BSC_S/4; |
||
1449 | volatile uint32_t* control = bcm2835_bsc0 + BCM2835_BSC_C/4; |
||
1450 | #else |
||
1451 | volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4; |
||
1452 | volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4; |
||
1453 | volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4; |
||
1454 | volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4; |
||
1455 | #endif |
||
1456 | uint32_t remaining = len; |
||
1457 | uint32_t i = 0; |
||
1458 | uint8_t reason = BCM2835_I2C_REASON_OK; |
||
1459 | |||
1460 | /* Clear FIFO */ |
||
1461 | bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1 , BCM2835_BSC_C_CLEAR_1 ); |
||
1462 | /* Clear Status */ |
||
1463 | bcm2835_peri_write(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE); |
||
1464 | /* Set Data Length */ |
||
1465 | bcm2835_peri_write(dlen, 1); |
||
1466 | /* Enable device and start transfer */ |
||
1467 | bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN); |
||
1468 | bcm2835_peri_write(fifo, regaddr[0]); |
||
1469 | bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST); |
||
1470 | |||
1471 | /* poll for transfer has started */ |
||
1472 | while ( !( bcm2835_peri_read(status) & BCM2835_BSC_S_TA ) ) |
||
1473 | { |
||
1474 | /* Linux may cause us to miss entire transfer stage */ |
||
1475 | if(bcm2835_peri_read(status) & BCM2835_BSC_S_DONE) |
||
1476 | break; |
||
1477 | } |
||
1478 | |||
1479 | /* Send a repeated start with read bit set in address */ |
||
1480 | bcm2835_peri_write(dlen, len); |
||
1481 | bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST | BCM2835_BSC_C_READ ); |
||
1482 | |||
1483 | /* Wait for write to complete and first byte back. */ |
||
1484 | bcm2835_delayMicroseconds(i2c_byte_wait_us * 3); |
||
1485 | |||
1486 | /* wait for transfer to complete */ |
||
1487 | while (!(bcm2835_peri_read(status) & BCM2835_BSC_S_DONE)) |
||
1488 | { |
||
1489 | /* we must empty the FIFO as it is populated and not use any delay */ |
||
1490 | while (remaining && bcm2835_peri_read(status) & BCM2835_BSC_S_RXD) |
||
1491 | { |
||
1492 | /* Read from FIFO */ |
||
1493 | buf[i] = bcm2835_peri_read(fifo); |
||
1494 | i++; |
||
1495 | remaining--; |
||
1496 | } |
||
1497 | } |
||
1498 | |||
1499 | /* transfer has finished - grab any remaining stuff in FIFO */ |
||
1500 | while (remaining && (bcm2835_peri_read(status) & BCM2835_BSC_S_RXD)) |
||
1501 | { |
||
1502 | /* Read from FIFO */ |
||
1503 | buf[i] = bcm2835_peri_read(fifo); |
||
1504 | i++; |
||
1505 | remaining--; |
||
1506 | } |
||
1507 | |||
1508 | /* Received a NACK */ |
||
1509 | if (bcm2835_peri_read(status) & BCM2835_BSC_S_ERR) |
||
1510 | { |
||
1511 | reason = BCM2835_I2C_REASON_ERROR_NACK; |
||
1512 | } |
||
1513 | |||
1514 | /* Received Clock Stretch Timeout */ |
||
1515 | else if (bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT) |
||
1516 | { |
||
1517 | reason = BCM2835_I2C_REASON_ERROR_CLKT; |
||
1518 | } |
||
1519 | |||
1520 | /* Not all data is sent */ |
||
1521 | else if (remaining) |
||
1522 | { |
||
1523 | reason = BCM2835_I2C_REASON_ERROR_DATA; |
||
1524 | } |
||
1525 | |||
1526 | bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE , BCM2835_BSC_S_DONE); |
||
1527 | |||
1528 | return reason; |
||
1529 | } |
||
1530 | |||
1531 | /* Sending an arbitrary number of bytes before issuing a repeated start |
||
1532 | // (with no prior stop) and reading a response. Some devices require this behavior. |
||
1533 | */ |
||
1534 | uint8_t bcm2835_i2c_write_read_rs(char* cmds, uint32_t cmds_len, char* buf, uint32_t buf_len) |
||
1535 | { |
||
1536 | #ifdef I2C_V1 |
||
1537 | volatile uint32_t* dlen = bcm2835_bsc0 + BCM2835_BSC_DLEN/4; |
||
1538 | volatile uint32_t* fifo = bcm2835_bsc0 + BCM2835_BSC_FIFO/4; |
||
1539 | volatile uint32_t* status = bcm2835_bsc0 + BCM2835_BSC_S/4; |
||
1540 | volatile uint32_t* control = bcm2835_bsc0 + BCM2835_BSC_C/4; |
||
1541 | #else |
||
1542 | volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4; |
||
1543 | volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4; |
||
1544 | volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4; |
||
1545 | volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4; |
||
1546 | #endif |
||
1547 | |||
1548 | uint32_t remaining = cmds_len; |
||
1549 | uint32_t i = 0; |
||
1550 | uint8_t reason = BCM2835_I2C_REASON_OK; |
||
1551 | |||
1552 | /* Clear FIFO */ |
||
1553 | bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1 , BCM2835_BSC_C_CLEAR_1 ); |
||
1554 | |||
1555 | /* Clear Status */ |
||
1556 | bcm2835_peri_write(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE); |
||
1557 | |||
1558 | /* Set Data Length */ |
||
1559 | bcm2835_peri_write(dlen, cmds_len); |
||
1560 | |||
1561 | /* pre populate FIFO with max buffer */ |
||
1562 | while( remaining && ( i < BCM2835_BSC_FIFO_SIZE ) ) |
||
1563 | { |
||
1564 | bcm2835_peri_write_nb(fifo, cmds[i]); |
||
1565 | i++; |
||
1566 | remaining--; |
||
1567 | } |
||
1568 | |||
1569 | /* Enable device and start transfer */ |
||
1570 | bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST); |
||
1571 | |||
1572 | /* poll for transfer has started (way to do repeated start, from BCM2835 datasheet) */ |
||
1573 | while ( !( bcm2835_peri_read(status) & BCM2835_BSC_S_TA ) ) |
||
1574 | { |
||
1575 | /* Linux may cause us to miss entire transfer stage */ |
||
1576 | if(bcm2835_peri_read_nb(status) & BCM2835_BSC_S_DONE) |
||
1577 | break; |
||
1578 | } |
||
1579 | |||
1580 | remaining = buf_len; |
||
1581 | i = 0; |
||
1582 | |||
1583 | /* Send a repeated start with read bit set in address */ |
||
1584 | bcm2835_peri_write(dlen, buf_len); |
||
1585 | bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST | BCM2835_BSC_C_READ ); |
||
1586 | |||
1587 | /* Wait for write to complete and first byte back. */ |
||
1588 | bcm2835_delayMicroseconds(i2c_byte_wait_us * (cmds_len + 1)); |
||
1589 | |||
1590 | /* wait for transfer to complete */ |
||
1591 | while (!(bcm2835_peri_read_nb(status) & BCM2835_BSC_S_DONE)) |
||
1592 | { |
||
1593 | /* we must empty the FIFO as it is populated and not use any delay */ |
||
1594 | while (remaining && bcm2835_peri_read(status) & BCM2835_BSC_S_RXD) |
||
1595 | { |
||
1596 | /* Read from FIFO, no barrier */ |
||
1597 | buf[i] = bcm2835_peri_read_nb(fifo); |
||
1598 | i++; |
||
1599 | remaining--; |
||
1600 | } |
||
1601 | } |
||
1602 | |||
1603 | /* transfer has finished - grab any remaining stuff in FIFO */ |
||
1604 | while (remaining && (bcm2835_peri_read(status) & BCM2835_BSC_S_RXD)) |
||
1605 | { |
||
1606 | /* Read from FIFO */ |
||
1607 | buf[i] = bcm2835_peri_read(fifo); |
||
1608 | i++; |
||
1609 | remaining--; |
||
1610 | } |
||
1611 | |||
1612 | /* Received a NACK */ |
||
1613 | if (bcm2835_peri_read(status) & BCM2835_BSC_S_ERR) |
||
1614 | { |
||
1615 | reason = BCM2835_I2C_REASON_ERROR_NACK; |
||
1616 | } |
||
1617 | |||
1618 | /* Received Clock Stretch Timeout */ |
||
1619 | else if (bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT) |
||
1620 | { |
||
1621 | reason = BCM2835_I2C_REASON_ERROR_CLKT; |
||
1622 | } |
||
1623 | |||
1624 | /* Not all data is sent */ |
||
1625 | else if (remaining) |
||
1626 | { |
||
1627 | reason = BCM2835_I2C_REASON_ERROR_DATA; |
||
1628 | } |
||
1629 | |||
1630 | bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE , BCM2835_BSC_S_DONE); |
||
1631 | |||
1632 | return reason; |
||
1633 | } |
||
1634 | |||
1635 | /* SMI support courtesy Benoit Bouchez */ |
||
1636 | int bcm2835_smi_begin(void) |
||
1637 | { |
||
1638 | volatile uint32_t* paddr; |
||
1639 | uint32_t defConfig; |
||
1640 | |||
1641 | if (bcm2835_smi == MAP_FAILED) |
||
1642 | return 0; /* bcm2835_smi_init() failed, or not root */ |
||
1643 | |||
1644 | /* Set the SMI pins to the Alt 1 function to enable SMI access on them */ |
||
1645 | bcm2835_gpio_fsel(2, BCM2835_GPIO_FSEL_ALT1); /* SA3 */ |
||
1646 | bcm2835_gpio_fsel(3, BCM2835_GPIO_FSEL_ALT1); /* SA2 */ |
||
1647 | bcm2835_gpio_fsel(4, BCM2835_GPIO_FSEL_ALT1); /* SA1 */ |
||
1648 | bcm2835_gpio_fsel(5, BCM2835_GPIO_FSEL_ALT1); /* SA0 */ |
||
1649 | bcm2835_gpio_fsel(6, BCM2835_GPIO_FSEL_ALT1); /* SOE_N / SE */ |
||
1650 | bcm2835_gpio_fsel(7, BCM2835_GPIO_FSEL_ALT1); /* SWE_N / SRW_N */ |
||
1651 | bcm2835_gpio_fsel(8, BCM2835_GPIO_FSEL_ALT1); /* SD0 */ |
||
1652 | bcm2835_gpio_fsel(9, BCM2835_GPIO_FSEL_ALT1); /* SD1 */ |
||
1653 | bcm2835_gpio_fsel(10, BCM2835_GPIO_FSEL_ALT1); /* SD2 */ |
||
1654 | bcm2835_gpio_fsel(11, BCM2835_GPIO_FSEL_ALT1); /* SD3 */ |
||
1655 | bcm2835_gpio_fsel(12, BCM2835_GPIO_FSEL_ALT1); /* SD4 */ |
||
1656 | bcm2835_gpio_fsel(13, BCM2835_GPIO_FSEL_ALT1); /* SD5 */ |
||
1657 | bcm2835_gpio_fsel(14, BCM2835_GPIO_FSEL_ALT1); /* SD6 */ |
||
1658 | bcm2835_gpio_fsel(15, BCM2835_GPIO_FSEL_ALT1); /* SD7 */ |
||
1659 | |||
1660 | /* Set the SMI clock to 125MHz -> one clock period lasts 8 ns */ |
||
1661 | paddr = bcm2835_clk + SMICLK_CNTL; |
||
1662 | bcm2835_peri_write (paddr, 0x5A000000); /* Disable SMI clock */ |
||
1663 | paddr = bcm2835_clk + SMICLK_DIV; |
||
1664 | bcm2835_peri_write (paddr, 0x5A004000); /* Set clock divider to 4 */ |
||
1665 | paddr = bcm2835_clk + SMICLK_CNTL; |
||
1666 | bcm2835_peri_write (paddr, 0x5A000016); /* Enable SMI clock with PLLD */ |
||
1667 | |||
1668 | /* Set a default useable configuration for the four SMI config slots */ |
||
1669 | /* 8 bits, Intel mode, always pace, 10 clocks for R/W setup = 80 ns |
||
1670 | 20 clocks for R/W strobe = 160 ns, 20 clocks for R/W hold = 160 ns, |
||
1671 | 1 clock for pace control (not used but a value is needed) */ |
||
1672 | defConfig = BCM2835_SMI_RW_WID8 | BCM2835_SMI_RW_MODE80 | |
||
1673 | BCM2835_SMI_RW_PACEALL | (10<<BCM2835_SMI_RW_SETUP_LS) | |
||
1674 | (20<<BCM2835_SMI_RW_STROBE_LS) | (20<<BCM2835_SMI_RW_HOLD_LS) | |
||
1675 | (1<<BCM2835_SMI_RW_PACE_LS); |
||
1676 | |||
1677 | paddr = bcm2835_smi + BCM2835_SMI_READ0; |
||
1678 | bcm2835_peri_write (paddr, defConfig); |
||
1679 | paddr = bcm2835_smi + BCM2835_SMI_WRITE0; |
||
1680 | bcm2835_peri_write (paddr, defConfig); |
||
1681 | paddr = bcm2835_smi + BCM2835_SMI_READ1; |
||
1682 | bcm2835_peri_write (paddr, defConfig); |
||
1683 | paddr = bcm2835_smi + BCM2835_SMI_WRITE1; |
||
1684 | bcm2835_peri_write (paddr, defConfig); |
||
1685 | paddr = bcm2835_smi + BCM2835_SMI_READ2; |
||
1686 | bcm2835_peri_write (paddr, defConfig); |
||
1687 | paddr = bcm2835_smi + BCM2835_SMI_WRITE2; |
||
1688 | bcm2835_peri_write (paddr, defConfig); |
||
1689 | paddr = bcm2835_smi + BCM2835_SMI_READ3; |
||
1690 | bcm2835_peri_write (paddr, defConfig); |
||
1691 | paddr = bcm2835_smi + BCM2835_SMI_WRITE3; |
||
1692 | bcm2835_peri_write (paddr, defConfig); |
||
1693 | |||
1694 | return 1; // OK |
||
1695 | } /* bcm2835_smi_begin */ |
||
1696 | /* --------------------------------------------------- */ |
||
1697 | |||
1698 | void bcm2835_smi_end(void) |
||
1699 | { |
||
1700 | /* Set all the SMI pins back to input */ |
||
1701 | bcm2835_gpio_fsel(2, BCM2835_GPIO_FSEL_INPT); /* SA3 */ |
||
1702 | bcm2835_gpio_fsel(3, BCM2835_GPIO_FSEL_INPT); /* SA2 */ |
||
1703 | bcm2835_gpio_fsel(4, BCM2835_GPIO_FSEL_INPT); /* SA1 */ |
||
1704 | bcm2835_gpio_fsel(5, BCM2835_GPIO_FSEL_INPT); /* SA0 */ |
||
1705 | bcm2835_gpio_fsel(6, BCM2835_GPIO_FSEL_INPT); /* SOE_N / SE */ |
||
1706 | bcm2835_gpio_fsel(7, BCM2835_GPIO_FSEL_INPT); /* SWE_N / SRW_N */ |
||
1707 | bcm2835_gpio_fsel(8, BCM2835_GPIO_FSEL_INPT); /* SD0 */ |
||
1708 | bcm2835_gpio_fsel(9, BCM2835_GPIO_FSEL_INPT); /* SD1 */ |
||
1709 | bcm2835_gpio_fsel(10, BCM2835_GPIO_FSEL_INPT); /* SD2 */ |
||
1710 | bcm2835_gpio_fsel(11, BCM2835_GPIO_FSEL_INPT); /* SD3 */ |
||
1711 | bcm2835_gpio_fsel(12, BCM2835_GPIO_FSEL_INPT); /* SD4 */ |
||
1712 | bcm2835_gpio_fsel(13, BCM2835_GPIO_FSEL_INPT); /* SD5 */ |
||
1713 | bcm2835_gpio_fsel(14, BCM2835_GPIO_FSEL_INPT); /* SD6 */ |
||
1714 | bcm2835_gpio_fsel(15, BCM2835_GPIO_FSEL_INPT); /* SD7 */ |
||
1715 | } /* bcm2835_smi_end */ |
||
1716 | /* --------------------------------------------------- */ |
||
1717 | |||
1718 | void bcm2835_smi_set_timing (uint32_t smichannel, uint32_t readchannel, |
||
1719 | uint32_t setupcycles, uint32_t strobecycles, |
||
1720 | uint32_t holdcycles, uint32_t pacecycles) |
||
1721 | { |
||
1722 | int RegOffset; |
||
1723 | volatile uint32_t* psmitiming; |
||
1724 | uint32_t RegValue; |
||
1725 | |||
1726 | if (readchannel!=0) |
||
1727 | { |
||
1728 | switch (smichannel) |
||
1729 | { |
||
1730 | case 0 : RegOffset = BCM2835_SMI_READ0; break; |
||
1731 | case 1 : RegOffset = BCM2835_SMI_READ1; break; |
||
1732 | case 2 : RegOffset = BCM2835_SMI_READ2; break; |
||
1733 | case 3 : RegOffset = BCM2835_SMI_READ3; break; |
||
1734 | default : return; |
||
1735 | } |
||
1736 | } |
||
1737 | else |
||
1738 | { |
||
1739 | switch (smichannel) |
||
1740 | { |
||
1741 | case 0 : RegOffset = BCM2835_SMI_WRITE0; break; |
||
1742 | case 1 : RegOffset = BCM2835_SMI_WRITE1; break; |
||
1743 | case 2 : RegOffset = BCM2835_SMI_WRITE2; break; |
||
1744 | case 3 : RegOffset = BCM2835_SMI_WRITE3; break; |
||
1745 | default : return; |
||
1746 | } |
||
1747 | } |
||
1748 | |||
1749 | /* Get current timing configuration of the slot */ |
||
1750 | psmitiming = bcm2835_smi + RegOffset; |
||
1751 | RegValue = bcm2835_peri_read (psmitiming); |
||
1752 | /* Clear timing fields in register */ |
||
1753 | RegValue &= ~(BCM2835_SMI_RW_SETUP_MSK|BCM2835_SMI_RW_HOLD_MSK|BCM2835_SMI_RW_PACE_MSK|BCM2835_SMI_RW_STROBE_MSK); |
||
1754 | /* Set timing values and write back to register */ |
||
1755 | RegValue |= (setupcycles << BCM2835_SMI_RW_SETUP_LS) | |
||
1756 | (strobecycles << BCM2835_SMI_RW_STROBE_LS) | |
||
1757 | (holdcycles << BCM2835_SMI_RW_HOLD_LS) | |
||
1758 | (pacecycles << BCM2835_SMI_RW_PACE_LS); |
||
1759 | bcm2835_peri_write (psmitiming, RegValue); |
||
1760 | } /* bcm2835_set_smi_timing */ |
||
1761 | /* --------------------------------------------------- */ |
||
1762 | |||
1763 | void bcm2835_smi_write(uint32_t smichannel, uint8_t data, uint32_t address) |
||
1764 | { |
||
1765 | uint32_t status; |
||
1766 | volatile uint32_t* psmics = bcm2835_smi + BCM2835_SMI_DIRCS; |
||
1767 | volatile uint32_t* psmiaddr = bcm2835_smi + BCM2835_SMI_DIRADDR; |
||
1768 | volatile uint32_t* psmidata = bcm2835_smi + BCM2835_SMI_DIRDATA; |
||
1769 | |||
1770 | /* Make sure we use a configuration that exists */ |
||
1771 | if (smichannel>3) return; |
||
1772 | |||
1773 | /* clear done bit if set */ |
||
1774 | if (bcm2835_peri_read(psmics) & BCM2835_SMI_DIRCS_DONE) |
||
1775 | { |
||
1776 | bcm2835_peri_write (psmics, BCM2835_SMI_DIRCS_DONE); |
||
1777 | } |
||
1778 | |||
1779 | /* Start write transfer */ |
||
1780 | bcm2835_peri_write (psmiaddr, (smichannel<<BCM2835_SMI_DIRADRS_DEV_LS) | (address&BCM2835_SMI_DIRADRS_MSK)); |
||
1781 | bcm2835_peri_write (psmidata, data); |
||
1782 | bcm2835_peri_write (psmics, BCM2835_SMI_DIRCS_WRITE|BCM2835_SMI_DIRCS_START|BCM2835_SMI_DIRCS_ENABLE); |
||
1783 | |||
1784 | /* Wait until write cycle is finished */ |
||
1785 | do { |
||
1786 | status = bcm2835_peri_read(psmics); |
||
1787 | } while ((status & BCM2835_SMI_DIRCS_DONE)==0); |
||
1788 | |||
1789 | /* clear done bit */ |
||
1790 | bcm2835_peri_write (psmics, BCM2835_SMI_DIRCS_DONE); |
||
1791 | } /* bcm2835_smi_write */ |
||
1792 | /* --------------------------------------------------- */ |
||
1793 | |||
1794 | uint32_t bcm2835_smi_read (uint32_t smichannel, uint32_t address) |
||
1795 | { |
||
1796 | uint32_t status; |
||
1797 | uint32_t data; |
||
1798 | volatile uint32_t* psmics = bcm2835_smi + BCM2835_SMI_DIRCS; |
||
1799 | volatile uint32_t* psmiaddr = bcm2835_smi + BCM2835_SMI_DIRADDR; |
||
1800 | volatile uint32_t* psmidata = bcm2835_smi + BCM2835_SMI_DIRDATA; |
||
1801 | |||
1802 | /* Make sure we use a configuration that exists */ |
||
1803 | if (smichannel>3) return 0; |
||
1804 | |||
1805 | /* clear done bit if set */ |
||
1806 | if (bcm2835_peri_read(psmics) & BCM2835_SMI_DIRCS_DONE) |
||
1807 | { |
||
1808 | bcm2835_peri_write (psmics, BCM2835_SMI_DIRCS_DONE); |
||
1809 | } |
||
1810 | |||
1811 | /* Start read transfer */ |
||
1812 | bcm2835_peri_write (psmiaddr, (smichannel<<BCM2835_SMI_DIRADRS_DEV_LS) | (address&BCM2835_SMI_DIRADRS_MSK)); |
||
1813 | bcm2835_peri_write (psmics, BCM2835_SMI_DIRCS_START|BCM2835_SMI_DIRCS_ENABLE); |
||
1814 | |||
1815 | /* Wait until read cycle is finished */ |
||
1816 | do { |
||
1817 | status = bcm2835_peri_read(psmics); |
||
1818 | } while ((status & BCM2835_SMI_DIRCS_DONE)==0); |
||
1819 | |||
1820 | /* Read data */ |
||
1821 | data = bcm2835_peri_read (psmidata); |
||
1822 | |||
1823 | /* clear done bit */ |
||
1824 | bcm2835_peri_write (psmics, BCM2835_SMI_DIRCS_DONE); |
||
1825 | |||
1826 | return data; |
||
1827 | } /* bcm2835_smi_read */ |
||
1828 | /* --------------------------------------------------- */ |
||
1829 | |||
1830 | /* Read the System Timer Counter (64-bits) */ |
||
1831 | uint64_t bcm2835_st_read(void) |
||
1832 | { |
||
1833 | volatile uint32_t* paddr; |
||
1834 | uint32_t hi, lo; |
||
1835 | uint64_t st; |
||
1836 | |||
1837 | if (bcm2835_st==MAP_FAILED) |
||
1838 | return 0; |
||
1839 | |||
1840 | paddr = bcm2835_st + BCM2835_ST_CHI/4; |
||
1841 | hi = bcm2835_peri_read(paddr); |
||
1842 | |||
1843 | paddr = bcm2835_st + BCM2835_ST_CLO/4; |
||
1844 | lo = bcm2835_peri_read(paddr); |
||
1845 | |||
1846 | paddr = bcm2835_st + BCM2835_ST_CHI/4; |
||
1847 | st = bcm2835_peri_read(paddr); |
||
1848 | |||
1849 | /* Test for overflow */ |
||
1850 | if (st == hi) |
||
1851 | { |
||
1852 | st <<= 32; |
||
1853 | st += lo; |
||
1854 | } |
||
1855 | else |
||
1856 | { |
||
1857 | st <<= 32; |
||
1858 | paddr = bcm2835_st + BCM2835_ST_CLO/4; |
||
1859 | st += bcm2835_peri_read(paddr); |
||
1860 | } |
||
1861 | return st; |
||
1862 | } |
||
1863 | |||
1864 | /* Delays for the specified number of microseconds with offset */ |
||
1865 | void bcm2835_st_delay(uint64_t offset_micros, uint64_t micros) |
||
1866 | { |
||
1867 | uint64_t compare = offset_micros + micros; |
||
1868 | |||
1869 | while(bcm2835_st_read() < compare) |
||
1870 | ; |
||
1871 | } |
||
1872 | |||
1873 | /* PWM */ |
||
1874 | |||
1875 | void bcm2835_pwm_set_clock(uint32_t divisor) |
||
1876 | { |
||
1877 | if ( bcm2835_clk == MAP_FAILED |
||
1878 | || bcm2835_pwm == MAP_FAILED) |
||
1879 | return; /* bcm2835_init() failed or not root */ |
||
1880 | |||
1881 | /* From Gerts code */ |
||
1882 | divisor &= 0xfff; |
||
1883 | /* Stop PWM clock */ |
||
1884 | bcm2835_peri_write(bcm2835_clk + BCM2835_PWMCLK_CNTL, BCM2835_PWM_PASSWRD | 0x01); |
||
1885 | bcm2835_delay(110); /* Prevents clock going slow */ |
||
1886 | /* Wait for the clock to be not busy */ |
||
1887 | while ((bcm2835_peri_read(bcm2835_clk + BCM2835_PWMCLK_CNTL) & 0x80) != 0) |
||
1888 | bcm2835_delay(1); |
||
1889 | /* set the clock divider and enable PWM clock */ |
||
1890 | bcm2835_peri_write(bcm2835_clk + BCM2835_PWMCLK_DIV, BCM2835_PWM_PASSWRD | (divisor << 12)); |
||
1891 | bcm2835_peri_write(bcm2835_clk + BCM2835_PWMCLK_CNTL, BCM2835_PWM_PASSWRD | 0x11); /* Source=osc and enable */ |
||
1892 | } |
||
1893 | |||
1894 | void bcm2835_pwm_set_mode(uint8_t channel, uint8_t markspace, uint8_t enabled) |
||
1895 | { |
||
1896 | if ( bcm2835_clk == MAP_FAILED |
||
1897 | || bcm2835_pwm == MAP_FAILED) |
||
1898 | return; /* bcm2835_init() failed or not root */ |
||
1899 | |||
1900 | uint32_t control = bcm2835_peri_read(bcm2835_pwm + BCM2835_PWM_CONTROL); |
||
1901 | |||
1902 | if (channel == 0) |
||
1903 | { |
||
1904 | if (markspace) |
||
1905 | control |= BCM2835_PWM0_MS_MODE; |
||
1906 | else |
||
1907 | control &= ~BCM2835_PWM0_MS_MODE; |
||
1908 | if (enabled) |
||
1909 | control |= BCM2835_PWM0_ENABLE; |
||
1910 | else |
||
1911 | control &= ~BCM2835_PWM0_ENABLE; |
||
1912 | } |
||
1913 | else if (channel == 1) |
||
1914 | { |
||
1915 | if (markspace) |
||
1916 | control |= BCM2835_PWM1_MS_MODE; |
||
1917 | else |
||
1918 | control &= ~BCM2835_PWM1_MS_MODE; |
||
1919 | if (enabled) |
||
1920 | control |= BCM2835_PWM1_ENABLE; |
||
1921 | else |
||
1922 | control &= ~BCM2835_PWM1_ENABLE; |
||
1923 | } |
||
1924 | |||
1925 | /* If you use the barrier here, wierd things happen, and the commands dont work */ |
||
1926 | bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM_CONTROL, control); |
||
1927 | /* bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM_CONTROL, BCM2835_PWM0_ENABLE | BCM2835_PWM1_ENABLE | BCM2835_PWM0_MS_MODE | BCM2835_PWM1_MS_MODE); */ |
||
1928 | |||
1929 | } |
||
1930 | |||
1931 | void bcm2835_pwm_set_range(uint8_t channel, uint32_t range) |
||
1932 | { |
||
1933 | if ( bcm2835_clk == MAP_FAILED |
||
1934 | || bcm2835_pwm == MAP_FAILED) |
||
1935 | return; /* bcm2835_init() failed or not root */ |
||
1936 | |||
1937 | if (channel == 0) |
||
1938 | bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM0_RANGE, range); |
||
1939 | else if (channel == 1) |
||
1940 | bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM1_RANGE, range); |
||
1941 | } |
||
1942 | |||
1943 | void bcm2835_pwm_set_data(uint8_t channel, uint32_t data) |
||
1944 | { |
||
1945 | if ( bcm2835_clk == MAP_FAILED |
||
1946 | || bcm2835_pwm == MAP_FAILED) |
||
1947 | return; /* bcm2835_init() failed or not root */ |
||
1948 | |||
1949 | if (channel == 0) |
||
1950 | bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM0_DATA, data); |
||
1951 | else if (channel == 1) |
||
1952 | bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM1_DATA, data); |
||
1953 | } |
||
1954 | |||
1955 | /* Allocate page-aligned memory. */ |
||
1956 | void *malloc_aligned(size_t size) |
||
1957 | { |
||
1958 | void *mem; |
||
1959 | errno = posix_memalign(&mem, BCM2835_PAGE_SIZE, size); |
||
1960 | return (errno ? NULL : mem); |
||
1961 | } |
||
1962 | |||
1963 | /* Map 'size' bytes starting at 'off' in file 'fd' to memory. |
||
1964 | // Return mapped address on success, MAP_FAILED otherwise. |
||
1965 | // On error print message. |
||
1966 | */ |
||
1967 | static void *mapmem(const char *msg, size_t size, int fd, off_t off) |
||
1968 | { |
||
1969 | void *map = mmap(NULL, size, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, off); |
||
1970 | if (map == MAP_FAILED) |
||
1971 | fprintf(stderr, "bcm2835_init: %s mmap failed: %s\n", msg, strerror(errno)); |
||
1972 | return map; |
||
1973 | } |
||
1974 | |||
1975 | static void unmapmem(void **pmem, size_t size) |
||
1976 | { |
||
1977 | if (*pmem == MAP_FAILED) return; |
||
1978 | munmap(*pmem, size); |
||
1979 | *pmem = MAP_FAILED; |
||
1980 | } |
||
1981 | |||
1982 | /* Initialise this library. */ |
||
1983 | int bcm2835_init(void) |
||
1984 | { |
||
1985 | int memfd; |
||
1986 | int ok; |
||
1987 | FILE *fp; |
||
1988 | |||
1989 | if (debug) |
||
1990 | { |
||
1991 | bcm2835_peripherals = (uint32_t*)BCM2835_PERI_BASE; |
||
1992 | |||
1993 | bcm2835_pads = bcm2835_peripherals + BCM2835_GPIO_PADS/4; |
||
1994 | bcm2835_clk = bcm2835_peripherals + BCM2835_CLOCK_BASE/4; |
||
1995 | bcm2835_gpio = bcm2835_peripherals + BCM2835_GPIO_BASE/4; |
||
1996 | bcm2835_pwm = bcm2835_peripherals + BCM2835_GPIO_PWM/4; |
||
1997 | bcm2835_spi0 = bcm2835_peripherals + BCM2835_SPI0_BASE/4; |
||
1998 | bcm2835_bsc0 = bcm2835_peripherals + BCM2835_BSC0_BASE/4; |
||
1999 | bcm2835_bsc1 = bcm2835_peripherals + BCM2835_BSC1_BASE/4; |
||
2000 | bcm2835_st = bcm2835_peripherals + BCM2835_ST_BASE/4; |
||
2001 | bcm2835_aux = bcm2835_peripherals + BCM2835_AUX_BASE/4; |
||
2002 | bcm2835_spi1 = bcm2835_peripherals + BCM2835_SPI1_BASE/4; |
||
2003 | /* BEB */ |
||
2004 | bcm2835_smi = bcm2835_peripherals + BCM2835_SMI_BASE/4; |
||
2005 | |||
2006 | |||
2007 | return 1; /* Success */ |
||
2008 | } |
||
2009 | |||
2010 | /* Figure out the base and size of the peripheral address block |
||
2011 | // using the device-tree. Required for RPi2/3/4, optional for RPi 1 |
||
2012 | */ |
||
2013 | if ((fp = fopen(BMC2835_RPI2_DT_FILENAME , "rb"))) |
||
2014 | { |
||
2015 | unsigned char buf[16]; |
||
2016 | uint32_t base_address; |
||
2017 | uint32_t peri_size; |
||
2018 | if (fread(buf, 1, sizeof(buf), fp) >= 8) |
||
2019 | { |
||
2020 | base_address = (buf[4] << 24) | |
||
2021 | (buf[5] << 16) | |
||
2022 | (buf[6] << 8) | |
||
2023 | (buf[7] << 0); |
||
2024 | |||
2025 | peri_size = (buf[8] << 24) | |
||
2026 | (buf[9] << 16) | |
||
2027 | (buf[10] << 8) | |
||
2028 | (buf[11] << 0); |
||
2029 | |||
2030 | if (!base_address) |
||
2031 | { |
||
2032 | /* looks like RPI 4 */ |
||
2033 | base_address = (buf[8] << 24) | |
||
2034 | (buf[9] << 16) | |
||
2035 | (buf[10] << 8) | |
||
2036 | (buf[11] << 0); |
||
2037 | |||
2038 | peri_size = (buf[12] << 24) | |
||
2039 | (buf[13] << 16) | |
||
2040 | (buf[14] << 8) | |
||
2041 | (buf[15] << 0); |
||
2042 | } |
||
2043 | /* check for valid known range formats */ |
||
2044 | if ((buf[0] == 0x7e) && |
||
2045 | (buf[1] == 0x00) && |
||
2046 | (buf[2] == 0x00) && |
||
2047 | (buf[3] == 0x00) && |
||
2048 | ((base_address == BCM2835_PERI_BASE) || (base_address == BCM2835_RPI2_PERI_BASE) || (base_address == BCM2835_RPI4_PERI_BASE))) |
||
2049 | { |
||
2050 | bcm2835_peripherals_base = (off_t)base_address; |
||
2051 | bcm2835_peripherals_size = (size_t)peri_size; |
||
2052 | if( base_address == BCM2835_RPI4_PERI_BASE ) |
||
2053 | { |
||
2054 | pud_type_rpi4 = 1; |
||
2055 | } |
||
2056 | } |
||
2057 | |||
2058 | } |
||
2059 | |||
2060 | fclose(fp); |
||
2061 | } |
||
2062 | /* else we are prob on RPi 1 with BCM2835, and use the hardwired defaults */ |
||
2063 | |||
2064 | /* Now get ready to map the peripherals block |
||
2065 | * If we are not root, try for the new /dev/gpiomem interface and accept |
||
2066 | * the fact that we can only access GPIO |
||
2067 | * else try for the /dev/mem interface and get access to everything |
||
2068 | */ |
||
2069 | memfd = -1; |
||
2070 | ok = 0; |
||
2071 | if (geteuid() == 0 |
||
2072 | #ifdef BCM2835_HAVE_LIBCAP |
||
2073 | || bcm2835_has_capability(CAP_SYS_RAWIO) |
||
2074 | #endif |
||
2075 | ) |
||
2076 | { |
||
2077 | /* Open the master /dev/mem device */ |
||
2078 | if ((memfd = open("/dev/mem", O_RDWR | O_SYNC) ) < 0) |
||
2079 | { |
||
2080 | fprintf(stderr, "bcm2835_init: Unable to open /dev/mem: %s\n", |
||
2081 | strerror(errno)) ; |
||
2082 | goto exit; |
||
2083 | } |
||
2084 | |||
2085 | /* Base of the peripherals block is mapped to VM */ |
||
2086 | bcm2835_peripherals = mapmem("gpio", bcm2835_peripherals_size, memfd, bcm2835_peripherals_base); |
||
2087 | if (bcm2835_peripherals == MAP_FAILED) goto exit; |
||
2088 | |||
2089 | /* Now compute the base addresses of various peripherals, |
||
2090 | // which are at fixed offsets within the mapped peripherals block |
||
2091 | // Caution: bcm2835_peripherals is uint32_t*, so divide offsets by 4 |
||
2092 | */ |
||
2093 | bcm2835_gpio = bcm2835_peripherals + BCM2835_GPIO_BASE/4; |
||
2094 | bcm2835_pwm = bcm2835_peripherals + BCM2835_GPIO_PWM/4; |
||
2095 | bcm2835_clk = bcm2835_peripherals + BCM2835_CLOCK_BASE/4; |
||
2096 | bcm2835_pads = bcm2835_peripherals + BCM2835_GPIO_PADS/4; |
||
2097 | bcm2835_spi0 = bcm2835_peripherals + BCM2835_SPI0_BASE/4; |
||
2098 | bcm2835_bsc0 = bcm2835_peripherals + BCM2835_BSC0_BASE/4; /* I2C */ |
||
2099 | bcm2835_bsc1 = bcm2835_peripherals + BCM2835_BSC1_BASE/4; /* I2C */ |
||
2100 | bcm2835_st = bcm2835_peripherals + BCM2835_ST_BASE/4; |
||
2101 | bcm2835_aux = bcm2835_peripherals + BCM2835_AUX_BASE/4; |
||
2102 | bcm2835_spi1 = bcm2835_peripherals + BCM2835_SPI1_BASE/4; |
||
2103 | /* BEB */ |
||
2104 | bcm2835_smi = bcm2835_peripherals + BCM2835_SMI_BASE/4; |
||
2105 | |||
2106 | |||
2107 | ok = 1; |
||
2108 | } |
||
2109 | else |
||
2110 | { |
||
2111 | /* Not root, try /dev/gpiomem */ |
||
2112 | /* Open the master /dev/mem device */ |
||
2113 | if ((memfd = open("/dev/gpiomem", O_RDWR | O_SYNC) ) < 0) |
||
2114 | { |
||
2115 | fprintf(stderr, "bcm2835_init: Unable to open /dev/gpiomem: %s\n", |
||
2116 | strerror(errno)) ; |
||
2117 | goto exit; |
||
2118 | } |
||
2119 | |||
2120 | /* Base of the peripherals block is mapped to VM */ |
||
2121 | bcm2835_peripherals_base = 0; |
||
2122 | bcm2835_peripherals = mapmem("gpio", bcm2835_peripherals_size, memfd, bcm2835_peripherals_base); |
||
2123 | if (bcm2835_peripherals == MAP_FAILED) goto exit; |
||
2124 | bcm2835_gpio = bcm2835_peripherals; |
||
2125 | ok = 1; |
||
2126 | } |
||
2127 | |||
2128 | exit: |
||
2129 | if (memfd >= 0) |
||
2130 | close(memfd); |
||
2131 | |||
2132 | if (!ok) |
||
2133 | bcm2835_close(); |
||
2134 | |||
2135 | return ok; |
||
2136 | } |
||
2137 | |||
2138 | /* Close this library and deallocate everything */ |
||
2139 | int bcm2835_close(void) |
||
2140 | { |
||
2141 | if (debug) return 1; /* Success */ |
||
2142 | |||
2143 | unmapmem((void**) &bcm2835_peripherals, bcm2835_peripherals_size); |
||
2144 | bcm2835_peripherals = MAP_FAILED; |
||
2145 | bcm2835_gpio = MAP_FAILED; |
||
2146 | bcm2835_pwm = MAP_FAILED; |
||
2147 | bcm2835_clk = MAP_FAILED; |
||
2148 | bcm2835_pads = MAP_FAILED; |
||
2149 | bcm2835_spi0 = MAP_FAILED; |
||
2150 | bcm2835_bsc0 = MAP_FAILED; |
||
2151 | bcm2835_bsc1 = MAP_FAILED; |
||
2152 | bcm2835_st = MAP_FAILED; |
||
2153 | bcm2835_aux = MAP_FAILED; |
||
2154 | bcm2835_spi1 = MAP_FAILED; |
||
2155 | /* BEB */ |
||
2156 | bcm2835_smi = MAP_FAILED; |
||
2157 | |||
2158 | return 1; /* Success */ |
||
2159 | } |
||
2160 | |||
2161 | #ifdef BCM2835_TEST |
||
2162 | /* this is a simple test program that prints out what it will do rather than |
||
2163 | // actually doing it |
||
2164 | */ |
||
2165 | int main(int argc, char **argv) |
||
2166 | { |
||
2167 | /* Be non-destructive */ |
||
2168 | bcm2835_set_debug(1); |
||
2169 | |||
2170 | if (!bcm2835_init()) |
||
2171 | return 1; |
||
2172 | |||
2173 | /* Configure some GPIO pins fo some testing |
||
2174 | // Set RPI pin P1-11 to be an output |
||
2175 | */ |
||
2176 | bcm2835_gpio_fsel(RPI_GPIO_P1_11, BCM2835_GPIO_FSEL_OUTP); |
||
2177 | /* Set RPI pin P1-15 to be an input */ |
||
2178 | bcm2835_gpio_fsel(RPI_GPIO_P1_15, BCM2835_GPIO_FSEL_INPT); |
||
2179 | /* with a pullup */ |
||
2180 | bcm2835_gpio_set_pud(RPI_GPIO_P1_15, BCM2835_GPIO_PUD_UP); |
||
2181 | /* And a low detect enable */ |
||
2182 | bcm2835_gpio_len(RPI_GPIO_P1_15); |
||
2183 | /* and input hysteresis disabled on GPIOs 0 to 27 */ |
||
2184 | bcm2835_gpio_set_pad(BCM2835_PAD_GROUP_GPIO_0_27, BCM2835_PAD_SLEW_RATE_UNLIMITED|BCM2835_PAD_DRIVE_8mA); |
||
2185 | |||
2186 | #if 1 |
||
2187 | /* Blink */ |
||
2188 | while (1) |
||
2189 | { |
||
2190 | /* Turn it on */ |
||
2191 | bcm2835_gpio_write(RPI_GPIO_P1_11, HIGH); |
||
2192 | |||
2193 | /* wait a bit */ |
||
2194 | bcm2835_delay(500); |
||
2195 | |||
2196 | /* turn it off */ |
||
2197 | bcm2835_gpio_write(RPI_GPIO_P1_11, LOW); |
||
2198 | |||
2199 | /* wait a bit */ |
||
2200 | bcm2835_delay(500); |
||
2201 | } |
||
2202 | #endif |
||
2203 | |||
2204 | #if 0 |
||
2205 | /* Read input */ |
||
2206 | while (1) |
||
2207 | { |
||
2208 | /* Read some data */ |
||
2209 | uint8_t value = bcm2835_gpio_lev(RPI_GPIO_P1_15); |
||
2210 | printf("read from pin 15: %d\n", value); |
||
2211 | |||
2212 | /* wait a bit */ |
||
2213 | bcm2835_delay(500); |
||
2214 | } |
||
2215 | #endif |
||
2216 | |||
2217 | #if 0 |
||
2218 | /* Look for a low event detection |
||
2219 | // eds will be set whenever pin 15 goes low |
||
2220 | */ |
||
2221 | while (1) |
||
2222 | { |
||
2223 | if (bcm2835_gpio_eds(RPI_GPIO_P1_15)) |
||
2224 | { |
||
2225 | /* Now clear the eds flag by setting it to 1 */ |
||
2226 | bcm2835_gpio_set_eds(RPI_GPIO_P1_15); |
||
2227 | printf("low event detect for pin 15\n"); |
||
2228 | } |
||
2229 | |||
2230 | /* wait a bit */ |
||
2231 | bcm2835_delay(500); |
||
2232 | } |
||
2233 | #endif |
||
2234 | |||
2235 | if (!bcm2835_close()) |
||
2236 | return 1; |
||
2237 | |||
2238 | return 0; |
||
2239 | } |
||
2240 | #endif |
||
2241 | |||
2242 | |||
2243 |