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.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +4 -0
  3. data/LICENSE +1 -1
  4. data/README.md +181 -132
  5. data/Rakefile +0 -5
  6. data/board_maps/README.md +59 -0
  7. data/board_maps/le_potato.yml +89 -0
  8. data/board_maps/orange_pi_zero_2w.yml +85 -0
  9. data/board_maps/radxa_zero3.yml +88 -0
  10. data/board_maps/raspberry_pi.yml +95 -0
  11. data/board_maps/raspberry_pi5.yml +95 -0
  12. data/denko_piboard.gemspec +6 -7
  13. data/examples/digital_io/bench_out.rb +22 -0
  14. data/examples/digital_io/rotary_encoder.rb +31 -0
  15. data/examples/display/ssd1306.rb +53 -0
  16. data/examples/i2c/bitbang_aht10.rb +18 -0
  17. data/examples/i2c/bitbang_search.rb +24 -0
  18. data/examples/i2c/bitbang_ssd1306_bench.rb +29 -0
  19. data/examples/i2c/search.rb +24 -0
  20. data/examples/led/blink.rb +10 -0
  21. data/examples/led/fade.rb +22 -0
  22. data/examples/led/ws2812_bounce.rb +36 -0
  23. data/examples/motor/servo.rb +16 -0
  24. data/examples/pi_system_monitor.rb +10 -8
  25. data/examples/pulse_io/buzzer.rb +34 -0
  26. data/examples/pulse_io/infrared.rb +25 -0
  27. data/examples/sensor/aht10.rb +17 -0
  28. data/examples/sensor/dht.rb +24 -0
  29. data/examples/sensor/ds18b20.rb +59 -0
  30. data/examples/sensor/hcsr04.rb +16 -0
  31. data/examples/sensor/neat_tph_readings.rb +32 -0
  32. data/examples/spi/bb_loopback.rb +31 -0
  33. data/examples/spi/loopback.rb +37 -0
  34. data/examples/spi/output_register.rb +38 -0
  35. data/lib/denko/piboard.rb +10 -2
  36. data/lib/denko/piboard_base.rb +21 -63
  37. data/lib/denko/piboard_core.rb +150 -130
  38. data/lib/denko/piboard_core_optimize_lookup.rb +31 -0
  39. data/lib/denko/piboard_hardware_pwm.rb +32 -0
  40. data/lib/denko/piboard_i2c.rb +59 -82
  41. data/lib/denko/piboard_i2c_bb.rb +48 -0
  42. data/lib/denko/piboard_infrared.rb +7 -44
  43. data/lib/denko/piboard_led_array.rb +9 -0
  44. data/lib/denko/piboard_map.rb +125 -38
  45. data/lib/denko/piboard_one_wire.rb +42 -0
  46. data/lib/denko/piboard_pulse.rb +11 -68
  47. data/lib/denko/piboard_spi.rb +47 -73
  48. data/lib/denko/piboard_spi_bb.rb +41 -0
  49. data/lib/denko/piboard_tone.rb +15 -26
  50. data/lib/denko/piboard_version.rb +1 -1
  51. data/scripts/99-denko.rules +9 -0
  52. data/scripts/set_permissions.rb +131 -0
  53. metadata +48 -21
  54. data/ext/gpiod/extconf.rb +0 -9
  55. data/ext/gpiod/gpiod.c +0 -179
  56. data/lib/denko/piboard_servo.rb +0 -18
  57. 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
@@ -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 = "Use Raspberry Pi built-in GPIO as a Board class with the denko gem"
8
- s.description = "Denko::PiBoard is a drop-in replacement for Denko::Board. Use denko features and component classes to be used directly on a Raspberry Pi."
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.add_dependency 'pigpio', '~> 0.1.12'
20
- s.add_dependency 'denko', '~> 0.13'
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,10 @@
1
+ require 'denko/piboard'
2
+
3
+ PIN = 272
4
+
5
+ board = Denko::PiBoard.new
6
+ led = Denko::LED.new(board: board, pin: PIN)
7
+
8
+ led.blink 0.5
9
+
10
+ sleep
@@ -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
- i2c = Denko::I2C::Bus.new(board: board, pin: :SDA)
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