SAMD21/SAMD51 ファミリー用クイックリファレンス
The Adafruit ItsyBitsy M4 Express board.
以下は、SAMD21/SAMD51 ベースのボードのためのクイックリファレンスです。このボードを初めて使う場合は、まず次のマイクロコントローラの概要を確認してみてください。
MicroPython のインストール
チュートリアルの章: SAMD での MicroPython の始め方 を参照してください。そこにはトラブルシューティングについても記載されています。
ボードの一般的な制御
MicroPython REPL は VCP モードに設定した USB ポートで利用できます。タブ補完は、オブジェクトにどのようなメソッドがあるかを調べるのに便利です。貼り付けモード(ctrl-E)は、大きめの Pythonコードを REPL に貼り付けるのに便利です。
machine モジュール
import machine
machine.freq() # CPU の現在の周波数を取得
machine.freq(96_000_000) # CPU の周波数を 96 MHz に設定
この関数コールが受け付ける範囲は、SAMD51 の場合は 1_000_000 から 200_000_000 (1 MHz から 200 MHz)、SAMD21 の場合は 1_000_000 から 54_000_000 (1 MHz から 54 MHz)です。データシートによると、SAMD51 の安全範囲は最大 120 MHz、SAMD21 では最大 48 MHz です。48Mhz以下の周波数は、48Mhzを整数で割った、24Mhz、16Mhz、12MHz などの離散的な周波数に限定して設定されます。8 MHz 未満の周波数では、USB が無効になります。48 MHz 未満の周波数を変更すると、UART, I2C, SPI のボーレートに影響があります。CPU の周波数を変更した後は、これらを再度設定する必要があります。ms および µs タイマーは、周波数変更の影響を受けません。
遅延とタイミング
time モジュールを使います:
import time
time.sleep(1) # 1秒間、一時停止する
time.sleep_ms(500) # 500ミリ秒間、一時停止する
time.sleep_us(10) # 10マイクロ秒間、一時停止する
start = time.ticks_ms() # ミリ秒カウンター値を取得
delta = time.ticks_diff(time.ticks_ms(), start) # 時差を計算
注記: time.sleep_us() はビジーウェイトによって遅延を発生させます。この間、他のタスクはスケジュールされません。
クロックとタイム
時間情報については、2つの関数群を用意しています。すべてのボードに datetime(), mktime(), time() 関数があります。32kHz の水晶振動子を持つボードは、RTC() モジュールも提供します。エポックのスタートは、2000.1.1です。
time モジュールを使います:
import time
date_time = time.localtime() # 現在の日時情報を取得
date_time = time.localtime(seconds) # 秒数の値から日時をデコード
seconds = time.mktime(date_time_tuple) # 日時のタプルから秒数に変換
second = time.time() # 現在のシステムタイムを返す
date_time タプルのフォーマットは標準にしたがいます。date_time タプルの µs 値は無視されます。RTC モジュールがないボードにおいて、time.localtime() はシステムタイムを返します。RTC は、RTC モジュールを使います。
from machine import RTC
rtc = RTC()
date_time = rtc.datetime() # 現在の日時を返す
rtc.datetime(date_time_tuple) # 日時を設定。weekday は無視
date_time = rtc.now() # Unix オーダで日時を返す
rtc.calibration(value) # キャリブレーション係数を設定
weekday (曜日)設定は無視され、実際の日付から返されるタプルで計算されます。rtc.now() は、SAMD51 ボードでのみ提供されます。rtc.calibration() で指定する値は -127 から 127 までの範囲です。これはおおよその ppm 量を定義していて、これによってクロックを高速化したり低速化したりすることができます。
タイマー
SAMD21/SAMD51 はソフトウェアタイマーをサポートします。 machine.Timer クラスを使います:
from machine import Timer
tim0 = Timer()
tim0.init(period=5000, mode=Timer.ONE_SHOT, callback=lambda t:print(0))
tim1 = Timer()
tim1.init(period=2000, mode=Timer.PERIODIC, callback=lambda t:print(1))
period の単位はミリ秒です。
ピンと GPIO
machine.Pin クラスを使います:
from machine import Pin
p0 = Pin('D0', Pin.OUT) # GPIO0 の出力ピンを作成
p0.on() # ピンを "on" (high) レベルに設定
p0.off() # ピンを "off" (low) レベルに設定
p0.value(1) # ピンを on/high に設定
p2 = Pin('D2', Pin.IN) # GPIO2 の入力ピンを作成
print(p2.value()) # 値 0 または 1 を取得
p4 = Pin('D4', Pin.IN, Pin.PULL_UP) # 内部プルアップ抵抗を有効化
p7 = Pin('PA07', Pin.OUT, value=1) # 作成時にピンを high に設定
ピンは文字列または数字で表すことができます。文字列は "D0" や "SDA" などの各ボードのピンラベル、または "Pxnn" という形式で、x は A,B,C,D、nn は 0-31 の範囲の 2 桁の数値です。例:"PA03"、"PD31"
ピン番号は、次の範囲の MCU ポート番号です:
PA0..PA31: 0..31
PB0..PB31: 32..63
PC0..PC31: 64..95
PD0..PD31: 96..127
注記: Adafruit 社の Feather と ItsyBity ボードでは、D5 ピンが外部ゲート出力に接続されているため、入力としてのみ使用可能です。
UART (シリアルバス)
machine.UART を参照
# ItsyBitsy M4 board の UART 3 を使用
from machine import UART
uart3 = UART(3, tx=Pin('D1'), rx=Pin('D0'), baudrate=115200)
uart3.write('hello') # 5バイト書き出す
uart3.read(5) # 5バイトまで読み込む
uart = UART() # デフォルトの is, rx, tx の値を使用
uart = UART(baudrate=9600) # デフォルトの UART を指定のボーレートで使用
SAMD21/SAMD51 MCU には、最大 8 つのハードウェア SERCOM デバイスがあり、UART、SPI、I2C デバイスとして使えますが、すべての MCU 製品とボードで、すべての TX および RX ピンをユーザーが使えるわけではありません。デバイスと UART 信号へのピンの割り当てについては SAMD の入出力ピン を参照してください。id、rx、tx ピンが指定されていない場合は、デフォルト値が適用されます。最初の位置引数が指定されていれば、それは UART の id と見なされます。ボーレートを変更する場合、UART id を省略するのであれば、baudrate キーワードを使って指定する必要があります。
PWM (パルス幅変調)
SAMD21/SAMD51 MCU の最大5つのタイマーデバイスが PWM 信号の作成に使われます。
PWM 機能は machine.PWM クラスによって提供されます。そのクラスにリストされているすべての基本メソッドをサポートします。
# Adafruit ItsyBitsy M4 Express 用のサンプル
from machine import Pin, PWM
# ピンから PWM オブジェクトを作成し、周波数とデューティ比を設定
pwm = PWM(Pin('D7'), freq=2000, duty_u16=32768)
pwm.freq() # 現在の周波数を取得
pwm.freq(1000) # 周波数を設定/変更
pwm.duty_u16() # 現在のデューティ比(0-65535 の範囲)を取得
pwm.duty_u16(200) # 0-65535 の範囲でデューティ比を設定
pwm.deinit() # このピンの PWM を無効化
pwm # PWM オブジェクトのプロパティを表示
PWM コンストラクタ
- class PWM(dest, *, freq, duty_u16, duty_ns, invert, device)
以下のパラメータで新しいPWMオブジェクトを構築して、返します。
dest は PWM が出力されるエンティティです。
PWM オブジェクトは TCC タイマーモジュールによって提供されます。TCC タイマーモジュールは、最大で 6 チャンネル、8 出力を備えています。モジュールのすべてのチャンネルは同じ周波数で動作しますが、異なるデューティサイクルを許容します。出力は、モジュロ n 方式でチャンネルに割り当てられます(nはチャンネル数)。チャンネルの出力は、周波数とデューティレートは同じですが、極性は異なる場合があります。たとえば、モジュールに4つのチャンネルがある場合、出力 0 と 4、1 と 5、2 と 6、3 と 7 は、同じ周波数とデューティーレートを共有します。
duty_u16 と duty_ns は、一度に1つだけ指定する必要があります。
キーワード引数:
freq は PWM 周期の周波数を Hz 単位で設定する整数でなければなりません。有効な周波数範囲はそれぞれ 1Hz から 最大 24MHz までです
duty_u16 は、デューティ比を
duty_u16 / 65535の比率で設定します。duty_ns は、パルス幅をナノ秒単位で設定します。X チャンネルに対する制限も同様に適用されます。
invert=True|False: ビットを設定することにより、それぞれの出力が反転されます。
device=n: TCC モジュール n が利用可能であれば使用する。ピンによっては2つの TCC モジュールを使えます。デバイスが指定されていない場合は、PWM 信号にまだ使用されていないモジュールを使おうとします。しかし、ピンの周波数やデューティサイクルが同じであれば、同じ TCC モジュールで駆動しなければなりません。
PWM メソッド
メソッドは汎用的な machine.PWM クラスと同じですが、init() メソッドのキーワード引数が追加され、コンストラクタの引数と同じになります。
PWM のピン割当て
ピンは Pin クラスと同様に指定します。PWM 信号線のピン割当てについては SAMD の入出力ピン を参照してください。
ADC (アナログ/デジタル変換)
SAMD21/SAMD51 の ADC 機能は「Ann」とラベル付けされたピンで利用できます。
machine.ADC クラスを使います:
from machine import ADC
adc0 = ADC(Pin('A0')) # ADC ピンの ADC オブジェクトを average=16 で作成
adc0.read_u16() # 値を 0-65535 (0.0v - 3.3v)の範囲で読み込む
adc1 = ADC(Pin('A1'), average=1) # ADC ピンの ADC オブジェクトを average=1 で作成
ADC の分解能は12bitで、read_u16() が返す値とは関係なく、10~11bit の精度を持ちます。より高い分解能や精度が必要な場合は、外部 ADC を使用してください。
ADC コンストラクタ
- class ADC(dest, *, average=16, bits=12, vref=ADC.AREF, callback=None)
SAMD21/SAMD51 の ADC 機能は「Ann」とラベル付けされたピンで利用できます。
machine.ADC クラスを使います:
from machine import ADC
adc0 = ADC(Pin("A0")) # ADC ピンの ADC オブジェクトを average=16 で作成
adc0.read_u16() # 値を 0-65535 (0.0v - 3.3v)の範囲で読み込む
adc1 = ADC(Pin("A1"), average=1) # ADC ピンの ADC オブジェクトを average=1 で作成
ADC の分解能は、bits キーワードオプションで指定します。デフォルト値は 12 です。適切な値は 8, 10, 12 です。より高い分解能または精度が必要な場合は、外部 ADC を使ってください。average のデフォルト値は16です。この平均化の指定はノイズを低減するために使われます。値が16の場合、LSB ノイズは約1桁です。平均化が有効になっている場合、分解能は12ビットに強制されます。vref=n オプションは、ADCの基準電圧を設定します。デフォルト設定は3.3Vです。他に設定できる値は次のとおりです:
定数名 |
値 |
SAMD21 |
SAMD51 |
|---|---|---|---|
INT_VREF |
0 |
1.0V 基準電圧 |
1V の 内部バンドギャップリファレンス |
VDDA |
1 |
1/1.48 アナログ電圧供給 |
アナログ電圧供給 |
VDDA2 |
2 |
1/2 アナログ電圧供給 |
1/2 アナログ電圧供給 |
AREF |
3 |
外部リファレンス A (PA03) |
外部リファレンス A (PA03) |
AREFB |
4 |
外部リファレンス B (PA04) |
外部リファレンス B (PA04) |
AREFC |
5 |
外部リファレンス C (PA06) |
callback キーワードオプションは、周期 ADC サンプリングに使われます。コールバックは、すべてのデータがサンプリングされた後に実行されます。
ADC メソッド
- read_u16()
1つの ADC 値を符号なし16ビット量として読み出します。電圧範囲はコンストラクタの vref オプションで、分解能は bits オプションで定義します。
- read_timed(data, freq)
freq に指定した周期で ADC 値をデータバッファに読み込みます。バッファは事前に割り当てておく必要があります。値は bits オプションで指定されたバイナリ範囲の16ビット値として格納されます。bits=12 の場合、値の範囲は 0~4095 です。電圧範囲は vref オプションで定義されます。サンプリング周波数範囲は、bits と average の設定によって異なります。bits=8, average=1 の場合、最大レートはSAMD51で1MHz超、SAMD21で350kHzです。最小サンプリングレートは1Hzです。メソッドの呼び出しは即座に戻ります。データ転送はバックグラウンドでハードウェアタイマーによって制御されるDMAによって行われます。コンストラクタでコールバックが定義されている場合、すべてのデータが読み取られた後にコールバックが呼び出されます。あるいは busy() メソッドを使ってキャプチャが完了したかどうかを確認できます。
adc.read_timed() の呼び出しとコールバックの例:
from machine import ADC
from array import array
def finished(adc_o):
print("Sampling finished on ADC", adc_o)
# create ADC object on ADC pin A0, average=1
adc = ADC(Pin("A0"), average=1, callback=finished)
buffer = array("H", bytearray(512)) # 256 ADC 値の配列を作成
adc.read_timed(buffer, 10000) # 周期 10kHz で 256 の 12 ビット値を
# 読み込み、完了時に finished() を呼び出す。
- busy()
busy() は、read_timed() によるデータ取得が進行中の場合は True を返し、それ以外の場合は False を返します。
- deinit()
ADC オブジェクトを無効化し、それが使っていたリソース、特に ADC チャネルと read_timed() で使用されるタイマーを解放します。
DAC (デジタル/アナログ変換)
DAC Constructor
- class DAC(id, *, vref=3, callback=None)
DAC クラスは、デジタルからアナログへの高速変換を実現します。使用例:
from machine import DAC
dac0 = DAC(0) # DAC ピン A0 の DAC オブジェクトを作成
dac0.write(1023) # 電圧範囲 0.0V~3.3V を 0~4095の値で書き出す
dac1 = DAC(1) # DAC ピン A1 の DAC オブジェクトを作成
dac1.write(2000) # 電圧範囲 0.0V~3.3V を 0~4095の値で"書き出す
DAC の分解能は、SAMD51 では12ビット、SAMD21 では10ビットです。SAMD21 デバイスは、GPIO PA02 に1つの DAC チャンネルを持ち、ID として 0 のみを受け入れます。SAMD51 デバイスは、GPIO PA02 と PA05 に2つの DAC チャンネルを持ち、ID の値は 0 と 1 です。vref 引数は出力電圧範囲を定義し、コールバックオプションは dac_timed() で使われます。vref の適切な値は次のとおりです:
定数名 |
値 |
SAMD21 |
SAMD51 |
|---|---|---|---|
INT_VREF |
0 |
内部基準電圧 |
内部バンドギャップリファレンス(〜1V) |
VDDA |
1 |
アナログ電圧供給 |
アナログ電圧供給 |
AREF |
2 |
外部リファレンス |
バッファなし外部リファレンス |
AREFB |
3 |
バッファあり外部リファレンス |
DAC メソッド
- write(value)
選択した DAC 出力に1つの値を書き込みます。値の範囲は、SAMD21 の場合は 0-1023 で、SAMD51 の場合は 0-4095 です。電圧範囲は、vref の設定に依存します。
- write_timed(data, freq[, count=1])
dac_timed() 関数を呼び出すと、指定されたレートで一連のアナログ値を出力できます。データは、DAC の許容範囲((12 ビットのうち 10 ビット)の16ビット値を持つバッファである必要があります。freq の範囲は、SAMD21 の場合は 1Hz~200kHz、SAMD51 の場合は 1Hz~500kHz です。オプション引数 count は、データ出力が繰り返される頻度を指定します。範囲は 1 - (2**32 - 1) です。count が 0 の場合、deinit() が呼び出されて停止されるまでデータ出力が繰り返されます。データが count 回出力された場合、指定されていればコールバックが呼び出されます。
使用例:
from machine import DAC
from array import array
data = array("H", [i for i in range(0, 4096, 256)]) # ステップシーケンスを作成
def done(dac_o):
print("Sequence done at", dac_o)
dac = DAC(0, callback=done)
dac.write_timed(data, 1000, 10) # 1000値/秒のレートでデータを10回出力し、
# 完了時に done() を呼び出す。
データ転送は DMA によって行われ、Python コードの実行には影響されません。コールバック関数内で、変更されたパラメータを使って dac.write_timed() を再開することが可能です。
- busy()
write_timed() アクティビティが進行中かどうかを判定します。進行中の場合は True を、そうでない場合は False を返します。
- deinit()
DAC を無効化、DACが使用するリソース(特に DMA チャネルとタイマーなど)を解放します。ほとんどの SAMD21 ボードでは、dac.write_timed() と adc.read_timed() に使えるタイマーは1つしかありません。そのため、両方を同時に実行することはできず、タイマーを解放することが重要になる場合があります。DAC ドライバはかなりの電流を消費します。deinit() を実行すると、その消費電流も削減されます。deinit() を呼び出した後、DAC オブジェクトは使えなくなるため、再作成する必要があります。
ソフトウェア SPI バス
ソフトウェア SPI (ビットバンギング)はすべてのピンで動作し、 machine.SoftSPI クラスを介してアクセスします:
from machine import Pin, SoftSPI
# 与えたピンから SoftSPI バスを構築
# 極性 polarity は SCK のアイドル状態
# phase=0 は SCK の第1エッジでサンプルを意味、chase=1 は第2を意味
spi = SoftSPI(baudrate=100000, polarity=1, phase=0, sck=Pin('D7'), mosi=Pin('D9'), miso=Pin('D10'))
spi.init(baudrate=200000) # ボーレートを設定
spi.read(10) # MISO で 10 バイト読込み
spi.read(10, 0xff) # 10 バイト読込み、その間 MOSI に 0xff を出力
buf = bytearray(50) # バッファを作成
spi.readinto(buf) # 与えたバッファに読込み(この場合は 50 バイト)
spi.readinto(buf, 0xff) # 与えたバッファに読込み、MOSI に 0xff を出力
spi.write(b'12345') # MOSI に 5 バイト書込み
buf = bytearray(4) # バッファを作成
spi.write_readinto(b'1234', buf) # MOSI に書き込み、MISO からバッファに読み込み
spi.write_readinto(buf, buf) # MOSI に buf を書き込み、MISO から buf に読み込み
サポートしている最大ボーレートは 500000 です。
ハードウェア SPI バス
SAMD21/SAMD51 MCU には、最大 8 つのハードウェア SERCOM デバイスがあり、UART、SPI、I2C デバイスとして使えますが、すべての MCU 製品とボードがすべての信号ピンをユーザーに公開しているわけではありません。ハードウェア SPI は machine.SPI クラスを使ってアクセスしますこのクラスには先述のソフトウェア SPI と同じメソッドがあります:
from machine import SPI
spi = SPI(1, sck=Pin("SCK"), mosi=Pin("MOSI"), miso=Pin("MISO"), baudrate=10000000)
spi.write('Hello World')
SPI デバイスおよび信号へのピンの割り当てについては SAMD の入出力ピン を参照してください。id、miso、mosi、sck ピンを指定しない場合は、デフォルト値が適用されます。そのため、次のようにして SPI オブジェクトを作成できます。
from machine import SPI
spi = SPI() # デフォルトのデバイスとデフォルトのボーレートを使用
spi = SPI(baudrate=12_000_000) # デフォルトのデバイスを使い使用し、ボーレートを変更
MISO 信号を省略する場合は miso=None として定義する必要があります。最初の位置引数を指定した場合、それは SPI の id として扱われます。SPI の id を省略し、ボーレートを変更する場合は、baudrate キーワードを使って指定する必要があります。
注記: 現時点で最も信頼性の高いボーレートが 24MHz 程度であっても、特に高いボーレートでは、ボーレートの設定が必ずしもその通りの周波数になるとは限りません。
ソフトウェア I2C バス
ソフトウェア I2C (ビット・バンギングを使用)は、出力可能なすべてのピンで動作し、 machine.SoftI2C クラスを使ってアクセスします。
from machine import Pin, SoftI2C
i2c = SoftI2C(scl=Pin('D10'), sda=Pin('D11'), freq=100000)
i2c.scan() # scan for devices
i2c.readfrom(0x3a, 4) # read 4 bytes from device with address 0x3a
i2c.writeto(0x3a, '12') # write '12' to device with address 0x3a
buf = bytearray(10) # create a buffer with 10 bytes
i2c.writeto(0x3a, buf) # write the given buffer to the slave
サポートしている最大周波数は 400000 です。
ハードウェア I2C バス
SAMD21/SAMD51 MCU には、最大 8 つのハードウェア SERCOM デバイスがあり、UART、SPI、I2C デバイスとして使えますが、すべての MCU 製品とボードがすべての信号ピンをユーザーに公開しているわけではありません。デバイスと I2C 信号線のピン割当てについては SAMD の入出力ピン を参照してください。id、scl、sda ピンを指定しない場合はデフォルト値が適用されます。
ハードウェア I2C は machine.I2C クラスを使ってアクセスしますこのクラスには先述のソフトウェア I2C と同じメソッドがあります:
from machine import I2C
i2c = I2C(2, scl=Pin("SCL"), sda=Pin("SDA"), freq=400_000)
i2c.writeto(0x76, b"Hello World")
i2c2 = I2C() # id, scl, sda はデフォルト値を使用
i2c2 = I2C(freq=100_000) # デフォルトのデバイスを使い、freq を指定
最初の位置引数が指定された場合、それは I2C の id として扱われます。I2C の id を省略し、freq を変更する場合、freq キーワードを使って指定する必要があります。
OneWire ドライバー
OneWire ドライバーはソフトウェアで実装され、すべてのピンで動作します:
from machine import Pin
import onewire
ow = onewire.OneWire(Pin('D12')) # GPIO12 で OneWire バスを作成
ow.scan() # バス上のデバイスリストをスキャン
ow.reset() # バスをリセット
ow.readbyte() # 1バイト読込み
ow.writebyte(0x12) # バスに1バイト書込み
ow.write('123') # バスに複数バイト書込み
ow.select_rom(b'12345678') # ROM コードで指定したデバイスを選択
DS18S20 と DS18B20 のデバイスに対応したドライバが用意されています:
import time, ds18x20
ds = ds18x20.DS18X20(ow)
roms = ds.scan()
ds.convert_temp()
time.sleep_ms(750)
for rom in roms:
print(ds.read_temp(rom))
4.7k のプルアップ抵抗をデータラインに接続してください。convert_temp() メソッドは、温度をサンプリングするたびに呼び出す必要があることに注意してください。
DHT ドライバー
DHT ドライバーはソフトウェアで実装され、すべてのピンで動作します:
import dht
import machine
d = dht.DHT11(machine.Pin('D4'))
d.measure()
d.temperature() # 例: 23 (°C)
d.humidity() # 例: 41 (% RH)
d = dht.DHT22(machine.Pin('D4'))
d.measure()
d.temperature() # 例: 23.6 (°C)
d.humidity() # 例: 41.3 (% RH)
4.7k のプルアップ抵抗をデータラインに接続してください。DHT モジュールの中にはプルアップ抵抗が実装済みのものもあります
APA102 LED の駆動
一部の Adafruit ボードにある APA102 は SoftSPI で制御できます:
from machine import SoftSPI, Pin
# SPI オブジェクトを作成。miso は未使用のピンのどれでもよい。
spi=SoftSPI(sck=Pin('D25'), mosi=Pin('D26'), miso=Pin('D14'))
# プリアンブルとポストフィックスを持つデータを書き込むための# 小さな関数を定義
def write(red, green, blue):
spi.write(b"\x00\x00\x00\x00\xff")
spi.write(bytearray((blue, green, red)))
spi.write(b"\xff\xff\xff")
# LED を赤に設定
write(128, 0, 0)
SoftSPI では miso を未定義にできないため、miso を未使用のピンに割り当てる必要があります。
Neopixel LED の駆動
組込みの machine.bitstream() メソッドは、MicroPython ドライバーライブラリにあるNeopixel ドライバーと組み合わせて、NeoPixel LED の駆動をサポートします:
import neopixel
import machine
# Adafruit Feather ボードの Pin D8 に繋げられている 1 LED
p = machine.Pin(8, machine.Pin.OUT)
n = neopixel.NeoPixel(p, 1)
# LED を赤に設定
n[0] = (128, 0, 0)
# LED の表示を更新
n.write()
machine.bitstream() は、SAMD21 のクロック周波数 48MHz と SAMD51 のクロック周波数 120MHz を想定して設定されています。他のクロック周波数では、タイミングが合いません。
ファイル転送
mpremote ツールを使って、SAMD21/SAMD51 デバイスにファイルを転送できます。SAMD21/SAMD51 ボードにファイルを転送する方法として、コミュニティがサポートする代替手段(rshell や Thonny など)については MicroPython フォーラムを参照してください。