Skip to content
朝日薫 edited this page Dec 31, 2022 · 8 revisions

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 */
}

<api/TWIM.h>

依存性:<avr/io.h> <avr/pgmspace.h> <util/atomic.h> <Portmux.h> <Print.h> <peripheral.h>

#define Wire Wire0

デフォルトインスタンスを指すWireは通常、Wire0を指すエイリアスである。 更にWire0Wire0Aを指すように定義されている。

<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 周辺機能比較一覧] を参照のこと。

TWIM_Class& begin (const uint32_t _baudrate = 100000L, bool _pullup = true)

指定の通信速度で I2C主装置動作を開始する。第一引数省略時は 100kbps。 第二引数には内蔵プルアップの有無を bool値で指定する。省略時は内蔵プルアップ有効。

  • 引数はArduino互換APIと異なる。省略時のみ一致。
  • 外部プルアップが実装されているなら(リーク電流を断つため)false 指定で内蔵プルアップを無効にすべき。
  • しかし HOTSWAP可能な構成の場合、どこからもプルアップされていない状態になったなら、 ハングアップを生じる。

この関数は事前コンパイル済定数ではない通信速度を渡すと32bitの整数除算を伴うため実装記憶を無駄にする。 内部的には計算結果でinitiateを呼び出している。 動作速度範囲は F_CPU に依存し、制御範囲外になる場合は正しく動作しない。

CPU主クロックは設定ボーレートの 4倍以上 512倍未満でなければならない。

自身のオブジェクトを返すので、メソッドチェーンが後続できる。

TWIM_Class& initiate (const uint8_t _baudrate, bool _pullup = true)

指定の通信速度ラベルで、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バス仕様書を参照のこと)

自身のオブジェクトを返すので、メソッドチェーンが後続できる。

void end (void)

主装置動作を終了して専有していた外部端子を開放する。

データがまだ送信中または受信中にこれを行うと強制断となるので (I2Cバスが異常状態で無いならば)stopを先に使用する。

bool scan (const uint8_t _addr)

従装置アドレスを指定して、start condition と stop condition を続けて発効する。 従装置がACKを返したならtrueを、そうでなければfalseを返す。

従装置が SMBus 装置でかつ BUS休眠動作に入っていたなら、 これはその従装置を活性化させるだろう。

TWIM_Class& start (const uint8_t _addr, size_t _count = ~0)

従装置アドレスを指定して、start condition を発行する。 成功するとI2Cバスは送信制御方向になりwrite可能になる。

アドレス送信が完了し、ACK/NACKが確定するまで制御は戻らない。 従装置が応答したならis_ackは真を返す。

自身のオブジェクトを返すので、メソッドチェーンが後続できる。

_countは stop condition を自動発行(stop)するまでにwriteするバイト数を 事前に指定する。省略したならstoprequestが必要。 requestが後続するなら省略しなければならない。

TWIM_Class& stop (void)

stop condition を必要なら発行する。 現在送受信が進行中ならばそれが済むまで待たされる。 startまたは writeのあとrequestが不要ならこれを用いる。

そうでなければ通常は自動的に状態制御されるので必要ない。 requestのあと途中で受信処理を中断するならば あるいはCPU休止状態に遷移しようとしているならば これを用いる。

自身のオブジェクトを返すので、メソッドチェーンが後続できる。

size_t write (const uint8_t _c)

1バイトを書く。書けたなら 1を返す。 書くことが出来ないバス状態であれば 0を返す。 送信緩衝バッファにまだ前のデータが残っているなら空くまで待機する。 全体割込禁止中でも使える。

size_t write (const uint8_t* _buffer, size_t _length)

指定のバッファから指定の量を書き出す。書けた量を返す。

  • Arduino互換APIのWireでは普通 31バイトまでしか書けないが これはSIZE_MAX-1まで連続して書ける。

TWIM_Class& request (const uint8_t _addr, size_t _count)

従装置アドレスと要求量_countを指定して start/repeat condition を発行する。 要求量は 1以上SIZE\_MAX-1以下の範囲で指定できる。 アドレス送信が完了し、ACKNACKが確定するまで制御は戻らない。 従装置が応答したならis_ackは真を返しread可能になる。

自身のオブジェクトを返すので、メソッドチェーンが後続できる。

  • Arduino互換APIのWireでは普通 31までしか指定できないが これはSIZE_MAX-1まで許容する。

int read (void)

受信緩衝バッファから1バイトを読む。 読める状態になければ待機する。 全体割込禁止中でも使える。 requestで指定した要求量に達すると その最後の読み取りで自動的にNACK応答と stop condition が発行される。 要求量に達してもうそれ以上読めないかis_failが真であるなら -1 を返す。

size_t read (uint8_t* _buff, size_t _length)

指定の作業バッファに指定量まで読み込む。 読める状態になければ待機する。 実際に読めた量を返す。 requestで指定した要求量に達するとそこで打ち切られ NACKと stop condirion を発行する。

size_t reverse_read (void* _buff, size_t _length)

指定の作業バッファに指定量までを「逆順に」読み込む。 読める状態になければ待機する。 実際に読めた量を返す。 読めた結果はバッファ後方、右詰めとなることに注意。 requestで指定した要求量に達するとそこで打ち切られ NACKと stop condirion を発行する。

このメソッドは Big endian で結果を返却するデバイスに有用。

size_t available (void)

requestで指定した要求量の残量を返す。 それ以上readできないなら 0を返す。

size_t availableForWrite (void)

write可能かを調べ、書けるなら1を返す。 従装置がNACKを返したか、書けなければ 0を返す。

int peek (void)

機能しない。常に -1 を返す。

void flush (void)

機能しない。送受信作業バッファを持たず割込通知もないので何もしない。

Print& print (...)

print文とその派生メソッドは<api/Print.h>を参照のこと。

uint8_t is_baud (void)

現在の主装置速度値(TWIn.MBAUD レジスタの値)を返す。 これはinitiateの第一引数に直接渡すことが出来る 0〜255 の数値である。

通信対象との相性や F_CPU に対するジッタ、プルアップ抵抗値、配線環境によっては、 この値を加減しなければならない。(バスインピーダンス依存)

uint8_t is_status (void)

現在の主装置状態(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は真を返す。
  • TWI_CLKHOLD_bm -- I2Cバスクロック送出保持中
    • start/request成功
  • TWI_WIF_bm -- データ緩衝レジスタ送出完了
    • start/request完了+write/request
    • 送信成功という意味ではない
  • TWI_RIF_bm -- データ緩衝レジスタ受信完了
    • read
    • 受信成功という意味ではない
    • 受信完了+NACKは正当で、それ以上受信するデータはないと解釈する

受信完了と送信完了は排他で、同時に立つことはない。

bool is_ack (void)

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();    /* 制御終了 */

bool is_fail (void)

I2Cバス制御を損ねた状態ならば真を返す。 そうであるならendを実行すべき。

uint8_t last_read (void)

一番最後に受信した、正当なバイトを保持している。

TWIM_Class& send (const uint8_t _c)

write(_c)の代替で、メソッドチェーン可能。 _cchar int longでもよい。

TWIM_Class& send (const uint8_t* _buffer, size_t _length)

write(_buffer, _length)の代替で、メソッドチェーン可能。 _bufferconst PGM_t*型でも良い。

TWIM_Class& recv (void* _buff, size_t _length)

read(_buff, _length)の代替で、メソッドチェーン可能。

TWIM_Class& reverse_recv (void* _buff, size_t _length)

reverse_read(_buff, _length)の代替で、メソッドチェーン可能。

size_t write_size (void)

連続するsend系メソッドがwriteした総量を返す。 メソッドチェーンの最後で呼ぶと便利。 startメソッドでリセットされる。

size_t read_size (void)

連続するrecv系メソッドがreadした総量を返す。 メソッドチェーンの最後で呼ぶと便利。 requestメソッドでリセットされる。

TWIM_Class& loop_until_is_write (void)

送信緩衝バッファが空くのを待つ。 自身のオブジェクトを返すので、メソッドチェーンが後続できる。

TWIM_Class& loop_until_is_read (void)

受信緩衝バッファが満たされるのを待つ。 自身のオブジェクトを返すので、メソッドチェーンが後続できる。

TWIM_Class& loop_until_busy_idle (void)

I2Cバスが待機状態以外になるのを待つ。 バスエラーを検出してもループを抜ける。 自身のオブジェクトを返すので、メソッドチェーンが後続できる。

TWIM_Class& loop_until_is_idle (void)

I2Cバスが待機状態になるのを待つ。 自身のオブジェクトを返すので、メソッドチェーンが後続できる。

TWIM_Class& loop_until_is_owner (void)

I2Cバスが制御権獲得状態になるのを待つ。 自身のオブジェクトを返すので、メソッドチェーンが後続できる。

void setClock (uint32_t frequency)

void beginTransmission (uint8_t address)

uint8_t endTransmission (bool sendStop = true)

uint8_t requestFrom (uint8_t address, size_t quantity, bool sendStop = true)

Arduino互換APIのWireクラスに対する互換メソッド群。 それぞれTWIMクラスの同等メソッドにマッピングされるか、あるいは何もしない。 返値もダミーであって実際のエラーを返さない。 互換記述ではその仕様上、動作速度は 100kbps 固定となる。 (クロック指定方法が異なる+setClockは機能しない)

LINKS

multix.jp/てくにかるむ(休眠中)
Multix Zinnia Product SDK [*AVR]
AVR.JP(日本語訳)
AVR-LIBC(日本語訳)

Clone this wiki locally