Chromium Code Reviews| 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 |