wiringpi 0.0.1-armv6l-linux
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/wiringpi/extconf.rb +2 -0
- data/ext/wiringpi/wiringpi.c +587 -0
- data/ext/wiringpi/wiringpi.h +63 -0
- data/ext/wiringpi/wiringpi_wrap.c +2346 -0
- data/lib/wiringpi.rb +111 -0
- metadata +54 -0
@@ -0,0 +1,587 @@
|
|
1
|
+
/*
|
2
|
+
* wiringPi:
|
3
|
+
* Arduino compatable (ish) Wiring library for the Raspberry Pi
|
4
|
+
* Copyright (c) 2012 Gordon Henderson
|
5
|
+
*
|
6
|
+
* Thanks to code samples from Gert Jan van Loo and the
|
7
|
+
* BCM2835 ARM Peripherals manual, however it's missing
|
8
|
+
* the clock section /grr/mutter/
|
9
|
+
***********************************************************************
|
10
|
+
* This file is part of wiringPi:
|
11
|
+
* https://projects.drogon.net/raspberry-pi/wiringpi/
|
12
|
+
*
|
13
|
+
* wiringPi is free software: you can redistribute it and/or modify
|
14
|
+
* it under the terms of the GNU General Public License as published by
|
15
|
+
* the Free Software Foundation, either version 3 of the License, or
|
16
|
+
* (at your option) any later version.
|
17
|
+
*
|
18
|
+
* wiringPi is distributed in the hope that it will be useful,
|
19
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
20
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
21
|
+
* GNU General Public License for more details.
|
22
|
+
*
|
23
|
+
* You should have received a copy of the GNU General Public License
|
24
|
+
* along with wiringPi. If not, see <http://www.gnu.org/licenses/>.
|
25
|
+
***********************************************************************
|
26
|
+
*/
|
27
|
+
|
28
|
+
// Revisions:
|
29
|
+
// 11 Jun 2012:
|
30
|
+
// Fixed some typos.
|
31
|
+
// Added c++ support for the .h file
|
32
|
+
// Added a new function to allow for using my "pin" numbers, or native
|
33
|
+
// GPIO pin numbers.
|
34
|
+
// Removed my busy-loop delay and replaced it with a call to delayMicroseconds
|
35
|
+
//
|
36
|
+
// 02 May 2012:
|
37
|
+
// Added in the 2 UART pins
|
38
|
+
// Change maxPins to numPins to more accurately reflect purpose
|
39
|
+
|
40
|
+
// Pad drive current fiddling
|
41
|
+
|
42
|
+
#undef DEBUG_PADS
|
43
|
+
|
44
|
+
#include <stdio.h>
|
45
|
+
#include <stdint.h>
|
46
|
+
#include <errno.h>
|
47
|
+
#include <string.h>
|
48
|
+
#include <time.h>
|
49
|
+
#include <fcntl.h>
|
50
|
+
#include <sys/mman.h>
|
51
|
+
|
52
|
+
#include "wiringpi.h"
|
53
|
+
|
54
|
+
#ifndef TRUE
|
55
|
+
#define TRUE (1==1)
|
56
|
+
#define FALSE (1==2)
|
57
|
+
#endif
|
58
|
+
|
59
|
+
// Port function select bits
|
60
|
+
|
61
|
+
#define FSEL_INPT 0b000
|
62
|
+
#define FSEL_OUTP 0b001
|
63
|
+
#define FSEL_ALT0 0b100
|
64
|
+
#define FSEL_ALT0 0b100
|
65
|
+
#define FSEL_ALT1 0b101
|
66
|
+
#define FSEL_ALT2 0b110
|
67
|
+
#define FSEL_ALT3 0b111
|
68
|
+
#define FSEL_ALT4 0b011
|
69
|
+
#define FSEL_ALT5 0b010
|
70
|
+
|
71
|
+
// Access from ARM Running Linux
|
72
|
+
// Take from Gerts code. Some of this is not in the manual
|
73
|
+
// that I can find )-:
|
74
|
+
|
75
|
+
#define BCM2708_PERI_BASE 0x20000000
|
76
|
+
#define GPIO_PADS (BCM2708_PERI_BASE + 0x100000)
|
77
|
+
#define CLOCK_BASE (BCM2708_PERI_BASE + 0x101000)
|
78
|
+
#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000)
|
79
|
+
#define GPIO_PWM (BCM2708_PERI_BASE + 0x20C000)
|
80
|
+
|
81
|
+
#define PAGE_SIZE (4*1024)
|
82
|
+
#define BLOCK_SIZE (4*1024)
|
83
|
+
|
84
|
+
// PWM
|
85
|
+
|
86
|
+
#define PWM_CONTROL 0
|
87
|
+
#define PWM_STATUS 1
|
88
|
+
#define PWM0_RANGE 4
|
89
|
+
#define PWM0_DATA 5
|
90
|
+
#define PWM1_RANGE 8
|
91
|
+
#define PWM1_DATA 9
|
92
|
+
|
93
|
+
#define PWMCLK_CNTL 40
|
94
|
+
#define PWMCLK_DIV 41
|
95
|
+
|
96
|
+
#define PWM1_MS_MODE 0x8000 // Run in MS mode
|
97
|
+
#define PWM1_USEFIFO 0x2000 // Data from FIFO
|
98
|
+
#define PWM1_REVPOLAR 0x1000 // Reverse polarity
|
99
|
+
#define PWM1_OFFSTATE 0x0800 // Ouput Off state
|
100
|
+
#define PWM1_REPEATFF 0x0400 // Repeat last value if FIFO empty
|
101
|
+
#define PWM1_SERIAL 0x0200 // Run in serial mode
|
102
|
+
#define PWM1_ENABLE 0x0100 // Channel Enable
|
103
|
+
|
104
|
+
#define PWM0_MS_MODE 0x0080 // Run in MS mode
|
105
|
+
#define PWM0_USEFIFO 0x0020 // Data from FIFO
|
106
|
+
#define PWM0_REVPOLAR 0x0010 // Reverse polarity
|
107
|
+
#define PWM0_OFFSTATE 0x0008 // Ouput Off state
|
108
|
+
#define PWM0_REPEATFF 0x0004 // Repeat last value if FIFO empty
|
109
|
+
#define PWM0_SERIAL 0x0002 // Run in serial mode
|
110
|
+
#define PWM0_ENABLE 0x0001 // Channel Enable
|
111
|
+
|
112
|
+
|
113
|
+
// Locals to hold pointers to the hardware
|
114
|
+
|
115
|
+
static volatile uint32_t *gpio ;
|
116
|
+
static volatile uint32_t *pwm ;
|
117
|
+
static volatile uint32_t *clk ;
|
118
|
+
|
119
|
+
// The BCM2835 has 54 GPIO pins.
|
120
|
+
// BCM2835 data sheet, Page 90 onwards.
|
121
|
+
// There are 6 control registers, each control the functions of a block
|
122
|
+
// of 10 pins.
|
123
|
+
// Each control register has 10 sets of 3 bits per GPIO pin:
|
124
|
+
//
|
125
|
+
// 000 = GPIO Pin X is an input
|
126
|
+
// 001 = GPIO Pin X is an output
|
127
|
+
// 100 = GPIO Pin X takes alternate function 0
|
128
|
+
// 101 = GPIO Pin X takes alternate function 1
|
129
|
+
// 110 = GPIO Pin X takes alternate function 2
|
130
|
+
// 111 = GPIO Pin X takes alternate function 3
|
131
|
+
// 011 = GPIO Pin X takes alternate function 4
|
132
|
+
// 010 = GPIO Pin X takes alternate function 5
|
133
|
+
//
|
134
|
+
// So the 3 bits for port X are:
|
135
|
+
// X / 10 + ((X % 10) * 3)
|
136
|
+
|
137
|
+
// mode
|
138
|
+
|
139
|
+
static int gpioPinMode ;
|
140
|
+
|
141
|
+
// Doing it the Arduino way with lookup tables...
|
142
|
+
// Yes, it's probably more innefficient than all the bit-twidling, but it
|
143
|
+
// does tend to make it all a bit clearer. At least to me!
|
144
|
+
|
145
|
+
// pinToGpio:
|
146
|
+
// Take a Wiring pin (0 through X) and re-map it to the BCM_GPIO pin
|
147
|
+
|
148
|
+
static int pinToGpio [] =
|
149
|
+
{
|
150
|
+
17, 18, 21, 22, 23, 24, 25, 4, // From the Original Wiki - GPIO 0 through 7
|
151
|
+
0, 1, // I2C - SDA0, SCL0
|
152
|
+
8, 7, // SPI - CE1, CE0
|
153
|
+
10, 9, 11, // SPI - MISO, MOSI, SCLK
|
154
|
+
14, 15, // UART - Tx, Rx
|
155
|
+
} ;
|
156
|
+
|
157
|
+
// gpioToGPFSEL:
|
158
|
+
// Map a BCM_GPIO pin to it's control port. (GPFSEL 0-5)
|
159
|
+
|
160
|
+
static uint8_t gpioToGPFSEL [] =
|
161
|
+
{
|
162
|
+
0,0,0,0,0,0,0,0,0,0,
|
163
|
+
1,1,1,1,1,1,1,1,1,1,
|
164
|
+
2,2,2,2,2,2,2,2,2,2,
|
165
|
+
3,3,3,3,3,3,3,3,3,3,
|
166
|
+
4,4,4,4,4,4,4,4,4,4,
|
167
|
+
5,5,5,5,5,5,5,5,5,5,
|
168
|
+
} ;
|
169
|
+
|
170
|
+
// gpioToShift
|
171
|
+
// Define the shift up for the 3 bits per pin in each GPFSEL port
|
172
|
+
|
173
|
+
static uint8_t gpioToShift [] =
|
174
|
+
{
|
175
|
+
0,3,6,9,12,15,18,21,24,27,
|
176
|
+
0,3,6,9,12,15,18,21,24,27,
|
177
|
+
0,3,6,9,12,15,18,21,24,27,
|
178
|
+
0,3,6,9,12,15,18,21,24,27,
|
179
|
+
0,3,6,9,12,15,18,21,24,27,
|
180
|
+
} ;
|
181
|
+
|
182
|
+
// gpioToGPSET:
|
183
|
+
// (Word) offset to the GPIO Set registers for each GPIO pin
|
184
|
+
|
185
|
+
static uint8_t gpioToGPSET [] =
|
186
|
+
{
|
187
|
+
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
188
|
+
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
189
|
+
} ;
|
190
|
+
|
191
|
+
// gpioToGPCLR:
|
192
|
+
// (Word) offset to the GPIO Clear registers for each GPIO pin
|
193
|
+
|
194
|
+
static uint8_t gpioToGPCLR [] =
|
195
|
+
{
|
196
|
+
10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
|
197
|
+
11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
|
198
|
+
} ;
|
199
|
+
|
200
|
+
// gpioToGPLEV:
|
201
|
+
// (Word) offset to the GPIO Input level registers for each GPIO pin
|
202
|
+
|
203
|
+
static uint8_t gpioToGPLEV [] =
|
204
|
+
{
|
205
|
+
13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
|
206
|
+
14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,
|
207
|
+
} ;
|
208
|
+
|
209
|
+
// gpioToPUDCLK
|
210
|
+
// (Word) offset to the Pull Up Down Clock regsiter
|
211
|
+
|
212
|
+
static uint8_t gpioToPUDCLK [] =
|
213
|
+
{
|
214
|
+
38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,
|
215
|
+
39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,
|
216
|
+
} ;
|
217
|
+
|
218
|
+
// gpioToPwmALT
|
219
|
+
// the ALT value to put a GPIO pin into PWM mode
|
220
|
+
|
221
|
+
static uint8_t gpioToPwmALT [] =
|
222
|
+
{
|
223
|
+
0, 0, 0, 0, 0, 0, 0, 0, // 0 -> 7
|
224
|
+
0, 0, 0, 0, FSEL_ALT0, FSEL_ALT0, 0, 0, // 8 -> 15
|
225
|
+
0, 0, FSEL_ALT5, FSEL_ALT5, 0, 0, 0, 0, // 16 -> 23
|
226
|
+
0, 0, 0, 0, 0, 0, 0, 0, // 24 -> 31
|
227
|
+
0, 0, 0, 0, 0, 0, 0, 0, // 32 -> 39
|
228
|
+
FSEL_ALT0, FSEL_ALT0, 0, 0, 0, FSEL_ALT0, 0, 0, // 40 -> 47
|
229
|
+
0, 0, 0, 0, 0, 0, 0, 0, // 48 -> 55
|
230
|
+
0, 0, 0, 0, 0, 0, 0, 0, // 56 -> 63
|
231
|
+
} ;
|
232
|
+
|
233
|
+
static uint8_t gpioToPwmPort [] =
|
234
|
+
{
|
235
|
+
0, 0, 0, 0, 0, 0, 0, 0, // 0 -> 7
|
236
|
+
0, 0, 0, 0, PWM0_DATA, PWM1_DATA, 0, 0, // 8 -> 15
|
237
|
+
0, 0, PWM0_DATA, PWM1_DATA, 0, 0, 0, 0, // 16 -> 23
|
238
|
+
0, 0, 0, 0, 0, 0, 0, 0, // 24 -> 31
|
239
|
+
0, 0, 0, 0, 0, 0, 0, 0, // 32 -> 39
|
240
|
+
PWM0_DATA, PWM1_DATA, 0, 0, 0, PWM1_DATA, 0, 0, // 40 -> 47
|
241
|
+
0, 0, 0, 0, 0, 0, 0, 0, // 48 -> 55
|
242
|
+
0, 0, 0, 0, 0, 0, 0, 0, // 56 -> 63
|
243
|
+
|
244
|
+
} ;
|
245
|
+
|
246
|
+
|
247
|
+
//////////////////////////////////////////////////////////////////////////////////
|
248
|
+
|
249
|
+
|
250
|
+
/*
|
251
|
+
* wiringPiGpioMode:
|
252
|
+
* Set the mode - use Pin numbers (0-16) or GPIO number (seemingly random)
|
253
|
+
*********************************************************************************
|
254
|
+
*/
|
255
|
+
|
256
|
+
void wiringPiGpioMode (int mode)
|
257
|
+
{
|
258
|
+
gpioPinMode = mode ;
|
259
|
+
}
|
260
|
+
|
261
|
+
|
262
|
+
/*
|
263
|
+
* wiringPiSetup:
|
264
|
+
* Must be called once at the start of your program execution.
|
265
|
+
*********************************************************************************
|
266
|
+
*/
|
267
|
+
|
268
|
+
int wiringPiSetup (void)
|
269
|
+
{
|
270
|
+
int fd ;
|
271
|
+
uint8_t *gpioMem, *pwmMem, *clkMem ;
|
272
|
+
|
273
|
+
#ifdef DEBUG_PADS
|
274
|
+
uint8_t *gpioMem, *padsMem, *pwmMem, *clkMem ;
|
275
|
+
uint32_t *pads ;
|
276
|
+
#endif
|
277
|
+
|
278
|
+
// Set Pin mode by default
|
279
|
+
|
280
|
+
wiringPiGpioMode (WPI_MODE_PINS) ;
|
281
|
+
|
282
|
+
// Open the master /dev/memory device
|
283
|
+
|
284
|
+
if ((fd = open ("/dev/mem", O_RDWR | O_SYNC) ) < 0)
|
285
|
+
{
|
286
|
+
fprintf (stderr, "wiringPiSetup: Unable to open /dev/mem: %s\n", strerror (errno)) ;
|
287
|
+
return -1 ;
|
288
|
+
}
|
289
|
+
|
290
|
+
// GPIO:
|
291
|
+
|
292
|
+
// Allocate 2 pages - 1 ...
|
293
|
+
|
294
|
+
if ((gpioMem = malloc (BLOCK_SIZE + (PAGE_SIZE-1))) == NULL)
|
295
|
+
{
|
296
|
+
fprintf (stderr, "wiringPiSetup: malloc failed: %s\n", strerror (errno)) ;
|
297
|
+
return -1 ;
|
298
|
+
}
|
299
|
+
|
300
|
+
// ... presumably to make sure we can round it up to a whole page size
|
301
|
+
|
302
|
+
if (((uint32_t)gpioMem % PAGE_SIZE) != 0)
|
303
|
+
gpioMem += PAGE_SIZE - ((uint32_t)gpioMem % PAGE_SIZE) ;
|
304
|
+
|
305
|
+
gpio = (uint32_t *)mmap((caddr_t)gpioMem, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, fd, GPIO_BASE) ;
|
306
|
+
|
307
|
+
if ((int32_t)gpio < 0)
|
308
|
+
{
|
309
|
+
fprintf (stderr, "wiringPiSetup: mmap failed: %s\n", strerror (errno)) ;
|
310
|
+
return -1 ;
|
311
|
+
}
|
312
|
+
|
313
|
+
// PWM
|
314
|
+
|
315
|
+
if ((pwmMem = malloc (BLOCK_SIZE + (PAGE_SIZE-1))) == NULL)
|
316
|
+
{
|
317
|
+
fprintf (stderr, "wiringPiSetup: pwmMem malloc failed: %s\n", strerror (errno)) ;
|
318
|
+
return -1 ;
|
319
|
+
}
|
320
|
+
|
321
|
+
if (((uint32_t)pwmMem % PAGE_SIZE) != 0)
|
322
|
+
pwmMem += PAGE_SIZE - ((uint32_t)pwmMem % PAGE_SIZE) ;
|
323
|
+
|
324
|
+
pwm = (uint32_t *)mmap(pwmMem, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, fd, GPIO_PWM) ;
|
325
|
+
|
326
|
+
if ((int32_t)pwm < 0)
|
327
|
+
{
|
328
|
+
fprintf (stderr, "wiringPiSetup: mmap failed (pwm): %s\n", strerror (errno)) ;
|
329
|
+
return -1 ;
|
330
|
+
}
|
331
|
+
|
332
|
+
// Clock control (needed for PWM)
|
333
|
+
|
334
|
+
if ((clkMem = malloc (BLOCK_SIZE + (PAGE_SIZE-1))) == NULL)
|
335
|
+
{
|
336
|
+
fprintf (stderr, "wiringPiSetup: clkMem malloc failed: %s\n", strerror (errno)) ;
|
337
|
+
return -1 ;
|
338
|
+
}
|
339
|
+
|
340
|
+
if (((uint32_t)clkMem % PAGE_SIZE) != 0)
|
341
|
+
clkMem += PAGE_SIZE - ((uint32_t)clkMem % PAGE_SIZE) ;
|
342
|
+
|
343
|
+
clk = (uint32_t *)mmap(clkMem, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, fd, CLOCK_BASE) ;
|
344
|
+
|
345
|
+
if ((int32_t)clk < 0)
|
346
|
+
{
|
347
|
+
fprintf (stderr, "wiringPiSetup: mmap failed (clk): %s\n", strerror (errno)) ;
|
348
|
+
return -1 ;
|
349
|
+
}
|
350
|
+
|
351
|
+
#ifdef DEBUG_PADS
|
352
|
+
if ((padsMem = malloc (BLOCK_SIZE + (PAGE_SIZE-1))) == NULL)
|
353
|
+
{
|
354
|
+
fprintf (stderr, "wiringPiSetup: padsMem malloc failed: %s\n", strerror (errno)) ;
|
355
|
+
return -1 ;
|
356
|
+
}
|
357
|
+
|
358
|
+
if (((uint32_t)padsMem % PAGE_SIZE) != 0)
|
359
|
+
padsMem += PAGE_SIZE - ((uint32_t)padsMem % PAGE_SIZE) ;
|
360
|
+
|
361
|
+
pads = (uint32_t *)mmap(padsMem, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, fd, GPIO_PADS) ;
|
362
|
+
|
363
|
+
if ((int32_t)pads < 0)
|
364
|
+
{
|
365
|
+
fprintf (stderr, "wiringPiSetup: mmap failed (pads): %s\n", strerror (errno)) ;
|
366
|
+
return -1 ;
|
367
|
+
}
|
368
|
+
|
369
|
+
printf ("Checking pads @ 0x%08X\n", (unsigned int)pads) ;
|
370
|
+
|
371
|
+
printf ("%08X %08X %08X\n", *(pads + 11), *(pads + 12), *(pads + 13)) ;
|
372
|
+
// *(pads + 11) = 0x1F ;
|
373
|
+
printf ("%08X %08X %08X\n", *(pads + 11), *(pads + 12), *(pads + 13)) ;
|
374
|
+
#endif
|
375
|
+
|
376
|
+
return 0 ;
|
377
|
+
}
|
378
|
+
|
379
|
+
|
380
|
+
/*
|
381
|
+
* pinMode:
|
382
|
+
* Sets the mode of a pin to be input, output or PWM output
|
383
|
+
*********************************************************************************
|
384
|
+
*/
|
385
|
+
|
386
|
+
void pinMode (int pin, int mode)
|
387
|
+
{
|
388
|
+
static int pwmRunning = FALSE ;
|
389
|
+
|
390
|
+
int gpioPin, fSel, shift ;
|
391
|
+
int alt ;
|
392
|
+
|
393
|
+
|
394
|
+
if (gpioPinMode == WPI_MODE_PINS)
|
395
|
+
{
|
396
|
+
if ((pin < 0) || (pin >= NUM_PINS))
|
397
|
+
return ;
|
398
|
+
gpioPin = pinToGpio [pin] ;
|
399
|
+
}
|
400
|
+
else
|
401
|
+
gpioPin = pin ;
|
402
|
+
|
403
|
+
fSel = gpioToGPFSEL [gpioPin] ;
|
404
|
+
shift = gpioToShift [gpioPin] ;
|
405
|
+
|
406
|
+
|
407
|
+
/**/ if (mode == INPUT)
|
408
|
+
*(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) ; // Sets bits to zero = input
|
409
|
+
else if (mode == OUTPUT)
|
410
|
+
*(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) | (1 << shift) ;
|
411
|
+
else if (mode == PWM_OUTPUT)
|
412
|
+
{
|
413
|
+
if ((alt = gpioToPwmALT [gpioPin]) == 0) // Not a PWM pin
|
414
|
+
return ;
|
415
|
+
|
416
|
+
// Set pin to PWM mode
|
417
|
+
|
418
|
+
*(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) | (alt << shift) ;
|
419
|
+
|
420
|
+
// We didn't initialise the PWM hardware at setup time - because it's possible that
|
421
|
+
// something else is using the PWM - e.g. the Audio systems! So if we use PWM
|
422
|
+
// here, then we're assuming that nothing else is, otherwise things are going
|
423
|
+
// to sound a bit funny...
|
424
|
+
|
425
|
+
if (!pwmRunning)
|
426
|
+
{
|
427
|
+
|
428
|
+
// Gert/Doms Values
|
429
|
+
*(clk + PWMCLK_DIV) = 0x5A000000 | (32<<12) ; // set pwm div to 32 (19.2/3 = 600KHz)
|
430
|
+
*(clk + PWMCLK_CNTL) = 0x5A000011 ; // Source=osc and enable
|
431
|
+
digitalWrite (pin, LOW) ;
|
432
|
+
*(pwm + PWM_CONTROL) = 0 ; // Disable PWM
|
433
|
+
delayMicroseconds (10) ;
|
434
|
+
*(pwm + PWM0_RANGE) = 0x400 ;
|
435
|
+
delayMicroseconds (10) ;
|
436
|
+
*(pwm + PWM1_RANGE) = 0x400 ;
|
437
|
+
delayMicroseconds (10) ;
|
438
|
+
|
439
|
+
// Enable PWMs
|
440
|
+
|
441
|
+
*(pwm + PWM0_DATA) = 512 ;
|
442
|
+
*(pwm + PWM1_DATA) = 512 ;
|
443
|
+
|
444
|
+
*(pwm + PWM_CONTROL) = PWM0_ENABLE | PWM1_ENABLE ;
|
445
|
+
}
|
446
|
+
|
447
|
+
}
|
448
|
+
|
449
|
+
// When we change mode of any pin, we remove the pull up/downs
|
450
|
+
|
451
|
+
pullUpDnControl (pin, PUD_OFF) ;
|
452
|
+
}
|
453
|
+
|
454
|
+
|
455
|
+
/*
|
456
|
+
* digitalWrite:
|
457
|
+
* Set an output bit
|
458
|
+
*********************************************************************************
|
459
|
+
*/
|
460
|
+
|
461
|
+
void digitalWrite (int pin, int value)
|
462
|
+
{
|
463
|
+
int gpioPin ;
|
464
|
+
|
465
|
+
if (gpioPinMode == WPI_MODE_PINS)
|
466
|
+
{
|
467
|
+
if ((pin < 0) || (pin >= NUM_PINS))
|
468
|
+
return ;
|
469
|
+
gpioPin = pinToGpio [pin] ;
|
470
|
+
}
|
471
|
+
else
|
472
|
+
gpioPin = pin ;
|
473
|
+
|
474
|
+
if (value == HIGH)
|
475
|
+
*(gpio + gpioToGPSET [gpioPin]) = 1 << gpioPin ;
|
476
|
+
else
|
477
|
+
*(gpio + gpioToGPCLR [gpioPin]) = 1 << gpioPin ;
|
478
|
+
}
|
479
|
+
|
480
|
+
|
481
|
+
/*
|
482
|
+
* pwnWrite:
|
483
|
+
* Set an output PWM value
|
484
|
+
*********************************************************************************
|
485
|
+
*/
|
486
|
+
|
487
|
+
void pwmWrite (int pin, int value)
|
488
|
+
{
|
489
|
+
int port, gpioPin ;
|
490
|
+
|
491
|
+
if (gpioPinMode == WPI_MODE_PINS)
|
492
|
+
{
|
493
|
+
if ((pin < 0) || (pin >= NUM_PINS))
|
494
|
+
return ;
|
495
|
+
gpioPin = pinToGpio [pin] ;
|
496
|
+
}
|
497
|
+
else
|
498
|
+
gpioPin = pin ;
|
499
|
+
|
500
|
+
port = gpioToPwmPort [gpioPin] ;
|
501
|
+
|
502
|
+
*(pwm + port) = value & ~0x400 ;
|
503
|
+
}
|
504
|
+
|
505
|
+
|
506
|
+
/*
|
507
|
+
* digitalRead:
|
508
|
+
* Read the value of a given Pin, returning HIGH or LOW
|
509
|
+
*********************************************************************************
|
510
|
+
*/
|
511
|
+
|
512
|
+
int digitalRead (int pin)
|
513
|
+
{
|
514
|
+
int gpioPin ;
|
515
|
+
|
516
|
+
if (gpioPinMode == WPI_MODE_PINS)
|
517
|
+
{
|
518
|
+
if ((pin < 0) || (pin >= NUM_PINS))
|
519
|
+
return 0 ;
|
520
|
+
gpioPin = pinToGpio [pin] ;
|
521
|
+
}
|
522
|
+
else
|
523
|
+
gpioPin = pin ;
|
524
|
+
|
525
|
+
if ((*(gpio + gpioToGPLEV [gpioPin]) & (1 << gpioPin)) != 0)
|
526
|
+
return HIGH ;
|
527
|
+
else
|
528
|
+
return LOW ;
|
529
|
+
}
|
530
|
+
|
531
|
+
/*
|
532
|
+
* pullUpDownCtrl:
|
533
|
+
* Control the internal pull-up/down resistors on a GPIO pin
|
534
|
+
* The Arduino only has pull-ups and these are enabled by writing 1
|
535
|
+
* to a port when in input mode - this paradigm doesn't quite apply
|
536
|
+
* here though.
|
537
|
+
*********************************************************************************
|
538
|
+
*/
|
539
|
+
|
540
|
+
void pullUpDnControl (int pin, int pud)
|
541
|
+
{
|
542
|
+
int gpioPin ;
|
543
|
+
|
544
|
+
if (gpioPinMode == WPI_MODE_PINS)
|
545
|
+
{
|
546
|
+
if ((pin < 0) || (pin >= NUM_PINS))
|
547
|
+
return ;
|
548
|
+
gpioPin = pinToGpio [pin] ;
|
549
|
+
}
|
550
|
+
else
|
551
|
+
gpioPin = pin ;
|
552
|
+
|
553
|
+
*(gpio + 37) = pud ;
|
554
|
+
delayMicroseconds (10) ;
|
555
|
+
*(gpio + gpioToPUDCLK [gpioPin]) = 1 << gpioPin ;
|
556
|
+
delayMicroseconds (10) ;
|
557
|
+
|
558
|
+
*(gpio + 37) = 0 ;
|
559
|
+
*(gpio + gpioToPUDCLK [gpioPin]) = 0 ;
|
560
|
+
}
|
561
|
+
|
562
|
+
|
563
|
+
/*
|
564
|
+
* delay: delayMicroseconds
|
565
|
+
* Wait for some number of milli/micro seconds
|
566
|
+
*********************************************************************************
|
567
|
+
*/
|
568
|
+
|
569
|
+
void delay (unsigned int howLong)
|
570
|
+
{
|
571
|
+
struct timespec sleeper, dummy ;
|
572
|
+
|
573
|
+
sleeper.tv_sec = (time_t)(howLong / 1000) ;
|
574
|
+
sleeper.tv_nsec = (long)(howLong % 1000) * 1000000 ;
|
575
|
+
|
576
|
+
nanosleep (&sleeper, &dummy) ;
|
577
|
+
}
|
578
|
+
|
579
|
+
void delayMicroseconds (unsigned int howLong)
|
580
|
+
{
|
581
|
+
struct timespec sleeper, dummy ;
|
582
|
+
|
583
|
+
sleeper.tv_sec = 0 ;
|
584
|
+
sleeper.tv_nsec = (long)(howLong * 1000) ;
|
585
|
+
|
586
|
+
nanosleep (&sleeper, &dummy) ;
|
587
|
+
}
|