SH1107G

2020年10月15日 (木)

XIAO/M5AtomでOLED128x128(I2C)を制御する((XIAO/Arduino版、M5Atom/Arduino版)

2020/10/16
wio-terminal用のplatformio.iniを追加した。

2020/10/15
初版

PlatformIO XAIO M5ATOM OLED128x128(I2C)

PlatformIO XAIO M5ATOM OLED128x128(I2C)

概要

XIAO/M5Atomで以下のOLED128x128(I2C)を制御する((XIAO/Arduino版、M5Atom/Arduino版)。
platformがArduinoなのでソースを共通化して動かしてみる。

・https://wiki.seeedstudio.com/Grove-OLED_Display_1.12inch/
・https://github.com/SeeedDocument/Seeed-WiKi/blob/master/docs/Grove-OLED_Display_1.12inch.md
本ボードは、ボードのバージョンによって、解像度が96x96または128x128であり、それぞれでコントローラも異なる。
入手したボードは、v1.1で解像度は128x128でコントローラはSH1107Gであった。(Vdd:3.3V/5V両用対応)

開発ツールplatformioのインストールについては以下を参照のこと:
開発ツールPlatformIOをcliで使う(Seeeduino-XIAO版)
M5Atomを開発ツールPlatformIOで使う(M5Atom/Arduino版)
M5Atomを開発ツールPlatformIOで使う(Windows10版)

接続

本モジュールはI2Cタイプなので(I2C用の)Grove-Conectorに接続する。
(XIAOは専用のshield経由で接続する)

platformio.ini

XIAO用:

; PlatformIO Project Configuration File ; ; Build options: build flags, source filter ; Upload options: custom upload port, speed and extra flags ; Library options: dependencies, extra library storages ; Advanced options: extra scripting ; ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html [env:seeed_xiao] platform = atmelsam board = seeed_xiao framework = arduino build_flags = -DXIAO upload_protocol = sam-ba monitor_speed = 115200 lib_deps = # Accept new functionality in a backwards compatible manner and patches olikraus/U8g2 @ ^2.28.7 lib_ldf_mode = deep+

M5ATOM用:

; PlatformIO Project Configuration File ; ; Build options: build flags, source filter ; Upload options: custom upload port, speed and extra flags ; Library options: dependencies, extra library storages ; Advanced options: extra scripting ; ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html [env:m5stick-c] platform = espressif32 board = m5stick-c framework = arduino build_flags = -DM5ATOM monitor_speed = 115200 lib_deps = # use M5Atom lib 3113 # use "FastLED" 126 # Accept new functionality in a backwards compatible manner and patches olikraus/U8g2 @ ^2.28.7 lib_ldf_mode = deep+

デモ・スケッチ

以下のようなファイルを作成する:
src/helloworld.ino

#ifdef M5ATOM #include "M5Atom.h" #endif #include <Arduino.h> #include <U8g2lib.h> #include <U8x8lib.h> #include <Wire.h> #ifdef M5ATOM // Grove Connector of Atom Matrix (I2C GPIO Pin: G26,G32) #define SCL 32 #define SDA 26 #endif U8G2_SH1107_SEEED_128X128_1_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE); U8X8_SH1107_SEEED_128X128_SW_I2C u8x8(/* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE); void setup(void) { /* NO NEED in this sketch #ifdef M5ATOM M5.begin(); // Wire.begin() must be after M5.begin() Wire.begin(26, 32); // Grove Connector of Atom Matrix (I2C GPIO Pin: G26,G32) #endif */ u8g2.begin(); u8g2.enableUTF8Print(); u8x8.begin() ; } void loop(void) { // using u8g2 lib u8g2.firstPage(); do { u8g2.setFont(u8g2_font_ncenB10_tr); u8g2.drawStr(0,12,"Hello World! #0"); u8g2.drawStr(0,24,"Hello World! #1"); u8g2.drawStr(0,36,"Hello World! #2"); u8g2.drawStr(0,48,"Hello World! #3"); u8g2.drawStr(0,60,"Hello World! #4"); u8g2.drawStr(0,72,"Hello World! #5"); u8g2.drawStr(0,84,"Hello World! #6"); u8g2.drawStr(0,96,"Hello World! #7"); u8g2.drawStr(0,108,"Hello World! #8"); u8g2.drawStr(0,120,"Hello World! #9"); u8g2.drawStr(0,132,"Hello World! #10"); } while ( u8g2.nextPage() ); delay(1000); //---------------- // kanji display u8g2.setFont(u8g2_font_b10_t_japanese1); u8g2.setFontDirection(0); u8g2.firstPage(); do { u8g2.setCursor(0, 15); u8g2.print("Hello World!"); u8g2.setCursor(0, 40); u8g2.print("こんにちは世界"); u8g2.setCursor(0, 50); u8g2.print("今日は良い天気/晴天です。"); u8g2.setCursor(0, 60); u8g2.print("明日は台風で強風でしょう。"); u8g2.setCursor(0, 70); u8g2.print("佐藤、田中、鈴木、青木、小松、増野、茅野、松岡"); } while ( u8g2.nextPage() ); delay(1000); // using u8x8 lib u8x8.setFont(u8x8_font_artossans8_r) ; u8x8.clear(); u8x8.println("Text Test") ; u8x8.println("XIAO/M5Atom\n") ; u8x8.print("OLED") ; u8x8.print("128x128(i2c)\n"); u8x8.println(millis()); u8x8.println(123.45); delay(1000); //-------------------- }

ビルド・実行

以下の手順でビルド・実行する:
(platformio.iniは、ボードごとに切り替える)

run pio -t upload

スケッチが起動すると、LCDに文字が表示される。
u8g2ライブラリ、u8x8ライブラリを交互に使用して文字を表示する。
日本語も表示するが、すべての漢字を持っているわけでないようだ。
(このデモでは人名が一部表示されない)

追加(wio-terminal用platformio.ini)

以下のplatformio.iniに切り替えるとwio-terminalでビルド・実行できる:

; PlatformIO Project Configuration File ; ; Build options: build flags, source filter ; Upload options: custom upload port, speed and extra flags ; Library options: dependencies, extra library storages ; Advanced options: extra scripting ; ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html [env:seeed_wio_terminal] platform = atmelsam board = seeed_wio_terminal framework = arduino build_flags = -DWIO_TERMINAL lib_deps = # Accept new functionality in a backwards compatible manner and patches olikraus/U8g2 @ ^2.28.7 upload_protocol = sam-ba monitor_speed = 115200 lib_ldf_mode = deep+

参考情報

U8g2 Library wiki: U8g2 is a monochrome graphics library
u8g2 reference

Seeeduino XIAO用Grove シールド バッテリー管理チップ 搭載

XIAO/M5Atomで気圧センサー(HP206C)を動かす(XIAO/Arduino版、M5Atom/Arduino版)
XIAO/M5AtomでLCD240x240(SPI)を制御する((XIAO/Arduino版、M5Atom/Arduino版)

M5AtomでOLED128x128(SPI)を制御する(Arduino版)
XIAOでOLED128x128(SPI)を制御する(Arduino版)
XIAOでLCD160x80(SPI)を制御する(Arduino版)

以上

続きを読む "XIAO/M5AtomでOLED128x128(I2C)を制御する((XIAO/Arduino版、M5Atom/Arduino版)"

| | コメント (0)

2020年4月25日 (土)

Grove-OLED-i2cにFramebufferモジュールを使ってイメージを表示する

2020/4/25+

MCP2221A adafruit_blinka Framebuffer Image

MCP2221A adafruit_blinka Framebuffer Image

概要

MCP2221Aボードで以下のGrove-OLED-i2cにFramebufferモジュールを使ってイメージを表示する. 本記事は「Grove-OLED-i2cをFramebufferモジュールで機能拡張する」の続きになる。

Grove - OLED Display 1.12"

本ボードは、ボードのバージョンによって、解像度が96x96または128x128であり、それぞれでコントローラも異なる。 入手したボードは、v1.1で解像度は128x128でコントローラはSH1107Gであった。(Vdd:3.3V/5V両用対応)

接続

MCP2221Aボードのi2cに本件のOLEDを接続する。(Vdd=3.3V)

該当モジュールのインストール

cd ~/mcp2221a_ws # 仮想環境に切り替える source blinka/bin/activate # sh1107g_cpy.pyをダウンロードする wget https://beta-notes.way-nifty.com/blog/files/sh1107g_cpy.py # adafruit_framebufをインストールする pip3 install adafruit-circuitpython-framebuf # framebufで使用するフォントをダウンロードする wget https://github.com/adafruit/Adafruit_CircuitPython_framebuf/blob/master/examples/font5x8.bin # python3のimageライブラリーをインストールする pip3 install Pillow # adafruit_imageloadモジュールをダウンロードする(CircuitPython用) git clone https://github.com/adafruit/Adafruit_CircuitPython_ImageLoad.git cp -r Adafruit_CircuitPython_ImageLoad/adafruit_imageload . # テスト用画像をダウンロードする(これは任意の画像で良い) wget https://upload.wikimedia.org/wikipedia/en/5/58/Blinka.png

テスト用画像をビットマップ画像に変換する

以下のスクリプトを実行してテスト用ビットマップ画像を作る:
mk_b1image.py

#!/usr/bin/python3 from PIL import Image im = Image.open('Blinka.png') resized_im = im.resize((128,128)) gray_im = resized_im.convert("L") # 以下の「x < 90」の「90」の画像によって調整すること tmp_im = gray_im.point(lambda x: 0 if x < 90 else 255) b1_im = tmp_im.convert('1') b1_im.save('blinka_b1.bmp') # inverted image # 以下の「x < 90」の「90」の画像によって調整すること tmp_im = gray_im.point(lambda x: 255 if x < 90 else 0) inv_b1_im = tmp_im.convert('1') inv_b1_im.save('blinka_inv_b1.bmp')

これにより以下の2つのファイルが作られる。
blinka_b1.bmp
blinka_inv_b1.bmp

デモ・スクリプト(python3/circuitpython兼用)

test_fb1_sh1107g.py

#CIRCUITPY = True CIRCUITPY = False # import image related module if CIRCUITPY: import displayio import adafruit_imageload else: from PIL import Image # for CircuitPython/blinka import time import busio import board i2c = busio.I2C(board.SCL, board.SDA) i2c.try_lock() from sh1107g_cpy import SH1107G oled = SH1107G(i2c) oled.clear() #----------------------------- # framebuffer related import adafruit_framebuf # pixel size for display WIDTH = 128 HEIGHT = 128 fbuf = bytearray(round(WIDTH * HEIGHT / 8)) fb = adafruit_framebuf.FrameBuffer(fbuf, WIDTH, HEIGHT, buf_format=adafruit_framebuf.MVLSB) #------------------------------ # write image into framebuffer def fb_image(fb,img): # Iterate through the pixels for x in range(img.width): for y in range(img.height): if img.getpixel((x, y)): fb.pixel(x, y, 1) else: fb.pixel(x, y, 0) # for circuitpython def fb_image_cpy(fb,img): # Iterate through the pixels for x in range(img.width): for y in range(img.height): if img[x, y]: fb.pixel(x, y, 1) else: fb.pixel(x, y, 0) # (for debug) Ascii printer for very small framebufs! def print_buffer(the_fb): print("." * (the_fb.width+2)) for y in range(the_fb.height): print(".", end='') for x in range(the_fb.width): if fb.pixel(x, y): print("*", end='') else: print(" ", end='') print(".") print("." * (the_fb.width+2)) # clear framebuffer def clear_fbuf(): for i, _ in enumerate(fbuf): fbuf[i] = 0 #---------------------------------- print("image test1: ") clear_fbuf() if CIRCUITPY: im, pal = adafruit_imageload.load( "blinka_b1.bmp", bitmap=displayio.Bitmap, palette=displayio.Palette) fb_image_cpy(fb, im) else: im = Image.open('blinka_b1.bmp') im.show() fb_image(fb, im) # show display oled.draw(fbuf, len(fbuf)) time.sleep(4) print("image test2: ") clear_fbuf() if CIRCUITPY: im, pal = adafruit_imageload.load( "blinka_inv_b1.bmp", bitmap=displayio.Bitmap, palette=displayio.Palette) fb_image_cpy(fb, im) else: im = Image.open('blinka_inv_b1.bmp') im.show() fb_image(fb, im) # show display oled.draw(fbuf, len(fbuf)) time.sleep(4)

変数CIRCUITPYのTrue/Falseでcircuitpython/python3用を切り換えている。

実行

PC(python3)の場合

# 仮想環境を有効化する source blinka/bin/activate # 実行する export BLINKA_MCP2221=1 python3 test_fb1_sh1107g.py

注意:変数CIRCUITPYをFalseにすること。

CircuitPythonの場合

REPL: import test_fb1_sh1107g

注意:変数CIRCUITPYをTrueにすること。

なお、CircuitPythonで実行する場合、 以下のファイル/ディレクトリをCIRCUITPYにコピーする:

(1)sh1107g_cpy.py (2)blinka/lib/python3.6/site-packages/adafruit_framebuf.py # 「python3.6」の部分は、ホストPCの状況に合わせる (3)test_fb1_sh1107g.py (4)blinka_b1.bmp (5)blinka_inv_b1.bmp (6)adafruit_imageload(デレクトリ) これは、CIRCUITPY/lib以下にコピーする

動作実績

(1)MCP2221Aボード
正常に動作した(Vdd=3.3V)
(2)CircutPython Teensy4.0
正常に動作した(Vdd=3.3V)
(3)FT232Hボード
i2c.scan()でデバイス・アドレスが返ってこない。(動作せず)(Vdd=5V)
デバイスの仕様としては、5V/3.3V両用対応になっているが本ボードでは動作しないようだ。

参照情報

PIL/Pillow チートシート

Framebuffer API
Famebuffer docs (MicroPython-based)

Python library for Seeedstudio Grove devices
Arduino Library for this Grove - OLED Display 1.12inch
download datasheet SH1107_v2.1.pdf

USB-I2CブリッジボードV2(GROVE対応ボード)【MR-GROVE-B】
USB-I2CブリッジボードV2(GROVE対応ブレッドボード版)【MR-GROVE-BB】
MCP2221 Blinka Pinout

CircuitPython Libraries on any Computer with MCP2221

CircuitPython on Linux and Raspberry Pi
CircuitPython 5.0.x - I2C

PCのpython3でCircuitPythonのAPIを使用する(FT232H版)
PCのpython3でCircuitPythonのAPIを使用する(MCP2221A版)

以上

続きを読む "Grove-OLED-i2cにFramebufferモジュールを使ってイメージを表示する"

| | コメント (0)

2020年4月24日 (金)

Grove-OLED-i2cをFramebufferモジュールで機能拡張する

2020/4/24

MCP2221A adafruit_blinka Grove-OLED128x128-i2c Framebuffer

MCP2221A adafruit_blinka Grove-OLED128x128-i2c Framebuffer

概要

MCP2221Aボードで以下のGrove-OLED-i2cをFramebufferモジュールで機能拡張する。本記事は「MCP2221AボードでGrove-OLED-i2cを動かす」の続きになる。

Grove - OLED Display 1.12"

本ボードは、ボードのバージョンによって、解像度が96x96または128x128であり、それぞれでコントローラも異なる。 入手したボードは、v1.1で解像度は128x128でコントローラはSH1107Gであった。(Vdd:3.3V/5V両用対応)

接続

MCP2221Aボードのi2cに本件のOLEDを接続する。(Vdd=3.3V)

モジュールのインストール

cd ~/mcp2221a_ws # 仮想環境に切り替える source blinka/bin/activate # sh1107g_cpy.pyをダウンロードする wget https://beta-notes.way-nifty.com/blog/files/sh1107g_cpy.py # adafruit_framebufをインストールする pip3 install adafruit-circuitpython-framebuf # framebufで使用するフォントをダウンロードする wget https://github.com/adafruit/Adafruit_CircuitPython_framebuf/blob/master/examples/font5x8.bin

デモ・スクリプト

test_fb_sh1107g.py

# for CircuitPython import time import busio import board i2c = busio.I2C(board.SCL, board.SDA) i2c.try_lock() from sh1107g_cpy import SH1107G oled = SH1107G(i2c) oled.clear() #----------------------------- # framebuffer related import adafruit_framebuf # pixel size for display WIDTH = 128 HEIGHT = 128 fbuf = bytearray(round(WIDTH * HEIGHT / 8)) fb = adafruit_framebuf.FrameBuffer(fbuf, WIDTH, HEIGHT, buf_format=adafruit_framebuf.MVLSB) #------------------------------- # (for debug) Ascii printer for very small framebufs! def print_buffer(the_fb): print("." * (the_fb.width+2)) for y in range(the_fb.height): print(".", end='') for x in range(the_fb.width): if fb.pixel(x, y): print("*", end='') else: print(" ", end='') print(".") print("." * (the_fb.width+2)) # clear framebuffer def clear_fbuf(): for i, _ in enumerate(fbuf): fbuf[i] = 0 #---------------------------------- print("Text test: ") clear_fbuf() fb.text("hello world! #0", 0, 0, True) fb.text("Integer:{} #1".format(1234), 0, 8, True) fb.text("Float:{} #2".format(12.34), 0, 16, True) fb.text("1234567890-^\\ #3", 0, 24, True) fb.text("!\"#$%&'()~=~| #4", 0, 32, True) fb.text("ABCDEFGHIJKLM #5", 0, 40, 1) fb.text("OPQRSTUVWXYZ #6", 0, 48, 1) fb.text("abcdefghijklm #7", 0, 56, 1) fb.text("opqrstuvwxyz #8", 0, 64, 1) fb.text(",./\;:[] #9", 0, 72, 1) fb.text("<>?_+*{} #10", 0, 80, 1) fb.text("Hello World! #11", 0, 88, 1) fb.text("hello world! #12", 0, 96, 1) fb.text("Hello World! #13", 0, 104, 1) fb.text("hello world! #14", 0, 112, 1) fb.text("Hello World! #15", 0, 120, 1) # show display oled.draw(fbuf, len(fbuf)) time.sleep(4) print("Shapes test: ") clear_fbuf() fb.pixel(13, 5, 1) fb.rect(0, 0, fb.width, fb.height, 1) fb.line(1, 1, fb.width-2, fb.height-2, 1) fb.fill_rect(25, 4, 4, 5, 1) fb.circle(64,64,20,1) fb.hline(20,30,40,1) fb.vline(20,30,40,1) fb.scroll(10,20) # show display oled.draw(fbuf, len(fbuf)) time.sleep(4) print("larger text test: ") clear_fbuf() fb.text("Hello", 8, 0, 1, size = 4) # show display oled.draw(fbuf, len(fbuf))

実行

PCの場合

# 仮想環境を有効化する source blinka/bin/activate # 実行する export BLINKA_MCP2221=1 python3 test_fb_sh1107g.py

CircuitPythonの場合

REPL: import test_fb_sh1107g

なお、CircuitPythonで実行する場合、 以下の4つのファイルをCIRCUITPYにコピーする:

(1)sh1107g_cpy.py (2)blinka/lib/python3.6/site-packages/adafruit_framebuf.py # 「python3.6」の部分は、ホストPCの状況に合わせる (3)font5x8.bin (4)test_fb_sh1107g.py

動作実績

(1)MCP2221Aボード
正常に動作した(Vdd=3.3V)
(2)CircutPython Teensy4.0
正常に動作した(Vdd=3.3V)
(3)FT232Hボード
i2c.scan()でデバイス・アドレスが返ってこない。(動作せず)(Vdd=5V)
デバイスの仕様としては、5V/3.3V両用対応になっているが本ボードでは動作しないようだ。

Framebufferの関数リスト

circle(center_x, center_y, radius, color) Draw a circle at the given midpoint location, radius and color. The `circle` method draws only a 1 pixel outline. fill(color) Fill the entire FrameBuffer with the specified color. fill_rect(x, y, width, height, color) Draw a rectangle at the given location, size and color. The fill_rect method draws both the outline and interior. hline(x, y, width, color) Draw a horizontal line up to a given length. image(img) Set buffer to value of Python Imaging Library image. The image should be in 1 bit mode and a size equal to the display size. line(x_0, y_0, x_1, y_1, color) Bresenham’s line algorithm pixel(x, y, color=None) If color is not given, get the color value of the specified pixel. If color is given, set the specified pixel to the given color. rect(x, y, width, height, color, *, fill=False) Draw a rectangle at the given location, size and color. The `rect` method draws only a 1 pixel outline. rotation The rotation setting of the display, can be one of (0, 1, 2, 3) scroll(delta_x, delta_y) shifts framebuf in x and y direction text(string, x, y, color, *, font_name='font5x8.bin', size=1) Place text on the screen in variables sizes. Breaks on to next line. Does not break on line going off screen. vline(x, y, height, color) Draw a vertical line up to a given length. 追記: colorは、モノクロの場合、1またはTrueになる。

参照情報

Framebuffer API
Famebuffer docs (MicroPython-based)

Python library for Seeedstudio Grove devices
Arduino Library for this Grove - OLED Display 1.12inch
download datasheet SH1107_v2.1.pdf

USB-I2CブリッジボードV2(GROVE対応ボード)【MR-GROVE-B】
USB-I2CブリッジボードV2(GROVE対応ブレッドボード版)【MR-GROVE-BB】
MCP2221 Blinka Pinout

CircuitPython Libraries on any Computer with MCP2221

CircuitPython on Linux and Raspberry Pi
CircuitPython 5.0.x - I2C

PCのpython3でCircuitPythonのAPIを使用する(FT232H版)
PCのpython3でCircuitPythonのAPIを使用する(MCP2221A版)

以上

続きを読む "Grove-OLED-i2cをFramebufferモジュールで機能拡張する"

| | コメント (0)

2020年4月23日 (木)

MCP2221AボードでGrove-OLED-i2cを動かす

2020/4/22+

MCP2221A adafruit_blinka Grove-OLED128x128-i2c

MCP2221A adafruit_blinka Grove-OLED128x128-i2c

概要

MCP2221Aボードで以下のGrove-OLED-i2cを動かす。

Grove - OLED Display 1.12"

本ボードは、ボードのバージョンによって、解像度が96x96または128x128であり、それぞれでコントローラも異なる。 入手したボードは、v1.1で解像度は128x128でコントローラはSH1107Gであった。(Vdd:3.3V/5V両用対応)

接続

MCP2221Aボードのi2cに本件のOLEDを接続する。(Vdd=3.3V)

モジュールのインストール

cd ~/mcp2221a_ws wget https://raw.githubusercontent.com/Seeed-Studio/grove.py/master/grove/display/sh1107g.py cp sh1107g.py sh1107g_cpy.py # sh1107g_cpy.pyをCircuitPython対応にするために # 次の内容に変更する:

sh1107g_cpy.py
「#m」を含む行が修正箇所になるが 変更が多いので、修正済みのものをアップロードしてある。
以下のリンクからダウンロードして使用する。
sh1107g_cpy.py

# forked for CircuitPython 2020/4/22 # this program forked from the flollwing source: # https://raw.githubusercontent.com/Seeed-Studio/grove.py/master/grove/display/sh1107g.py # #!/usr/bin/env python # -*- coding: utf-8 -*- # # The MIT License (MIT) # Copyright (C) 2018 Seeed Technology Co.,Ltd. # # This is the library for Grove Base Hat # which used to connect grove sensors for Raspberry Pi. ''' This is the code for - `OLED Display 1.12" <https://www.seeedstudio.com/Grove-OLED-Display-1-1-p-824.html>`_ - `OLED Display 1.12" V2 <https://www.seeedstudio.com/Grove-OLED-Display-1-12-V2-p-3031.html>`_ Examples: .. code-block:: python # for CircuitPython import time import busio import board i2c = busio.I2C(board.SCL, board.SDA) i2c.try_lock() from sh1107g_cpy import SH1107G oled = SH1107G(i2c) oled.setCursor(0, 0) oled.write("hello world!") oled.setCursor(1, 0) oled.write("integer:{}".format(1234)) oled.setCursor(2, 0) oled.write('float:{}'.format(12.34)) oled.setCursor(3, 0) oled.write("abcdefghijklmnop") oled.setCursor(4, 0) oled.write("qrstuvwxyz") oled.setCursor(5, 0) oled.write("ABCDEFGHIJKLMNOP") oled.setCursor(6, 0) oled.write("QRSTUVWXYZ") time.sleep(3) oled.clear() ========================================== import time from grove.factory import Factory oled = Factory.getDisplay("SH1107G") rows, cols = oled.size() print("OLED model: {}".format(oled.name)) print("OLED type : {} x {}".format(cols, rows)) oled.setCursor(0, 0) oled.write("hello world!") oled.setCursor(0, cols - 1) oled.write('X') oled.setCursor(rows - 1, 0) for i in range(cols): oled.write(chr(ord('A') + i)) time.sleep(3) oled.clear() ''' MAX_GRAY = 100 _REG_CMD = 0x00 _REG_DATA = 0x40 _PAGE_CNT = 16 _PAGE_BYTES = 128 _TOTAL_BYTES= _PAGE_CNT * _PAGE_BYTES BASE_PAGE_START_ADDR = 0xb0 BASE_LOW_COLUMN_ADDR = 0x00 BASE_HIGH_COLUMN_ADDR = 0x10 #m from grove.display.base import * #m from upm.pyupm_lcd import * #m from grove.i2c import Bus #m import sys, mraa # sphinx autoapi required #m __all__ = ["SH1107G_SSD1327"] BasicFont = [ [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00], <省略> [0x00,0x02,0x05,0x05,0x02,0x00,0x00,0x00], ] #m class SH1107G_SSD1327(Display): class SH1107G(object): #m ''' OLED Display 1.12"(v2) use chip SSD1327 or SH1107G. Args: address(int): I2C device address, default to 0x3E. ''' #m def __init__(self, address = 0x3C): def __init__(self, i2c, address = 0x3C): #m #m super(SH1107G_SSD1327, self).__init__() # self._bus = Bus() #m self._bus = mraa.I2c(0) self._bus = i2c #m self._addr = address #m self._bus.address(self._addr) #m if self._bus.writeByte(0): ba1 = bytearray(1) #m ba1[0] = 0 #m if self._bus.writeto(self._addr, ba1): #m print("Check if the OLED SH1107G/SSD1307 inserted, then try again") sys.exit(1) # id = self._bus.read_byte_data(self._addr, SH1107G_SSD1327._REG_CMD) #m id = self._bus.readReg(SH1107G_SSD1327._REG_CMD) self._cmd(_REG_CMD) #m ba1 = bytearray(1) #m self._bus.readfrom_into(self._addr, ba1) #m id = ba1[0] #m # print(" id = 0x{:2x}".format(id)) self._sh1107 = (id & 0x3F) == 0x07 #print(self._sh1107) # for debug #m if not self._sh1107: #m #m self._ssd1327 = SSD1327(0) #m print('Not SH1107 error') #m #m return #m blk = [0xAE] # Display OFF blk.append(0xD5) # Set Dclk blk.append(0x50) # 100Hz blk.append(0x20) # Set row address blk.append(0x81) # Set contrast control blk.append(0x80) blk.append(0xA0) # Segment remap blk.append(0xA4) # Set Entire Display ON blk.append(0xA6) # Normal display blk.append(0xAD) # Set external VCC blk.append(0x80) blk.append(0xC0) # Set Common scan direction blk.append(0xD9) # Set phase leghth blk.append(0x1F) blk.append(0xDB) # Set Vcomh voltage blk.append(0x27) blk.append(0xAF) # Display ON blk.append(0xB0) blk.append(0x00) blk.append(0x10) self._cmds(blk) self.clear() def _cmd(self, cmd): ba2 = bytearray(2) #m ba2[0] = _REG_CMD #m ba2[1] = cmd #m try: self._bus.writeto(self._addr, ba2) #m # self._bus.write_byte_data(self._addr, #mself._bus.writeReg( #m SH1107G_SSD1327._REG_CMD, cmd) except IOError: print("*** Check if OLED module inserted ***") sys.exit(1) def _cmds(self, cmds): for c in cmds: self._cmd(c) def _datas(self, datas): length = len(datas) data = bytearray(length + 1) #mdata[0] = SH1107G_SSD1327._REG_DATA data[0] = _REG_DATA #m for i in range(length): data[i + 1] = datas[i] try: #m self._bus.write(data) self._bus.writeto(self._addr, data) #m # self._bus.write_i2c_block_data(self._addr, # SH1107G_SSD1327._REG_DATA, datas) except IOError: print("*** Check if OLED module inserted ***") sys.exit(1) @property def name(self): ''' Get device name Returns: string: SH1107G/SSD1307 depends your device plugin. ''' return "SH1107G" if self._sh1107 else "SSD1327" def type(self): ''' Get device type Returns: int: ``TYPE_GRAY`` ''' return TYPE_GRAY def size(self): if not self._sh1107: # Gray OLED 96x96 return 12, 12 # Gray OLED 128x128 return 16, 16 def clear(self): ''' Clears the screen and positions the cursor in the upper-left corner. ''' #mif not self._sh1107: #m self._ssd1327.clear() #m return #mzeros = [ 0x0 for dummy in range(SH1107G_SSD1327._TOTAL_BYTES) ] #mself.draw(zeros, SH1107G_SSD1327._TOTAL_BYTES) #mzeros = [ 0x0 for dummy in range(_TOTAL_BYTES) ] #mself.draw(zeros, _TOTAL_BYTES) zeros = [ 0x0 for dummy in range(128) ] #m for i in range(16): self._cmd(0xb0+i) self._cmd(0x0) self._cmd(0x10) self._datas(zeros) # code for C #for (i = 0; i < 16; i++) { # sendCommand(0xb0 + i); # sendCommand(0x0); # sendCommand(0x10); # for (j = 0; j < 128; j++) { # sendData(0x00); # } #} def draw(self, data, bytes): ''' Quickly transfer/draw bulk data (specified by data) to OLED, transfer size specified by bytes. Args: data (list of int): the data to transfer/draw bytes (int) : data size ''' #mif not self._sh1107: #m self._ssd1327.draw(data, bytes) #m return # all pages fill with data #mfor i in range(SH1107G_SSD1327._PAGE_CNT): for i in range(_PAGE_CNT): #m #mif i > bytes / SH1107G_SSD1327._PAGE_BYTES: if i > bytes / _PAGE_BYTES: #m return self._cmd(BASE_PAGE_START_ADDR + i) self._cmd(BASE_LOW_COLUMN_ADDR) self._cmd(BASE_HIGH_COLUMN_ADDR) # fill one PAGE bytes #for k in range(0, SH1107G_SSD1327._PAGE_BYTES, 32): for k in range(0, _PAGE_BYTES, 32): #m # I2C limit to 32 bytes each transfer #mbegin = i * SH1107G_SSD1327._PAGE_BYTES + k begin = i * _PAGE_BYTES + k #m end = begin + 32 self._datas(data[begin:end]) def home(self): ''' Positions the cursor in the upper-left of the OLED. That is, use that location in outputting subsequent text to the display. ''' if not self._sh1107: self._ssd1327.home() return self.setCusor(0, 0) def setCursor(self, row, column): ''' Position the OLED cursor; that is, set the location at which subsequent text written to the OLED will be displayed. Args: row (int): the row at which to position cursor, with 0 being the first row column(int): the column at which to position cursor, with 0 being the first column Returns: None ''' #mif not self._sh1107: #m self._ssd1327.setCursor(row, column) #m return #mself._cmd(BASE_PAGE_START_ADDR + row) #mself._cmd(0x08 if column % 2 else BASE_LOW_COLUMN_ADDR) #mself._cmd(BASE_HIGH_COLUMN_ADDR + (column >> 1)) self._cmd(0xb0 + (row & 0x0F)) self._cmd(0x10 + ((column >> 4) & 0x07)) self._cmd(column & 0x0F) # code for C #sendCommand(0xb0 + (Row & 0x0F)); // set page/row #sendCommand(0x10 + ((Column >> 4) & 0x07)); // set column high 3 byte #sendCommand(Column & 0x0F); // set column low 4 byte def _putchar(self, c): asc = ord(c) if asc < 32 or asc > 127: asc = ord(' ') for i in range(8): fontmap = [] fontmap.append(BasicFont[asc - 32][i]) self._datas(fontmap) def write(self, msg): ''' Write character(s) to the OLED. Args: msg (string): the character(s) to write to the display Returns: None ''' if not self._sh1107: self._ssd1327.write(msg) return for i in range(len(msg)): self._putchar(msg[i]) def _backlight_on(self, en): self._cmd(DISPLAY_CMD_ON if en else DISPLAY_CMD_OFF)

本モジュールは、micropythonとCircuitPythonの共通のAPIを使用しているので、micropythonとCircuitPythonの両方で利用できるはずである。

デモ・スクリプト

test_sh1107g.py

# for CircuitPython import time import busio import board i2c = busio.I2C(board.SCL, board.SDA) i2c.try_lock() from sh1107g_cpy import SH1107G oled = SH1107G(i2c) oled.setCursor(0, 0) oled.write("hello world!") oled.setCursor(1, 0) oled.write("integer:{}".format(1234)) oled.setCursor(2, 0) oled.write('float:{}'.format(12.34)) oled.setCursor(3, 0) oled.write("abcdefghijklmnop") oled.setCursor(4, 0) oled.write("qrstuvwxyz") oled.setCursor(5, 0) oled.write("ABCDEFGHIJKLMNOP") oled.setCursor(6, 0) oled.write("QRSTUVWXYZ") oled.setCursor(7, 0) oled.write("1234567890-^\\") oled.setCursor(8, 0) oled.write("!\"#$%&'()~=~|") oled.setCursor(9, 0) oled.write("hello world! #9") oled.setCursor(10, 0) oled.write("hello world! #10") oled.setCursor(11, 0) oled.write("hello world! #11") oled.setCursor(12, 0) oled.write("hello world! #12") oled.setCursor(13, 0) oled.write("hello world! #13") oled.setCursor(14, 0) oled.write("hello world! #14") oled.setCursor(15, 0) oled.write("hello world! #15") time.sleep(10) oled.clear() oled.setCursor(0,0) oled.write("test finished.")

実行

PCの場合

# 仮想環境を有効化する source blinka/bin/activate # 実行する export BLINKA_MCP2221=1 python3 test_sh1107g.py

CircuitPythonの場合

REPL: import test_sh1107g

動作実績

(1)MCP2221Aボード
正常に動作した(Vdd=3.3V)
(2)CircutPython Teensy4.0
正常に動作した(Vdd=3.3V)
(3)FT232Hボード
i2c.scan()でデバイス・アドレスが返ってこない。(動作せず)(Vdd=5V)
デバイスの仕様としては、5V/3.3V両用対応になっているが本ボードでは動作しないようだ。

参照情報

Python library for Seeedstudio Grove devices
Arduino Library for this Grove - OLED Display 1.12inch
download datasheet SH1107_v2.1.pdf

USB-I2CブリッジボードV2(GROVE対応ボード)【MR-GROVE-B】
USB-I2CブリッジボードV2(GROVE対応ブレッドボード版)【MR-GROVE-BB】
MCP2221 Blinka Pinout

CircuitPython Libraries on any Computer with MCP2221

CircuitPython on Linux and Raspberry Pi
CircuitPython 5.0.x - I2C

PCのpython3でCircuitPythonのAPIを使用する(FT232H版)
PCのpython3でCircuitPythonのAPIを使用する(MCP2221A版)

以上

続きを読む "MCP2221AボードでGrove-OLED-i2cを動かす"

| | コメント (0)