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 |
| 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. |
| 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); |
| 220 // GPIO output set and output clear registers each have 1 bits for 32 pins. |
| 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. |
| 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 |