MCP2221AボードでGrove-OLED-i2cを動かす
2020/4/22+
MCP2221A adafruit_blinka Grove-OLED128x128-i2c
MCP2221A adafruit_blinka Grove-OLED128x128-i2c
概要
MCP2221Aボードで以下のGrove-OLED-i2cを動かす。
本ボードは、ボードのバージョンによって、解像度が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版)
以上
| 固定リンク
「CircuitPython」カテゴリの記事
- MicroPython/CircuitPython Performance Test(2021.02.07)
- PicoボードにMicropython/CircuitPythonをインストールする(2021.02.03)
- XIAOでMPL3115A2(気圧・高度・気温センサ)を使用する(CircuitPython版)(2020.07.02)
- XIAOでMCP9808(温度センサ)を使用する(CircuitPython版)(2020.07.02)
- XIAOにCircuitPythonをインストールする(2020.06.09)
「MCP2221A」カテゴリの記事
- Grove-OLED-i2cにFramebufferモジュールを使ってイメージを表示する(2020.04.25)
- MCP2221AボードでGrove-OLED-i2cを動かす(2020.04.23)
「SH1107G」カテゴリの記事
- XIAO/M5AtomでOLED128x128(I2C)を制御する((XIAO/Arduino版、M5Atom/Arduino版)(2020.10.15)
- Grove-OLED-i2cにFramebufferモジュールを使ってイメージを表示する(2020.04.25)
- Grove-OLED-i2cをFramebufferモジュールで機能拡張する(2020.04.24)
- MCP2221AボードでGrove-OLED-i2cを動かす(2020.04.23)
この記事へのコメントは終了しました。
コメント