denko 0.14.0 → 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/.github/workflows/build_atmega_avr.yml +2 -1
- data/.github/workflows/build_atmega_megaavr.yml +2 -1
- data/.github/workflows/build_atsam3x.yml +1 -0
- data/.github/workflows/build_atsamd21.yml +2 -1
- data/.github/workflows/build_esp32.yml +4 -2
- data/.github/workflows/build_esp32c3.yml +4 -3
- data/.github/workflows/build_esp32c6.yml +4 -2
- data/.github/workflows/build_esp32h2.yml +4 -2
- data/.github/workflows/build_esp32s2.yml +4 -2
- data/.github/workflows/build_esp32s3.yml +4 -2
- data/.github/workflows/build_esp8266.yml +2 -1
- data/.github/workflows/build_ra4m1.yml +1 -0
- data/.github/workflows/build_rp2040.yml +4 -3
- data/.github/workflows/ruby.yml +1 -1
- data/CHANGELOG.md +203 -0
- data/DEPS_CLI.md +16 -16
- data/DEPS_IDE.md +31 -30
- data/MICROCONTROLLERS.md +103 -0
- data/PERIPHERALS.md +178 -0
- data/README.md +28 -21
- data/denko.gemspec +6 -1
- data/lib/denko/analog_io/ads1118.rb +5 -5
- data/lib/denko/analog_io/ads111x.rb +23 -19
- data/lib/denko/analog_io/joystick.rb +87 -0
- data/lib/denko/analog_io/potentiometer.rb +1 -5
- data/lib/denko/analog_io.rb +22 -8
- data/lib/denko/behaviors/bus_controller.rb +2 -1
- data/lib/denko/behaviors/bus_peripheral.rb +1 -1
- data/lib/denko/behaviors/callbacks.rb +18 -16
- data/lib/denko/behaviors/component.rb +0 -4
- data/lib/denko/behaviors/lifecycle.rb +1 -1
- data/lib/denko/behaviors/listener.rb +9 -3
- data/lib/denko/behaviors/multi_pin.rb +4 -6
- data/lib/denko/behaviors/poller.rb +11 -2
- data/lib/denko/behaviors/reader.rb +109 -21
- data/lib/denko/behaviors/single_pin.rb +2 -4
- data/lib/denko/behaviors/state.rb +18 -13
- data/lib/denko/behaviors/threaded.rb +19 -8
- data/lib/denko/behaviors.rb +36 -23
- data/lib/denko/board/eeprom.rb +1 -1
- data/lib/denko/board/i2c.rb +1 -1
- data/lib/denko/board/i2c_bit_bang.rb +9 -5
- data/lib/denko/board/map.rb +6 -2
- data/lib/denko/board/one_wire.rb +3 -3
- data/lib/denko/board/spi.rb +30 -30
- data/lib/denko/board/spi_bit_bang.rb +8 -11
- data/lib/denko/board.rb +6 -3
- data/lib/denko/connection/flow_control.rb +1 -1
- data/lib/denko/connection/serial.rb +5 -5
- data/lib/denko/digital_io/output.rb +12 -4
- data/lib/denko/digital_io/pcf8574.rb +114 -0
- data/lib/denko/digital_io/rotary_encoder.rb +10 -6
- data/lib/denko/digital_io.rb +24 -6
- data/lib/denko/display/canvas.rb +350 -157
- data/lib/denko/display/font/bmp_5x7.rb +142 -0
- data/lib/denko/display/font/bmp_6x8.rb +142 -0
- data/lib/denko/display/font/bmp_8x16.rb +141 -0
- data/lib/denko/display/font.rb +22 -0
- data/lib/denko/display/hd44780.rb +24 -20
- data/lib/denko/display/il0373.rb +186 -0
- data/lib/denko/display/mono_oled.rb +193 -0
- data/lib/denko/display/pcd8544.rb +154 -0
- data/lib/denko/display/pixel_common.rb +83 -0
- data/lib/denko/display/sh1106.rb +17 -21
- data/lib/denko/display/sh1107.rb +10 -0
- data/lib/denko/display/spi_common.rb +35 -0
- data/lib/denko/display/spi_epaper_common.rb +30 -0
- data/lib/denko/display/ssd1306.rb +6 -228
- data/lib/denko/display/ssd1680.rb +14 -0
- data/lib/denko/display/ssd1681.rb +8 -0
- data/lib/denko/display/ssd168x.rb +227 -0
- data/lib/denko/display/st7302.rb +207 -0
- data/lib/denko/display/st7565.rb +166 -0
- data/lib/denko/display.rb +40 -4
- data/lib/denko/eeprom/at24c.rb +67 -0
- data/lib/denko/eeprom/board.rb +69 -0
- data/lib/denko/eeprom.rb +15 -1
- data/lib/denko/helpers/engine_check.rb +13 -0
- data/lib/denko/{mutex_stub.rb → helpers/mutex_stub.rb} +6 -0
- data/lib/denko/helpers.rb +6 -0
- data/lib/denko/i2c/bit_bang.rb +1 -0
- data/lib/denko/i2c/bus_common.rb +9 -4
- data/lib/denko/i2c/peripheral.rb +5 -1
- data/lib/denko/i2c.rb +17 -4
- data/lib/denko/led/apa102.rb +1 -3
- data/lib/denko/led/base.rb +5 -0
- data/lib/denko/led/rgb.rb +16 -10
- data/lib/denko/led/seven_segment.rb +1 -1
- data/lib/denko/led.rb +17 -8
- data/lib/denko/motor/{stepper.rb → a3967.rb} +1 -1
- data/lib/denko/motor/servo.rb +16 -6
- data/lib/denko/motor.rb +16 -3
- data/lib/denko/one_wire/bus.rb +20 -16
- data/lib/denko/one_wire/bus_enumerator.rb +25 -14
- data/lib/denko/one_wire/helper.rb +4 -2
- data/lib/denko/one_wire.rb +18 -5
- data/lib/denko/pulse_io/buzzer.rb +2 -6
- data/lib/denko/pulse_io/ir_output.rb +1 -5
- data/lib/denko/pulse_io/pwm_output.rb +56 -31
- data/lib/denko/pulse_io.rb +17 -3
- data/lib/denko/rtc/ds3231.rb +4 -3
- data/lib/denko/rtc.rb +14 -1
- data/lib/denko/sensor/aht.rb +16 -20
- data/lib/denko/sensor/bme280.rb +23 -36
- data/lib/denko/sensor/bmp180.rb +8 -13
- data/lib/denko/sensor/dht.rb +17 -7
- data/lib/denko/sensor/ds18b20.rb +5 -4
- data/lib/denko/sensor/hdc1080.rb +174 -0
- data/lib/denko/sensor/htu21d.rb +17 -6
- data/lib/denko/sensor/htu31d.rb +6 -5
- data/lib/denko/sensor/jsnsr04t.rb +49 -0
- data/lib/denko/sensor/qmp6988.rb +14 -30
- data/lib/denko/sensor/rcwl9620.rb +1 -0
- data/lib/denko/sensor/sht3x.rb +6 -5
- data/lib/denko/sensor/sht4x.rb +125 -0
- data/lib/denko/sensor/vl53l0x.rb +58 -0
- data/lib/denko/sensor.rb +33 -15
- data/lib/denko/spi/base_register.rb +11 -7
- data/lib/denko/spi/bus_common.rb +12 -15
- data/lib/denko/spi/input_register.rb +6 -6
- data/lib/denko/spi/output_register.rb +13 -4
- data/lib/denko/spi/peripheral.rb +82 -84
- data/lib/denko/spi.rb +20 -10
- data/lib/denko/uart/bit_bang.rb +2 -27
- data/lib/denko/uart/common.rb +33 -0
- data/lib/denko/uart/hardware.rb +1 -26
- data/lib/denko/uart.rb +16 -2
- data/lib/denko/version.rb +1 -1
- data/lib/denko.rb +22 -25
- data/lib/denko_cli/targets.rb +7 -7
- data/lib/denko_cli/targets.txt +19 -20
- data/src/lib/Denko.cpp +26 -13
- data/src/lib/Denko.h +4 -4
- data/src/lib/DenkoDefines.h +7 -26
- data/src/lib/DenkoLEDArray.cpp +1 -8
- data/src/lib/DenkoSPI.cpp +31 -29
- data/src/lib/DenkoSPIBB.cpp +12 -14
- data/test/analog_io/input_test.rb +1 -1
- data/test/analog_io/potentiometer_test.rb +2 -2
- data/test/behaviors/bus_peripheral_test.rb +4 -4
- data/test/behaviors/callbacks_test.rb +20 -10
- data/test/behaviors/component_test.rb +18 -8
- data/test/board/board_test.rb +9 -9
- data/test/board/one_wire_test.rb +25 -14
- data/test/board/spi_test.rb +31 -15
- data/test/digital_io/input_test.rb +2 -2
- data/test/display/canvas_test.rb +306 -0
- data/test/display/hd44780_test.rb +34 -7
- data/test/eeprom/board_test.rb +45 -0
- data/test/helpers/mruby_minitest.rb +95 -0
- data/test/helpers/mruby_runner.rb +13 -0
- data/test/i2c/bus_test.rb +93 -30
- data/test/i2c/peripheral_test.rb +2 -2
- data/test/led/apa102_test.rb +24 -0
- data/test/led/rgb_test.rb +4 -4
- data/test/motor/{stepper_test.rb → a3967_test.rb} +2 -2
- data/test/one_wire/bus_enumerator_test.rb +1 -1
- data/test/one_wire/bus_test.rb +42 -35
- data/test/one_wire/peripheral_test.rb +5 -17
- data/test/pulse_io/ir_output_test.rb +5 -0
- data/test/pulse_io/pwm_output_test.rb +10 -10
- data/test/rtc/ds3231_test.rb +3 -2
- data/test/sensor/dht_test.rb +11 -11
- data/test/spi/bitbang_test.rb +27 -0
- data/test/spi/bus_test.rb +19 -29
- data/test/spi/input_register_test.rb +2 -2
- data/test/spi/{peripheral_multi_pin_test.rb → peripheral_test.rb} +25 -5
- data/test/test_helper.rb +44 -124
- data/vendor/board-maps/BoardMap.h +264 -0
- data/vendor/board-maps/yaml/ALFREDO_NOU3.yml +2 -0
- data/vendor/board-maps/yaml/ATD143_S3.yml +1 -0
- data/vendor/board-maps/yaml/BHARATPI_A7672S_4G.yml +14 -0
- data/vendor/board-maps/yaml/BHARATPI_LORA.yml +14 -0
- data/vendor/board-maps/yaml/BHARATPI_NODE_WIFI.yml +14 -0
- data/vendor/board-maps/yaml/BPI_LEAF_S3.yml +0 -1
- data/vendor/board-maps/yaml/CEZERIO_DEV_ESP32C6.yml +14 -0
- data/vendor/board-maps/yaml/CEZERIO_MINI_DEV_ESP32C6.yml +12 -0
- data/vendor/board-maps/yaml/CIRCUITART_ZERO_S3.yml +71 -0
- data/vendor/board-maps/yaml/CODECELLC3.yml +13 -0
- data/vendor/board-maps/yaml/CYOBOT_V2_ESP32S3.yml +7 -0
- data/vendor/board-maps/yaml/EDGES3D.yml +25 -0
- data/vendor/board-maps/yaml/ESP32C6_DEV.yml +3 -4
- data/vendor/board-maps/yaml/ESP32C6_THING_PLUS.yml +0 -1
- data/vendor/board-maps/yaml/ESP32H2_DEV.yml +0 -1
- data/vendor/board-maps/yaml/ESP32H2_DEVKIT_LIPO.yml +0 -1
- data/vendor/board-maps/yaml/ESP32P4_DEV.yml +35 -0
- data/vendor/board-maps/yaml/ESP32S2_DEV.yml +0 -1
- data/vendor/board-maps/yaml/ESP32S2_DEVKIT_LIPO.yml +0 -1
- data/vendor/board-maps/yaml/ESP32S2_DEVKIT_LIPO_USB.yml +0 -1
- data/vendor/board-maps/yaml/ESP32_2432S028R.yml +14 -0
- data/vendor/board-maps/yaml/FEATHERS3.yml +1 -1
- data/vendor/board-maps/yaml/FRI3D_2024_ESP32S3.yml +43 -0
- data/vendor/board-maps/yaml/GEEKBLE_ESP32C3.yml +0 -1
- data/vendor/board-maps/yaml/GEEKBLE_NANO_ESP32S3.yml +25 -0
- data/vendor/board-maps/yaml/HELTEC_VISION_MASTER_E290.yml +41 -0
- data/vendor/board-maps/yaml/HELTEC_VISION_MASTER_E_213.yml +41 -0
- data/vendor/board-maps/yaml/HELTEC_VISION_MASTER_T190.yml +41 -0
- data/vendor/board-maps/yaml/HUIDU_HD_WF2.yml +5 -0
- data/vendor/board-maps/yaml/HUIDU_HD_WF4.yml +1 -0
- data/vendor/board-maps/yaml/LILYGO_LORA_CC1101.yml +6 -0
- data/vendor/board-maps/yaml/LILYGO_LORA_LR1121.yml +6 -0
- data/vendor/board-maps/yaml/LILYGO_LORA_SI4432.yml +6 -0
- data/vendor/board-maps/yaml/LILYGO_LORA_SX1262.yml +6 -0
- data/vendor/board-maps/yaml/LILYGO_LORA_SX1280.yml +6 -0
- data/vendor/board-maps/yaml/LOLIN_C3_MINI.yml +0 -1
- data/vendor/board-maps/yaml/LOLIN_C3_PICO.yml +1 -2
- data/vendor/board-maps/yaml/LoPy.yml +0 -1
- data/vendor/board-maps/yaml/LoPy4.yml +0 -1
- data/vendor/board-maps/yaml/M5STACK_DINMETER.yml +8 -0
- data/vendor/board-maps/yaml/M5STACK_FIRE.yml +1 -1
- data/vendor/board-maps/yaml/OMGS3.yml +25 -0
- data/vendor/board-maps/yaml/PCBCUPID_GLYPHC3.yml +23 -0
- data/vendor/board-maps/yaml/PCBCUPID_GLYPHC6.yml +32 -0
- data/vendor/board-maps/yaml/PCBCUPID_GLYPHH2.yml +24 -0
- data/vendor/board-maps/yaml/PYCOM_GPY.yml +0 -1
- data/vendor/board-maps/yaml/SENSEBOX_MCU_ESP32S2.yml +1 -1
- data/vendor/board-maps/yaml/SPARKFUN_ESP32S3_THING_PLUS.yml +13 -0
- data/vendor/board-maps/yaml/SPARKLEMOTIONMINI_ESP32.yml +12 -0
- data/vendor/board-maps/yaml/SPARKLEMOTIONSTICK_ESP32.yml +11 -0
- data/vendor/board-maps/yaml/SPARKLEMOTION_ESP32.yml +12 -0
- data/vendor/board-maps/yaml/SQUIXL.yml +7 -0
- data/vendor/board-maps/yaml/THINGPULSE_EPULSE_FEATHER_C6.yml +0 -1
- data/vendor/board-maps/yaml/T_LORA_PAGER.yml +6 -0
- data/vendor/board-maps/yaml/T_WATCH_S3.yml +7 -0
- data/vendor/board-maps/yaml/T_WATCH_S3_ULTRA.yml +6 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_LCD_146.yml +41 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_LCD_147.yml +41 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_LCD_169.yml +38 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_LCD_185.yml +41 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_RELAY_6CH.yml +41 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_AMOLED_143.yml +7 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_AMOLED_164.yml +7 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_AMOLED_18.yml +38 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_AMOLED_191.yml +7 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_AMOLED_241.yml +7 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_146.yml +41 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_169.yml +38 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_185.yml +41 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_185_BOX.yml +41 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_21.yml +41 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_28.yml +41 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_4.yml +36 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_43.yml +38 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_43B.yml +38 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_5.yml +38 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_5B.yml +38 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_TOUCH_LCD_7.yml +38 -0
- data/vendor/board-maps/yaml/WAVESHARE_ESP32_S3_ZERO.yml +36 -0
- data/vendor/board-maps/yaml/WIPY3.yml +0 -1
- data/vendor/board-maps/yaml/WS_ESP32_S3_MATRIX.yml +38 -0
- data/vendor/board-maps/yaml/XIAO_ESP32S3_PLUS.yml +46 -0
- data/vendor/board-maps/yaml/YB_ESP32S3_AMP_V2.yml +28 -0
- data/vendor/board-maps/yaml/YB_ESP32S3_AMP_V3.yml +28 -0
- data/vendor/board-maps/yaml/YB_ESP32S3_ETH.yml +40 -0
- data/vendor/board-maps/yaml/mercury.yml +20 -0
- metadata +116 -101
- data/.vscode/settings.json +0 -5
- data/.vscode/tasks.json +0 -20
- data/HARDWARE.md +0 -263
- data/benchmarks/analog_listen.rb +0 -49
- data/benchmarks/digital_write.rb +0 -28
- data/benchmarks/i2c_ssd1306_refresh.rb +0 -91
- data/examples/advanced/m5_env3.rb +0 -46
- data/examples/advanced/rotary_encoder_mac_volume.rb +0 -53
- data/examples/advanced/ssd1306_time_temp_rh.rb +0 -43
- data/examples/analog_io/ads1100.rb +0 -48
- data/examples/analog_io/ads1115.rb +0 -57
- data/examples/analog_io/ads1118.rb +0 -65
- data/examples/analog_io/dac_loopback.rb +0 -34
- data/examples/analog_io/input.rb +0 -56
- data/examples/analog_io/input_smoothing.rb +0 -27
- data/examples/analog_io/potentiometer.rb +0 -31
- data/examples/connection/binary_echo.rb +0 -34
- data/examples/connection/tcp.rb +0 -19
- data/examples/digital_io/button.rb +0 -17
- data/examples/digital_io/relay.rb +0 -17
- data/examples/digital_io/rotary_encoder.rb +0 -36
- data/examples/display/hd44780.png +0 -0
- data/examples/display/hd44780.rb +0 -47
- data/examples/display/ssd1306.rb +0 -43
- data/examples/display/ssd1306_s2_pico.rb +0 -29
- data/examples/eeprom/built_in.rb +0 -32
- data/examples/i2c/search.rb +0 -39
- data/examples/led/apa102_bounce.rb +0 -32
- data/examples/led/apa102_fade.rb +0 -44
- data/examples/led/builtin_blink.rb +0 -14
- data/examples/led/builtin_fade.rb +0 -19
- data/examples/led/rgb_led.rb +0 -31
- data/examples/led/seven_segment_char_echo.rb +0 -17
- data/examples/led/ws2812_bounce.rb +0 -30
- data/examples/led/ws2812_builtin_blink.rb +0 -22
- data/examples/led/ws2812_fade.rb +0 -43
- data/examples/motor/l298.rb +0 -45
- data/examples/motor/servo.rb +0 -17
- data/examples/motor/stepper.png +0 -0
- data/examples/motor/stepper.rb +0 -43
- data/examples/one_wire/search.rb +0 -32
- data/examples/pulse_io/buzzer.rb +0 -35
- data/examples/pulse_io/ir_output.rb +0 -51
- data/examples/pulse_io/pwm_output.rb +0 -30
- data/examples/rtc/ds3231.rb +0 -31
- data/examples/sensor/aht10.rb +0 -17
- data/examples/sensor/aht20.rb +0 -17
- data/examples/sensor/bme280.rb +0 -38
- data/examples/sensor/bmp180.rb +0 -26
- data/examples/sensor/dht.rb +0 -29
- data/examples/sensor/ds18b20.rb +0 -57
- data/examples/sensor/generic_pir.rb +0 -27
- data/examples/sensor/hcsr04.rb +0 -17
- data/examples/sensor/htu21d.rb +0 -43
- data/examples/sensor/htu31d.rb +0 -33
- data/examples/sensor/neat_tph_readings.rb +0 -32
- data/examples/sensor/qmp6988.rb +0 -51
- data/examples/sensor/rcwl9620.rb +0 -15
- data/examples/sensor/sht3x.rb +0 -32
- data/examples/spi/bitbang_loopback.rb +0 -46
- data/examples/spi/input_register.rb +0 -40
- data/examples/spi/output_register.rb +0 -41
- data/examples/spi/ssd_through_registers.rb +0 -28
- data/examples/spi/two_registers.rb +0 -40
- data/examples/uart/bit_bang_demo.rb +0 -25
- data/examples/uart/board_passthrough.rb +0 -40
- data/examples/uart/hardware_loopback.rb +0 -16
- data/lib/denko/eeprom/built_in.rb +0 -72
- data/lib/denko/fonts.rb +0 -106
- data/test/eeprom/built_in_test.rb +0 -61
- data/test/spi/peripheral_single_pin_test.rb +0 -48
- data/tutorial/01-led/led.fzz +0 -0
- data/tutorial/01-led/led.pdf +0 -0
- data/tutorial/01-led/led.rb +0 -73
- data/tutorial/02-button/button.fzz +0 -0
- data/tutorial/02-button/button.pdf +0 -0
- data/tutorial/02-button/button.rb +0 -65
- data/tutorial/03-potentiometer/potentiometer.fzz +0 -0
- data/tutorial/03-potentiometer/potentiometer.pdf +0 -0
- data/tutorial/03-potentiometer/potentiometer.rb +0 -66
- data/tutorial/04-pwm_led/pwm_led.fzz +0 -0
- data/tutorial/04-pwm_led/pwm_led.pdf +0 -0
- data/tutorial/04-pwm_led/pwm_led.rb +0 -64
- data/tutorial/05-rgb_led/rgb_led.fzz +0 -0
- data/tutorial/05-rgb_led/rgb_led.pdf +0 -0
- data/tutorial/05-rgb_led/rgb_led.rb +0 -58
- data/tutorial/05-rgb_led/rgb_mapping.rb +0 -76
@@ -0,0 +1,186 @@
|
|
1
|
+
module Denko
|
2
|
+
module Display
|
3
|
+
class IL0373
|
4
|
+
include SPIEPaperCommon
|
5
|
+
include Behaviors::Lifecycle
|
6
|
+
|
7
|
+
COLUMNS = 212
|
8
|
+
ROWS = 104
|
9
|
+
|
10
|
+
# Subset of used commands from datasheet:
|
11
|
+
PANEL_SETTING = 0x00
|
12
|
+
POWER_SETTING = 0x01
|
13
|
+
POWER_OFF = 0x02
|
14
|
+
POWER_OFF_SEQUENCE = 0x03
|
15
|
+
POWER_ON = 0x04
|
16
|
+
POWER_ON_MEASURE = 0x05
|
17
|
+
BOOSTER_SOFT_START = 0x06
|
18
|
+
DEEP_SLEEP = 0x07
|
19
|
+
DATA_START_1 = 0x10
|
20
|
+
DATA_STOP = 0x11
|
21
|
+
DISPLAY_REFRESH = 0x12
|
22
|
+
DATA_START_2 = 0x13
|
23
|
+
VCOM_DATA_SETTING = 0x50
|
24
|
+
RESOLUTION_SETTING = 0x61
|
25
|
+
PARTIAL_WINDOW = 0x90
|
26
|
+
PARTIAL_IN = 0x91
|
27
|
+
PARTIAL_OUT = 0x92
|
28
|
+
|
29
|
+
def set_power_setting
|
30
|
+
# Defaults from datasheet.
|
31
|
+
command [POWER_SETTING]
|
32
|
+
data [0x03, 0x00, 0x26, 0x26, 0x03]
|
33
|
+
end
|
34
|
+
|
35
|
+
def set_panel_setting
|
36
|
+
# NOT DEFAULTS
|
37
|
+
# From datasheet:
|
38
|
+
# Bits 7..6: Enable all source and gate channels
|
39
|
+
# Bit 5: 0 = LUT from OTP
|
40
|
+
# Bit 4: 0 = B/W/R mode, 1 = B/W mode
|
41
|
+
# Bit 3: 0 = Gate scan decrements (1 increments)
|
42
|
+
# Bit 2: 0 = Source scan decrements (1 increments)
|
43
|
+
# Bit 1: 1 = Enable booster
|
44
|
+
# Bit 0: 1 = Soft reset
|
45
|
+
value = 0b0000_0011
|
46
|
+
|
47
|
+
# Handle colors
|
48
|
+
value |= (1 << 4) if colors == 2
|
49
|
+
|
50
|
+
# Handle screen size
|
51
|
+
source_gate_bits = 0b11
|
52
|
+
source_gate_bits = 0b10 if (rows <= 128)
|
53
|
+
source_gate_bits = 0b01 if (rows <= 96) && (columns <= 252)
|
54
|
+
source_gate_bits = 0b00 if (rows <= 96) && (columns <= 230)
|
55
|
+
value |= source_gate_bits
|
56
|
+
|
57
|
+
# Handle hardware reflection/rotation
|
58
|
+
value |= (1 << 2) if @reflect_y
|
59
|
+
value |= (1 << 3) if @reflect_x
|
60
|
+
|
61
|
+
command [PANEL_SETTING]
|
62
|
+
data [value]
|
63
|
+
end
|
64
|
+
|
65
|
+
def reflect_x
|
66
|
+
@reflect_x = !@reflect_x
|
67
|
+
end
|
68
|
+
|
69
|
+
def reflect_y
|
70
|
+
@reflect_y = !@reflect_y
|
71
|
+
end
|
72
|
+
|
73
|
+
def rotate
|
74
|
+
@reflect_x = !@reflect_x
|
75
|
+
@reflect_y = !@reflect_y
|
76
|
+
end
|
77
|
+
|
78
|
+
def set_vcom_data_setting
|
79
|
+
# Default value from data sheet.
|
80
|
+
value = 0b0000_0111
|
81
|
+
|
82
|
+
# Datsheet may be wrong here. Bit 5 set seems to always invert DATA2, so Bit 4 does DATA1?
|
83
|
+
# In B/W mode: set bit 5 to avoid black channel inversion relative to Canvas.
|
84
|
+
# In B/W/R mode: set bit 4 to avoid black channel inversion relative to Canvas.
|
85
|
+
if (colors == 2)
|
86
|
+
value |= (1 << 4) unless @invert_black
|
87
|
+
else
|
88
|
+
value |= (1 << 5) unless @invert_black
|
89
|
+
end
|
90
|
+
|
91
|
+
command [VCOM_DATA_SETTING]
|
92
|
+
data [value]
|
93
|
+
end
|
94
|
+
|
95
|
+
def invert_black
|
96
|
+
@invert_black = !@invert_black
|
97
|
+
end
|
98
|
+
|
99
|
+
def set_resolution
|
100
|
+
command [RESOLUTION_SETTING]
|
101
|
+
data [
|
102
|
+
p_max+1 << 3,
|
103
|
+
(columns >> 8) & 0b1,
|
104
|
+
columns & 0xFF
|
105
|
+
]
|
106
|
+
end
|
107
|
+
|
108
|
+
def booster_soft_start
|
109
|
+
# Defaults from datasheet.
|
110
|
+
command [BOOSTER_SOFT_START]
|
111
|
+
data [0x17, 0x17, 0x17]
|
112
|
+
end
|
113
|
+
|
114
|
+
def power_on
|
115
|
+
command [POWER_ON]
|
116
|
+
busy_wait
|
117
|
+
end
|
118
|
+
|
119
|
+
def wake
|
120
|
+
hw_reset
|
121
|
+
set_power_setting
|
122
|
+
set_panel_setting
|
123
|
+
set_vcom_data_setting
|
124
|
+
set_resolution
|
125
|
+
booster_soft_start
|
126
|
+
power_on
|
127
|
+
end
|
128
|
+
|
129
|
+
def deep_sleep
|
130
|
+
# Default from datasheet.
|
131
|
+
command [DEEP_SLEEP]
|
132
|
+
data [0xA5]
|
133
|
+
end
|
134
|
+
|
135
|
+
# Treat what the datasheet calls x as vertical (y, page), and vertical as horizontal (x).
|
136
|
+
def set_window(x_start=x_min, x_finish=x_max, p_start=p_min, p_finish=p_max)
|
137
|
+
command [PARTIAL_WINDOW]
|
138
|
+
data [
|
139
|
+
p_start << 3,
|
140
|
+
p_finish << 3,
|
141
|
+
(x_start >> 8) & 0b1,
|
142
|
+
x_start & 0xFF,
|
143
|
+
(x_finish >> 8) & 0b1,
|
144
|
+
x_finish & 0xFF,
|
145
|
+
0b0
|
146
|
+
]
|
147
|
+
command [PARTIAL_IN]
|
148
|
+
end
|
149
|
+
|
150
|
+
def draw(*args, **kwargs)
|
151
|
+
wake
|
152
|
+
super(*args, **kwargs)
|
153
|
+
end
|
154
|
+
|
155
|
+
def draw_partial(buffer, x_start, x_finish, p_start, p_finish, color=1)
|
156
|
+
set_window(x_start, x_finish, p_start, p_finish)
|
157
|
+
|
158
|
+
if (colors == 2)
|
159
|
+
# In B/W/Red mode, red goes in DATA2, black in DATA1
|
160
|
+
(color == 2) ? command[DATA_START_2] : command[DATA_START_1]
|
161
|
+
else
|
162
|
+
# In B/W mode, always write to DATA2
|
163
|
+
command [DATA_START_2]
|
164
|
+
end
|
165
|
+
|
166
|
+
# Can't control address increment to go horizontally, always vertical.
|
167
|
+
# So get partial from the full buffer and reorder the bytes.
|
168
|
+
transformed_buffer = []
|
169
|
+
(x_start..x_finish).each do |x|
|
170
|
+
(p_start..p_finish).to_a.reverse.each do |page|
|
171
|
+
index = (page * columns) + x
|
172
|
+
transformed_buffer << buffer[index]
|
173
|
+
end
|
174
|
+
end
|
175
|
+
transformed_buffer.each_slice(transfer_limit) { |slice| data(slice) }
|
176
|
+
|
177
|
+
command [DATA_STOP]
|
178
|
+
end
|
179
|
+
|
180
|
+
def refresh
|
181
|
+
command [DISPLAY_REFRESH]
|
182
|
+
busy_wait
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
@@ -0,0 +1,193 @@
|
|
1
|
+
module Denko
|
2
|
+
module Display
|
3
|
+
module MonoOLED
|
4
|
+
include Behaviors::BusPeripheral
|
5
|
+
include Behaviors::Lifecycle
|
6
|
+
|
7
|
+
# I2C Defaults
|
8
|
+
I2C_ADDRESS = 0x3C
|
9
|
+
I2C_FREQUENCY = 400_000
|
10
|
+
|
11
|
+
# Fundamental Commands
|
12
|
+
# Single byte (no need to OR with anything)
|
13
|
+
PIXELS_FROM_RAM = 0xA4
|
14
|
+
PIXELS_ALL_ON = 0xA5
|
15
|
+
INVERT_OFF = 0xA6
|
16
|
+
INVERT_ON = 0xA7
|
17
|
+
DISPLAY_OFF = 0xAE
|
18
|
+
DISPLAY_ON = 0xAF
|
19
|
+
|
20
|
+
# Double byte (following byte sets value)
|
21
|
+
CONTRAST = 0x81
|
22
|
+
# Values: 0x00 to 0xFF. Default is 0x7F
|
23
|
+
|
24
|
+
# Scrolling commands ignored.
|
25
|
+
|
26
|
+
# Address Setting Commands
|
27
|
+
# Single byte. OR with value. These are for page addressing mode only.
|
28
|
+
COLUMN_START_LOWER = 0x00 # lower 4 bytes of column
|
29
|
+
COLUMN_START_UPPER = 0x10 # upper 4 bytes of column
|
30
|
+
PAGE_START = 0xB0 # page 0-7
|
31
|
+
|
32
|
+
# Double byte. Following byte sets value.
|
33
|
+
ADDRESSING_MODE = 0x20
|
34
|
+
# Values:
|
35
|
+
# 0x00 = horizontal (Pages auto-increment. Used for SSD1306)
|
36
|
+
# 0x01 = vertical
|
37
|
+
# 0x02 = page (Default. Page and column must be set each time. Needed on SH1106, SH1107)
|
38
|
+
ADDRESSING_MODE_DEFAULT = 0x00
|
39
|
+
|
40
|
+
# Triple byte. Following 2 bytes sets value. For H/V addressing modes only.
|
41
|
+
COLUMN_ADDRESS_RANGE = 0x21
|
42
|
+
PAGE_ADDRESS_RANGE = 0x22
|
43
|
+
# For both: first value = min column/row, second value = max column/row
|
44
|
+
|
45
|
+
# Hardware Configuration Commands
|
46
|
+
# Single byte. OR with value.
|
47
|
+
START_LINE = 0x40 # Value: lowest 6 bits set RAM start line (default 0b000000)
|
48
|
+
SEGMENT_REMAP = 0xA0 # Value: 0x00 = default, 0x01 = column draw order reversed (horizontal reflection)
|
49
|
+
COM_DIRECTION = 0xC0 # Value: 0x00 = default, 0x08 = row draw order reversed (vertical reflection)
|
50
|
+
|
51
|
+
# Double-byte commands. Following byte sets value.
|
52
|
+
CHARGE_PUMP = 0x8D # Value: 0x10 = disable/external, 0x14 = enable/internal
|
53
|
+
MULTIPLEX_RATIO = 0xA8 # Value: rows of display - 1
|
54
|
+
DISPLAY_OFFSET = 0xD3 # Value: lowest 5 bits. Vertically shifts COM by that amount.
|
55
|
+
COM_PIN_CONFIG = 0xDA
|
56
|
+
# 0x02 = sequential, left and right not swapped
|
57
|
+
# 0x12 = alternative, left and right not swapped (default)
|
58
|
+
# 0x22 = sequential, left and right sawpped
|
59
|
+
# 0x32 = alternative, left and right swapped
|
60
|
+
|
61
|
+
# Timing & Driving Commands
|
62
|
+
# Double-byte commands. Following byte sets value.
|
63
|
+
CLOCK = 0xD5 # Lowest 4 bits = divider. Upper 4 bits = oscillator frequency.
|
64
|
+
PRECHARGE_PERIOD = 0xD9 # Lowest 4 bits = phase 1. Upper 4 bits = phase 2. 0xF1 for internal charge pump. 0x22 for external.
|
65
|
+
VCOM_DESELECT_LEVEL = 0xDB # 0x00 = 0.65 x Vcc, 0x20 = x 0.77 * Vcc (default), 0x30 = 0.83 x Vcc
|
66
|
+
|
67
|
+
# Valid widths and heights for displays
|
68
|
+
WIDTHS = [64,96,128]
|
69
|
+
HEIGHTS = [16,32,48,64,128]
|
70
|
+
|
71
|
+
# Default to a 128x64 display.
|
72
|
+
COLUMNS = 128
|
73
|
+
ROWS = 64
|
74
|
+
|
75
|
+
# Decide whether this instance is I2C or SPI.
|
76
|
+
before_initialize do
|
77
|
+
bus = params[:bus] || params[:board]
|
78
|
+
|
79
|
+
if bus.class.ancestors.include?(Denko::I2C::BusCommon)
|
80
|
+
mutate_i2c
|
81
|
+
elsif bus.class.ancestors.include?(Denko::SPI::BusCommon)
|
82
|
+
mutate_spi
|
83
|
+
else
|
84
|
+
raise ArgumentError, "#{self.class} must be connected to either an I2C or SPI bus"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def mutate_i2c
|
89
|
+
singleton_class.class_eval do
|
90
|
+
include I2C::Peripheral
|
91
|
+
include PixelCommon
|
92
|
+
|
93
|
+
# Commands are I2C messages prefixed with 0x00.
|
94
|
+
def command(bytes)
|
95
|
+
i2c_write([0x00] + bytes)
|
96
|
+
end
|
97
|
+
|
98
|
+
# Data are I2C messages prefixed with 0x40.
|
99
|
+
def data(bytes)
|
100
|
+
i2c_write([0x40] + bytes)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Data prefix always takes one byte, so subtract that.
|
104
|
+
def transfer_limit
|
105
|
+
@transfer_limit ||= bus.board.i2c_limit - 1
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def mutate_spi
|
111
|
+
singleton_class.class_eval do
|
112
|
+
include SPICommon
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
after_initialize do
|
117
|
+
# Validate known sizes.
|
118
|
+
raise ArgumentError, "error in #{self.class} width: #{columns}. Must be in: #{WIDTHS.inspect}" unless WIDTHS.include?(columns)
|
119
|
+
raise ArgumentError, "error in #{self.class} height: #{rows}. Must be in: #{HEIGHTS.inspect}" unless HEIGHTS.include?(rows)
|
120
|
+
|
121
|
+
# Everything except 96x16 size uses clock 0x80.
|
122
|
+
clock = 0x80
|
123
|
+
clock = 0x60 if (columns == 96 && rows == 16)
|
124
|
+
|
125
|
+
# 128x32 and 96x16 sizes use com pin config 0x02
|
126
|
+
com_pin_config = 0x12
|
127
|
+
com_pin_config = 0x02 if (columns == 96 && rows == 16) || (columns == 128 && rows == 32)
|
128
|
+
|
129
|
+
# Defaul to no reflection or rotation.
|
130
|
+
@seg_remap = 0x00
|
131
|
+
@com_direction = 0x00
|
132
|
+
|
133
|
+
# Startup sequence. SPI needs 2 repeats for some reason.
|
134
|
+
startup_count = 1
|
135
|
+
startup_count = 2 if singleton_class.ancestors.include? Denko::SPI::Peripheral
|
136
|
+
startup_count.times do
|
137
|
+
command [
|
138
|
+
MULTIPLEX_RATIO, rows - 1,
|
139
|
+
DISPLAY_OFFSET, 0x00,
|
140
|
+
START_LINE | 0x00,
|
141
|
+
SEGMENT_REMAP | @seg_remap,
|
142
|
+
COM_DIRECTION | @com_direction,
|
143
|
+
COM_PIN_CONFIG, com_pin_config,
|
144
|
+
PIXELS_FROM_RAM,
|
145
|
+
INVERT_OFF,
|
146
|
+
CLOCK, clock,
|
147
|
+
VCOM_DESELECT_LEVEL, 0x20,
|
148
|
+
PRECHARGE_PERIOD, 0xF1, # Charge period for internal charge pump
|
149
|
+
CHARGE_PUMP, 0x14, # Internal charge pump
|
150
|
+
ADDRESSING_MODE, self.class::ADDRESSING_MODE_DEFAULT,
|
151
|
+
DISPLAY_ON
|
152
|
+
]
|
153
|
+
end
|
154
|
+
|
155
|
+
draw
|
156
|
+
end
|
157
|
+
|
158
|
+
def off
|
159
|
+
command [DISPLAY_OFF]
|
160
|
+
end
|
161
|
+
|
162
|
+
def on
|
163
|
+
command [DISPLAY_ON]
|
164
|
+
end
|
165
|
+
|
166
|
+
def contrast=(value)
|
167
|
+
raise ArgumentError, "contrast must be in range 0..255" if (value < 0 || value > 255)
|
168
|
+
command [CONTRAST, value]
|
169
|
+
end
|
170
|
+
|
171
|
+
def reflect_x
|
172
|
+
# Swap @seg_remap to the other value and write it.
|
173
|
+
@seg_remap = (@seg_remap == 0x00) ? 0x01 : 0x00
|
174
|
+
command [SEGMENT_REMAP | @seg_remap]
|
175
|
+
end
|
176
|
+
|
177
|
+
def reflect_y
|
178
|
+
# Swap @com_direction to the other value and write it.
|
179
|
+
@com_direction = (@com_direction == 0x00) ? 0x08 : 0x00
|
180
|
+
command [COM_DIRECTION | @com_direction]
|
181
|
+
end
|
182
|
+
|
183
|
+
def rotate
|
184
|
+
reflect_x
|
185
|
+
reflect_y
|
186
|
+
end
|
187
|
+
|
188
|
+
def draw_partial(buffer, x_min, x_max, p_min, p_max)
|
189
|
+
raise NotImplementedError, "#draw_partial must be implemented for each class including MonoOLED"
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
module Denko
|
2
|
+
module Display
|
3
|
+
class PCD8544
|
4
|
+
include Behaviors::Lifecycle
|
5
|
+
include SPICommon
|
6
|
+
|
7
|
+
COLUMNS = 84
|
8
|
+
ROWS = 48
|
9
|
+
|
10
|
+
FUNCTION_SET = 0b00100000
|
11
|
+
# OR these options into lowest 3 bits:
|
12
|
+
POWER_UP = 0b000
|
13
|
+
POWER_DOWN = 0b100
|
14
|
+
H_ADDRESSING = 0b00
|
15
|
+
V_ADDRESSING = 0b10
|
16
|
+
BASIC_INS_SET = 0b0
|
17
|
+
EXT_INS_SET = 0b1
|
18
|
+
|
19
|
+
#
|
20
|
+
# Basic Instruciton Set (H = 0)
|
21
|
+
#
|
22
|
+
DISPLAY_CONTROL_SET = 0b00001000
|
23
|
+
# OR these options into lowest 3 bits:
|
24
|
+
DISPLAY_BLANK = 0b000
|
25
|
+
DISPLAY_NORMAL = 0b100
|
26
|
+
DISPLAY_ALL_SEGS = 0b001
|
27
|
+
DISPLAY_INVERT = 0b101
|
28
|
+
|
29
|
+
RAM_Y_SET = 0b01000000 # OR Y value into lowest 3 bits
|
30
|
+
RAM_X_SET = 0b10000000 # OR X value into lowest 7 bits
|
31
|
+
|
32
|
+
#
|
33
|
+
# Extended Instruciton Set (H = 1)
|
34
|
+
#
|
35
|
+
TEMP_COEFF_SET = 0b00000100 # OR temperature coeff. into lowest 2 bits
|
36
|
+
BIAS_SET = 0b00010000 # OR bias system values into lowest 3 bits
|
37
|
+
VOP_SET = 0b10000000 # OR VOP values into lowest 7 bits
|
38
|
+
|
39
|
+
def power_up
|
40
|
+
@function_state = (function_state & 0b11111011) | POWER_UP
|
41
|
+
command [function_state]
|
42
|
+
end
|
43
|
+
|
44
|
+
def power_down
|
45
|
+
@function_state = (function_state & 0b11111011) | POWER_DOWN
|
46
|
+
command [function_state]
|
47
|
+
end
|
48
|
+
|
49
|
+
def basic_instruction_mode
|
50
|
+
@function_state = (function_state & 0b11111110) | BASIC_INS_SET
|
51
|
+
command [function_state]
|
52
|
+
end
|
53
|
+
|
54
|
+
def extended_instruction_mode
|
55
|
+
@function_state = (function_state & 0b11111110) | EXT_INS_SET
|
56
|
+
command [function_state]
|
57
|
+
end
|
58
|
+
|
59
|
+
def function_state
|
60
|
+
@function_state ||= FUNCTION_SET
|
61
|
+
end
|
62
|
+
|
63
|
+
VALID_VOPS = (0..127).to_a
|
64
|
+
|
65
|
+
def vop=(value)
|
66
|
+
raise ArgumentError, "invalid Vop: #{value}" unless VALID_VOPS.include?(value)
|
67
|
+
extended_instruction_mode
|
68
|
+
command [VOP_SET | value]
|
69
|
+
basic_instruction_mode
|
70
|
+
@vop = value
|
71
|
+
end
|
72
|
+
|
73
|
+
VALID_BIASES = (0..7).to_a
|
74
|
+
|
75
|
+
def bias=(value)
|
76
|
+
raise ArgumentError, "invalid bias: #{value}" unless VALID_BIASES.include?(value)
|
77
|
+
extended_instruction_mode
|
78
|
+
command [BIAS_SET | value]
|
79
|
+
basic_instruction_mode
|
80
|
+
@bias = value
|
81
|
+
end
|
82
|
+
|
83
|
+
VALID_TCOEFFS = (0..3).to_a
|
84
|
+
|
85
|
+
def temperature_coefficient=(value)
|
86
|
+
raise ArgumentError, "invalid temperature coefficient: #{value}" unless VALID_TCOEFFS.include?(value)
|
87
|
+
extended_instruction_mode
|
88
|
+
command [TEMP_COEFF_SET | value]
|
89
|
+
basic_instruction_mode
|
90
|
+
@temperature_coefficient = value
|
91
|
+
end
|
92
|
+
|
93
|
+
def vop
|
94
|
+
@vop ||= 0
|
95
|
+
end
|
96
|
+
|
97
|
+
def bias
|
98
|
+
@bias ||= 0
|
99
|
+
end
|
100
|
+
|
101
|
+
def temperature_coefficient
|
102
|
+
@temperature_coefficient ||= 0
|
103
|
+
end
|
104
|
+
|
105
|
+
def set_display_control(value)
|
106
|
+
command [DISPLAY_CONTROL_SET | value]
|
107
|
+
end
|
108
|
+
|
109
|
+
def blank
|
110
|
+
set_display_control(DISPLAY_BLANK)
|
111
|
+
end
|
112
|
+
|
113
|
+
def all_segments_on
|
114
|
+
set_display_control(DISPLAY_ALL_SEGS)
|
115
|
+
end
|
116
|
+
|
117
|
+
def invert
|
118
|
+
@inverted = !@inverted
|
119
|
+
value = @inverted ? DISPLAY_INVERT : DISPLAY_NORMAL
|
120
|
+
set_display_control(value)
|
121
|
+
end
|
122
|
+
|
123
|
+
after_initialize do
|
124
|
+
# Reset sequence.
|
125
|
+
reset.low if reset
|
126
|
+
sleep 0.001
|
127
|
+
reset.high if reset
|
128
|
+
|
129
|
+
self.vop = 56
|
130
|
+
self.bias = 4
|
131
|
+
set_display_control(DISPLAY_NORMAL)
|
132
|
+
self.temperature_coefficient = 0
|
133
|
+
end
|
134
|
+
|
135
|
+
def draw_partial(buffer, x_start, x_finish, p_start, p_finish, color=1)
|
136
|
+
# Always use horizontal addressing mode.
|
137
|
+
basic_instruction_mode
|
138
|
+
|
139
|
+
(p_start..p_finish).each do |page|
|
140
|
+
# Set start page and column.
|
141
|
+
command [RAM_X_SET | x_start, RAM_Y_SET | page]
|
142
|
+
|
143
|
+
# Get needed bytes for this page only.
|
144
|
+
src_start = (columns * page) + x_start
|
145
|
+
src_end = (columns * page) + x_finish
|
146
|
+
partial_buffer = buffer[src_start..src_end]
|
147
|
+
|
148
|
+
# Send in chunks up to maximum transfer size.
|
149
|
+
partial_buffer.each_slice(transfer_limit) { |slice| data(slice) }
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module Denko
|
2
|
+
module Display
|
3
|
+
module PixelCommon
|
4
|
+
def columns
|
5
|
+
return @columns if @columns
|
6
|
+
@columns = self.class.const_get("COLUMNS") if self.class.const_defined?("COLUMNS")
|
7
|
+
@columns = params[:width] if params[:width]
|
8
|
+
@columns = params[:columns] if params[:columns]
|
9
|
+
@columns
|
10
|
+
end
|
11
|
+
alias :cols :columns
|
12
|
+
|
13
|
+
def rows
|
14
|
+
return @rows if @rows
|
15
|
+
@rows = self.class.const_get("ROWS") if self.class.const_defined?("ROWS")
|
16
|
+
@rows = params[:height] if params[:height]
|
17
|
+
@rows = params[:rows] if params[:rows]
|
18
|
+
@rows
|
19
|
+
end
|
20
|
+
|
21
|
+
def x_min
|
22
|
+
@x_min ||= 0
|
23
|
+
end
|
24
|
+
|
25
|
+
def x_max
|
26
|
+
@x_max ||= columns - 1
|
27
|
+
end
|
28
|
+
|
29
|
+
def y_min
|
30
|
+
@y_min ||= 0
|
31
|
+
end
|
32
|
+
|
33
|
+
def y_max
|
34
|
+
@y_max ||= rows - 1
|
35
|
+
end
|
36
|
+
|
37
|
+
def p_min
|
38
|
+
@p_min ||= 0
|
39
|
+
end
|
40
|
+
|
41
|
+
def p_max
|
42
|
+
@p_max ||= (rows / 8.0).ceil - 1
|
43
|
+
end
|
44
|
+
|
45
|
+
def colors
|
46
|
+
@colors ||= params[:colors] || 1
|
47
|
+
end
|
48
|
+
|
49
|
+
def canvas
|
50
|
+
@canvas ||= Canvas.new(columns, rows, colors: colors)
|
51
|
+
end
|
52
|
+
|
53
|
+
def refresh
|
54
|
+
end
|
55
|
+
|
56
|
+
def get_partial_buffer(buffer, x_start, x_finish, p_start, p_finish)
|
57
|
+
# If bounds == max bounds, just return the buffer.
|
58
|
+
return buffer if (x_start == x_min) && (x_finish == x_max) && (p_start == p_min) && (p_finish == p_max)
|
59
|
+
|
60
|
+
# Copy bytes for the given rectangle into a temp buffer.
|
61
|
+
temp_buffer = []
|
62
|
+
(p_start..p_finish).each do |page|
|
63
|
+
src_start = (columns * page) + x_start
|
64
|
+
src_end = (columns * page) + x_finish
|
65
|
+
temp_buffer += buffer[src_start..src_end]
|
66
|
+
end
|
67
|
+
temp_buffer
|
68
|
+
end
|
69
|
+
|
70
|
+
def draw(x_start=x_min, x_finish=x_max, y_start=y_min, y_finish=y_max)
|
71
|
+
# Convert y-coords to page coords.
|
72
|
+
p_start = y_start / 8
|
73
|
+
p_finish = y_finish / 8
|
74
|
+
|
75
|
+
colors.times do |i|
|
76
|
+
draw_partial(canvas.framebuffers[i], x_start, x_finish, p_start, p_finish, i+1)
|
77
|
+
end
|
78
|
+
|
79
|
+
refresh
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/lib/denko/display/sh1106.rb
CHANGED
@@ -1,40 +1,36 @@
|
|
1
|
-
require_relative 'ssd1306'
|
2
|
-
|
3
1
|
module Denko
|
4
2
|
module Display
|
5
|
-
class SH1106
|
3
|
+
class SH1106
|
4
|
+
include MonoOLED
|
6
5
|
#
|
7
|
-
#
|
6
|
+
# SH1106/SH1107 only support page addressing mode.
|
8
7
|
# Can't send all data as sequential pages and let page index auto-increment,
|
9
8
|
# like with horizontal addressing on the SSD1306.
|
10
9
|
#
|
11
10
|
ADDRESSING_MODE_DEFAULT = 0x02
|
11
|
+
RAM_X_OFFSET = 2
|
12
|
+
#
|
13
|
+
# SH1106 has RAM for 132 columns, but only 128 pixels, so offset by 2 to center.
|
14
|
+
def ram_x_offset
|
15
|
+
@ram_x_offset ||= self.class.const_get("RAM_X_OFFSET")
|
16
|
+
end
|
12
17
|
|
13
|
-
def
|
14
|
-
|
15
|
-
p_min = y_min / 8
|
16
|
-
p_max = y_max / 8
|
17
|
-
|
18
|
-
# Offset x_min by 2, since SH1106 has RAM for 132 columns, but we only use 128, then convert to nibbles.
|
19
|
-
x = x_min + 2
|
18
|
+
def draw_partial(buffer, x_start, x_finish, p_start, p_finish, color=1)
|
19
|
+
x = x_start + ram_x_offset
|
20
20
|
x_lower = (x & 0b00001111)
|
21
21
|
x_upper = (x & 0b11110000) >> 4
|
22
22
|
|
23
|
-
(
|
23
|
+
(p_start..p_finish).each do |page|
|
24
24
|
# Set the page and column to start writing at.
|
25
25
|
command [PAGE_START | page, COLUMN_START_LOWER | x_lower, COLUMN_START_UPPER | x_upper]
|
26
26
|
|
27
27
|
# Get needed bytes for this page only.
|
28
|
-
src_start
|
29
|
-
src_end
|
30
|
-
|
28
|
+
src_start = (columns * page) + x_start
|
29
|
+
src_end = (columns * page) + x_finish
|
30
|
+
partial_buffer = buffer[src_start..src_end]
|
31
31
|
|
32
|
-
# Send
|
33
|
-
|
34
|
-
data(buffer)
|
35
|
-
else
|
36
|
-
buffer.each_slice(bus.board.i2c_limit - 1) { |slice| data(slice) }
|
37
|
-
end
|
32
|
+
# Send in chunks up to maximum transfer size.
|
33
|
+
partial_buffer.each_slice(transfer_limit) { |slice| data(slice) }
|
38
34
|
end
|
39
35
|
end
|
40
36
|
end
|