denko-piboard 0.13.2 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +4 -0
- data/LICENSE +1 -1
- data/README.md +181 -132
- data/Rakefile +0 -5
- data/board_maps/README.md +59 -0
- data/board_maps/le_potato.yml +89 -0
- data/board_maps/orange_pi_zero_2w.yml +85 -0
- data/board_maps/radxa_zero3.yml +88 -0
- data/board_maps/raspberry_pi.yml +95 -0
- data/board_maps/raspberry_pi5.yml +95 -0
- data/denko_piboard.gemspec +6 -7
- data/examples/digital_io/bench_out.rb +22 -0
- data/examples/digital_io/rotary_encoder.rb +31 -0
- data/examples/display/ssd1306.rb +53 -0
- data/examples/i2c/bitbang_aht10.rb +18 -0
- data/examples/i2c/bitbang_search.rb +24 -0
- data/examples/i2c/bitbang_ssd1306_bench.rb +29 -0
- data/examples/i2c/search.rb +24 -0
- data/examples/led/blink.rb +10 -0
- data/examples/led/fade.rb +22 -0
- data/examples/led/ws2812_bounce.rb +36 -0
- data/examples/motor/servo.rb +16 -0
- data/examples/pi_system_monitor.rb +10 -8
- data/examples/pulse_io/buzzer.rb +34 -0
- data/examples/pulse_io/infrared.rb +25 -0
- data/examples/sensor/aht10.rb +17 -0
- data/examples/sensor/dht.rb +24 -0
- data/examples/sensor/ds18b20.rb +59 -0
- data/examples/sensor/hcsr04.rb +16 -0
- data/examples/sensor/neat_tph_readings.rb +32 -0
- data/examples/spi/bb_loopback.rb +31 -0
- data/examples/spi/loopback.rb +37 -0
- data/examples/spi/output_register.rb +38 -0
- data/lib/denko/piboard.rb +10 -2
- data/lib/denko/piboard_base.rb +21 -63
- data/lib/denko/piboard_core.rb +150 -130
- data/lib/denko/piboard_core_optimize_lookup.rb +31 -0
- data/lib/denko/piboard_hardware_pwm.rb +32 -0
- data/lib/denko/piboard_i2c.rb +59 -82
- data/lib/denko/piboard_i2c_bb.rb +48 -0
- data/lib/denko/piboard_infrared.rb +7 -44
- data/lib/denko/piboard_led_array.rb +9 -0
- data/lib/denko/piboard_map.rb +125 -38
- data/lib/denko/piboard_one_wire.rb +42 -0
- data/lib/denko/piboard_pulse.rb +11 -68
- data/lib/denko/piboard_spi.rb +47 -73
- data/lib/denko/piboard_spi_bb.rb +41 -0
- data/lib/denko/piboard_tone.rb +15 -26
- data/lib/denko/piboard_version.rb +1 -1
- data/scripts/99-denko.rules +9 -0
- data/scripts/set_permissions.rb +131 -0
- metadata +48 -21
- data/ext/gpiod/extconf.rb +0 -9
- data/ext/gpiod/gpiod.c +0 -179
- data/lib/denko/piboard_servo.rb +0 -18
- data/lib/gpiod.rb +0 -6
@@ -0,0 +1,88 @@
|
|
1
|
+
#
|
2
|
+
# Tested on Radxa Zero 3W, running Armbian, Kernel 6.1.75-vendor-rk35xx
|
3
|
+
#
|
4
|
+
# Note: Overlays are not packaged with Armbian for some reason. Hopefully this changes soon,
|
5
|
+
# but I've built the .dtbo files for the kernel given above, and made them available here:
|
6
|
+
# https://github.com/vickash/linux-sbc-overlays/tree/master/radxa/rockchip
|
7
|
+
# To use them, save all the .dtbo files into:
|
8
|
+
# /boot/dtb/rockchip/overlay
|
9
|
+
#
|
10
|
+
---
|
11
|
+
pins:
|
12
|
+
# Left side (odd numbered)
|
13
|
+
# PIN 1 is 3V3
|
14
|
+
32: { phy: 3, chip: 1, line: 0 }
|
15
|
+
33: { phy: 5, chip: 1, line: 1 }
|
16
|
+
116: { phy: 7, chip: 3, line: 20 }
|
17
|
+
# PIN 9 is GND
|
18
|
+
97: { phy: 11, chip: 3, line: 1 }
|
19
|
+
98: { phy: 13, chip: 3, line: 2 }
|
20
|
+
104: { phy: 15, chip: 3, line: 8 }
|
21
|
+
# PIN 17 is 3V3
|
22
|
+
147: { phy: 19, chip: 4, line: 19 }
|
23
|
+
149: { phy: 21, chip: 4, line: 21 }
|
24
|
+
146: { phy: 23, chip: 4, line: 18 }
|
25
|
+
# PIN 25 is GND
|
26
|
+
138: { phy: 27, chip: 4, line: 10 }
|
27
|
+
107: { phy: 29, chip: 3, line: 11 }
|
28
|
+
108: { phy: 31, chip: 3, line: 12 }
|
29
|
+
115: { phy: 33, chip: 3, line: 19 }
|
30
|
+
100: { phy: 35, chip: 3, line: 4 }
|
31
|
+
36: { phy: 37, chip: 1, line: 4 }
|
32
|
+
# PIN 39 is GND
|
33
|
+
|
34
|
+
# Right side (even numbered)
|
35
|
+
# PIN 2 is 5V
|
36
|
+
# PIN 4 is 5V
|
37
|
+
# PIN 6 is GND
|
38
|
+
24: { phy: 8, chip: 0, line: 24 }
|
39
|
+
25: { phy: 10, chip: 0, line: 25 }
|
40
|
+
99: { phy: 12, chip: 3, line: 3 }
|
41
|
+
# PIN 14 is GND
|
42
|
+
105: { phy: 16, chip: 3, line: 9 }
|
43
|
+
106: { phy: 18, chip: 3, line: 10 }
|
44
|
+
# PIN 20 is GND
|
45
|
+
113: { phy: 22, chip: 3, line: 17 }
|
46
|
+
150: { phy: 24, chip: 4, line: 22 }
|
47
|
+
# PIN 26 is NC
|
48
|
+
139: { phy: 28, chip: 4, line: 11 }
|
49
|
+
# PIN 30 is GND
|
50
|
+
114: { phy: 32, chip: 3, line: 18 }
|
51
|
+
# PIN 34 is GND
|
52
|
+
103: { phy: 36, chip: 3, line: 7 }
|
53
|
+
102: { phy: 38, chip: 3, line: 6 }
|
54
|
+
101: { phy: 40, chip: 3, line: 5 }
|
55
|
+
|
56
|
+
pwms:
|
57
|
+
#
|
58
|
+
# Add to overlays= line in /boot/amrbianEnv.txt
|
59
|
+
# pwm8-m0 pwm9-m0
|
60
|
+
105:
|
61
|
+
pwmchip: 0
|
62
|
+
channel: 0
|
63
|
+
overlay: pwm8-m0
|
64
|
+
106:
|
65
|
+
pwmchip: 1
|
66
|
+
channel: 0
|
67
|
+
overlay: pwm9-m0
|
68
|
+
|
69
|
+
i2cs:
|
70
|
+
#
|
71
|
+
# Add to overlays= line in /boot/amrbianEnv.txt
|
72
|
+
# i2c3-m0
|
73
|
+
3:
|
74
|
+
scl: 33
|
75
|
+
sda: 32
|
76
|
+
reserved_addresses: [0x22]
|
77
|
+
overlay: i2c3-m0
|
78
|
+
|
79
|
+
spis:
|
80
|
+
#
|
81
|
+
# Add to overlays= line in /boot/amrbianEnv.txt
|
82
|
+
# ispi3-m1-cs0-spidev
|
83
|
+
3:
|
84
|
+
clk: 146
|
85
|
+
mosi: 147
|
86
|
+
miso: 149
|
87
|
+
cs0: 150
|
88
|
+
overlay: spi3-m1-cs0-spidev
|
@@ -0,0 +1,95 @@
|
|
1
|
+
#
|
2
|
+
# Tested on:
|
3
|
+
# - Raspberry Pi 4B with Raspberry Pi OS, Kernel 6.6.47
|
4
|
+
# - Raspberry Pi Zero W, with Raspberry Pi OS, Kernel 6.6.51
|
5
|
+
#
|
6
|
+
# Should work for all 40-pin Raspberry Pi models on this OS,
|
7
|
+
# EXCEPT Raspberry Pi 5.
|
8
|
+
#
|
9
|
+
---
|
10
|
+
pins:
|
11
|
+
# Left side (odd numbered physical pins)
|
12
|
+
# PIN 1 is 3V3
|
13
|
+
2: { phy: 3, chip: 0, line: 2 }
|
14
|
+
3: { phy: 5, chip: 0, line: 3 }
|
15
|
+
4: { phy: 7, chip: 0, line: 4 }
|
16
|
+
# PIN 9 is GND
|
17
|
+
17: { phy: 11, chip: 0, line: 17 }
|
18
|
+
27: { phy: 13, chip: 0, line: 27 }
|
19
|
+
22: { phy: 15, chip: 0, line: 22 }
|
20
|
+
# PIN 17 is 3V3
|
21
|
+
10: { phy: 19, chip: 0, line: 10 }
|
22
|
+
9: { phy: 21, chip: 0, line: 9 }
|
23
|
+
11: { phy: 23, chip: 0, line: 11 }
|
24
|
+
# PIN 25 is GND
|
25
|
+
0: { phy: 27, chip: 0, line: 0 }
|
26
|
+
5: { phy: 29, chip: 0, line: 5 }
|
27
|
+
6: { phy: 31, chip: 0, line: 6 }
|
28
|
+
13: { phy: 33, chip: 0, line: 13 }
|
29
|
+
19: { phy: 35, chip: 0, line: 19 }
|
30
|
+
26: { phy: 37, chip: 0, line: 26 }
|
31
|
+
# PIN 39 is GND
|
32
|
+
|
33
|
+
# Right side (even numbered physical pins)
|
34
|
+
# PIN 2 is 5V
|
35
|
+
# PIN 4 is 5V
|
36
|
+
# PIN 6 is GND
|
37
|
+
14: { phy: 8, chip: 0, line: 14 }
|
38
|
+
15: { phy: 10, chip: 0, line: 15 }
|
39
|
+
18: { phy: 12, chip: 0, line: 18 }
|
40
|
+
# PIN 14 is GND
|
41
|
+
23: { phy: 16, chip: 0, line: 23 }
|
42
|
+
24: { phy: 18, chip: 0, line: 24 }
|
43
|
+
# PIN 20 is GND
|
44
|
+
25: { phy: 22, chip: 0, line: 25 }
|
45
|
+
8: { phy: 24, chip: 0, line: 8 }
|
46
|
+
7: { phy: 6, chip: 0, line: 7 }
|
47
|
+
1: { phy: 28, chip: 0, line: 1 }
|
48
|
+
# PIN 30 is GND
|
49
|
+
12: { phy: 32, chip: 0, line: 12 }
|
50
|
+
# PIN 34 is GND
|
51
|
+
16: { phy: 36, chip: 0, line: 16 }
|
52
|
+
20: { phy: 38, chip: 0, line: 20 }
|
53
|
+
21: { phy: 40, chip: 0, line: 21 }
|
54
|
+
|
55
|
+
pwms:
|
56
|
+
#
|
57
|
+
# To enable in /boot/config.txt:
|
58
|
+
# dtoverlay=pwm-2chan,pin=12,func=4,pin2=13,func2=4
|
59
|
+
12:
|
60
|
+
pwmchip: 0
|
61
|
+
channel: 0
|
62
|
+
13:
|
63
|
+
pwmchip: 0
|
64
|
+
channel: 1
|
65
|
+
|
66
|
+
i2cs:
|
67
|
+
#
|
68
|
+
# To enable in /boot/config.txt:
|
69
|
+
# dtparam=i2c_arm=on
|
70
|
+
# dtparam=i2c_arm_baudrate=400000
|
71
|
+
1:
|
72
|
+
scl: 3
|
73
|
+
sda: 2
|
74
|
+
|
75
|
+
spis:
|
76
|
+
#
|
77
|
+
# To enable in /boot/config.txt:
|
78
|
+
# dtoverlay=spi0-0cs
|
79
|
+
0:
|
80
|
+
clk: 11
|
81
|
+
mosi: 10
|
82
|
+
miso: 9
|
83
|
+
# cs0: 8 # only if using dtoverlay=spi0-1cs or dtoverlay=spi0-2cs
|
84
|
+
# cs1: 7 # only if using dtoverlay=spi0-2cs
|
85
|
+
|
86
|
+
#
|
87
|
+
# To enable in /boot/config.txt:
|
88
|
+
# dtoverlay=spi1-1cs
|
89
|
+
# 1:
|
90
|
+
# clk: 21
|
91
|
+
# mosi: 20
|
92
|
+
# miso: 19
|
93
|
+
# cs0: 18
|
94
|
+
# cs1: 17 # only if using dtoverlay=spi1-2cs or dtoverlay=spi1-3cs
|
95
|
+
# cs2: 16 # only if using dtoverlay=spi1-3cs
|
@@ -0,0 +1,95 @@
|
|
1
|
+
#
|
2
|
+
# This is based on Rasperry Pi documentation, but UNTESTED in hardware.
|
3
|
+
# It should work for the Raspberry Pi 5.
|
4
|
+
# - GPIO line numbers are same as older Pis, but the gpiochip has changed from 0 to 4.
|
5
|
+
# - dtparam/dtoverlay for PWM, I2C and SPI are all unchanged, based on info from:
|
6
|
+
# https://github.com/raspberrypi/firmware/blob/master/boot/overlays/README
|
7
|
+
# - Expected to work on current Raspberry Pi OS.
|
8
|
+
#
|
9
|
+
---
|
10
|
+
pins:
|
11
|
+
# Left side (odd numbered physical pins)
|
12
|
+
# PIN 1 is 3V3
|
13
|
+
2: { phy: 3, chip: 4, line: 2 }
|
14
|
+
3: { phy: 5, chip: 4, line: 3 }
|
15
|
+
4: { phy: 7, chip: 4, line: 4 }
|
16
|
+
# PIN 9 is GND
|
17
|
+
17: { phy: 11, chip: 4, line: 17 }
|
18
|
+
27: { phy: 13, chip: 4, line: 27 }
|
19
|
+
22: { phy: 15, chip: 4, line: 22 }
|
20
|
+
# PIN 17 is 3V3
|
21
|
+
10: { phy: 19, chip: 4, line: 10 }
|
22
|
+
9: { phy: 21, chip: 4, line: 9 }
|
23
|
+
11: { phy: 23, chip: 4, line: 11 }
|
24
|
+
# PIN 25 is GND
|
25
|
+
0: { phy: 27, chip: 4, line: 0 }
|
26
|
+
5: { phy: 29, chip: 4, line: 5 }
|
27
|
+
6: { phy: 31, chip: 4, line: 6 }
|
28
|
+
13: { phy: 33, chip: 4, line: 13 }
|
29
|
+
19: { phy: 35, chip: 4, line: 19 }
|
30
|
+
26: { phy: 37, chip: 4, line: 26 }
|
31
|
+
# PIN 39 is GND
|
32
|
+
|
33
|
+
# Right side (even numbered physical pins)
|
34
|
+
# PIN 2 is 5V
|
35
|
+
# PIN 4 is 5V
|
36
|
+
# PIN 6 is GND
|
37
|
+
14: { phy: 8, chip: 4, line: 14 }
|
38
|
+
15: { phy: 10, chip: 4, line: 15 }
|
39
|
+
18: { phy: 12, chip: 4, line: 18 }
|
40
|
+
# PIN 14 is GND
|
41
|
+
23: { phy: 16, chip: 4, line: 23 }
|
42
|
+
24: { phy: 18, chip: 4, line: 24 }
|
43
|
+
# PIN 20 is GND
|
44
|
+
25: { phy: 22, chip: 4, line: 25 }
|
45
|
+
8: { phy: 24, chip: 4, line: 8 }
|
46
|
+
7: { phy: 6, chip: 4, line: 7 }
|
47
|
+
1: { phy: 28, chip: 4, line: 1 }
|
48
|
+
# PIN 30 is GND
|
49
|
+
12: { phy: 32, chip: 4, line: 12 }
|
50
|
+
# PIN 34 is GND
|
51
|
+
16: { phy: 36, chip: 4, line: 16 }
|
52
|
+
20: { phy: 38, chip: 4, line: 20 }
|
53
|
+
21: { phy: 40, chip: 4, line: 21 }
|
54
|
+
|
55
|
+
pwms:
|
56
|
+
#
|
57
|
+
# To enable in /boot/config.txt:
|
58
|
+
# dtoverlay=pwm-2chan,pin=12,func=4,pin2=13,func2=4
|
59
|
+
12:
|
60
|
+
pwmchip: 0
|
61
|
+
channel: 0
|
62
|
+
13:
|
63
|
+
pwmchip: 0
|
64
|
+
channel: 1
|
65
|
+
|
66
|
+
i2cs:
|
67
|
+
#
|
68
|
+
# To enable in /boot/config.txt:
|
69
|
+
# dtparam=i2c_arm=on
|
70
|
+
# dtparam=i2c_arm_baudrate=400000
|
71
|
+
1:
|
72
|
+
scl: 3
|
73
|
+
sda: 2
|
74
|
+
|
75
|
+
spis:
|
76
|
+
#
|
77
|
+
# To enable in /boot/config.txt:
|
78
|
+
# dtoverlay=spi0-0cs
|
79
|
+
0:
|
80
|
+
clk: 11
|
81
|
+
mosi: 10
|
82
|
+
miso: 9
|
83
|
+
# cs0: 8 # only if using dtoverlay=spi0-1cs or dtoverlay=spi0-2cs
|
84
|
+
# cs1: 7 # only if using dtoverlay=spi0-2cs
|
85
|
+
|
86
|
+
#
|
87
|
+
# To enable in /boot/config.txt:
|
88
|
+
# dtoverlay=spi1-1cs
|
89
|
+
# 1:
|
90
|
+
# clk: 21
|
91
|
+
# mosi: 20
|
92
|
+
# miso: 19
|
93
|
+
# cs0: 18
|
94
|
+
# cs1: 17 # only if using dtoverlay=spi1-2cs or dtoverlay=spi1-3cs
|
95
|
+
# cs2: 16 # only if using dtoverlay=spi1-3cs
|
data/denko_piboard.gemspec
CHANGED
@@ -4,18 +4,17 @@ Gem::Specification.new do |s|
|
|
4
4
|
s.name = 'denko-piboard'
|
5
5
|
s.version = Denko::PiBoard::VERSION
|
6
6
|
s.licenses = ['MIT']
|
7
|
-
s.summary = "
|
8
|
-
s.description = "
|
7
|
+
s.summary = "Linux SBC GPIO in Ruby"
|
8
|
+
s.description = "Use Linux single-board-computer GPIO, I2C, SPI and PWM in Ruby"
|
9
9
|
|
10
10
|
s.authors = ["vickash"]
|
11
11
|
s.email = 'mail@vickash.com'
|
12
12
|
s.files = Dir['**/*'].reject { |f| f.match /.gem\z/}
|
13
13
|
s.homepage = 'https://github.com/denko-rb/denko-piboard'
|
14
14
|
s.metadata = { "source_code_uri" => "https://github.com/denko-rb/denko-piboard" }
|
15
|
-
|
16
|
-
# libgpio C extension
|
17
|
-
s.extensions = %w[ext/gpiod/extconf.rb]
|
18
15
|
|
19
|
-
s.
|
20
|
-
|
16
|
+
s.required_ruby_version = '>=3'
|
17
|
+
|
18
|
+
s.add_dependency 'lgpio', '~> 0.1'
|
19
|
+
s.add_dependency 'denko', '~> 0.15'
|
21
20
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'denko/piboard'
|
2
|
+
|
3
|
+
PIN = 272
|
4
|
+
COUNT = 1000000
|
5
|
+
|
6
|
+
board = Denko::PiBoard.new
|
7
|
+
output = Denko::DigitalIO::Output.new(board: board, pin: PIN)
|
8
|
+
|
9
|
+
t1 = Time.now
|
10
|
+
COUNT.times do
|
11
|
+
# If bit-banging in Ruby, this is the level to work at.
|
12
|
+
board.digital_write(PIN, 1)
|
13
|
+
board.digital_write(PIN, 0)
|
14
|
+
|
15
|
+
# These methods set output.state on every call (slower).
|
16
|
+
# output.high
|
17
|
+
# output.low
|
18
|
+
end
|
19
|
+
t2 = Time.now
|
20
|
+
board.finish_write
|
21
|
+
|
22
|
+
puts "Toggles per second: #{COUNT.to_f / (t2 - t1).to_f}"
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#
|
2
|
+
# WARNING: This performs significantly better when used with a PiBoard instance
|
3
|
+
# (Linux SBC), compared to a Board instance (attached microcontroller),
|
4
|
+
# but still might not be perfect.
|
5
|
+
#
|
6
|
+
require 'denko/piboard'
|
7
|
+
|
8
|
+
PIN_A = 260
|
9
|
+
PIN_B = 76
|
10
|
+
|
11
|
+
board = Denko::PiBoard.new
|
12
|
+
encoder = Denko::DigitalIO::RotaryEncoder.new board: board,
|
13
|
+
pins: { a: PIN_A, b: PIN_B },
|
14
|
+
divider: 1, # Default. Applies only to Board. Read pin every 1ms.
|
15
|
+
debounce_time: 1, # Default. Applies only to PiBoard. Debounce filter set to 1 microsecond.
|
16
|
+
counts_per_revolution: 60 # Default
|
17
|
+
|
18
|
+
# Reverse direction if needed.
|
19
|
+
# encoder.reverse
|
20
|
+
|
21
|
+
# Reset angle and count to 0.
|
22
|
+
encoder.reset
|
23
|
+
|
24
|
+
encoder.add_callback do |state|
|
25
|
+
change_printable = state[:change].to_s
|
26
|
+
change_printable = "+#{change_printable}" if state[:change] > 0
|
27
|
+
|
28
|
+
puts "Encoder Change: #{change_printable} | Count: #{state[:count]} | Angle: #{state[:angle]}\xC2\xB0"
|
29
|
+
end
|
30
|
+
|
31
|
+
sleep
|
@@ -0,0 +1,53 @@
|
|
1
|
+
#
|
2
|
+
# Use SSD1306 OLED, over I2C or SPI.
|
3
|
+
#
|
4
|
+
require 'denko/piboard'
|
5
|
+
|
6
|
+
board = Denko::PiBoard.new
|
7
|
+
|
8
|
+
# Use the first hardware I2C interface.
|
9
|
+
i2c_index = board.map[:i2cs].keys.first
|
10
|
+
bus = Denko::I2C::Bus.new(board: board, index: i2c_index)
|
11
|
+
#
|
12
|
+
# Or a bit-bang I2C interface.
|
13
|
+
# bus = Denko::I2C::BitBang.new(board: board, pins: {scl: 228, sda: 270})
|
14
|
+
|
15
|
+
# Use the first hardware SPI interface, and its defined :cs0 pin.
|
16
|
+
# spi_index = board.map[:spis].keys.first
|
17
|
+
# chip_select = board.map[:spis][spi_index][:cs0]
|
18
|
+
# bus = Denko::SPI::Bus.new(board: board, index: spi_index)
|
19
|
+
#
|
20
|
+
# Or a bit-bang SPI interface.
|
21
|
+
# bus = Denko::SPI::BitBang.new(board: board, pins: {clock: 228, output: 270})
|
22
|
+
|
23
|
+
# I2C OLED, connected to I2C SDA and SCL.
|
24
|
+
oled = Denko::Display::SSD1306.new(bus: bus, rotate: true) # address: 0x3C is default
|
25
|
+
|
26
|
+
# SPI OLED, connected to SPI CLK and MOSI pins.
|
27
|
+
# select: and dc: pins must be given. reset is optional (can be pulled high instead).
|
28
|
+
# oled = Denko::Display::SSD1306.new(bus: bus, pins: {reset: 259, dc: 260, select: chip_select}, rotate: true)
|
29
|
+
|
30
|
+
# Transformation features in hardware.
|
31
|
+
# oled.reflect_x
|
32
|
+
# oled.reflect_y
|
33
|
+
oled.rotate
|
34
|
+
|
35
|
+
# Draw some text on the OLED's canvas (a Ruby memory buffer).
|
36
|
+
canvas = oled.canvas
|
37
|
+
baseline = 42
|
38
|
+
canvas.text_cursor = 27, baseline+15
|
39
|
+
canvas.text "Hello World!"
|
40
|
+
|
41
|
+
# Add some shapes to the canvas.
|
42
|
+
canvas.rectangle x: 10, y: baseline, w: 30, h: -30
|
43
|
+
canvas.circle x: 66, y: baseline-15, r: 15
|
44
|
+
canvas.triangle x1: 87, y1: baseline,
|
45
|
+
x2: 117, y2: baseline,
|
46
|
+
x3: 102, y3: baseline-30
|
47
|
+
|
48
|
+
# 1px border to test screen edges.
|
49
|
+
canvas.rectangle x1: 0, y1: 0, x2: canvas.x_max, y2: canvas.y_max
|
50
|
+
|
51
|
+
# Send the canvas to the OLED's graphics RAM so it shows.
|
52
|
+
oled.draw
|
53
|
+
board.finish_write
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#
|
2
|
+
# AHT10 sensor over bit-banged I2C.
|
3
|
+
#
|
4
|
+
require 'denko/piboard'
|
5
|
+
require_relative '../sensor/neat_tph_readings'
|
6
|
+
|
7
|
+
SCL = 228
|
8
|
+
SDA = 270
|
9
|
+
board = Denko::PiBoard.new
|
10
|
+
bus = Denko::I2C::BitBang.new(board: board, pins: {scl: SCL, sda: SDA})
|
11
|
+
aht10 = Denko::Sensor::AHT10.new(bus: bus) # address: 0x38 default
|
12
|
+
|
13
|
+
# Poll it and print readings.
|
14
|
+
aht10.poll(5) do |reading|
|
15
|
+
print_tph_reading(reading)
|
16
|
+
end
|
17
|
+
|
18
|
+
sleep
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#
|
2
|
+
# Search for connected devices on a bit-bang I2C bus.
|
3
|
+
#
|
4
|
+
require 'denko/piboard'
|
5
|
+
|
6
|
+
SCL = 228
|
7
|
+
SDA = 270
|
8
|
+
board = Denko::PiBoard.new
|
9
|
+
bus = Denko::I2C::BitBang.new(board: board, pins: {scl: SCL, sda: SDA})
|
10
|
+
|
11
|
+
bus.search
|
12
|
+
|
13
|
+
if bus.found_devices.empty?
|
14
|
+
puts "No devices found on I2C bus"
|
15
|
+
else
|
16
|
+
puts "I2C device addresses found:"
|
17
|
+
bus.found_devices.each do |address|
|
18
|
+
# Print as hexadecimal.
|
19
|
+
puts "0x#{address.to_s(16).upcase}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
puts
|
24
|
+
board.finish_write
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'denko/piboard'
|
2
|
+
|
3
|
+
START_ARRAY = [0, 33, 0, 127, 34, 0, 7]
|
4
|
+
PATTERN_1 = [64] + Array.new(1024) { 0b00110011 }
|
5
|
+
PATTERN_2 = [64] + Array.new(1024) { 0b11001100 }
|
6
|
+
|
7
|
+
SCL = 228
|
8
|
+
SDA = 270
|
9
|
+
board = Denko::PiBoard.new
|
10
|
+
bus = Denko::I2C::BitBang.new(board: board, pins: {scl: SCL, sda: SDA})
|
11
|
+
oled = Denko::Display::SSD1306.new(bus: bus, rotate: true)
|
12
|
+
|
13
|
+
FRAME_COUNT = 400
|
14
|
+
start = Time.now
|
15
|
+
(FRAME_COUNT / 2).times do
|
16
|
+
oled.i2c_write(START_ARRAY)
|
17
|
+
oled.i2c_write(PATTERN_1)
|
18
|
+
oled.i2c_write(START_ARRAY)
|
19
|
+
oled.i2c_write(PATTERN_2)
|
20
|
+
end
|
21
|
+
board.finish_write
|
22
|
+
finish = Time.now
|
23
|
+
|
24
|
+
fps = FRAME_COUNT / (finish - start)
|
25
|
+
# Also calculate C calls per second, using roughly 23 calls per byte written.
|
26
|
+
cps = (START_ARRAY.length + ((PATTERN_1.length + PATTERN_2.length) / 2) + 2) * 23 * fps
|
27
|
+
cps = (cps / 1000.0).round
|
28
|
+
|
29
|
+
puts "SSD1306 benchmark result: #{fps.round(2)} fps | #{cps}k C calls/s"
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#
|
2
|
+
# Search for connected devices on a hardware I2C bus.
|
3
|
+
#
|
4
|
+
require 'denko/piboard'
|
5
|
+
|
6
|
+
board = Denko::PiBoard.new
|
7
|
+
# Use the first hardware I2C interface.
|
8
|
+
i2c_index = board.map[:i2cs].keys.first
|
9
|
+
bus = Denko::I2C::Bus.new(board: board, index: i2c_index)
|
10
|
+
|
11
|
+
bus.search
|
12
|
+
|
13
|
+
if bus.found_devices.empty?
|
14
|
+
puts "No devices found on I2C bus"
|
15
|
+
else
|
16
|
+
puts "I2C device addresses found:"
|
17
|
+
bus.found_devices.each do |address|
|
18
|
+
# Print as hexadecimal.
|
19
|
+
puts "0x#{address.to_s(16).upcase}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
puts
|
24
|
+
board.finish_write
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'denko/piboard'
|
2
|
+
|
3
|
+
# Either a regular GPIO (uses software PWM) or a GPIO with a hardware PWM channel.
|
4
|
+
PIN = 226
|
5
|
+
|
6
|
+
board = Denko::PiBoard.new
|
7
|
+
led = Denko::LED.new(board: board, pin: PIN)
|
8
|
+
|
9
|
+
5.times do
|
10
|
+
led.on
|
11
|
+
sleep 0.2
|
12
|
+
led.off
|
13
|
+
sleep 0.2
|
14
|
+
end
|
15
|
+
|
16
|
+
# Seamless loop from 0-100 and back.
|
17
|
+
values = (0..100).to_a + (1..99).to_a.reverse
|
18
|
+
|
19
|
+
values.cycle do |v|
|
20
|
+
led.duty = v
|
21
|
+
sleep 0.020
|
22
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
#
|
2
|
+
# Walk a single pixel along the length of a WS2812 strip and back,
|
3
|
+
# changing color each time it returns to position 0.
|
4
|
+
#
|
5
|
+
require 'denko/piboard'
|
6
|
+
|
7
|
+
RED = [255, 0, 0]
|
8
|
+
GREEN = [0, 255, 0]
|
9
|
+
BLUE = [0, 0, 255]
|
10
|
+
WHITE = [255, 255, 255]
|
11
|
+
COLORS = [RED, GREEN, BLUE, WHITE]
|
12
|
+
|
13
|
+
PIXELS = 8
|
14
|
+
|
15
|
+
# Move along the strip and back, one pixel at a time.
|
16
|
+
positions = (0..PIXELS-1).to_a + (1..PIXELS-2).to_a.reverse
|
17
|
+
|
18
|
+
board = Denko::PiBoard.new
|
19
|
+
|
20
|
+
# On PiBoard, WS2812 must use a hardware Denko::SPI instance as its "board",
|
21
|
+
# and always outputs on its MOSI pin. Use the first hardware SPI interface.
|
22
|
+
spi_index = board.map[:spis].keys.first
|
23
|
+
mosi = board.map[:spis][spi_index][:mosi]
|
24
|
+
bus = Denko::SPI::Bus.new(board: board, index: spi_index)
|
25
|
+
strip = Denko::LED::WS2812.new(board: bus, pin: mosi, length: PIXELS)
|
26
|
+
|
27
|
+
loop do
|
28
|
+
COLORS.each do |color|
|
29
|
+
positions.each do |index|
|
30
|
+
strip.clear
|
31
|
+
strip[index] = color
|
32
|
+
strip.show
|
33
|
+
sleep 0.05
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
#
|
2
|
+
# Use a servo motor on a hardware PWM pin. Should raise an error
|
3
|
+
# if the GPIO given does not have a hardware PWM channel multiplexed.
|
4
|
+
#
|
5
|
+
require 'denko/piboard'
|
6
|
+
|
7
|
+
# Must be assigned to a hardware PWM channel in your board map.
|
8
|
+
PIN = 226
|
9
|
+
|
10
|
+
board = Denko::PiBoard.new
|
11
|
+
servo = Denko::Motor::Servo.new(board: board, pin: PIN)
|
12
|
+
|
13
|
+
[0, 90, 180, 90].cycle do |angle|
|
14
|
+
servo.position = angle
|
15
|
+
sleep 0.5
|
16
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
#
|
2
2
|
# This example uses an SSD1306 OLED display, connected to the Pi's I2C1 interface.
|
3
3
|
# I2C1 pins are GPIO2 (SDA) and GPIO3 (SCL).
|
4
|
-
#
|
4
|
+
#
|
5
5
|
# CPU usage is measured using `mpstat`. To install it:
|
6
6
|
# sudo apt install sysstat
|
7
7
|
#
|
@@ -16,7 +16,9 @@ require 'denko/piboard'
|
|
16
16
|
BAR_ELEMENT = [0x00, 0x7E, 0x7E, 0x7E, 0x00]
|
17
17
|
|
18
18
|
board = Denko::PiBoard.new
|
19
|
-
|
19
|
+
# Use the first hardware I2C interface.
|
20
|
+
i2c_index = board.map[:i2cs].keys.first
|
21
|
+
i2c = Denko::I2C::Bus.new(board: board, index: i2c_index)
|
20
22
|
|
21
23
|
oled = Denko::Display::SSD1306.new(bus: i2c, rotate: true)
|
22
24
|
canvas = oled.canvas
|
@@ -39,14 +41,14 @@ loop do
|
|
39
41
|
# CPU Usage (automatically delays for 1 second)
|
40
42
|
mpstat_result = `mpstat -P ALL 1 1 | awk '/^Average:/ && ++count == 2 {print 100 - $12"%"}'`
|
41
43
|
cpu_percent = mpstat_result.chop.to_f
|
42
|
-
|
44
|
+
|
43
45
|
canvas.clear
|
44
46
|
canvas.text_cursor = [0, 16]
|
45
47
|
canvas.print "CPU Usage: #{('%.3f' % cpu_percent).rjust(8, ' ')}%"
|
46
|
-
|
48
|
+
|
47
49
|
canvas.text_cursor = [0, 24]
|
48
50
|
(cpu_percent / 4).ceil.times { canvas.raw_char(BAR_ELEMENT) }
|
49
|
-
|
51
|
+
|
50
52
|
# RAM Usage
|
51
53
|
ram_string = `free -h | awk 'NR==2 {print $3}'`
|
52
54
|
ram_usage = ram_string.to_i
|
@@ -54,14 +56,14 @@ loop do
|
|
54
56
|
canvas.text_cursor = [0, 40]
|
55
57
|
ram_string = "#{ram_usage}/#{total_ram}M"
|
56
58
|
canvas.print "RAM Usage:#{ram_string.rjust(11, ' ')}"
|
57
|
-
|
59
|
+
|
58
60
|
canvas.text_cursor = [0, 48]
|
59
61
|
(ram_usage / ram_bar_factor).ceil.times { canvas.raw_char(BAR_ELEMENT) }
|
60
|
-
|
62
|
+
|
61
63
|
# Date and time just before write.
|
62
64
|
canvas.text_cursor = [0,0]
|
63
65
|
canvas.print(Time.now.strftime('%a %b %d %-l:%M %p'))
|
64
|
-
|
66
|
+
|
65
67
|
# Only refresh the area in use.
|
66
68
|
oled.draw(0, 127, 0, 56)
|
67
69
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
#
|
2
|
+
# Play a melody on a piezoelectric buzzer using (hardware) PWM.
|
3
|
+
# Will use software PWM if given a regular GPIO, but not as good as good.
|
4
|
+
#
|
5
|
+
require 'denko/piboard'
|
6
|
+
|
7
|
+
PIN = 227
|
8
|
+
|
9
|
+
board = Denko::PiBoard.new
|
10
|
+
buzzer = Denko::PulseIO::Buzzer.new(board: board, pin: PIN)
|
11
|
+
|
12
|
+
C4 = 262
|
13
|
+
D4 = 294
|
14
|
+
E4 = 330
|
15
|
+
|
16
|
+
notes = [
|
17
|
+
[E4, 1], [D4, 1], [C4, 1], [D4, 1], [E4, 1], [E4, 1], [E4, 2],
|
18
|
+
[D4, 1], [D4, 1], [D4, 2], [E4, 1], [E4, 1], [E4, 2],
|
19
|
+
[E4, 1], [D4, 1], [C4, 1], [D4, 1], [E4, 1], [E4, 1], [E4, 1], [E4, 1],
|
20
|
+
[D4, 1], [D4, 1], [E4, 1], [D4, 1], [C4, 4],
|
21
|
+
]
|
22
|
+
|
23
|
+
bpm = 240
|
24
|
+
beat_time = 60.to_f / bpm
|
25
|
+
|
26
|
+
notes.each do |note|
|
27
|
+
buzzer.tone(note[0], (note[1] * beat_time))
|
28
|
+
end
|
29
|
+
|
30
|
+
# Only works for PiBoard.
|
31
|
+
sleep 0.100 while (board.tone_busy(PIN) == 1)
|
32
|
+
|
33
|
+
buzzer.stop
|
34
|
+
board.finish_write
|