« docker/TinyGO Helper Script | トップページ | Grove-OLED-i2cをFramebufferモジュールで機能拡張する »

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版)

以上

|

« docker/TinyGO Helper Script | トップページ | Grove-OLED-i2cをFramebufferモジュールで機能拡張する »

CircuitPython」カテゴリの記事

MCP2221A」カテゴリの記事

SH1107G」カテゴリの記事

コメント

この記事へのコメントは終了しました。