Chromium Code Reviews| Index: pkg/raspberry_pi/lib/raspberry_pi.dart |
| diff --git a/pkg/raspberry_pi/lib/raspberry_pi.dart b/pkg/raspberry_pi/lib/raspberry_pi.dart |
| index d0a8df0fdfe1734c3b51483b878361a8b2771fdc..9734327377fe91aaa21173298b66b207abe22677 100644 |
| --- a/pkg/raspberry_pi/lib/raspberry_pi.dart |
| +++ b/pkg/raspberry_pi/lib/raspberry_pi.dart |
| @@ -5,9 +5,15 @@ |
| /// Library for the basic Raspberry Pi features. |
| library raspberry_pi; |
| +import 'dart:fletch.ffi'; |
| import 'dart:typed_data'; |
| import 'package:file/file.dart'; |
| +import 'package:gpio/gpio.dart' as gpio; |
| + |
| +// Foreign functions used. |
| +final ForeignFunction _open = ForeignLibrary.main.lookup('open'); |
| +final ForeignFunction _mmap = ForeignLibrary.main.lookup('mmap'); |
| /// Possible modes of the on-board LEDs |
| enum OnboardLEDMode { |
| @@ -23,6 +29,34 @@ enum OnboardLEDMode { |
| /// Class for accessing Raspberry Pi features. |
| /// |
| +/// Use GPIO through the memory mapped interface: |
| +/// |
| +/// ``` |
| +/// import 'package:raspberry_pi/raspberry_pi.dart'; |
| +/// import 'package:gpio/gpio.dart'; |
| +/// |
| +/// main() { |
| +/// RaspberryPi pi = new RaspberryPi(); |
| +/// GPIO gpio = pi.memoryMappedGPIO; // Selecting memory mapped GPIO. |
| +/// gpio.setMode(4, Mode.output); |
| +/// gpio.setPin(4, true); |
| +/// } |
| +/// ``` |
| +/// |
| +/// Use GPIO through the sysfs interface: |
| +/// |
| +/// ``` |
| +/// import 'package:raspberry_pi/raspberry_pi.dart'; |
| +/// import 'package:gpio/gpio.dart'; |
| +/// |
| +/// main() { |
| +/// RaspberryPi pi = new RaspberryPi(); |
| +/// GPIO gpio = pi.sysfsGPIO; // Selecting sysfs GPIO. |
| +/// gpio.setMode(4, Mode.output); |
| +/// gpio.setPin(4, true); |
| +/// } |
| +/// ``` |
| +/// |
| /// Change the activity LED to heartbeat mode: |
| /// |
| /// ``` |
| @@ -49,10 +83,176 @@ enum OnboardLEDMode { |
| /// } |
| /// ``` |
| class RaspberryPi { |
| + /// The number of GPIO pins on the Raspberry Pi 2. |
| + static const int gpioPins = 54; |
| + var _memoryMappedGPIO; |
| + var _sysfsGPIO; |
| + |
| /// Provide access to the on-board LEDs. |
| final OnBoardLEDs leds = new OnBoardLEDs._(); |
| RaspberryPi(); |
| + |
| + get memoryMappedGPIO { |
| + if (_memoryMappedGPIO == null) { |
| + _memoryMappedGPIO = new PiMemoryMappedGPIO(); |
| + } |
| + return _memoryMappedGPIO; |
| + } |
| + |
| + get sysfsGPIO { |
| + if (_sysfsGPIO == null) { |
| + _sysfsGPIO = new gpio.SysfsGPIO(gpioPins); |
| + } |
| + return _sysfsGPIO; |
| + |
| + } |
| +} |
| + |
| +/// Pull-up/down resistor state. |
| +enum PullUpDown { |
| + floating, |
| + pullDown, |
| + pullUp, |
| +} |
| + |
| +/// Provide GPIO access on Raspberry Pi using direct memory access. |
| +/// |
| +/// The following code shows how to turn on GPIO pin 4: |
| +/// |
| +/// ``` |
| +/// PiMemoryMappedGPIO gpio = new PiMemoryMappedGPIO(); |
| +/// gpio.setMode(4, Mode.output); |
| +/// gpio.setPin(4, true)); |
| +/// ``` |
| +/// |
| +/// The following code shows how to read GPIO pin 17: |
| +/// |
| +/// ``` |
| +/// PiMemoryMappedGPIO gpio = new PiMemoryMappedGPIO(); |
| +/// gpio.setMode(17, Mode.input); |
| +/// print(gpio.getPin(17)); |
| +/// ``` |
| +class PiMemoryMappedGPIO extends gpio.GPIOBase { |
| + // See datasheet: |
| + // https://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf |
| + |
| + // Raspberry Pi model 1 (A/A+/B) |
| + // BCM2708 / BCM 2835 |
| + |
| + // Raspberry Pi model 2 |
| + // BCM2709 / BCM 2836 |
| + |
| + // Peripherals base address. |
| + static const int _baseAddressModel1 = 0x20000000; |
| + static const int _baseAddressModel2 = 0x3F000000; |
| + static const int _baseAddressGPIOOffset = 0x00200000; |
| + |
| + // Size of the peripherals area. |
| + static const int _blockSize = 4096; |
| + |
| + // Offsets (in bytes) to various areas. |
| + static const int _gpioFunctionSelectBase = 0 << 2; |
| + static const int _gpioOutputSetBase = 7 << 2; |
| + static const int _gpioOutputClearBase = 10 << 2; |
| + static const int _gpioPinLevelBase = 13 << 2; |
| + static const int _gpioPullUpPullDown = 37 << 2; |
| + static const int _gpioPullUpPullDownClockBase = 38 << 2; |
| + |
| + // All alternative functions are mapped to `Mode.other` for now. |
| + static const _functionToMode = |
| + [gpio.Mode.input, gpio.Mode.output, |
| + gpio.Mode.other, gpio.Mode.other, |
| + gpio.Mode.other, gpio.Mode.other, gpio.Mode.other]; |
| + |
| + int _fd; // File descriptor for /dev/mem. |
| + ForeignPointer _addr; |
| + ForeignMemory _mem; |
| + |
| + PiMemoryMappedGPIO(): super(RaspberryPi.gpioPins) { |
| + // From /usr/include/x86_64-linux-gnu/bits/fcntl-linux.h. |
| + 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
|
| + // Found from C code 'printf("%x\n", O_SYNC);'. |
| + const int oSync = 0x101000; // O_SYNC |
| + |
| + // Open /dev/mem to get to the physical memory. |
| + var devMem = new ForeignMemory.fromStringAsUTF8('/dev/mem'); |
| + _fd = _open.icall$2Retry(devMem, oRDWR | oSync); |
| + if (_fd < 0) { |
| + throw new gpio.GPIOException("Failed to open '/dev/mem'", Foreign.errno); |
| + } |
| + devMem.free(); |
| + |
| + // From /usr/include/x86_64-linux-gnu/bits/mman-linux.h. |
| + const int protRead = 0x1; // PROT_READ. |
|
wibling
2015/10/05 07:43:37
Ditto.
|
| + const int protWrite = 0x2; // PROT_WRITE. |
| + const int mapShared = 0x01; // MAP_SHARED. |
| + |
| + _addr = _mmap.pcall$6(0, _blockSize, protRead | protWrite, mapShared, |
| + _fd, _baseAddressModel2 + _baseAddressGPIOOffset); |
| + _mem = new ForeignMemory.fromAddress(_addr.address, _blockSize); |
| + } |
| + |
| + void setMode(int pin, gpio.Mode mode) { |
| + checkPinRange(pin); |
| + // GPIO function select registers each have 3 bits for 10 pins. |
| + var fsel = (pin ~/ 10); |
| + var shift = (pin % 10) * 3; |
| + var function = mode == gpio.Mode.input ? 0 : 1; |
| + var offset = _gpioFunctionSelectBase + (fsel << 2); |
| + var value = _mem.getUint32(offset); |
| + value = (value & ~(0x07 << shift)) | function << shift; |
| + _mem.setUint32(offset, value); |
| + } |
| + |
| + gpio.Mode getMode(int pin) { |
| + checkPinRange(pin); |
| + // GPIO function select registers each have 3 bits for 10 pins. |
| + var fsel = (pin ~/ 10); |
| + var shift = (pin % 10) * 3; |
| + var offset = _gpioFunctionSelectBase + (fsel << 2); |
| + var function = (_mem.getUint32(offset) >> shift) & 0x07; |
| + return _functionToMode[function]; |
| + } |
| + |
| + void setPin(int pin, bool value) { |
| + checkPinRange(pin); |
|
wibling
2015/10/05 07:43:37
NIT: Could enforce mode and fail on mismatch.
|
| + // GPIO output set and output clear registers each have 1 bits for 32 pins. |
|
wibling
2015/10/05 07:43:37
NIT: bits -> bit
|
| + int register = pin ~/ 32; |
| + int shift = pin % 32; |
| + if (value) { |
| + _mem.setUint32(_gpioOutputSetBase + (register << 2), 1 << shift); |
| + } else { |
| + _mem.setUint32(_gpioOutputClearBase + (register << 2), 1 << shift); |
| + } |
| + } |
| + |
| + bool getPin(int pin) { |
| + checkPinRange(pin); |
| + // GPIO pin level registers each have 1 bits for 32 pins. |
|
wibling
2015/10/05 07:43:37
NIT: bits -> bit
|
| + int register = pin ~/ 32; |
| + int shift = pin % 32; |
| + return |
| + (_mem.getUint32(_gpioPinLevelBase + (register << 2)) & 1 << shift) != 0; |
| + } |
| + |
| + /// Set the floating/pull-up/pull-down state of [pin]. |
| + /// |
| + /// Use `0` for floating, `1` for pull down and `2` for pull-up. |
| + void setPullUpDown(int pin, PullUpDown pullUpDown) { |
| + checkPinRange(pin); |
| + int register = pin ~/ 32; |
| + int shift = pin % 32; |
| + // First set the value in the update register. |
| + _mem.setUint32(_gpioPullUpPullDown, pullUpDown.index); |
| + sleep(1); // Datasheet says: "Wait for 150 cycles". |
| + // Then set the clock bit. |
| + _mem.setUint32(_gpioPullUpPullDownClockBase + (register << 2), 1 << shift); |
| + sleep(1); // Datasheet says: "Wait for 150 cycles". |
| + // Clear value and clock bit. |
| + _mem.setUint32(_gpioPullUpPullDown, 0); |
| + _mem.setUint32(_gpioPullUpPullDownClockBase + (register << 2), 0); |
| + } |
| } |
| // The on-board LEDs. |