OLD | NEW |
---|---|
1 // Copyright (c) 2015, the Fletch project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Fletch project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE.md file. | 3 // BSD-style license that can be found in the LICENSE.md file. |
4 | 4 |
5 /// Library for the basic Raspberry Pi features. | 5 /// Library for the basic Raspberry Pi features. |
6 library raspberry_pi; | 6 library raspberry_pi; |
7 | 7 |
8 import 'dart:fletch.ffi'; | |
8 import 'dart:typed_data'; | 9 import 'dart:typed_data'; |
9 | 10 |
10 import 'package:file/file.dart'; | 11 import 'package:file/file.dart'; |
12 import 'package:gpio/gpio.dart' as gpio; | |
13 | |
14 // Foreign functions used. | |
15 final ForeignFunction _open = ForeignLibrary.main.lookup('open'); | |
16 final ForeignFunction _mmap = ForeignLibrary.main.lookup('mmap'); | |
11 | 17 |
12 /// Possible modes of the on-board LEDs | 18 /// Possible modes of the on-board LEDs |
13 enum OnboardLEDMode { | 19 enum OnboardLEDMode { |
14 /// The on-board LED is controlled by the system. | 20 /// The on-board LED is controlled by the system. |
15 system, | 21 system, |
16 /// The on-board LED is controlled by the user through GPIO. | 22 /// The on-board LED is controlled by the user through GPIO. |
17 gpio, | 23 gpio, |
18 /// The on-board LED is pulsing heart-beat. | 24 /// The on-board LED is pulsing heart-beat. |
19 heartbeat, | 25 heartbeat, |
20 /// The on-board LED is in timer state. | 26 /// The on-board LED is in timer state. |
21 timer, | 27 timer, |
22 } | 28 } |
23 | 29 |
24 /// Class for accessing Raspberry Pi features. | 30 /// Class for accessing Raspberry Pi features. |
25 /// | 31 /// |
32 /// Use GPIO through the memory mapped interface: | |
33 /// | |
34 /// ``` | |
35 /// import 'package:raspberry_pi/raspberry_pi.dart'; | |
36 /// import 'package:gpio/gpio.dart'; | |
37 /// | |
38 /// main() { | |
39 /// RaspberryPi pi = new RaspberryPi(); | |
40 /// GPIO gpio = pi.memoryMappedGPIO; // Selecting memory mapped GPIO. | |
41 /// gpio.setMode(4, Mode.output); | |
42 /// gpio.setPin(4, true); | |
43 /// } | |
44 /// ``` | |
45 /// | |
46 /// Use GPIO through the sysfs interface: | |
47 /// | |
48 /// ``` | |
49 /// import 'package:raspberry_pi/raspberry_pi.dart'; | |
50 /// import 'package:gpio/gpio.dart'; | |
51 /// | |
52 /// main() { | |
53 /// RaspberryPi pi = new RaspberryPi(); | |
54 /// GPIO gpio = pi.sysfsGPIO; // Selecting sysfs GPIO. | |
55 /// gpio.setMode(4, Mode.output); | |
56 /// gpio.setPin(4, true); | |
57 /// } | |
58 /// ``` | |
59 /// | |
26 /// Change the activity LED to heartbeat mode: | 60 /// Change the activity LED to heartbeat mode: |
27 /// | 61 /// |
28 /// ``` | 62 /// ``` |
29 /// import 'package:raspberry_pi/raspberry_pi.dart'; | 63 /// import 'package:raspberry_pi/raspberry_pi.dart'; |
30 /// | 64 /// |
31 /// main() { | 65 /// main() { |
32 /// RaspberryPi pi = new RaspberryPi(); | 66 /// RaspberryPi pi = new RaspberryPi(); |
33 /// pi.leds.activityLED.setMode(OnboardLEDMode.heartbeat); | 67 /// pi.leds.activityLED.setMode(OnboardLEDMode.heartbeat); |
34 /// } | 68 /// } |
35 /// ``` | 69 /// ``` |
36 /// | 70 /// |
37 /// Change the activity LED to gpio mode to allow it to be used as a | 71 /// Change the activity LED to gpio mode to allow it to be used as a |
38 /// normal GPIO pin. | 72 /// normal GPIO pin. |
39 /// | 73 /// |
40 /// ``` | 74 /// ``` |
41 /// import 'package:raspberry_pi/raspberry_pi.dart'; | 75 /// import 'package:raspberry_pi/raspberry_pi.dart'; |
42 /// import 'package:gpio/gpio.dart'; | 76 /// import 'package:gpio/gpio.dart'; |
43 /// | 77 /// |
44 /// main() { | 78 /// main() { |
45 /// RaspberryPi pi = new RaspberryPi(); | 79 /// RaspberryPi pi = new RaspberryPi(); |
46 /// GPIO gpio = new PiMemoryMappedGPIO(); | 80 /// GPIO gpio = new PiMemoryMappedGPIO(); |
47 /// pi.leds.activityLED.setMode(OnboardLEDMode.gpio); | 81 /// pi.leds.activityLED.setMode(OnboardLEDMode.gpio); |
48 /// gpio.setPin(pi.leds.activityLED.pin, true); | 82 /// gpio.setPin(pi.leds.activityLED.pin, true); |
49 /// } | 83 /// } |
50 /// ``` | 84 /// ``` |
51 class RaspberryPi { | 85 class RaspberryPi { |
86 /// The number of GPIO pins on the Raspberry Pi 2. | |
87 static const int gpioPins = 54; | |
88 var _memoryMappedGPIO; | |
89 var _sysfsGPIO; | |
90 | |
52 /// Provide access to the on-board LEDs. | 91 /// Provide access to the on-board LEDs. |
53 final OnBoardLEDs leds = new OnBoardLEDs._(); | 92 final OnBoardLEDs leds = new OnBoardLEDs._(); |
54 | 93 |
55 RaspberryPi(); | 94 RaspberryPi(); |
95 | |
96 get memoryMappedGPIO { | |
97 if (_memoryMappedGPIO == null) { | |
98 _memoryMappedGPIO = new PiMemoryMappedGPIO(); | |
99 } | |
100 return _memoryMappedGPIO; | |
101 } | |
102 | |
103 get sysfsGPIO { | |
104 if (_sysfsGPIO == null) { | |
105 _sysfsGPIO = new gpio.SysfsGPIO(gpioPins); | |
106 } | |
107 return _sysfsGPIO; | |
108 | |
109 } | |
110 } | |
111 | |
112 /// Pull-up/down resistor state. | |
113 enum PullUpDown { | |
114 floating, | |
115 pullDown, | |
116 pullUp, | |
117 } | |
118 | |
119 /// Provide GPIO access on Raspberry Pi using direct memory access. | |
120 /// | |
121 /// The following code shows how to turn on GPIO pin 4: | |
122 /// | |
123 /// ``` | |
124 /// PiMemoryMappedGPIO gpio = new PiMemoryMappedGPIO(); | |
125 /// gpio.setMode(4, Mode.output); | |
126 /// gpio.setPin(4, true)); | |
127 /// ``` | |
128 /// | |
129 /// The following code shows how to read GPIO pin 17: | |
130 /// | |
131 /// ``` | |
132 /// PiMemoryMappedGPIO gpio = new PiMemoryMappedGPIO(); | |
133 /// gpio.setMode(17, Mode.input); | |
134 /// print(gpio.getPin(17)); | |
135 /// ``` | |
136 class PiMemoryMappedGPIO extends gpio.GPIOBase { | |
137 // See datasheet: | |
138 // https://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripher als.pdf | |
139 | |
140 // Raspberry Pi model 1 (A/A+/B) | |
141 // BCM2708 / BCM 2835 | |
142 | |
143 // Raspberry Pi model 2 | |
144 // BCM2709 / BCM 2836 | |
145 | |
146 // Peripherals base address. | |
147 static const int _baseAddressModel1 = 0x20000000; | |
148 static const int _baseAddressModel2 = 0x3F000000; | |
149 static const int _baseAddressGPIOOffset = 0x00200000; | |
150 | |
151 // Size of the peripherals area. | |
152 static const int _blockSize = 4096; | |
153 | |
154 // Offsets (in bytes) to various areas. | |
155 static const int _gpioFunctionSelectBase = 0 << 2; | |
156 static const int _gpioOutputSetBase = 7 << 2; | |
157 static const int _gpioOutputClearBase = 10 << 2; | |
158 static const int _gpioPinLevelBase = 13 << 2; | |
159 static const int _gpioPullUpPullDown = 37 << 2; | |
160 static const int _gpioPullUpPullDownClockBase = 38 << 2; | |
161 | |
162 // All alternative functions are mapped to `Mode.other` for now. | |
163 static const _functionToMode = | |
164 [gpio.Mode.input, gpio.Mode.output, | |
165 gpio.Mode.other, gpio.Mode.other, | |
166 gpio.Mode.other, gpio.Mode.other, gpio.Mode.other]; | |
167 | |
168 int _fd; // File descriptor for /dev/mem. | |
169 ForeignPointer _addr; | |
170 ForeignMemory _mem; | |
171 | |
172 PiMemoryMappedGPIO(): super(RaspberryPi.gpioPins) { | |
173 // From /usr/include/x86_64-linux-gnu/bits/fcntl-linux.h. | |
174 const int oRDWR = 02; // O_RDWR | |
wibling
2015/10/05 07:43:37
NIT: Shouldn't we keep these as O_RDWR to make it
| |
175 // Found from C code 'printf("%x\n", O_SYNC);'. | |
176 const int oSync = 0x101000; // O_SYNC | |
177 | |
178 // Open /dev/mem to get to the physical memory. | |
179 var devMem = new ForeignMemory.fromStringAsUTF8('/dev/mem'); | |
180 _fd = _open.icall$2Retry(devMem, oRDWR | oSync); | |
181 if (_fd < 0) { | |
182 throw new gpio.GPIOException("Failed to open '/dev/mem'", Foreign.errno); | |
183 } | |
184 devMem.free(); | |
185 | |
186 // From /usr/include/x86_64-linux-gnu/bits/mman-linux.h. | |
187 const int protRead = 0x1; // PROT_READ. | |
wibling
2015/10/05 07:43:37
Ditto.
| |
188 const int protWrite = 0x2; // PROT_WRITE. | |
189 const int mapShared = 0x01; // MAP_SHARED. | |
190 | |
191 _addr = _mmap.pcall$6(0, _blockSize, protRead | protWrite, mapShared, | |
192 _fd, _baseAddressModel2 + _baseAddressGPIOOffset); | |
193 _mem = new ForeignMemory.fromAddress(_addr.address, _blockSize); | |
194 } | |
195 | |
196 void setMode(int pin, gpio.Mode mode) { | |
197 checkPinRange(pin); | |
198 // GPIO function select registers each have 3 bits for 10 pins. | |
199 var fsel = (pin ~/ 10); | |
200 var shift = (pin % 10) * 3; | |
201 var function = mode == gpio.Mode.input ? 0 : 1; | |
202 var offset = _gpioFunctionSelectBase + (fsel << 2); | |
203 var value = _mem.getUint32(offset); | |
204 value = (value & ~(0x07 << shift)) | function << shift; | |
205 _mem.setUint32(offset, value); | |
206 } | |
207 | |
208 gpio.Mode getMode(int pin) { | |
209 checkPinRange(pin); | |
210 // GPIO function select registers each have 3 bits for 10 pins. | |
211 var fsel = (pin ~/ 10); | |
212 var shift = (pin % 10) * 3; | |
213 var offset = _gpioFunctionSelectBase + (fsel << 2); | |
214 var function = (_mem.getUint32(offset) >> shift) & 0x07; | |
215 return _functionToMode[function]; | |
216 } | |
217 | |
218 void setPin(int pin, bool value) { | |
219 checkPinRange(pin); | |
wibling
2015/10/05 07:43:37
NIT: Could enforce mode and fail on mismatch.
| |
220 // GPIO output set and output clear registers each have 1 bits for 32 pins. | |
wibling
2015/10/05 07:43:37
NIT: bits -> bit
| |
221 int register = pin ~/ 32; | |
222 int shift = pin % 32; | |
223 if (value) { | |
224 _mem.setUint32(_gpioOutputSetBase + (register << 2), 1 << shift); | |
225 } else { | |
226 _mem.setUint32(_gpioOutputClearBase + (register << 2), 1 << shift); | |
227 } | |
228 } | |
229 | |
230 bool getPin(int pin) { | |
231 checkPinRange(pin); | |
232 // GPIO pin level registers each have 1 bits for 32 pins. | |
wibling
2015/10/05 07:43:37
NIT: bits -> bit
| |
233 int register = pin ~/ 32; | |
234 int shift = pin % 32; | |
235 return | |
236 (_mem.getUint32(_gpioPinLevelBase + (register << 2)) & 1 << shift) != 0; | |
237 } | |
238 | |
239 /// Set the floating/pull-up/pull-down state of [pin]. | |
240 /// | |
241 /// Use `0` for floating, `1` for pull down and `2` for pull-up. | |
242 void setPullUpDown(int pin, PullUpDown pullUpDown) { | |
243 checkPinRange(pin); | |
244 int register = pin ~/ 32; | |
245 int shift = pin % 32; | |
246 // First set the value in the update register. | |
247 _mem.setUint32(_gpioPullUpPullDown, pullUpDown.index); | |
248 sleep(1); // Datasheet says: "Wait for 150 cycles". | |
249 // Then set the clock bit. | |
250 _mem.setUint32(_gpioPullUpPullDownClockBase + (register << 2), 1 << shift); | |
251 sleep(1); // Datasheet says: "Wait for 150 cycles". | |
252 // Clear value and clock bit. | |
253 _mem.setUint32(_gpioPullUpPullDown, 0); | |
254 _mem.setUint32(_gpioPullUpPullDownClockBase + (register << 2), 0); | |
255 } | |
56 } | 256 } |
57 | 257 |
58 // The on-board LEDs. | 258 // The on-board LEDs. |
59 enum _OnboardLED { | 259 enum _OnboardLED { |
60 power, | 260 power, |
61 activity, | 261 activity, |
62 } | 262 } |
63 | 263 |
64 /// Access to the on-board LEDs. | 264 /// Access to the on-board LEDs. |
65 class OnBoardLEDs { | 265 class OnBoardLEDs { |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
172 void setMode(OnboardLEDMode mode) { | 372 void setMode(OnboardLEDMode mode) { |
173 _leds._setMode(_led, mode); | 373 _leds._setMode(_led, mode); |
174 } | 374 } |
175 | 375 |
176 /// Turn on the LED. | 376 /// Turn on the LED. |
177 void on() => _leds._setBrightness(_led, true); | 377 void on() => _leds._setBrightness(_led, true); |
178 | 378 |
179 /// Turn off the LED. | 379 /// Turn off the LED. |
180 void off() => _leds._setBrightness(_led, false); | 380 void off() => _leds._setBrightness(_led, false); |
181 } | 381 } |
OLD | NEW |