raspi_lcd 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/ext/RaspiLCD-V0.9.0/bcm2835.c +715 -0
- data/ext/RaspiLCD-V0.9.0/bcm2835.h +801 -0
- data/ext/RaspiLCD-V0.9.0/bmp_men.inc +89 -0
- data/ext/RaspiLCD-V0.9.0/bmp_raspi.inc +42 -0
- data/ext/RaspiLCD-V0.9.0/font_fixedsys_8x15.inc +913 -0
- data/ext/RaspiLCD-V0.9.0/font_lucida_10x16.inc +1137 -0
- data/ext/RaspiLCD-V0.9.0/font_terminal_12x16.inc +1137 -0
- data/ext/RaspiLCD-V0.9.0/font_terminal_6x8.inc +689 -0
- data/ext/RaspiLCD-V0.9.0/lcd.c +536 -0
- data/ext/RaspiLCD-V0.9.0/lcd.h +80 -0
- data/ext/RaspiLCD-V0.9.0/main.c +309 -0
- data/ext/RaspiLCD-V0.9.0/raspilcd.c +230 -0
- data/ext/RaspiLCD-V0.9.0/raspilcd.h +104 -0
- data/ext/RaspiLCD-V0.9.0/resource_bmp.inc +324 -0
- data/ext/RaspiLCD-V0.9.0/resource_font_6x8.inc +354 -0
- data/ext/RaspiLCD-V0.9.0/std_c.h +55 -0
- data/ext/raspi_lcd/extconf.rb +2 -0
- data/ext/raspi_lcd/raspi_lcd.c +137 -0
- data/ext/raspi_lcd/test.rb +31 -0
- data/lib/raspi_lcd.rb +5 -0
- metadata +66 -0
@@ -0,0 +1,715 @@
|
|
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 (mikem@open.com.au)
|
7
|
+
// Copyright (C) 2011 Mike McCauley
|
8
|
+
// $Id: bcm2835.c,v 1.4 2012/07/16 23:57:59 mikem Exp mikem $
|
9
|
+
|
10
|
+
#include <stdlib.h>
|
11
|
+
#include <stdio.h>
|
12
|
+
#include <errno.h>
|
13
|
+
#include <fcntl.h>
|
14
|
+
#include <sys/mman.h>
|
15
|
+
#include <string.h>
|
16
|
+
#include <time.h>
|
17
|
+
#include <unistd.h>
|
18
|
+
|
19
|
+
#include "bcm2835.h"
|
20
|
+
|
21
|
+
// This define enables a little test program (by default a blinking output on pin RPI_GPIO_PIN_11)
|
22
|
+
// You can do some safe, non-destructive testing on any platform with:
|
23
|
+
// gcc bcm2835.c -D BCM2835_TEST
|
24
|
+
// ./a.out
|
25
|
+
//#define BCM2835_TEST
|
26
|
+
|
27
|
+
// Locals to hold pointers to the hardware
|
28
|
+
static volatile uint32_t *gpio = MAP_FAILED;
|
29
|
+
static volatile uint32_t *pwm = MAP_FAILED;
|
30
|
+
static volatile uint32_t *clk = MAP_FAILED;
|
31
|
+
static volatile uint32_t *pads = MAP_FAILED;
|
32
|
+
static volatile uint32_t *spi0 = MAP_FAILED;
|
33
|
+
|
34
|
+
static int memfd = -1;
|
35
|
+
|
36
|
+
// This define allows us to test on hardware other than RPi.
|
37
|
+
// It prevents access to the kernel memory, and does not do any peripheral access
|
38
|
+
// Instead it prints out what it _would_ do if debug were 0
|
39
|
+
static uint8_t debug = 0;
|
40
|
+
|
41
|
+
|
42
|
+
//
|
43
|
+
// Low level register access functions
|
44
|
+
//
|
45
|
+
|
46
|
+
void bcm2835_set_debug(uint8_t d)
|
47
|
+
{
|
48
|
+
debug = d;
|
49
|
+
}
|
50
|
+
|
51
|
+
// safe read from peripheral
|
52
|
+
uint32_t bcm2835_peri_read(volatile uint32_t* paddr)
|
53
|
+
{
|
54
|
+
if (debug)
|
55
|
+
{
|
56
|
+
printf("bcm2835_peri_read paddr %08X\n", (unsigned) paddr);
|
57
|
+
return 0;
|
58
|
+
}
|
59
|
+
else
|
60
|
+
{
|
61
|
+
// Make sure we dont return the _last_ read which might get lost
|
62
|
+
// if subsequent code changes to a different peripheral
|
63
|
+
uint32_t ret = *paddr;
|
64
|
+
uint32_t dummy = *paddr;
|
65
|
+
return ret;
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
// read from peripheral without the read barrier
|
70
|
+
uint32_t bcm2835_peri_read_nb(volatile uint32_t* paddr)
|
71
|
+
{
|
72
|
+
if (debug)
|
73
|
+
{
|
74
|
+
printf("bcm2835_peri_read_nb paddr %08X\n", (unsigned) paddr);
|
75
|
+
return 0;
|
76
|
+
}
|
77
|
+
else
|
78
|
+
{
|
79
|
+
return *paddr;
|
80
|
+
}
|
81
|
+
}
|
82
|
+
|
83
|
+
// safe write to peripheral
|
84
|
+
void bcm2835_peri_write(volatile uint32_t* paddr, uint32_t value)
|
85
|
+
{
|
86
|
+
if (debug)
|
87
|
+
{
|
88
|
+
printf("bcm2835_peri_write paddr %08X, value %08X\n", (unsigned) paddr, value);
|
89
|
+
}
|
90
|
+
else
|
91
|
+
{
|
92
|
+
// Make sure we don't rely on the first write, which may get
|
93
|
+
// lost if the previous access was to a different peripheral.
|
94
|
+
*paddr = value;
|
95
|
+
*paddr = value;
|
96
|
+
}
|
97
|
+
}
|
98
|
+
|
99
|
+
// write to peripheral without the write barrier
|
100
|
+
void bcm2835_peri_write_nb(volatile uint32_t* paddr, uint32_t value)
|
101
|
+
{
|
102
|
+
if (debug)
|
103
|
+
{
|
104
|
+
printf("bcm2835_peri_write_nb paddr %08X, value %08X\n",
|
105
|
+
(unsigned) paddr, value);
|
106
|
+
}
|
107
|
+
else
|
108
|
+
{
|
109
|
+
*paddr = value;
|
110
|
+
}
|
111
|
+
}
|
112
|
+
|
113
|
+
// Set/clear only the bits in value covered by the mask
|
114
|
+
void bcm2835_peri_set_bits(volatile uint32_t* paddr, uint32_t value, uint32_t mask)
|
115
|
+
{
|
116
|
+
uint32_t v = bcm2835_peri_read(paddr);
|
117
|
+
v = (v & ~mask) | (value & mask);
|
118
|
+
bcm2835_peri_write(paddr, v);
|
119
|
+
}
|
120
|
+
|
121
|
+
//
|
122
|
+
// Low level convenience functions
|
123
|
+
//
|
124
|
+
|
125
|
+
// Function select
|
126
|
+
// pin is a BCM2835 GPIO pin number NOT RPi pin number
|
127
|
+
// There are 6 control registers, each control the functions of a block
|
128
|
+
// of 10 pins.
|
129
|
+
// Each control register has 10 sets of 3 bits per GPIO pin:
|
130
|
+
//
|
131
|
+
// 000 = GPIO Pin X is an input
|
132
|
+
// 001 = GPIO Pin X is an output
|
133
|
+
// 100 = GPIO Pin X takes alternate function 0
|
134
|
+
// 101 = GPIO Pin X takes alternate function 1
|
135
|
+
// 110 = GPIO Pin X takes alternate function 2
|
136
|
+
// 111 = GPIO Pin X takes alternate function 3
|
137
|
+
// 011 = GPIO Pin X takes alternate function 4
|
138
|
+
// 010 = GPIO Pin X takes alternate function 5
|
139
|
+
//
|
140
|
+
// So the 3 bits for port X are:
|
141
|
+
// X / 10 + ((X % 10) * 3)
|
142
|
+
void bcm2835_gpio_fsel(uint8_t pin, uint8_t mode)
|
143
|
+
{
|
144
|
+
// Function selects are 10 pins per 32 bit word, 3 bits per pin
|
145
|
+
volatile uint32_t* paddr = gpio + BCM2835_GPFSEL0/4 + (pin/10);
|
146
|
+
uint8_t shift = (pin % 10) * 3;
|
147
|
+
uint32_t mask = BCM2835_GPIO_FSEL_MASK << shift;
|
148
|
+
uint32_t value = mode << shift;
|
149
|
+
bcm2835_peri_set_bits(paddr, value, mask);
|
150
|
+
}
|
151
|
+
|
152
|
+
// Set output pin
|
153
|
+
void bcm2835_gpio_set(uint8_t pin)
|
154
|
+
{
|
155
|
+
volatile uint32_t* paddr = gpio + BCM2835_GPSET0/4 + pin/32;
|
156
|
+
uint8_t shift = pin % 32;
|
157
|
+
bcm2835_peri_write(paddr, 1 << shift);
|
158
|
+
}
|
159
|
+
|
160
|
+
// Clear output pin
|
161
|
+
void bcm2835_gpio_clr(uint8_t pin)
|
162
|
+
{
|
163
|
+
volatile uint32_t* paddr = gpio + BCM2835_GPCLR0/4 + pin/32;
|
164
|
+
uint8_t shift = pin % 32;
|
165
|
+
bcm2835_peri_write(paddr, 1 << shift);
|
166
|
+
}
|
167
|
+
|
168
|
+
// Read input pin
|
169
|
+
uint8_t bcm2835_gpio_lev(uint8_t pin)
|
170
|
+
{
|
171
|
+
volatile uint32_t* paddr = gpio + BCM2835_GPLEV0/4 + pin/32;
|
172
|
+
uint8_t shift = pin % 32;
|
173
|
+
uint32_t value = bcm2835_peri_read(paddr);
|
174
|
+
return (value & (1 << shift)) ? HIGH : LOW;
|
175
|
+
}
|
176
|
+
|
177
|
+
// See if an event detection bit is set
|
178
|
+
// Sigh cant support interrupts yet
|
179
|
+
uint8_t bcm2835_gpio_eds(uint8_t pin)
|
180
|
+
{
|
181
|
+
volatile uint32_t* paddr = gpio + BCM2835_GPEDS0/4 + pin/32;
|
182
|
+
uint8_t shift = pin % 32;
|
183
|
+
uint32_t value = bcm2835_peri_read(paddr);
|
184
|
+
return (value & (1 << shift)) ? HIGH : LOW;
|
185
|
+
}
|
186
|
+
|
187
|
+
// Write a 1 to clear the bit in EDS
|
188
|
+
void bcm2835_gpio_set_eds(uint8_t pin)
|
189
|
+
{
|
190
|
+
volatile uint32_t* paddr = gpio + BCM2835_GPEDS0/4 + pin/32;
|
191
|
+
uint8_t shift = pin % 32;
|
192
|
+
uint32_t value = 1 << shift;
|
193
|
+
bcm2835_peri_write(paddr, value);
|
194
|
+
}
|
195
|
+
|
196
|
+
// Rising edge detect enable
|
197
|
+
void bcm2835_gpio_ren(uint8_t pin)
|
198
|
+
{
|
199
|
+
volatile uint32_t* paddr = gpio + BCM2835_GPREN0/4 + pin/32;
|
200
|
+
uint8_t shift = pin % 32;
|
201
|
+
uint32_t value = 1 << shift;
|
202
|
+
bcm2835_peri_set_bits(paddr, value, value);
|
203
|
+
}
|
204
|
+
void bcm2835_gpio_clr_ren(uint8_t pin)
|
205
|
+
{
|
206
|
+
volatile uint32_t* paddr = gpio + BCM2835_GPREN0/4 + pin/32;
|
207
|
+
uint8_t shift = pin % 32;
|
208
|
+
uint32_t value = 1 << shift;
|
209
|
+
bcm2835_peri_set_bits(paddr, 0, value);
|
210
|
+
}
|
211
|
+
|
212
|
+
// Falling edge detect enable
|
213
|
+
void bcm2835_gpio_fen(uint8_t pin)
|
214
|
+
{
|
215
|
+
volatile uint32_t* paddr = gpio + BCM2835_GPFEN0/4 + pin/32;
|
216
|
+
uint8_t shift = pin % 32;
|
217
|
+
uint32_t value = 1 << shift;
|
218
|
+
bcm2835_peri_set_bits(paddr, value, value);
|
219
|
+
}
|
220
|
+
void bcm2835_gpio_clr_fen(uint8_t pin)
|
221
|
+
{
|
222
|
+
volatile uint32_t* paddr = gpio + BCM2835_GPFEN0/4 + pin/32;
|
223
|
+
uint8_t shift = pin % 32;
|
224
|
+
uint32_t value = 1 << shift;
|
225
|
+
bcm2835_peri_set_bits(paddr, 0, value);
|
226
|
+
}
|
227
|
+
|
228
|
+
// High detect enable
|
229
|
+
void bcm2835_gpio_hen(uint8_t pin)
|
230
|
+
{
|
231
|
+
volatile uint32_t* paddr = gpio + BCM2835_GPHEN0/4 + pin/32;
|
232
|
+
uint8_t shift = pin % 32;
|
233
|
+
uint32_t value = 1 << shift;
|
234
|
+
bcm2835_peri_set_bits(paddr, value, value);
|
235
|
+
}
|
236
|
+
void bcm2835_gpio_clr_hen(uint8_t pin)
|
237
|
+
{
|
238
|
+
volatile uint32_t* paddr = gpio + BCM2835_GPHEN0/4 + pin/32;
|
239
|
+
uint8_t shift = pin % 32;
|
240
|
+
uint32_t value = 1 << shift;
|
241
|
+
bcm2835_peri_set_bits(paddr, 0, value);
|
242
|
+
}
|
243
|
+
|
244
|
+
// Low detect enable
|
245
|
+
void bcm2835_gpio_len(uint8_t pin)
|
246
|
+
{
|
247
|
+
volatile uint32_t* paddr = gpio + BCM2835_GPLEN0/4 + pin/32;
|
248
|
+
uint8_t shift = pin % 32;
|
249
|
+
uint32_t value = 1 << shift;
|
250
|
+
bcm2835_peri_set_bits(paddr, value, value);
|
251
|
+
}
|
252
|
+
void bcm2835_gpio_clr_len(uint8_t pin)
|
253
|
+
{
|
254
|
+
volatile uint32_t* paddr = gpio + BCM2835_GPLEN0/4 + pin/32;
|
255
|
+
uint8_t shift = pin % 32;
|
256
|
+
uint32_t value = 1 << shift;
|
257
|
+
bcm2835_peri_set_bits(paddr, 0, value);
|
258
|
+
}
|
259
|
+
|
260
|
+
// Async rising edge detect enable
|
261
|
+
void bcm2835_gpio_aren(uint8_t pin)
|
262
|
+
{
|
263
|
+
volatile uint32_t* paddr = gpio + BCM2835_GPAREN0/4 + pin/32;
|
264
|
+
uint8_t shift = pin % 32;
|
265
|
+
uint32_t value = 1 << shift;
|
266
|
+
bcm2835_peri_set_bits(paddr, value, value);
|
267
|
+
}
|
268
|
+
void bcm2835_gpio_clr_aren(uint8_t pin)
|
269
|
+
{
|
270
|
+
volatile uint32_t* paddr = gpio + BCM2835_GPAREN0/4 + pin/32;
|
271
|
+
uint8_t shift = pin % 32;
|
272
|
+
uint32_t value = 1 << shift;
|
273
|
+
bcm2835_peri_set_bits(paddr, 0, value);
|
274
|
+
}
|
275
|
+
|
276
|
+
// Async falling edge detect enable
|
277
|
+
void bcm2835_gpio_afen(uint8_t pin)
|
278
|
+
{
|
279
|
+
volatile uint32_t* paddr = gpio + BCM2835_GPAFEN0/4 + pin/32;
|
280
|
+
uint8_t shift = pin % 32;
|
281
|
+
uint32_t value = 1 << shift;
|
282
|
+
bcm2835_peri_set_bits(paddr, value, value);
|
283
|
+
}
|
284
|
+
void bcm2835_gpio_clr_afen(uint8_t pin)
|
285
|
+
{
|
286
|
+
volatile uint32_t* paddr = gpio + BCM2835_GPAFEN0/4 + pin/32;
|
287
|
+
uint8_t shift = pin % 32;
|
288
|
+
uint32_t value = 1 << shift;
|
289
|
+
bcm2835_peri_set_bits(paddr, 0, value);
|
290
|
+
}
|
291
|
+
|
292
|
+
// Set pullup/down
|
293
|
+
void bcm2835_gpio_pud(uint8_t pud)
|
294
|
+
{
|
295
|
+
volatile uint32_t* paddr = gpio + BCM2835_GPPUD/4;
|
296
|
+
bcm2835_peri_write(paddr, pud);
|
297
|
+
}
|
298
|
+
|
299
|
+
// Pullup/down clock
|
300
|
+
// Clocks the value of pud into the GPIO pin
|
301
|
+
void bcm2835_gpio_pudclk(uint8_t pin, uint8_t on)
|
302
|
+
{
|
303
|
+
volatile uint32_t* paddr = gpio + BCM2835_GPPUDCLK0/4 + pin/32;
|
304
|
+
uint8_t shift = pin % 32;
|
305
|
+
bcm2835_peri_write(paddr, (on ? 1 : 0) << shift);
|
306
|
+
}
|
307
|
+
|
308
|
+
// Read GPIO pad behaviour for groups of GPIOs
|
309
|
+
uint32_t bcm2835_gpio_pad(uint8_t group)
|
310
|
+
{
|
311
|
+
volatile uint32_t* paddr = pads + BCM2835_PADS_GPIO_0_27/4 + group*2;
|
312
|
+
return bcm2835_peri_read(paddr);
|
313
|
+
}
|
314
|
+
|
315
|
+
// Set GPIO pad behaviour for groups of GPIOs
|
316
|
+
// powerup value for al pads is
|
317
|
+
// BCM2835_PAD_SLEW_RATE_UNLIMITED | BCM2835_PAD_HYSTERESIS_ENABLED | BCM2835_PAD_DRIVE_8mA
|
318
|
+
void bcm2835_gpio_set_pad(uint8_t group, uint32_t control)
|
319
|
+
{
|
320
|
+
volatile uint32_t* paddr = pads + BCM2835_PADS_GPIO_0_27/4 + group*2;
|
321
|
+
bcm2835_peri_write(paddr, control);
|
322
|
+
}
|
323
|
+
|
324
|
+
// Some convenient arduino like functions
|
325
|
+
// milliseconds
|
326
|
+
void bcm2835_delay(unsigned int millis)
|
327
|
+
{
|
328
|
+
struct timespec sleeper;
|
329
|
+
|
330
|
+
sleeper.tv_sec = (time_t)(millis / 1000);
|
331
|
+
sleeper.tv_nsec = (long)(millis % 1000) * 1000000;
|
332
|
+
nanosleep(&sleeper, NULL);
|
333
|
+
}
|
334
|
+
|
335
|
+
// microseconds
|
336
|
+
void bcm2835_delayMicroseconds(unsigned int micros)
|
337
|
+
{
|
338
|
+
struct timespec t0, t1;
|
339
|
+
double t_us;
|
340
|
+
// Calling nanosleep() takes at least 100-200 us, so use it for
|
341
|
+
// long waits and use a busy wait on the hires timer for the rest.
|
342
|
+
clock_gettime(CLOCK_MONOTONIC_RAW, &t0);
|
343
|
+
if (micros > 450)
|
344
|
+
{
|
345
|
+
t1.tv_sec = 0;
|
346
|
+
t1.tv_nsec = 1000 * (long)(micros - 200);
|
347
|
+
nanosleep(&t1, NULL);
|
348
|
+
}
|
349
|
+
|
350
|
+
while (1)
|
351
|
+
{
|
352
|
+
clock_gettime(CLOCK_MONOTONIC_RAW, &t1);
|
353
|
+
t_us = (t1.tv_sec - t0.tv_sec) * 1e6 + (t1.tv_nsec - t0.tv_nsec) * 1e-3;
|
354
|
+
if (t_us >= micros)
|
355
|
+
break;
|
356
|
+
}
|
357
|
+
}
|
358
|
+
|
359
|
+
//
|
360
|
+
// Higher level convenience functions
|
361
|
+
//
|
362
|
+
|
363
|
+
// Set the state of an output
|
364
|
+
void bcm2835_gpio_write(uint8_t pin, uint8_t on)
|
365
|
+
{
|
366
|
+
if (on)
|
367
|
+
{
|
368
|
+
bcm2835_gpio_set(pin);
|
369
|
+
}
|
370
|
+
else
|
371
|
+
{
|
372
|
+
bcm2835_gpio_clr(pin);
|
373
|
+
}
|
374
|
+
}
|
375
|
+
|
376
|
+
// Set the pullup/down resistor for a pin
|
377
|
+
//
|
378
|
+
// The GPIO Pull-up/down Clock Registers control the actuation of internal pull-downs on
|
379
|
+
// the respective GPIO pins. These registers must be used in conjunction with the GPPUD
|
380
|
+
// register to effect GPIO Pull-up/down changes. The following sequence of events is
|
381
|
+
// required:
|
382
|
+
// 1. Write to GPPUD to set the required control signal (i.e. Pull-up or Pull-Down or neither
|
383
|
+
// to remove the current Pull-up/down)
|
384
|
+
// 2. Wait 150 cycles ? this provides the required set-up time for the control signal
|
385
|
+
// 3. Write to GPPUDCLK0/1 to clock the control signal into the GPIO pads you wish to
|
386
|
+
// modify ? NOTE only the pads which receive a clock will be modified, all others will
|
387
|
+
// retain their previous state.
|
388
|
+
// 4. Wait 150 cycles ? this provides the required hold time for the control signal
|
389
|
+
// 5. Write to GPPUD to remove the control signal
|
390
|
+
// 6. Write to GPPUDCLK0/1 to remove the clock
|
391
|
+
//
|
392
|
+
// RPi has P1-03 and P1-05 with 1k8 pullup resistor
|
393
|
+
void bcm2835_gpio_set_pud(uint8_t pin, uint8_t pud)
|
394
|
+
{
|
395
|
+
bcm2835_gpio_pud(pud);
|
396
|
+
delayMicroseconds(10);
|
397
|
+
bcm2835_gpio_pudclk(pin, 1);
|
398
|
+
delayMicroseconds(10);
|
399
|
+
bcm2835_gpio_pud(BCM2835_GPIO_PUD_OFF);
|
400
|
+
bcm2835_gpio_pudclk(pin, 0);
|
401
|
+
}
|
402
|
+
|
403
|
+
void bcm2835_spi_begin(void)
|
404
|
+
{
|
405
|
+
// Set the SPI0 pins to the Alt 0 function to enable SPI0 access on them
|
406
|
+
bcm2835_gpio_fsel(RPI_GPIO_P1_26, BCM2835_GPIO_FSEL_ALT0); // CE1
|
407
|
+
bcm2835_gpio_fsel(RPI_GPIO_P1_24, BCM2835_GPIO_FSEL_ALT0); // CE0
|
408
|
+
bcm2835_gpio_fsel(RPI_GPIO_P1_21, BCM2835_GPIO_FSEL_ALT0); // MISO
|
409
|
+
bcm2835_gpio_fsel(RPI_GPIO_P1_19, BCM2835_GPIO_FSEL_ALT0); // MOSI
|
410
|
+
bcm2835_gpio_fsel(RPI_GPIO_P1_23, BCM2835_GPIO_FSEL_ALT0); // CLK
|
411
|
+
|
412
|
+
// Set the SPI CS register to the some sensible defaults
|
413
|
+
volatile uint32_t* paddr = spi0 + BCM2835_SPI0_CS/4;
|
414
|
+
bcm2835_peri_write(paddr, 0); // All 0s
|
415
|
+
|
416
|
+
// Clear TX and RX fifos
|
417
|
+
bcm2835_peri_write_nb(paddr, BCM2835_SPI0_CS_CLEAR);
|
418
|
+
}
|
419
|
+
|
420
|
+
void bcm2835_spi_end(void)
|
421
|
+
{
|
422
|
+
// Set all the SPI0 pins back to input
|
423
|
+
bcm2835_gpio_fsel(RPI_GPIO_P1_26, BCM2835_GPIO_FSEL_INPT); // CE1
|
424
|
+
bcm2835_gpio_fsel(RPI_GPIO_P1_24, BCM2835_GPIO_FSEL_INPT); // CE0
|
425
|
+
bcm2835_gpio_fsel(RPI_GPIO_P1_21, BCM2835_GPIO_FSEL_INPT); // MISO
|
426
|
+
bcm2835_gpio_fsel(RPI_GPIO_P1_19, BCM2835_GPIO_FSEL_INPT); // MOSI
|
427
|
+
bcm2835_gpio_fsel(RPI_GPIO_P1_23, BCM2835_GPIO_FSEL_INPT); // CLK
|
428
|
+
}
|
429
|
+
|
430
|
+
void bcm2835_spi_setBitOrder(uint8_t order)
|
431
|
+
{
|
432
|
+
// BCM2835_SPI_BIT_ORDER_MSBFIRST is the only one suported by SPI0
|
433
|
+
}
|
434
|
+
|
435
|
+
// defaults to 0, which means a divider of 65536.
|
436
|
+
// The divisor must be a power of 2. Odd numbers
|
437
|
+
// rounded down. The maximum SPI clock rate is
|
438
|
+
// of the APB clock
|
439
|
+
void bcm2835_spi_setClockDivider(uint16_t divider)
|
440
|
+
{
|
441
|
+
volatile uint32_t* paddr = spi0 + BCM2835_SPI0_CLK/4;
|
442
|
+
bcm2835_peri_write(paddr, divider);
|
443
|
+
}
|
444
|
+
|
445
|
+
void bcm2835_spi_setDataMode(uint8_t mode)
|
446
|
+
{
|
447
|
+
volatile uint32_t* paddr = spi0 + BCM2835_SPI0_CS/4;
|
448
|
+
// Mask in the CPO and CPHA bits of CS
|
449
|
+
bcm2835_peri_set_bits(paddr, mode << 2, BCM2835_SPI0_CS_CPOL | BCM2835_SPI0_CS_CPHA);
|
450
|
+
}
|
451
|
+
|
452
|
+
// Writes (and reads) a single byte to SPI
|
453
|
+
uint8_t bcm2835_spi_transfer(uint8_t value)
|
454
|
+
{
|
455
|
+
volatile uint32_t* paddr = spi0 + BCM2835_SPI0_CS/4;
|
456
|
+
volatile uint32_t* fifo = spi0 + BCM2835_SPI0_FIFO/4;
|
457
|
+
|
458
|
+
// This is Polled transfer as per section 10.6.1
|
459
|
+
// BUG ALERT: what happens if we get interupted in this section, and someone else
|
460
|
+
// accesses a different peripheral?
|
461
|
+
// Clear TX and RX fifos
|
462
|
+
bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR);
|
463
|
+
|
464
|
+
// Set TA = 1
|
465
|
+
bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA);
|
466
|
+
|
467
|
+
// Maybe wait for TXD
|
468
|
+
while (!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD))
|
469
|
+
delayMicroseconds(10);
|
470
|
+
|
471
|
+
// Write to FIFO, no barrier
|
472
|
+
bcm2835_peri_write_nb(fifo, value);
|
473
|
+
|
474
|
+
// Wait for DONE to be set
|
475
|
+
while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE))
|
476
|
+
delayMicroseconds(10);
|
477
|
+
|
478
|
+
// Read any byte that was sent back by the slave while we sere sending to it
|
479
|
+
uint32_t ret = bcm2835_peri_read_nb(fifo);
|
480
|
+
|
481
|
+
// Set TA = 0, and also set the barrier
|
482
|
+
bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA);
|
483
|
+
|
484
|
+
return ret;
|
485
|
+
}
|
486
|
+
|
487
|
+
// Writes (and reads) an number of bytes to SPI
|
488
|
+
void bcm2835_spi_transfernb(char* tbuf, char* rbuf, uint32_t len)
|
489
|
+
{
|
490
|
+
volatile uint32_t* paddr = spi0 + BCM2835_SPI0_CS/4;
|
491
|
+
volatile uint32_t* fifo = spi0 + BCM2835_SPI0_FIFO/4;
|
492
|
+
|
493
|
+
// This is Polled transfer as per section 10.6.1
|
494
|
+
// BUG ALERT: what happens if we get interupted in this section, and someone else
|
495
|
+
// accesses a different peripheral?
|
496
|
+
|
497
|
+
// Clear TX and RX fifos
|
498
|
+
bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR);
|
499
|
+
|
500
|
+
// Set TA = 1
|
501
|
+
bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA);
|
502
|
+
|
503
|
+
uint32_t i;
|
504
|
+
for (i = 0; i < len; i++)
|
505
|
+
{
|
506
|
+
// Maybe wait for TXD
|
507
|
+
while (!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD))
|
508
|
+
delayMicroseconds(10);
|
509
|
+
|
510
|
+
// Write to FIFO, no barrier
|
511
|
+
bcm2835_peri_write_nb(fifo, tbuf[i]);
|
512
|
+
|
513
|
+
// Wait for RXD
|
514
|
+
while (!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD))
|
515
|
+
delayMicroseconds(10);
|
516
|
+
|
517
|
+
// then read the data byte
|
518
|
+
rbuf[i] = bcm2835_peri_read_nb(fifo);
|
519
|
+
}
|
520
|
+
// Wait for DONE to be set
|
521
|
+
while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE))
|
522
|
+
delayMicroseconds(10);
|
523
|
+
|
524
|
+
// Set TA = 0, and also set the barrier
|
525
|
+
bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA);
|
526
|
+
}
|
527
|
+
|
528
|
+
// Writes (and reads) an number of bytes to SPI
|
529
|
+
// Read bytes are copied over onto the transmit buffer
|
530
|
+
void bcm2835_spi_transfern(char* buf, uint32_t len)
|
531
|
+
{
|
532
|
+
bcm2835_spi_transfernb(buf, buf, len);
|
533
|
+
}
|
534
|
+
|
535
|
+
void bcm2835_spi_chipSelect(uint8_t cs)
|
536
|
+
{
|
537
|
+
volatile uint32_t* paddr = spi0 + BCM2835_SPI0_CS/4;
|
538
|
+
// Mask in the CS bits of CS
|
539
|
+
bcm2835_peri_set_bits(paddr, cs, BCM2835_SPI0_CS_CS);
|
540
|
+
}
|
541
|
+
|
542
|
+
void bcm2835_spi_setChipSelectPolarity(uint8_t cs, uint8_t active)
|
543
|
+
{
|
544
|
+
volatile uint32_t* paddr = spi0 + BCM2835_SPI0_CS/4;
|
545
|
+
uint8_t shift = 21 + cs;
|
546
|
+
// Mask in the appropriate CSPOLn bit
|
547
|
+
bcm2835_peri_set_bits(paddr, active << shift, 1 << shift);
|
548
|
+
}
|
549
|
+
|
550
|
+
// Allocate page-aligned memory.
|
551
|
+
void *malloc_aligned(size_t size)
|
552
|
+
{
|
553
|
+
void *mem;
|
554
|
+
errno = posix_memalign(&mem, BCM2835_PAGE_SIZE, size);
|
555
|
+
return (errno ? NULL : mem);
|
556
|
+
}
|
557
|
+
|
558
|
+
// Map 'size' bytes starting at 'off' in file 'fd' to memory.
|
559
|
+
// Return mapped address on success, MAP_FAILED otherwise.
|
560
|
+
// On error print message.
|
561
|
+
static void *mapmem(const char *msg, size_t size, int fd, off_t off)
|
562
|
+
{
|
563
|
+
void *map = mmap(NULL, size, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, off);
|
564
|
+
if(MAP_FAILED == map){
|
565
|
+
fprintf(stderr, "bcm2835_init: %s mmap failed: %s\n", msg, strerror(errno)) ;
|
566
|
+
}
|
567
|
+
return map;
|
568
|
+
}
|
569
|
+
|
570
|
+
static void unmapmem(void **pmem, size_t size)
|
571
|
+
{
|
572
|
+
if(*pmem == MAP_FAILED) return;
|
573
|
+
munmap(*pmem, size);
|
574
|
+
*pmem = MAP_FAILED;
|
575
|
+
}
|
576
|
+
|
577
|
+
// Initialise this library.
|
578
|
+
int bcm2835_init(void)
|
579
|
+
{
|
580
|
+
if (debug) {
|
581
|
+
pads = (uint32_t*)BCM2835_GPIO_PADS;
|
582
|
+
clk = (uint32_t*)BCM2835_CLOCK_BASE;
|
583
|
+
gpio = (uint32_t*)BCM2835_GPIO_BASE;
|
584
|
+
pwm = (uint32_t*)BCM2835_GPIO_PWM;
|
585
|
+
spi0 = (uint32_t*)BCM2835_SPI0_BASE;
|
586
|
+
return 1; // Success
|
587
|
+
}
|
588
|
+
int ok = 0;
|
589
|
+
// Open the master /dev/memory device
|
590
|
+
if ((memfd = open("/dev/mem", O_RDWR | O_SYNC) ) < 0) {
|
591
|
+
fprintf(stderr, "bcm2835_init: Unable to open /dev/mem: %s\n",
|
592
|
+
strerror(errno)) ;
|
593
|
+
goto exit;
|
594
|
+
}
|
595
|
+
|
596
|
+
// GPIO:
|
597
|
+
gpio = mapmem("gpio", BCM2835_BLOCK_SIZE, memfd, BCM2835_GPIO_BASE);
|
598
|
+
if (gpio == MAP_FAILED) goto exit;
|
599
|
+
|
600
|
+
// PWM
|
601
|
+
pwm = mapmem("pwm", BCM2835_BLOCK_SIZE, memfd, BCM2835_GPIO_PWM);
|
602
|
+
if (pwm == MAP_FAILED) goto exit;
|
603
|
+
|
604
|
+
// Clock control (needed for PWM)
|
605
|
+
clk = mapmem("clk", BCM2835_BLOCK_SIZE, memfd, BCM2835_CLOCK_BASE);
|
606
|
+
if (clk == MAP_FAILED) goto exit;
|
607
|
+
|
608
|
+
pads = mapmem("pads", BCM2835_BLOCK_SIZE, memfd, BCM2835_GPIO_PADS);
|
609
|
+
if (pads == MAP_FAILED) goto exit;
|
610
|
+
|
611
|
+
spi0 = mapmem("spi0", BCM2835_BLOCK_SIZE, memfd, BCM2835_SPI0_BASE);
|
612
|
+
if (spi0 == MAP_FAILED) goto exit;
|
613
|
+
|
614
|
+
ok = 1;
|
615
|
+
exit:
|
616
|
+
if(!ok){
|
617
|
+
bcm2835_close();
|
618
|
+
}
|
619
|
+
return ok;
|
620
|
+
}
|
621
|
+
|
622
|
+
// Close this library and deallocate everything
|
623
|
+
int bcm2835_close(void)
|
624
|
+
{
|
625
|
+
int ok = 1; // Success.
|
626
|
+
if (debug) return ok;
|
627
|
+
unmapmem((void**) &gpio, BCM2835_BLOCK_SIZE);
|
628
|
+
unmapmem((void**) &pwm, BCM2835_BLOCK_SIZE);
|
629
|
+
unmapmem((void**) &clk, BCM2835_BLOCK_SIZE);
|
630
|
+
unmapmem((void**) &spi0, BCM2835_BLOCK_SIZE);
|
631
|
+
if (memfd >= 0)
|
632
|
+
{
|
633
|
+
close(memfd);
|
634
|
+
memfd = -1;
|
635
|
+
}
|
636
|
+
return ok;
|
637
|
+
}
|
638
|
+
|
639
|
+
#ifdef BCM2835_TEST
|
640
|
+
// this is a simple test program that prints out what it will do rather than
|
641
|
+
// actually doing it
|
642
|
+
int main(int argc, char **argv)
|
643
|
+
{
|
644
|
+
// Be non-destructive
|
645
|
+
bcm2835_set_debug(1);
|
646
|
+
|
647
|
+
if (!bcm2835_init())
|
648
|
+
return 1;
|
649
|
+
|
650
|
+
// Configure some GPIO pins fo some testing
|
651
|
+
// Set RPI pin P1-11 to be an output
|
652
|
+
bcm2835_gpio_fsel(RPI_GPIO_P1_11, BCM2835_GPIO_FSEL_OUTP);
|
653
|
+
// Set RPI pin P1-15 to be an input
|
654
|
+
bcm2835_gpio_fsel(RPI_GPIO_P1_15, BCM2835_GPIO_FSEL_INPT);
|
655
|
+
// with a pullup
|
656
|
+
bcm2835_gpio_set_pud(RPI_GPIO_P1_15, BCM2835_GPIO_PUD_UP);
|
657
|
+
// And a low detect enable
|
658
|
+
bcm2835_gpio_len(RPI_GPIO_P1_15);
|
659
|
+
// and input hysteresis disabled on GPIOs 0 to 27
|
660
|
+
bcm2835_gpio_set_pad(BCM2835_PAD_GROUP_GPIO_0_27, BCM2835_PAD_SLEW_RATE_UNLIMITED|BCM2835_PAD_DRIVE_8mA);
|
661
|
+
|
662
|
+
#if 1
|
663
|
+
// Blink
|
664
|
+
while (1)
|
665
|
+
{
|
666
|
+
// Turn it on
|
667
|
+
bcm2835_gpio_write(RPI_GPIO_P1_11, HIGH);
|
668
|
+
|
669
|
+
// wait a bit
|
670
|
+
bcm2835_delay(500);
|
671
|
+
|
672
|
+
// turn it off
|
673
|
+
bcm2835_gpio_write(RPI_GPIO_P1_11, LOW);
|
674
|
+
|
675
|
+
// wait a bit
|
676
|
+
bcm2835_delay(500);
|
677
|
+
}
|
678
|
+
#endif
|
679
|
+
|
680
|
+
#if 0
|
681
|
+
// Read input
|
682
|
+
while (1)
|
683
|
+
{
|
684
|
+
// Read some data
|
685
|
+
uint8_t value = bcm2835_gpio_lev(RPI_GPIO_P1_15);
|
686
|
+
printf("read from pin 15: %d\n", value);
|
687
|
+
|
688
|
+
// wait a bit
|
689
|
+
bcm2835_delay(500);
|
690
|
+
}
|
691
|
+
#endif
|
692
|
+
|
693
|
+
#if 0
|
694
|
+
// Look for a low event detection
|
695
|
+
// eds will be set whenever pin 15 goes low
|
696
|
+
while (1)
|
697
|
+
{
|
698
|
+
if (bcm2835_gpio_eds(RPI_GPIO_P1_15))
|
699
|
+
{
|
700
|
+
// Now clear the eds flag by setting it to 1
|
701
|
+
bcm2835_gpio_set_eds(RPI_GPIO_P1_15);
|
702
|
+
printf("low event detect for pin 15\n");
|
703
|
+
}
|
704
|
+
|
705
|
+
// wait a bit
|
706
|
+
bcm2835_delay(500);
|
707
|
+
}
|
708
|
+
#endif
|
709
|
+
|
710
|
+
if (!bcm2835_close())
|
711
|
+
return 1;
|
712
|
+
|
713
|
+
return 0;
|
714
|
+
}
|
715
|
+
#endif
|