/      English

mwf_periph_spi - SPI

mwf_periph_spi - SPI
SPIバスを利用するためのクラスオブジェクトです。

mwf_periph_spi - SPI

SPIバスを利用するためのクラスオブジェクトthe_spi1を実装しています。

  • SPI0 の対応コードは含まれません。
  • 一部 non blocking (非ブロック) を想定した定義が含まれますが、現バージョンでは blocking (ブロック) の API のみ利用可能です。

コード例

#include "mwf_periph_spi.hpp"

void func_spi_init() {
    if (!mwf::the_spi1) {
        mwf::spi::global_init_spi1_manager();
        Serial << crlf << "the_spi1 constructed.";
    }

    mwf::spi::config conf{};
    conf.baud = 4000000UL; // 4MHz
    conf.bits = 8;         // 8bit
    conf.dir  = mwf::spi::E_SPI_DIR::MSB_FIRST;
    conf.mode = mwf::spi::E_SPI_MODE::MODE_3_INV_RISE;
    conf.pin_ssel[0] = mwf::spi::E_PIN_SSEL::SSEL0_PIO3;
    conf.pin_ssel[1] = mwf::spi::E_PIN_SSEL::SSEL1_PIO16;
    mwf::the_spi1->init(conf);
}

void func_spi_transfer() {
    uint8_t tx[16] = { 0xa5, 0x5a, 0x11, 0x88 }; // data to transmit
    uint8_t rx[16];                              // receive buffer

    mwf::the_spi1->ssel_select(0);
    mwf::the_spi1->transfer_blocking(tx, rx, 4); // four bytes transfer
    CLOCK_uDelay(5); // wait 5us
    mwf::the_spi1->transfer_blocking(tx, rx, 4); // four bytes transfer
    mwf::the_spi1->ssel_deselect();
}

class mwf::periph::spi

struct config

mwf::periph::spi::config構造体は以下のように定義されています。

struct config {
    // evaluated only in init()
    E_PIN_MAIN pin_conf;    // master pin configuration (so far not used)
    E_PIN_SSEL pin_ssel[3]; // SSEL0..2 (assignment settings for slave select pins.
                            // At least pin_ssel[0] shall be configured.

    // evaluated in conf(), reconf()
    uint32_t baud;      // SPI frequency (default 50Mhz)
    E_SPI_DIR dir;      // transfer LSB first
    E_SPI_MODE mode;	// SPI mode (clock polarity and detect edge)
    uint8_t bits;       // bit width (0:default=8, ...)
    uint8_t ssel;       // 0..3 or 0x80..0x80 (if MSB is set, assert/deassert SSEL automatically)
};

構造体に値を設定してinit()を呼び出します。init()中で構造体の設定値は内部的にコピーされますので、呼び出し後は構造体領域を破棄しても構いません。

構造体の各メンバーの解説です。

信号名解説
pin_conf使用するピン割り当て(主・副)の指定を行います。E_PIN_CONF::NODEF(=0)を選択した場合は global_init_spi1_manager() の指定を利用します。
pin_ssel[3]SELECTピンを指定します。配列の0番目はSPI SELECTの0番目(SSEL0)のピン、1番目はSSEL1、2番目はSSEL2を指定します。SSEL0は必ず指定し SSEL1,2 は E_PIN_SSEL::SSEL_VOID=0にしておきます。ピンを2種類利用する場合は SSEL0, SSEL1 を指定し、3種類の場合は全てに値を格納します。
※ソフトウェア制御のピン(E_PIN_SSEL::SSEL0_PIO3 など )を指定した場合は、すべてのセレクトピンはソフトウェアによる制御を行います。ソフトウエア制御ではピンはHIGHレベルで常時出力設定となり、セレクト時に対象ピンが LOW レベルに変化します。なお、TWENETcmpt (AHIライブラリ互換) ではソフトウェア制御を用いています。
※ハードウェア制御の場合 SELECT ピンの制御は fsl_spi.c のSPI_MasterTransferNonBlocking() の動作に倣います。
baudSPIのクロック周波数を指定します。32Mhz まで設定可能ですがセンサーデバイスなどは 1Mhz 前後がよく使われます。
(動作は、fsl_spi.h の spi_master_config_t::bandRate_Bps, fsl_spi.c のSPI_MasterSetBaud()に倣います)
modeSPISELはinit()で指定します。
bits転送単位です。通常は8を指定します。1..16まで設定できます。9ビット以上の場合、データ転送時に指定するバイト配列は2バイト単位で読み出されるため、データ数の二倍必要で、1バイト目が LSB から 8ビット分2バイト目が 残りのビットを表現します。
(動作は、fsl_spi.hのSPI_MasterTransferBlocking()に倣います)
sselSPIのSELECTです。0..2 を指定します。

enum class E_PIN_CONF

enum class E_PIN_CONF : uint8_t {
    NODEF = 0,   // 未指定
    PRIMARY = 1, // 主割り当て (PIO10/11)
    ALT = 2      // 副割り当て (PIO15/16)
};
// enum class と int 型の代入、比較等をするための型。
using wE_PIN_CONF = mwf::enum_wapper<E_PIN_CONF>;

ピン割り当てを指定するための列挙体です。

enum class E_PIN_SSEL

enum class E_PIN_SSEL : uint8_t {
    SSEL_VOID = 0, // 未定義
    SSEL_PRIMARY,  // 主設定ピン
    SSEL_ALT,      // 副設定ピン
    SSEL_SOFT = 0x10,
    SSEL0_PIO3,  // SSEL0 をソフトウェア制御し PIO3 を使用する
    SSEL1_PIO16, // SSEL1 をソフトウェア制御し PIO16 を使用する
    SSEL2_PIO17, // SSEL2 をソフトウェア制御し PIO17 を使用する
    SSEL1_PIO4,  // SSEL1 をソフトウェア制御し PIO4 を使用する
    SSEL2_PIO13, // SSEL2 をソフトウェア制御し PIO13 を使用する
};

この列挙体はSPI SELECTピンの配置を決めます。spi::confg::pin_ssel[3]に対応する値か保存されます。

  • 利用デバイス数に応じてpin_ssel[]を設定します。

    • 1つの場合 pin_ssel[0]を設定。pin_ssel[1], pin_ssel[2]SSEL_VOID
    • 2つの場合 pin_ssel[0]pin_ssel[1]を設定。pin_ssel[2]SSEL_VOID
    • 3つの場合 pin_ssel[0],pin_ssel[1], pin_ssel[2] を設定。
  • ハードウェア制御を指定する場合SSEL_PRIMARYまたはSSEL_ALT (および SSEL_VOID)を指定します。混在させた場合は、ソフトウェア制御となります。

enum class E_SPI_DIR

enum class E_SPI_DIR {
    MSB_FIRST = 0,
    LSB_FIRST
};

ビットの並び順を指定します。通常は MSB_FIRST です。

enum class E_SPI_MODE

enum class E_SPI_MODE {
    MODE_0_RISE = 0,
    MODE_1_FALL = 1,
    MODE_2_INV_FALL = 2,
    MODE_3_INV_RISE = 3,
};

SPI転送モードの指定です。クロックの判定エッジと、その時の H/L の値を 0 とするか 1 とするかを決めます。接続デバイスのデータシートに従い設定します。

global_init_spi1_manager(), global_deinit_spi1_manager()

static void global_init_spi1_manager(E_PIN_MAIN pin_conf = E_PIN_MAIN::PRIMARY);
static void global_deinit_spi1_manager();

SPI1のバスを利用するためのクラスオブジェクトの生成と破棄を行います。クラスオブジェクト生成時にpin_confにより利用するためのピンの組み合わせを選択します。ピン設定の指定は E_PIN_MAIN::PRIMARY 値:0 及びE_PIN_MAIN::ALT 値:1を指定できます。

init()

void init();
void init(spi::config& cnf);
void init(spi::config&& cnf);

SPIバスを初期化します。パラメータcnfを与えることでいくつかの設定を行います。パラメータを省略した場合は、以前の設定を用いて最初期化します。

  • セレクトピンをユーザプログラムでソフトウェア制御する場合であっても、必ず1つは指定してください。指定されたピンはGPIOの出力として設定されます。unset_ssel_auto() を呼び出しておけば、当該ピンに対するライブラリによる制御は行われなくなります。

reconf()

void reconf();

ペリフェラルのパラメータを再反映します。内部設定にアクセスするには spi::config& get_conf() を用います。この手続でピンの設定 (pin_ssel[])は反映されません。

set_data_width()

void set_data_width(uint8_t bits);

転送データ幅を変更します。reconf()より軽い手続きです。

set|unset|get_ssel_auto()

void set_ssel_auto();
void unset_ssel_auto();
bool get_ssel_auto();

セレクトピンの自動制御フラグの設定、解除、取得。

  • ソフトウェア制御を利用する場合のみ有効。
  • transfer_blocking()呼び出し時に自動的にSELECTピンがLOWに制御され、終了時にSELECTピンがHIGHに設定される。

ssel_select()

void ssel_select(uint8_t select);

セレクトピンの指定を行います。selectは 0, 1, 2 の値をとり、各々 SSEL0..2 に対応します。

  • ハードウェア制御、ソフトウェア制御で自動制御フラグ(set_ssel_auto())設定時は、ピンの制御は転送API呼び出し時に行われる。
  • ソフトウェア制御の場合は、自動制御フラグの有無に関係なく ssel_select()呼び出し直後に、SELECTピンがLOWに設定される。
  • ハードウェア制御の場合は、reconf()を呼び出し再初期化します。この処理は処理時間のコストが大きいため、頻繁にデバイスを切り替えて転送を行う場合は、ソフトウエア制御を使用してください。

ssel_deselect()

void ssel_deselect();

セレクトピンの解除を行います。

  • ソフトウェア制御の場合は、セレクトピンをすべて HIGH レベルに戻します。
  • ハードウェア制御の場合は、なにもしません。
  • ssel_select()でのピンの指定は変更しません。

その他

bool has_init(); // init() 実行済みであれば true を返す
spi::config& get_conf(); // 内部保存の設定情報にアクセスする

ピンの割り当て

E_PIN_CONF::PRIMARYの場合

信号名PIO番号解説
SCK0クロック信号
MOSI2SPIMOSIです。TWELITE 側が出力、外部SPIデバイス側が入力です。
MISO5SPIMISOです。TWELITE 側が入力、外部SPIデバイス側が出力です。

セレクトピン

pin_sselE_PIN_SSELPIO備考
SSEL0 pin_ssel[0]SSEL_PRIMARY3
SSEL_ALT16
SSEL0_PIO33ソフトウェア制御
SSEL0_PIO1616ソフトウェア制御
SSEL1 pin_ssel[1]SSEL_PRIMARY4
SSEL_ALT14
SSEL1_PIO44ソフトウェア制御
SSEL1_PIO1414ソフトウェア制御
SSEL1_PIO1616ソフトウェア制御(SSEL0_PIO16の指定は不可)
SSEL_VOIDセレクトは SSEL0のみとする
SSEL2 pin_ssel[2]SSEL_PRIMARY13
SSEL2_PIO1313ソフトウェア制御
SSEL2_PIO1717ソフトウェア制御
SSEL_VOIDセレクトは SSEL0 SSEL1の2つとする
  • セレクトは SSEL0から順に SSEL1 SSEL2まで最大3種類設定できます。
  • pin_ssel[]のいずれかの指定がソフトウェア制御の場合、セレクトピンは全てライブラリ中でソフトウェア制御を行います。

E_PIN_CONF::ALTの場合

信号名PIO番号解説
SCK15クロック信号
MOSI17SPIMOSIです。TWELITE 側が出力、外部SPIデバイス側が入力です。
MISO18SPIMISOです。TWELITE 側が入力、外部SPIデバイス側が出力です。

セレクトピン

pin_sselE_PIN_SSELPIO備考
SSEL0 pin_ssel[0]SSEL_PRIMARY16
SSEL_ALT3
SSEL0_PIO33ソフトウェア制御
SSEL0_PIO1616ソフトウェア制御
SSEL1 pin_ssel[1]SSEL_PRIMARY14SSEL0の指定必須
SSEL_ALT4
SSEL1_PIO44ソフトウェア制御
SSEL1_PIO1414ソフトウェア制御
SSEL_VOIDセレクトは SSEL0のみとする
SSEL2 pin_ssel[2]SSEL_PRIMARY13
SSEL_ALT5PRGピンでもあるので注意が必要。
SSEL2_PIO55ソフトウェア制御。PRGピンでもあるので注意が必要。
SSEL2_PIO1313ソフトウェア制御
SSEL_VOIDセレクトは SSEL0 SSEL1の2つとする
  • セレクトは SSEL0から順に SSEL1 SSEL2まで最大3種類設定できます。
  • pin_ssel[]のいずれかの指定がソフトウェア制御の場合、セレクトピンは全てライブラリ中でソフトウェア制御を行います。

class mwf::periph::spi (sys_ev_handler)

on_sleep()

スリープ前の手続きとして、SPIを未使用状態に戻す。

init() により初期化済みであればこれを保存しておく。

on_wakeup()

スリープ前に初期化状態であれば、SPI バスを利用できるように最初期化します。