lgpio 0.1.4 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +43 -24
- data/examples/bench_in.rb +1 -1
- data/examples/bench_out.rb +1 -1
- data/examples/blink.rb +1 -1
- data/examples/dht.rb +47 -0
- data/examples/group_in.rb +2 -2
- data/examples/group_out.rb +1 -1
- data/examples/hcsr04.rb +32 -0
- data/examples/i2c_aht10.rb +3 -2
- data/examples/i2c_aht10_zip.rb +3 -2
- data/examples/i2c_bitbang-rb_aht10.rb +40 -0
- data/examples/i2c_bitbang-rb_ssd1306_bench.rb +35 -0
- data/examples/i2c_bitbang_aht10.rb +40 -0
- data/examples/i2c_bitbang_search.rb +20 -0
- data/examples/i2c_bitbang_ssd1306_bench.rb +35 -0
- data/examples/i2c_ssd1306_bench.rb +7 -6
- data/examples/infrared.rb +22 -0
- data/examples/momentary.rb +2 -2
- data/examples/one_wire_ds18b20.rb +30 -0
- data/examples/one_wire_search.rb +15 -0
- data/examples/pwm.rb +1 -1
- data/examples/reports.rb +1 -1
- data/examples/rotary_encoder.rb +3 -3
- data/examples/rotary_encoder_led.rb +4 -4
- data/examples/servo.rb +36 -0
- data/examples/spi_bitbang_loopback.rb +25 -0
- data/examples/spi_bitbang_ssd1306_bench.rb +51 -0
- data/examples/spi_bitbang_ssd1306_sim_bench.rb +48 -0
- data/examples/wave.rb +1 -1
- data/ext/lgpio/lgpio.c +454 -9
- data/lib/lgpio/hardware_pwm.rb +83 -0
- data/lib/lgpio/i2c_bitbang.rb +117 -0
- data/lib/lgpio/infrared.rb +8 -0
- data/lib/lgpio/one_wire.rb +171 -0
- data/lib/lgpio/positional_servo.rb +28 -0
- data/lib/lgpio/spi_bitbang.rb +109 -0
- data/lib/lgpio/version.rb +1 -1
- data/lib/lgpio.rb +9 -0
- metadata +22 -3
- data/examples/spi_read.rb +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0ba4963055ec58ea685427a0c9395eedfbc20cf0159df764edbd3b735dd7ce40
|
4
|
+
data.tar.gz: b4149669d2ac089120582d09db4ab6d0e9bb45f8c93e22a62164272f9150c758
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9e3397df71dadb44d9ebfb96d6732d9ba211f9dc5a530b96747e7ec2ee93e22b6412218f61938560864c10208fdc60609b93c18707ca67332c2a8800e880d21c
|
7
|
+
data.tar.gz: 7ebd239afcd78e16ea893943f1e226b06e68c9b0b2cf4c3a98acebe3f23a33e044fa51c1309b1779ac5415877be8512b78cff651e48a87fc0fe860ef2405531f
|
data/README.md
CHANGED
@@ -1,34 +1,52 @@
|
|
1
1
|
# lgpio
|
2
2
|
|
3
|
-
Ruby bindings for the [lgpio (lg)](https://github.com/joan2937/lg)
|
3
|
+
Ruby gem with bindings for the [lgpio (lg)](https://github.com/joan2937/lg) C library. This is for single-board-computers (SBCs) running Linux, such as Orange Pi, Raspberry Pi, etc. It provides low-level access to the GPIO, I2C, SPI, and PWM subsytems.
|
4
|
+
|
5
|
+
## Standard LGPIO Features
|
4
6
|
|
5
|
-
## Standard LGPIO Functions
|
6
7
|
- [x] GPIO Read/Write
|
7
8
|
- [x] GPIO Group Read/Write
|
8
|
-
- [x] GPIO Alerts
|
9
|
-
-
|
10
|
-
-
|
11
|
-
|
9
|
+
- [x] GPIO Alerts
|
10
|
+
- Alerts are generated by a separate thread, and can be read from a queue in Ruby.
|
11
|
+
- No real "callback" functionality.
|
12
|
+
- [x] Software PWM Output
|
13
|
+
- Timing not 100% precise, but works on any GPIO.
|
14
|
+
- Not recommended for servo motors, will jitter.
|
12
15
|
- [x] Wave
|
13
|
-
- Software timed on any pin, as with PWM.
|
14
|
-
- [x] I2C
|
15
|
-
- [x] SPI
|
16
|
+
- Software timed on any pin(s), as with PWM.
|
17
|
+
- [x] Hardware I2C
|
18
|
+
- [x] Hardware SPI
|
19
|
+
|
20
|
+
## Extra Features (Built on LGPIO)
|
21
|
+
|
22
|
+
- [x] `LGPIO.gpio_read_ultrasonic` sends a pulse on a `trigger` pin, then measures a single pulse on a separate `echo` pin. Used for HC-SR04 or similar. See `examples/hcsr04.rb`.
|
23
|
+
- [x] `LGPIO.gpio_read_pulses_us` outputs a reset pulse on a pin, then polls for a sequence of input pulses. Used for DHT enviro sensors or similar. See `examples/dht.rb`.
|
24
|
+
- [x] Bit Bang I2C
|
25
|
+
- [x] Bit Bang SPI
|
26
|
+
- [x] Bit Bang 1-Wire
|
27
|
+
- [x] WS2812 addressable LEDs over hardware SPI
|
28
|
+
- Outputs on MOSI/PICO pin
|
29
|
+
- Must be able to set SPI clock frequency to 2.4 MHz
|
30
|
+
|
31
|
+
## Hardware PWM Features
|
32
|
+
|
33
|
+
These use the sysfs PWM interface, not lgpio C, but are a good fit for this gem.
|
34
|
+
|
35
|
+
- [x] Hardware PWM Output
|
36
|
+
- [x] Servo (based on hardware PWM)
|
37
|
+
- [x] On-off Keying (OOK) Modulated Waves
|
38
|
+
- Carrier generated by hardware PWM. Software modulated with monotonic clock timing.
|
39
|
+
- Useful for sending infrared signals at 38kHz, for example.
|
16
40
|
|
17
|
-
|
18
|
-
- [x] WS2812 over SPI
|
19
|
-
- Only outputs on a SPI MOSI pin. Must be able to set SPI clock frequency to 2.4 MHz.
|
20
|
-
- [ ] Bit Bang SPI
|
21
|
-
- [ ] Bit Bang I2C
|
41
|
+
**Note:** Once hardware PWM is used on a pin, it stays PWM until reboot. The associated GPIO won't work.
|
22
42
|
|
23
43
|
## Installation
|
24
44
|
On Debian-based Linuxes (RaspberryPi OS, Armbian, DietPi etc.):
|
25
45
|
```bash
|
26
46
|
sudo apt install swig python3-dev python3-setuptools
|
27
47
|
|
28
|
-
#
|
29
|
-
|
30
|
-
wget https://github.com/joan2937/lg/archive/master.zip
|
31
|
-
# wget https://github.com/vickash/lg/archive/refs/heads/master.zip
|
48
|
+
# Temporary fork of: wget https://github.com/joan2937/lg/archive/master.zip
|
49
|
+
wget https://github.com/vickash/lg/archive/refs/heads/master.zip
|
32
50
|
|
33
51
|
unzip master.zip
|
34
52
|
cd lg-master
|
@@ -39,17 +57,18 @@ gem install lgpio
|
|
39
57
|
```
|
40
58
|
|
41
59
|
## Enabling Hardware & Permissions
|
42
|
-
Depending on your SBC and Linux distro/version, you may need to manually enable I2C and
|
60
|
+
Depending on your SBC and Linux distro/version, you may need to manually enable hardware I2C, SPI, and PWM. You should use the config tool that came with your distro for that, if possible.
|
43
61
|
|
44
|
-
|
62
|
+
Even when these are enabled, you may not have permission to access them. To run without `sudo`, you need read+write permission to some or all of the following:
|
45
63
|
```
|
46
|
-
/dev/gpiochip*
|
47
|
-
/dev/i2c-*
|
48
|
-
/dev/spidev*
|
64
|
+
/dev/gpiochip* (For GPIO, example: /dev/gpiochip0)
|
65
|
+
/dev/i2c-* (For I2C, example: /dev/i2c-1)
|
66
|
+
/dev/spidev* (For SPI, example: /dev/spidev0.1)
|
67
|
+
/sys/class/pwm/pwmchip* (For PWM, example: /sys/class/pwm/pwmchip0)
|
49
68
|
```
|
50
69
|
|
51
70
|
## Documentation
|
52
|
-
- See examples folder for demos of
|
71
|
+
- See examples folder for demos of everything implemented.
|
53
72
|
- Development was done on an Orange Pi Zero 2W. Your GPIO numbers may be different, so change them.
|
54
73
|
- For more info, see the [lgpio C API docs.](https://abyz.me.uk/lg/lgpio.html)
|
55
74
|
- As much as possible, the Ruby methods closely follow the C API functions, except:
|
data/examples/bench_in.rb
CHANGED
data/examples/bench_out.rb
CHANGED
data/examples/blink.rb
CHANGED
data/examples/dht.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'lgpio'
|
2
|
+
|
3
|
+
GPIO_CHIP = 0
|
4
|
+
DHT_PIN = 267
|
5
|
+
chip_handle = LGPIO.chip_open(GPIO_CHIP)
|
6
|
+
#
|
7
|
+
# Read a series of pulses input to a GPIO, with an (optional) reset output pulse at start.
|
8
|
+
# Arguments in order are:
|
9
|
+
# gpiochip handle
|
10
|
+
# GPIO number
|
11
|
+
# Starting (reset) output pulse time in microseconds (0 for no reset)
|
12
|
+
# Reset pulse level (0 or 1)
|
13
|
+
# Maximum number of pulses to read
|
14
|
+
# Timeout in milliseconds
|
15
|
+
#
|
16
|
+
data = LGPIO.gpio_read_pulses_us(chip_handle, DHT_PIN, 20_000, 0, 84, 100)
|
17
|
+
|
18
|
+
# Handle errors.
|
19
|
+
raise "error: DHT sensor not connected" unless data
|
20
|
+
raise "LGPIO error: #{data}" if data.class == Integer
|
21
|
+
|
22
|
+
# Discard unneeded pulses
|
23
|
+
data = data.last(81)
|
24
|
+
raise "error: incomplete DHT data" unless data.length == 81
|
25
|
+
data = data.first(80)
|
26
|
+
|
27
|
+
# Convert to bytes
|
28
|
+
bytes = []
|
29
|
+
data.each_slice(16) do |b|
|
30
|
+
byte = 0b00000000
|
31
|
+
b.each_slice(2) do |x,y|
|
32
|
+
bit = (y<x) ? 0 : 1
|
33
|
+
byte = (byte << 1) | bit
|
34
|
+
end
|
35
|
+
bytes << byte
|
36
|
+
end
|
37
|
+
|
38
|
+
# CRC
|
39
|
+
crc = bytes[0..3].reduce(0, :+) & 0xFF == bytes[4]
|
40
|
+
raise "error: DHT CRC check failed" unless crc
|
41
|
+
|
42
|
+
# Convert and display
|
43
|
+
temperature = ((bytes[2] << 8) | bytes[3]).to_f / 10
|
44
|
+
humidity = ((bytes[0] << 8) | bytes[1]).to_f / 10
|
45
|
+
|
46
|
+
puts "DHT Temperature: #{temperature} \xC2\xB0C"
|
47
|
+
puts "DHT Humidity: #{humidity} %"
|
data/examples/group_in.rb
CHANGED
data/examples/group_out.rb
CHANGED
data/examples/hcsr04.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#
|
2
|
+
# Example showing an HC-S04 ultrasonic distance sensor.
|
3
|
+
#
|
4
|
+
# NOTE: Some versions of this sensor require 5V power to function properly.
|
5
|
+
# If using one of these, use a 5V to 3.3V level shifter between your board and
|
6
|
+
# the sensor, at least on the echo pin.
|
7
|
+
#
|
8
|
+
require 'lgpio'
|
9
|
+
|
10
|
+
GPIO_CHIP = 0
|
11
|
+
ECHO_PIN = 228
|
12
|
+
TRIGGER_PIN = 270
|
13
|
+
SPEED_OF_SOUND = 343.0
|
14
|
+
|
15
|
+
chip_handle = LGPIO.chip_open(GPIO_CHIP)
|
16
|
+
|
17
|
+
loop do
|
18
|
+
# Arguments in order are:
|
19
|
+
# chip handle, trigger pin, echo pin, trigger time (us)
|
20
|
+
#
|
21
|
+
# HC-SR04 uses 10 microseconds for trigger. Some others use 20us.
|
22
|
+
#
|
23
|
+
microseconds = LGPIO.gpio_read_ultrasonic(chip_handle, TRIGGER_PIN, ECHO_PIN, 10)
|
24
|
+
|
25
|
+
if microseconds
|
26
|
+
mm = (microseconds / 2000.0) * SPEED_OF_SOUND
|
27
|
+
puts "Distance: #{mm.round} mm"
|
28
|
+
else
|
29
|
+
puts "Cound not read HC-SR04 sensor"
|
30
|
+
end
|
31
|
+
sleep 0.5
|
32
|
+
end
|
data/examples/i2c_aht10.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'lgpio'
|
2
2
|
|
3
|
-
I2C_DEV
|
3
|
+
I2C_DEV = 3
|
4
|
+
ADDRESS = 0x38
|
4
5
|
POWER_ON_DELAY = 0.100
|
5
6
|
RESET_DELAY = 0.020
|
6
7
|
COMMAND_DELAY = 0.010
|
@@ -10,7 +11,7 @@ SOFT_RESET = [0xBA]
|
|
10
11
|
INIT_AND_CALIBRATE = [0xE1, 0x08, 0x00]
|
11
12
|
START_MEASUREMENT = [0xAC, 0x33, 0x00]
|
12
13
|
|
13
|
-
aht10_handle = LGPIO.i2c_open(I2C_DEV,
|
14
|
+
aht10_handle = LGPIO.i2c_open(I2C_DEV, ADDRESS, 0)
|
14
15
|
|
15
16
|
# Startup sequence
|
16
17
|
sleep(POWER_ON_DELAY)
|
data/examples/i2c_aht10_zip.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'lgpio'
|
2
2
|
|
3
|
-
I2C_DEV
|
3
|
+
I2C_DEV = 3
|
4
|
+
ADDRESS = 0x38
|
4
5
|
POWER_ON_DELAY = 0.100
|
5
6
|
RESET_DELAY = 0.020
|
6
7
|
COMMAND_DELAY = 0.010
|
@@ -10,7 +11,7 @@ INIT_AND_CALIBRATE = [5, 3, 0xE1, 0x08, 0x00, 0]
|
|
10
11
|
START_MEASUREMENT = [5, 3, 0xAC, 0x33, 0x00, 0]
|
11
12
|
READ_SIX = [4, 6, 0]
|
12
13
|
|
13
|
-
aht10_handle = LGPIO.i2c_open(I2C_DEV,
|
14
|
+
aht10_handle = LGPIO.i2c_open(I2C_DEV, ADDRESS, 0)
|
14
15
|
|
15
16
|
# Startup sequence
|
16
17
|
sleep(POWER_ON_DELAY)
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'lgpio'
|
2
|
+
|
3
|
+
POWER_ON_DELAY = 0.100
|
4
|
+
RESET_DELAY = 0.020
|
5
|
+
COMMAND_DELAY = 0.010
|
6
|
+
MEASURE_DELAY = 0.080
|
7
|
+
DATA_LENGTH = 6
|
8
|
+
SOFT_RESET = [0xBA]
|
9
|
+
INIT_AND_CALIBRATE = [0xE1, 0x08, 0x00]
|
10
|
+
START_MEASUREMENT = [0xAC, 0x33, 0x00]
|
11
|
+
|
12
|
+
GPIO_CHIP = 0
|
13
|
+
SCL_PIN = 228
|
14
|
+
SDA_PIN = 270
|
15
|
+
ADDRESS = 0x38
|
16
|
+
|
17
|
+
chip_handle = LGPIO.chip_open(GPIO_CHIP)
|
18
|
+
i2c_bb = LGPIO::I2CBitBang.new(chip_handle, SCL_PIN, SDA_PIN)
|
19
|
+
|
20
|
+
# Startup sequence
|
21
|
+
sleep(POWER_ON_DELAY)
|
22
|
+
i2c_bb.write(ADDRESS, SOFT_RESET)
|
23
|
+
sleep(RESET_DELAY)
|
24
|
+
i2c_bb.write(ADDRESS, INIT_AND_CALIBRATE)
|
25
|
+
sleep(COMMAND_DELAY)
|
26
|
+
|
27
|
+
# Read and close
|
28
|
+
i2c_bb.write(ADDRESS, START_MEASUREMENT)
|
29
|
+
sleep(MEASURE_DELAY)
|
30
|
+
bytes = i2c_bb.read(ADDRESS, DATA_LENGTH)
|
31
|
+
|
32
|
+
# Humidity uses the upper 4 bits of the shared byte as its lowest 4 bits.
|
33
|
+
h_raw = ((bytes[1] << 16) | (bytes[2] << 8) | (bytes[3])) >> 4
|
34
|
+
humidity = (h_raw.to_f / 2**20) * 100
|
35
|
+
|
36
|
+
# Temperature uses the lower 4 bits of the shared byte as its highest 4 bits.
|
37
|
+
t_raw = ((bytes[3] & 0x0F) << 16) | (bytes[4] << 8) | bytes[5]
|
38
|
+
temperature = (t_raw.to_f / 2**20) * 200 - 50
|
39
|
+
|
40
|
+
puts "#{Time.now.strftime '%Y-%m-%d %H:%M:%S'} - Temperature: #{temperature.round(2)} \xC2\xB0C | Humidity: #{humidity.round(2)} %"
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'lgpio'
|
2
|
+
|
3
|
+
INIT_ARRAY = [0, 168, 63, 211, 0, 64, 161, 200, 218, 18, 164, 166, 213, 128, 219, 32, 217, 241, 141, 20, 32, 0, 175]
|
4
|
+
START_ARRAY = [0, 33, 0, 127, 34, 0, 7]
|
5
|
+
PATTERN_1 = [64] + Array.new(1024) { 0b00110011 }
|
6
|
+
PATTERN_2 = [64] + Array.new(1024) { 0b11001100 }
|
7
|
+
|
8
|
+
GPIO_CHIP = 0
|
9
|
+
SCL_PIN = 228
|
10
|
+
SDA_PIN = 270
|
11
|
+
ADDRESS = 0x3C
|
12
|
+
|
13
|
+
chip_handle = LGPIO.chip_open(GPIO_CHIP)
|
14
|
+
i2c_bb = LGPIO::I2CBitBang.new(chip_handle, SCL_PIN, SDA_PIN)
|
15
|
+
|
16
|
+
i2c_bb.write(ADDRESS, INIT_ARRAY)
|
17
|
+
FRAME_COUNT = 400
|
18
|
+
|
19
|
+
start = Time.now
|
20
|
+
(FRAME_COUNT / 2).times do
|
21
|
+
i2c_bb.write(ADDRESS, START_ARRAY)
|
22
|
+
i2c_bb.write(ADDRESS, PATTERN_1)
|
23
|
+
i2c_bb.write(ADDRESS, START_ARRAY)
|
24
|
+
i2c_bb.write(ADDRESS, PATTERN_2)
|
25
|
+
end
|
26
|
+
finish = Time.now
|
27
|
+
|
28
|
+
LGPIO.chip_close(chip_handle)
|
29
|
+
|
30
|
+
fps = FRAME_COUNT / (finish - start)
|
31
|
+
# Also calculate C calls per second, using roughly 23 calls per byte written.
|
32
|
+
cps = (START_ARRAY.length + ((PATTERN_1.length + PATTERN_2.length) / 2) + 2) * 23 * fps
|
33
|
+
cps = (cps / 1000.0).round
|
34
|
+
|
35
|
+
puts "SSD1306 benchmark result: #{fps.round(2)} fps | #{cps}k C calls/s"
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'lgpio'
|
2
|
+
|
3
|
+
POWER_ON_DELAY = 0.100
|
4
|
+
RESET_DELAY = 0.020
|
5
|
+
COMMAND_DELAY = 0.010
|
6
|
+
MEASURE_DELAY = 0.080
|
7
|
+
DATA_LENGTH = 6
|
8
|
+
SOFT_RESET = [0xBA]
|
9
|
+
INIT_AND_CALIBRATE = [0xE1, 0x08, 0x00]
|
10
|
+
START_MEASUREMENT = [0xAC, 0x33, 0x00]
|
11
|
+
|
12
|
+
GPIO_CHIP = 0
|
13
|
+
SCL_PIN = 228
|
14
|
+
SDA_PIN = 270
|
15
|
+
ADDRESS = 0x38
|
16
|
+
|
17
|
+
chip_handle = LGPIO.chip_open(GPIO_CHIP)
|
18
|
+
LGPIO.i2c_bb_claim(chip_handle, SCL_PIN, SDA_PIN)
|
19
|
+
|
20
|
+
# Startup sequence
|
21
|
+
sleep(POWER_ON_DELAY)
|
22
|
+
LGPIO.i2c_bb_write(chip_handle, SCL_PIN, SDA_PIN, ADDRESS, SOFT_RESET)
|
23
|
+
sleep(RESET_DELAY)
|
24
|
+
LGPIO.i2c_bb_write(chip_handle, SCL_PIN, SDA_PIN, ADDRESS, INIT_AND_CALIBRATE)
|
25
|
+
sleep(COMMAND_DELAY)
|
26
|
+
|
27
|
+
# Read and close
|
28
|
+
LGPIO.i2c_bb_write(chip_handle, SCL_PIN, SDA_PIN, ADDRESS, START_MEASUREMENT)
|
29
|
+
sleep(MEASURE_DELAY)
|
30
|
+
bytes = LGPIO.i2c_bb_read(chip_handle, SCL_PIN, SDA_PIN, ADDRESS, DATA_LENGTH)
|
31
|
+
|
32
|
+
# Humidity uses the upper 4 bits of the shared byte as its lowest 4 bits.
|
33
|
+
h_raw = ((bytes[1] << 16) | (bytes[2] << 8) | (bytes[3])) >> 4
|
34
|
+
humidity = (h_raw.to_f / 2**20) * 100
|
35
|
+
|
36
|
+
# Temperature uses the lower 4 bits of the shared byte as its highest 4 bits.
|
37
|
+
t_raw = ((bytes[3] & 0x0F) << 16) | (bytes[4] << 8) | bytes[5]
|
38
|
+
temperature = (t_raw.to_f / 2**20) * 200 - 50
|
39
|
+
|
40
|
+
puts "#{Time.now.strftime '%Y-%m-%d %H:%M:%S'} - Temperature: #{temperature.round(2)} \xC2\xB0C | Humidity: #{humidity.round(2)} %"
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'lgpio'
|
2
|
+
|
3
|
+
GPIO_CHIP = 0
|
4
|
+
SCL_PIN = 228
|
5
|
+
SDA_PIN = 270
|
6
|
+
|
7
|
+
chip_handle = LGPIO.chip_open(GPIO_CHIP)
|
8
|
+
LGPIO.i2c_bb_claim(chip_handle, SCL_PIN, SDA_PIN)
|
9
|
+
|
10
|
+
devices = LGPIO.i2c_bb_search(chip_handle, SCL_PIN, SDA_PIN)
|
11
|
+
|
12
|
+
if devices.empty?
|
13
|
+
puts "No devices found on I2C bus"
|
14
|
+
else
|
15
|
+
puts "I2C device addresses found:"
|
16
|
+
devices.each do |address|
|
17
|
+
# Print as hexadecimal.
|
18
|
+
puts "0x#{address.to_s(16).upcase}"
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'lgpio'
|
2
|
+
|
3
|
+
INIT_ARRAY = [0, 168, 63, 211, 0, 64, 161, 200, 218, 18, 164, 166, 213, 128, 219, 32, 217, 241, 141, 20, 32, 0, 175]
|
4
|
+
START_ARRAY = [0, 33, 0, 127, 34, 0, 7]
|
5
|
+
PATTERN_1 = [64] + Array.new(1024) { 0b00110011 }
|
6
|
+
PATTERN_2 = [64] + Array.new(1024) { 0b11001100 }
|
7
|
+
|
8
|
+
GPIO_CHIP = 0
|
9
|
+
SCL_PIN = 228
|
10
|
+
SDA_PIN = 270
|
11
|
+
ADDRESS = 0x3C
|
12
|
+
|
13
|
+
chip_handle = LGPIO.chip_open(GPIO_CHIP)
|
14
|
+
LGPIO.i2c_bb_claim(chip_handle, SCL_PIN, SDA_PIN)
|
15
|
+
|
16
|
+
LGPIO.i2c_bb_write(chip_handle, SCL_PIN, SDA_PIN, ADDRESS, INIT_ARRAY)
|
17
|
+
FRAME_COUNT = 400
|
18
|
+
|
19
|
+
start = Time.now
|
20
|
+
(FRAME_COUNT / 2).times do
|
21
|
+
LGPIO.i2c_bb_write(chip_handle, SCL_PIN, SDA_PIN, ADDRESS, START_ARRAY)
|
22
|
+
LGPIO.i2c_bb_write(chip_handle, SCL_PIN, SDA_PIN, ADDRESS, PATTERN_1)
|
23
|
+
LGPIO.i2c_bb_write(chip_handle, SCL_PIN, SDA_PIN, ADDRESS, START_ARRAY)
|
24
|
+
LGPIO.i2c_bb_write(chip_handle, SCL_PIN, SDA_PIN, ADDRESS, PATTERN_2)
|
25
|
+
end
|
26
|
+
finish = Time.now
|
27
|
+
|
28
|
+
LGPIO.chip_close(chip_handle)
|
29
|
+
|
30
|
+
fps = FRAME_COUNT / (finish - start)
|
31
|
+
# Also calculate C calls per second, using roughly 23 calls per byte written.
|
32
|
+
cps = (START_ARRAY.length + ((PATTERN_1.length + PATTERN_2.length) / 2) + 2) * 23 * fps
|
33
|
+
cps = (cps / 1000.0).round
|
34
|
+
|
35
|
+
puts "SSD1306 benchmark result: #{fps.round(2)} fps | #{cps}k C calls/s"
|
@@ -1,21 +1,22 @@
|
|
1
1
|
require 'lgpio'
|
2
2
|
|
3
|
-
I2C_DEV
|
3
|
+
I2C_DEV = 3
|
4
|
+
ADDRESS = 0x3C
|
4
5
|
INIT_ARRAY = [0, 168, 63, 211, 0, 64, 161, 200, 218, 18, 164, 166, 213, 128, 219, 32, 217, 241, 141, 20, 32, 0, 175]
|
5
6
|
START_ARRAY = [0, 33, 0, 127, 34, 0, 7]
|
6
|
-
|
7
|
-
|
7
|
+
PATTERN_1 = [64] + Array.new(1024) { 0b00110011 }
|
8
|
+
PATTERN_2 = [64] + Array.new(1024) { 0b11001100 }
|
8
9
|
|
9
|
-
ssd1306_handle = LGPIO.i2c_open(I2C_DEV,
|
10
|
+
ssd1306_handle = LGPIO.i2c_open(I2C_DEV, ADDRESS, 0)
|
10
11
|
LGPIO.i2c_write_device(ssd1306_handle, INIT_ARRAY)
|
11
12
|
FRAME_COUNT = 100
|
12
13
|
|
13
14
|
start = Time.now
|
14
15
|
(FRAME_COUNT / 2).times do
|
15
16
|
LGPIO.i2c_write_device(ssd1306_handle, START_ARRAY)
|
16
|
-
LGPIO.i2c_write_device(ssd1306_handle,
|
17
|
+
LGPIO.i2c_write_device(ssd1306_handle, PATTERN_1)
|
17
18
|
LGPIO.i2c_write_device(ssd1306_handle, START_ARRAY)
|
18
|
-
LGPIO.i2c_write_device(ssd1306_handle,
|
19
|
+
LGPIO.i2c_write_device(ssd1306_handle, PATTERN_2)
|
19
20
|
end
|
20
21
|
finish = Time.now
|
21
22
|
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'lgpio'
|
2
|
+
|
3
|
+
FREQUENCY = 38_000
|
4
|
+
|
5
|
+
# NEC Raw-Data=0xF708FB04. LSBFIRST, so the binary for each hex digit below is backward.
|
6
|
+
CODE = [ 9000, 500, # Start bit
|
7
|
+
560, 560, 560, 560, 560, 1690, 560, 560, # 0010 0x4 command
|
8
|
+
560, 560, 560, 560, 560, 560, 560, 560, # 0000 0x0 command
|
9
|
+
560, 1690, 560, 1690, 560,560, 560, 1690, # 1101 0xB command inverted
|
10
|
+
560, 1690, 560, 1690, 560, 1690, 560, 1690, # 1111 0xF command inverted
|
11
|
+
560, 560, 560, 560, 560, 560, 560, 1690, # 0001 0x8 address
|
12
|
+
560, 560, 560, 560, 560, 560, 560, 560, # 0000 0x0 address
|
13
|
+
560, 1690, 560, 1690, 560, 1690, 560, 560, # 1110 0x7 address inverted
|
14
|
+
560, 1690, 560, 1690, 560, 1690, 560, 1690, # 1111 0xF address inverted
|
15
|
+
560] # Stop bit
|
16
|
+
|
17
|
+
infrared = LGPIO::Infrared.new(0, 2, frequency: FREQUENCY)
|
18
|
+
|
19
|
+
loop do
|
20
|
+
infrared.transmit(CODE)
|
21
|
+
sleep 1
|
22
|
+
end
|
data/examples/momentary.rb
CHANGED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'lgpio'
|
2
|
+
|
3
|
+
GPIO_CHIP = 0
|
4
|
+
PIN = 256
|
5
|
+
PARASITE = false
|
6
|
+
|
7
|
+
chip_handle = LGPIO.chip_open(GPIO_CHIP)
|
8
|
+
one_wire = LGPIO::OneWire.new(chip_handle, PIN)
|
9
|
+
|
10
|
+
one_wire.reset
|
11
|
+
# Skip ROM
|
12
|
+
one_wire.write([LGPIO::OneWire::SKIP_ROM], parasite: PARASITE)
|
13
|
+
# Start conversion
|
14
|
+
one_wire.write([LGPIO::OneWire::CONVERT_T], parasite: PARASITE)
|
15
|
+
# Wait for conversion
|
16
|
+
sleep(1)
|
17
|
+
# Reset
|
18
|
+
one_wire.reset
|
19
|
+
# Skip ROM
|
20
|
+
one_wire.write([LGPIO::OneWire::SKIP_ROM], parasite: PARASITE)
|
21
|
+
# Read 9 bytes from scratchpad
|
22
|
+
one_wire.write([LGPIO::OneWire::READ_SCRATCH], parasite: PARASITE)
|
23
|
+
bytes = one_wire.read(9)
|
24
|
+
|
25
|
+
# Temperature is the first 16 bits (2 bytes of 9 read).
|
26
|
+
# It's a signed, 2's complement, little-endian decimal. LSB = 2 ^ -4.
|
27
|
+
#
|
28
|
+
temperature = bytes[0..1].pack('C*').unpack('s<')[0] * (2.0 ** -4)
|
29
|
+
|
30
|
+
puts "DS18B20 reading: #{temperature} \xC2\xB0C"
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'lgpio'
|
2
|
+
|
3
|
+
GPIO_CHIP = 0
|
4
|
+
PIN = 256
|
5
|
+
|
6
|
+
chip_handle = LGPIO.chip_open(GPIO_CHIP)
|
7
|
+
one_wire = LGPIO::OneWire.new(chip_handle, PIN)
|
8
|
+
one_wire.search
|
9
|
+
|
10
|
+
puts; puts "Found these 1-wire addresss (HEX) on the bus:"; puts
|
11
|
+
|
12
|
+
one_wire.found_addresses.each do |address|
|
13
|
+
puts address.to_s(16)
|
14
|
+
end
|
15
|
+
puts
|
data/examples/pwm.rb
CHANGED
data/examples/reports.rb
CHANGED
data/examples/rotary_encoder.rb
CHANGED
@@ -5,10 +5,10 @@
|
|
5
5
|
require 'lgpio'
|
6
6
|
|
7
7
|
GPIO_CHIP = 0
|
8
|
-
PIN_A =
|
9
|
-
PIN_B =
|
8
|
+
PIN_A = 260
|
9
|
+
PIN_B = 76
|
10
10
|
|
11
|
-
PIN_LED =
|
11
|
+
PIN_LED = 272
|
12
12
|
PWM_FREQ = 500
|
13
13
|
PWM_OFFSET = 0
|
14
14
|
PWM_CYCLES = 0 # 0 = infinite
|
@@ -44,7 +44,7 @@ loop do
|
|
44
44
|
elsif report[:gpio] == PIN_B
|
45
45
|
delta = (report[:level] == state_a) ? -1 : 1
|
46
46
|
state_b = report[:level]
|
47
|
-
|
47
|
+
|
48
48
|
led_duty += delta
|
49
49
|
led_duty = 0 if led_duty < 0
|
50
50
|
led_duty = 100 if led_duty > 100
|
data/examples/servo.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'lgpio'
|
2
|
+
#
|
3
|
+
# Writing directly to a hardware PWM channel to control a servo.
|
4
|
+
# Arguments in order are:
|
5
|
+
# pwmchip index (X in /sys/class/pwm/pwmchipX/)
|
6
|
+
# PWM channel on the chip (Y in /sys/class/pwm/pwmchipX/pwmY)
|
7
|
+
# period: given in nanoseconds
|
8
|
+
# OR frequency: given in Hz
|
9
|
+
#
|
10
|
+
servo = LGPIO::HardwarePWM.new(0, 1, period: 20_000_000)
|
11
|
+
#
|
12
|
+
# Duty cycle is given in nanoseconds by default. Extra setter methods
|
13
|
+
# are provided for microseconds, and percent.
|
14
|
+
#
|
15
|
+
# servo.duty_percent = 2.5
|
16
|
+
# servo.duty_us = 500
|
17
|
+
servo.duty = 500_000
|
18
|
+
|
19
|
+
#
|
20
|
+
# Using the Servo class instead.
|
21
|
+
# Arguments in order are:
|
22
|
+
# pwmchip index (X in /sys/class/pwm/pwmchipX/)
|
23
|
+
# PWM channel on the chip (Y in /sys/class/pwm/pwmchipX/pwmY)
|
24
|
+
# Minimum servo duty cycle in microseconds
|
25
|
+
# Maximum servo duty cicle in microseconds
|
26
|
+
# Minimum servo angle
|
27
|
+
# Maximum servo angle
|
28
|
+
#
|
29
|
+
servo = LGPIO::PositionalServo.new(0, 1, 500, 2500, 0, 180)
|
30
|
+
|
31
|
+
angles = [0, 30, 60, 90, 120, 150, 180, 150, 120, 90, 60, 30]
|
32
|
+
|
33
|
+
angles.cycle do |angle|
|
34
|
+
servo.angle = angle
|
35
|
+
sleep 1
|
36
|
+
end
|