-
Notifications
You must be signed in to change notification settings - Fork 0
TWIM
最小フットプリントの、二線式I2C通信主装置用TWIM_Class
基本クラス。
Arduino互換APIの<Wire.h>
を代替する。
最大1000kbpsに対応する。
割込も計時器周辺機能もFIFOバッファも使用しない。
従って全体割り込み禁止中でも、割込ハンドラの中からでも使用できる。
最低速度は 0bps以上。クロックストレッチングに対応する。
主装置専用で、従装置機能や二元制御機能はない。
reduceAVR は未対応
有効ならENABLE_CLASS_TWI
マクロに1が定義される。
クラスインスタンスはスケッチ.ino
では自動で設定され、無宣言で使用できる。
そうでなければ<peripheral.h>
({build.variant}
に置かれている)
をインクルードすることで準備される。
<Wire.h>
とコード互換性のある書き方をする場合は次の通り。
ただし完全な機能互換ではないことに注意。
/* #include <peripheral.h> */ /* *.ino 以外 */
void setup (void) {
Wire.begin(); /* Standard Mode speed setting */
}
void loop (void) {
const uint8_t i2c_addr = 0x51; /* Target 7bit addr */
Wire.beginTransmission(i2c_addr); /* Send Start condition and Write addr-field 0xA2 */
Wire.write(0x04); /* Set target register addr */
Wire.endTransmission(false); /* Send Repeat condition */
Wire.requestFrom(i2c_addr, 2) /* Read addr-field 0xA3 and 2 read length */
int c = Wire.read(); /* Get target register 1 byte */
int d = Wire.read(); /* Get target register next byte */
Wire.endTransmission(true); /* Stop contdition */
}
この<api/TWIM.h>
本来の記法は次の通り。
#include <peripheral.h>
/* #include <TWIM.h> */
void setup (void) {
Wire.initiate(TWI_SM); /* Standard Mode speed setting */
}
void loop (void) {
const uint8_t i2c_addr = 0x51; /* Target 7bit addr */
uint8_t *buffer[2];
Wire
.start(i2c_addr) /* Send Start condition and Write addr-field 0xA2 */
.write(0x04) /* Set target register addr */
;
Wire /* Auto Repeat Condition */
.request(i2c_addr, 2) /* Read addr-field 0xA3 and 2 read length */
.read(&buffer, 2) /* Get target register 2 bytes */
; /* Auto Stop Condition */
}
依存性:<avr/io.h>
<avr/pgmspace.h>
<util/atomic.h>
<Portmux.h>
<Print.h>
<peripheral.h>
デフォルトインスタンスを指すWire
は通常、Wire0
を指すエイリアスである。
更にWire0
はWire0A
を指すように定義されている。
<peripheral.h>
で定まる事前定義は次のようになっている。
対応する SCL/SDA 入出力外部端子ペアは一意に決まっているので、
そのバリアントで使えない定義は存在しない。
定義されていても実体が使われないインスタンスは
最終出力 HEX/bin には書き出されない。
#ifndef Wire
#define Wire Wire0 /* 代表エイリアス */
#endif
#define Wire0 Wire0A
#define Wire1 Wire1A
;;;
TWIM_Class Wire0A {&TWI0, &_portmux_twi0a}; /* TWI0_DEFAULT */
TWIM_Class Wire0B {&TWI0, &_portmux_twi0b}; /* TWI0_ALT_1 */
TWIM_Class Wire0C {&TWI0, &_portmux_twi0c}; /* TWI0_ALT_2 */
TWIM_Class Wire0D {&TWI0, &_portmux_twi0d}; /* TWI0_ALT_3 */
TWIM_Class Wire1A {&TWI1, &_portmux_twi1a}; /* TWI1_DEFAULT */
TWIM_Class Wire1B {&TWI1, &_portmux_twi1b}; /* TWI1_ALT_1 */
TWIM_Class Wire1C {&TWI1, &_portmux_twi1c}; /* TWI1_ALT_2 */
TWIM_Class Wire1D {&TWI1, &_portmux_twi1d}; /* TWI1_ALT_3 */
プライマリが
0
、以後追加ポート以降に1
2
... の識別子が付く。
PORTMUX の DEFAULT選択がA
、ALTERNATE_1がB
、以後C
D
... の接尾子が付く。
インスタンスが複数あっても同一周辺機能なら同時使用できないことに注意。
どの型番でどの周辺機能が使用できるかは [modernAVR 周辺機能比較一覧] を参照のこと。
指定の通信速度で I2C主装置動作を開始する。第一引数省略時は 100kbps。 第二引数には内蔵プルアップの有無を bool値で指定する。省略時は内蔵プルアップ有効。
- 引数はArduino互換APIと異なる。省略時のみ一致。
- 外部プルアップが実装されているなら(リーク電流を断つため)false 指定で内蔵プルアップを無効にすべき。
- しかし HOTSWAP可能な構成の場合、どこからもプルアップされていない状態になったなら、 ハングアップを生じる。
この関数は事前コンパイル済定数ではない通信速度を渡すと32bitの整数除算を伴うため実装記憶を無駄にする。
内部的には計算結果でinitiate
を呼び出している。
動作速度範囲は F_CPU
に依存し、制御範囲外になる場合は正しく動作しない。
CPU主クロックは設定ボーレートの 4倍以上 512倍未満でなければならない。
自身のオブジェクトを返すので、メソッドチェーンが後続できる。
指定の通信速度ラベルで、I2C主装置動作を開始する。
定数ラベルは<api/Portmux_private.h>
で事前定義されており、
TWI_SM
TWI_FM
TWI_FMP
が使用でき、
それぞれ 100k 400k 1000k bps を意味する。
除算は使われない。
第二引数には内蔵プルアップの有無を bool値で指定する。省略時は内蔵プルアップ有効。
- 外部プルアップが実装されているなら(リーク電流を断つため)false 指定で内蔵プルアップを無効にすべき。
- しかし HOTSWAP可能な構成の場合、どこからもプルアップされていない状態になると問題を生じる。
動作速度範囲は F_CPU
に依存するが、範囲外の場合は可能な限りの最大・最低速度に設定される。
- 定数ラベルでの設定値は内蔵プルアップ抵抗向けに理想値より幾分遅くなるよう補正されている。
制御開始時にはダミークロックを送出し、NACK
を検出するまで待機することで
回路リセット後の I2Cバス調停異常を回避すべく善処する。
(この機能は Arduino互換APIにはない。詳しくはI2Cバス仕様書を参照のこと)
自身のオブジェクトを返すので、メソッドチェーンが後続できる。
主装置動作を終了して専有していた外部端子を開放する。
データがまだ送信中または受信中にこれを行うと強制断となるので
(I2Cバスが異常状態で無いならば)stop
を先に使用する。
従装置アドレスを指定して、start condition と stop condition を続けて発効する。
従装置がACK
を返したならtrue
を、そうでなければfalse
を返す。
従装置が SMBus 装置でかつ BUS休眠動作に入っていたなら、 これはその従装置を活性化させるだろう。
従装置アドレスを指定して、start condition を発行する。
成功するとI2Cバスは送信制御方向になりwrite
可能になる。
アドレス送信が完了し、ACK
/NACK
が確定するまで制御は戻らない。
従装置が応答したならis_ack
は真を返す。
自身のオブジェクトを返すので、メソッドチェーンが後続できる。
_count
は stop condition を自動発行(stop)するまでにwrite
するバイト数を
事前に指定する。省略したならstop
かrequest
が必要。
request
が後続するなら省略しなければならない。
stop condition を必要なら発行する。
現在送受信が進行中ならばそれが済むまで待たされる。
start
または
write
のあとrequest
が不要ならこれを用いる。
そうでなければ通常は自動的に状態制御されるので必要ない。
request
のあと途中で受信処理を中断するならば
あるいはCPU休止状態に遷移しようとしているならば
これを用いる。
自身のオブジェクトを返すので、メソッドチェーンが後続できる。
1バイトを書く。書けたなら 1を返す。 書くことが出来ないバス状態であれば 0を返す。 送信緩衝バッファにまだ前のデータが残っているなら空くまで待機する。 全体割込禁止中でも使える。
指定のバッファから指定の量を書き出す。書けた量を返す。
- Arduino互換APIのWireでは普通 31バイトまでしか書けないが
これは
SIZE_MAX-1
まで連続して書ける。
従装置アドレスと要求量_count
を指定して start/repeat condition を発行する。
要求量は 1以上SIZE\_MAX-1
以下の範囲で指定できる。
アドレス送信が完了し、ACK
かNACK
が確定するまで制御は戻らない。
従装置が応答したならis_ack
は真を返しread
可能になる。
自身のオブジェクトを返すので、メソッドチェーンが後続できる。
- Arduino互換APIのWireでは普通 31までしか指定できないが
これは
SIZE_MAX-1
まで許容する。
受信緩衝バッファから1バイトを読む。
読める状態になければ待機する。
全体割込禁止中でも使える。
request
で指定した要求量に達すると
その最後の読み取りで自動的にNACK
応答と stop condition が発行される。
要求量に達してもうそれ以上読めないかis_fail
が真であるなら -1 を返す。
指定の作業バッファに指定量まで読み込む。
読める状態になければ待機する。
実際に読めた量を返す。
request
で指定した要求量に達するとそこで打ち切られ
NACK
と stop condirion を発行する。
指定の作業バッファに指定量までを「逆順に」読み込む。
読める状態になければ待機する。
実際に読めた量を返す。
読めた結果はバッファ後方、右詰めとなることに注意。
request
で指定した要求量に達するとそこで打ち切られ
NACK
と stop condirion を発行する。
このメソッドは Big endian で結果を返却するデバイスに有用。
request
で指定した要求量の残量を返す。
それ以上read
できないなら 0を返す。
write
可能かを調べ、書けるなら1を返す。
従装置がNACK
を返したか、書けなければ 0を返す。
機能しない。常に -1 を返す。
機能しない。送受信作業バッファを持たず割込通知もないので何もしない。
print文とその派生メソッドは<api/Print.h>
を参照のこと。
現在の主装置速度値(TWIn.MBAUD レジスタの値)を返す。
これはinitiate
の第一引数に直接渡すことが出来る 0〜255 の数値である。
通信対象との相性や F_CPU
に対するジッタ、プルアップ抵抗値、配線環境によっては、
この値を加減しなければならない。(バスインピーダンス依存)
現在の主装置状態(TWI[01]_MSTATUS
レジスタの値)を返す。
TWI_BUSSTATE_gm
とで論理積を取ると次の値が得られる。
-
TWI_BUSSTATE_UNKNOWN_gc
-- I2Cバス状態不明(未初期化) -
TWI_BUSSTATE_IDLE_gc
-- I2Cバス待機状態(start/request可能) -
TWI_BUSSTATE_OWNER_gc
-- I2Cバス主導権獲得中(request可能) -
TWI_BUSSTATE_BUSY_gc
-- I2Cバス多忙中(他装置制御中)
その他に以下のビット情報が得られる。
-
TWI_BUSERR_bm
-- I2Cバス異常検出(他装置衝突) -
TWI_ARBLOST_bm
-- I2Cバス調停敗退(他装置制御中)- このいずれかが真なら
is_fail
は真を返す。
- このいずれかが真なら
-
TWI_RXACK_bm
-- 従装置NACK
検出- 以上3種がすべて偽なら
is_ack
は真を返す。
- 以上3種がすべて偽なら
-
TWI_CLKHOLD_bm
-- I2Cバスクロック送出保持中-
start
/request
成功
-
- TWI_WIF_bm -- データ緩衝レジスタ送出完了
-
start
/request
完了+write
/request
可 - 送信成功という意味ではない
-
-
TWI_RIF_bm
-- データ緩衝レジスタ受信完了-
read
可 - 受信成功という意味ではない
- 受信完了+
NACK
は正当で、それ以上受信するデータはないと解釈する
-
受信完了と送信完了は排他で、同時に立つことはない。
addr/data 送出 完了 後の従装置の最新応答がACK
であるなら
(かつバスエラーでも調停敗退でも無ければ)
真を返す。
/* I2Cバススキャン(scanメソッドを使わずに書いた場合)*/
Wire.begin();
/* 予約アドレスは除く */
for (uint8_t addr = 8; addr < 0x78; addr++) {
if (Wire.start(addr) /* 7bitアドレスを送信 */
.is_ack()) { /* ACK が返ればそのアドレスで従装置は存在する */
/* found ! */
}
Wire.stop(); /* I2Cバス開放 */
}
Wire.end(); /* 制御終了 */
I2Cバス制御を損ねた状態ならば真を返す。
そうであるならend
を実行すべき。
一番最後に受信した、正当なバイトを保持している。
write(_c)
の代替で、メソッドチェーン可能。
_c
はchar
int
long
でもよい。
write(_buffer, _length)
の代替で、メソッドチェーン可能。
_buffer
はconst PGM_t*
型でも良い。
read(_buff, _length)
の代替で、メソッドチェーン可能。
reverse_read(_buff, _length)
の代替で、メソッドチェーン可能。
連続するsend
系メソッドがwrite
した総量を返す。
メソッドチェーンの最後で呼ぶと便利。
start
メソッドでリセットされる。
連続するrecv
系メソッドがread
した総量を返す。
メソッドチェーンの最後で呼ぶと便利。
request
メソッドでリセットされる。
送信緩衝バッファが空くのを待つ。 自身のオブジェクトを返すので、メソッドチェーンが後続できる。
受信緩衝バッファが満たされるのを待つ。 自身のオブジェクトを返すので、メソッドチェーンが後続できる。
I2Cバスが待機状態以外になるのを待つ。 バスエラーを検出してもループを抜ける。 自身のオブジェクトを返すので、メソッドチェーンが後続できる。
I2Cバスが待機状態になるのを待つ。 自身のオブジェクトを返すので、メソッドチェーンが後続できる。
I2Cバスが制御権獲得状態になるのを待つ。 自身のオブジェクトを返すので、メソッドチェーンが後続できる。
Arduino互換APIのWire
クラスに対する互換メソッド群。
それぞれTWIM
クラスの同等メソッドにマッピングされるか、あるいは何もしない。
返値もダミーであって実際のエラーを返さない。
互換記述ではその仕様上、動作速度は 100kbps 固定となる。
(クロック指定方法が異なる+setClock
は機能しない)
Twitter(X): @askn37
BlueSky Social: @multix.jp
GitHub: https://github.com/askn37/
Product: https://askn37.github.io/
Copyright (c) 2022,2023 askn (K.Sato) multix.jp
Released under the MIT license
https://opensource.org/licenses/mit-license.php
https://www.oshwa.org/
multix.jp/てくにかるむ(休眠中)
Multix Zinnia Product SDK [*AVR]
AVR.JP(日本語訳)
AVR-LIBC(日本語訳)