セクションの複数ページをまとめています。 印刷またはPDF形式で保存...

もとのページに戻る

2025-08-08 現在

TWENETmwf - ペリフェラルC++ライブラリ

マイコンのペリフェラルを扱うためのライブラリ
マイコンのペリフェラルを扱う手続きを C++ クラスとして、簡素化したものです。

TWENETmwf - ペリフェラルC++ライブラリ

マイコンのペリフェラルを扱う手続きを C++ クラスとして、簡素化したものです。

定義済みオブジェクトが用意されており(例mwf::the_i2c0はI2C0)、このオブジェクト経由で機能にアクセスします。定義済みオブジェクトはstd::unique_ptr<>によるスマートポインタで、初回の初期化により実体を構築します。

このライブラリでは定義済みオブジェクトは、スリープ前、スリープ復帰時の手続きが含まれ、一括してスリープ前処理、復帰処理を行うことが出来ます。

ペリフェラルオブジェクトについて

ペリフェラルの多くは、初期化などの手続きが一体になっています。そのため、クラスオブジェクトとして、その生成から破棄までを管理します。

クラスオブジェクトは、全て std::unique_ptr<> によるスマートポインタになっています。オブジェクトの生成前は nullptr になっているため、いかなるアクセスも行えません(おそらくヌルポインタアクセスによりハングアップします)。利用時には nullptr のチェックを挟むようにしてください。

   if (the_adc) { // nullptr チェックをしてから
      the_adc->enable((1UL << 0) | (1UL << 1));
      the_adc->start();
   }

定義済みのペリフェラルクラスオブジェクト

オブジェクト名説明
the_adcアナログディジタル変換(ADC)を利用する
the_gpio汎用IO(GPIO)割り込みを利用する。(割り込みを利用しない場合はクラスオブジェクトは利用しません)
the_i2c0I2Cバスを利用する。(I2C0のみ)
the_ntagNTAG用のEEPROMを利用する
the_pwm[0..9]PWM0..9を利用する
the_rng乱数生成ライブラリ
the_spi1SPIバスを利用する (SPI1のみ)
the_wtimerウェイクアップタイマーを利用する
the_wwdtウォッチドッグタイマーを利用する

ライブラリについて

オブジェクト名説明
mwf_common共通定義、ペリフェラルオブジェクトの基底クラスの定義
mwf_periph_common共通定義、ピン操作のための手続き
mwf_periph_adcADC利用のための手続き
mwf_periph_gint汎用IO(GPIO)割り込み
mwf_periph_i2cI2Cバスを利用する。(I2C0のみ)
mwf_periph_ntagNTAG用のEEPROMを利用する
mwf_periph_pwmPWM0..9を利用する
mwf_periph_rng乱数生成ライブラリ
mwf_periph_spiSPIバスを利用する (SPI1のみ)
mwf_periph_wtimerウェイクアップタイマーを利用する
mwf_periph_wwdtウォッチドッグタイマーを利用する

名前空間について

原則として、以下の名前空間にクラスや関数を定義しています。

  • mwf::
  • mwf::periph::

1 - mwf_common

mwf 共通定義
共通定義やペリフェラル用のクラスのための基底クラスを定義する。

mwf_common

共通定義やペリフェラル用のクラスのための基底クラスを定義する。

マクロ

BEGIN_CRITICAL, END_CRITICAL (割込み禁止)

#define BEGIN_CRITICAL { uint32_t __TWENET_regPrimask = DisableGlobalIRQ();
#define END_CRITICAL() EnableGlobalIRQ(__TWENET_regPrimask); }

// 例
extern volatile int critical_value;
void some_func() {
    ...
    // 以下はクリティカルセクション
    BEGIN_CRITICAL
    {
       critical_value++;
    }
    END_CRITICAL();
}

割込み禁止区間を設定するためのマクロです。DisableGlobalIRQ(), EnableGlobalIRQ() を呼び出すだけのマクロですが、ローカル変数を定義する必要があるなど、記述が煩雑に見えるため do {…} while() 構文に似せたマクロを定義しています。

上記例では、割り込みハンドラなどで変更しうる値 critical_valueがある場合に、アプリケーション処理内でその値を安全に更新するための手続きです。

※ このマクロは C++ コードのみで使用できます。

定数・列挙体など

enum class ID_SYSHAND

ペリフェラルクラスオブジェクトを識別するための ID を定義しています。

class sys_ev_handler

スリープとスリープ復帰時の手続きを共通化するためのインタフェース定義を行う上位(抽象)クラス。

on_sleep()

ペリフェラルのスリープ前の手続きを記述する。

on_wakeup(bool init_2nd)

スリープ復帰時に、スリープ前の状態に復帰するためのペリフェラルの手続きを記述する。この関数は2回呼び出されることを想定しています。

  • init_endfalseの場合は、起床後ごく初期の段階で呼び出されます。主に変数の初期化などを行いますが、デバイスなどの再初期化などはここでは行いません。trueで呼び出された2回目で。デバイスの再初期化などを行い、スリープ前の状態に復元します。

  • TWENETでは vAHI_OnWakeup_MW() の呼び出し中に処理されます。以下のような呼び出し順になります。詳細は TWENETmcu の twenet_main.c を参照してください。

    • WarmMain()関数の呼び出し (スリープ復帰時に最初に呼び出される関数)
      • vAHI_OnWakeup_MW(FALSE)
        • ここで mwf ライブラリオブジェクトの on_wakeup(false) が呼び出される
      • ToCoNet_vInit_Warm_Pre()
        • cbAppWarmStart(FALSE) (mwxでは init_warm())
      • ToCoNet_vBoard_Init()
        • 無線マイコンのハードウェアの初期化(クロックなど)
        • vAHI_OnWakeup_MW(TRUE)
          • ここで mwf ライブラリオブジェクトの on_wakeup(true) が呼び出される
      • ToCoNet_vInit_Warm()
        • cbAppWarmStart(TRUE) (mwx では setup())
      • TWENET初期化
      • TWENETアプリケーションループ

class sys_global_resource_handler

I2C, PWMなど同一機能が複数単位定義される場合に、初期化と破棄の手続きを管理する上位クラス。

これら複数利用可能なペリフェラルでは一度だけ初期化の際に行う手続きと、全て利用終了してから破棄する手続きが存在する場合に利用する。(左記のペリフェラルであっても、実装状況に応じて本クラスを利用したりしない場合がある)

初期化と破棄の手続きは、オブジェクトが生成・破棄されるたびに更新される参照カウンタ(コンストラクタより渡す)により行う。

※ sys_ev_handler は抽象クラスだが、本クラスは CRTP を用いている。

init()

参照カウンタが1になったとき(=初期化が必要な場合)に T::global_init() を呼び出す。

※ このメンバ関数はペリフェラルクラスのコンストラクタから明示的に呼び出すこと。

deinit()

参照カウンタが0になったとき T::global_deinit() を呼び出す。

※ このメンバ関数はペリフェラルクラスのデストラクタから明示的に呼び出すこと。

class sys_ev_manager

ペリフェラルクラスオブジェクトを一括管理するためのコレクションクラス。ただし、オブジェクトの所有はせず、sys_ev_handlerクラスポインタを格納する固定配列にID_SYSHAND列挙体が示すIDをインデックスとして格納する。

主目的はon_sleep(), on_wake() の手続きを一括で行うためである。

どのペリフェラルクラスオブジェクトが生成されるかはユーザプログラム次第であるため、すべてのクラスオブジェクトに対して if(the_pwm1) the_pwm1->on_sleep();といった呼び出しは余分なコードをリンクすることにもなり非効率である。sys_ev_handler型の抽象オブジェクトとして格納し、virtualメソッドを呼び出している。

global_init_sysevmgr()

the_sys_ev_managerインスタンスを生成する。

global_deinit_sysevmgr()

the_sys_ev_managerインスタンスを破棄する。

reg_obj()

ペリフェラルクラスオブジェクトを登録する。

unreg_obj()

ペリフェラルクラスオブジェクトを登録から除外する。

on_wakeup(bool init_2nd)

登録オブジェクトに全てに対し、on_wake()を実行する。

void on_sleep()

登録オブジェクトに全てに対し、on_sleep()を実行する。

ペリフェラルクラスの定義例

class timer_n_pwm :
      public mwf::sys_ev_handler // 基底クラス
    , public mwf::sys_global_resource_handler<timer_n_pwm> // 基底クラス(必要な場合のみ)
{
  using global_hdr = mwf::sys_global_resource_handler<timer_n_pwm>;
    // 長いので省略形を定義しておく
  static uint32_t _global_init_ct;
    // sys_global_resource_handlerの参照カウンタ

public:
  static void global_init_pwm(uint8_t u8_pwm_id, ...) { ... }
  static void global_deinit_pwm_manager(uint8_t u8_pwm_id) { ... }
     // the_pwm? の実体を生成・破棄するための手続き。

public:
  // コンストラクタ
  timer_n_pwm(/* コンストラクタ引数 */)
    : mwf::sys_ev_handler(/*ID*/ ,static_cast<sys_ev_handler*>(this))
    , mwf::sys_global_resource_handler<timer_n_pwm>(_global_init_ct)
  {
	global_hdr::init(); // sys_global_resource_handler<>の生成手続き
  }

  // デストラクタ (抽象クラスを継承しているため virtual 定義する)
  virtual ~timer_n_pwm()
  {
    global_hdr::deinit(); // sys_global_resource_handler<>の破棄手続き
  }

  // sys_ev_handlerクラスの実装
  virtual void on_sleep() { ... } // スリープ前に呼び出す
  virtual void on_wakeup() { ... } // スリープ復帰後に呼び出す

  // sys_global_resource_handler<>の実装。staticメンバ関数。
  static void global_init(); // 一番最初の初期化手続き
  static void global_deinit(); // 一番最後の破棄手続き
};

...
uint32_t mwf::periph::timer_n_pwm::_global_init_ct; // 参照カウンタの実体

上記は PWM (mwf_periph_pwm.hpp) ペリフェラルクラスの定義抜粋です。他の殆どのクラスではsys_global_resource_handler<>を利用していません。

2 - mwf_periph_common - ペリフェラル共通

mwf_periph_common - ペリフェラル共通
ペリフェラル共通定義やピン操作の定義。

mwf_periph_common - ペリフェラル共通

include

#include "mwf_periph_common.hpp"

GPIO操作関数

struct pin 内に定義する static 関数(インライン関数)を呼び出します。

set_pin_as_input()

static void set_pin_as_input(uint8_t pin, uint32_t param = 0)

pinを入力状態に設定します。

  • paramは未使用です。

set_pin_as_output()

static void set_pin_as_output(uint8_t pin, uint32_t param = PORTOUT_INITSTATE_HIGH)

pinを出力状態に設定します。

  • paramPORTOUT_INITSTATE_HIGHを指定すると、本関数の呼び出し時にHIGH側に設定されます。

set_output()

 void set_output(uint8_t pin, uint8_t value)

pinの出力状態を変更します。valuePORT_HIGH(1)にするとHIGH、PORT_LOW(0)にするとLOWにします。

get_input()

 static uint8_t get_input(uint8_t pin)

入力状態にあるpinの状態を読み出します。戻り値はHIGHの場合はPORT_HIGH(1)、LOWの場合はPORT_LOW(0)です。

get_input_bm()

static uint32_t get_input_bm(uint32_t u32mask = 0x3FFFFF)

// 例
  uint32_t bm = get_input_bm((1ul << 0) | (1ul << 3));
  if (bm & (1ul << 3)) { ... } // PIO3 が HIGH の場合
  else { ... }                 // PIO3 が LOW の場合

全ピンの入力状態をビットマップで読み出します。

  • PIOnの値は (1UL « n) のビットに対応します。
  • 入力状態にないピンの値は未定義です。

例ではピンのビットマップ(u32mask)を指定し、入力ピンの状態をまとめて取得します。ビットマップは、例えば PIO0 と PIO3 の値が必要な場合は (1ul << 0) | (1ul << 3)と指定します。

戻り値も同様に入力状態のビットマップです。HIGHレベルが1、LOWレベルが0で表現します。例えば PIO3 が HIGH の場合は LSB から数えて4番目のビットが 1 になります。

set_output_bm()

static void set_output_bm(uint32_t u32mask, uint8_t value)

// 例
  set_output_bm((1ul << 0) | (1ul << 3), 0); // PIO0, 3 を LOW レベルに設定する

u32maskで指定したビットマップに対応するピンについて出力状態を変更する。

  • PIOnの値は (1UL « n) のビットに対応します。
  • valuePORT_HIGH(1)にするとHIGH、PORT_LOW(0)にするとLOWにします。

例ではピンのビットマップ(u32mask)を指定し、出力の状態をまとめて設定します。ビットマップは、例えば PIO0 と PIO3 を設定する場合は (1ul << 0) | (1ul << 3)と指定します。また出力状態value1がHIGHレベル、0がLOWレベルです。

PIN操作関数

struct pin 内に定義する static 関数(インライン関数)を呼び出します。

static void __conf_digital()

static void __conf_digital(uint8_t pin, uint8_t func)

指定したピンpinのPIOレジスタに対してIOCON_PIO_FUNC(func)を設定します。

			IOCON->PIO[0][pin] =
							( 0
							| IOCON_PIO_FUNC(func) // SETFUNC (e.g. PWM is 0x04)
							| IOCON_PIO_MODE(0x00u) // 0x00:pullup
							| IOCON_PIO_DIGIMODE(0x01u)
							| IOCON_PIO_INPFILT_OFF
							);

static void conf_default()

static void conf_default(uint8_t pin)

ピンをデフォルト定義に戻します。TWENETmcu ライブラリ中の board/pin_mux.c で設定した値にします。

static void __conf_gpio_input()

static void __conf_gpio_input(uint8_t pin)

内部的に使用します。ピンpinを GPIO の入力とします。

※ ユーザプログラムでは set_pin_as_input() を使用します。

static void __conf_gpio_output()

static void __conf_gpio_output(uint8_t pin, bool b_init_high = true)

内部的に使用します。ピンpinをGPIOの出力とします。b_init_hightrueにすると規定出力がHIGH(Vcc)レベル、falseならLOW(GND)レベルです。

※ ユーザプログラムでは set_pin_as_output()を使用します。

static void set_pullup()

static void set_pullup(uint8_t pin, uint8_t mode)

指定したピンpinのPIOレジスタに対してIOCON_PIO_MODE(mode)を設定します。プルアップの制御のビットです。

static void conf_pwmout()

static void conf_pwmout(uint8_t pin, bool b_enable)

__conf_digital() を用い、指定したピンpinのPIOレジスタに対してIOCON_PIO_FUNC(0x04)を設定します。通常はPWM出力に設定されます。

static void conf_adc_input()

static void conf_adc_input(uint8_t pin)

PIO14..19に対してADCに設定するため以下の指定を行います。

IOCON->PIO[0][pin] =
( 0
| IOCON_PIO_FUNC(0x00u) // FUNC_ALT0
| IOCON_PIO_MODE(0x00u) // 0x00:pullup
| IOCON_PIO_DIGIMODE(0x00u) // ANALOGUE
| IOCON_PIO_INPFILT_OFF
);

static void conf_sclN_pioM()

		static void conf_scl0_pio10() {
		    __conf_digital(10, 0x05);
		}

		static void conf_sda0_pio11() {
		    __conf_digital(11, 0x05);
		}

		static void conf_scl0_pio15() {
		    __conf_digital(15, 0x05);
		}

		static void conf_sda0_pio16() {
		    __conf_digital(11, 0x05);
		}

		static void conf_scl1_pio06() {
		    __conf_digital(06, 0x05);
		}

		static void conf_sda1_pio07() {
		    __conf_digital(07, 0x05);
		}

		static void conf_scl1_pio12() {
		    __conf_digital(12, 0x05);
		}

		static void conf_sda1_pio13() {
		    __conf_digital(13, 0x05);
		}

ピンをI2Cで利用するための設定関数です。

static void conf_uart1(uint8_t tx, uint8_t rx)

static void conf_uart1(uint8_t tx, uint8_t rx)

UART1のTXDピンをtxに、RXDピンをrxに指定します。

  • 本関数では、TXD または RDX の一方のみを設定することはできません。

その他

struct ts_retention_context

struct ts_retention_context {
    uint32_t u32_bm_io;
    uint32_t u32_bm_set;
    void save();
    void restore();
};
static ts_retention_context s_retention_context;

static void retention_on_sleep()
static void retention_on_wake()

内部的に利用します。GPIO出力状態のスリープ時の保持に関する処理と必要なデータを管理します。

static bool __b_check_swdbg_port(uint8_t pin)

static bool __b_check_swdbg_port(uint8_t pin)

内部的に利用します。pinがデバッグ時に、デバッガで使用されるかどうかを判定します。

スリープ時のふるまい

  • GPIO の出力状態を set_pin_as_output() による手続きを行ったピンについて、スリープ時にも出力状態が維持されます。ただし retention_on_sleep() 並びに retention_on_wake()が適切に呼び出される必要があります。TWENETでは、TWENETmcu,TWENETcmptライブラリ内で処理されるスリープ前処理、スリープ復帰処理でこれらが呼び出されています。

3 - mwf_periph_adc - ADC

mwf_periph_adc - ADC
アナログディジタル変換(ADC)を利用するための手続きをまとめたペリフェラルオブジェクトです。

mwf_periph_adc - ADC

アナログディジタル変換(ADC)を利用するための手続きをまとめたペリフェラルオブジェクトです。

コード例

以下の例では mwf:: 名前空間を明示的に指定しています。省略する場合は using namespape mwf; を記述してください。

  • include
#include "mwf_periph_adc.hpp"
  • 初期化手続き
// the_adc クラスオブジェクトの生成
mwf::the_adc->global_init_adc_manager();

// ADCの入力ピンを指定
mwf::pin::conf_adc_input(14);
mwf::pin::conf_adc_input(15);

// 初期化
mwf::the_adc->init();
  • ADCの開始(ワンショット)
// チャネルの指定
mwf::the_adc->enable(
     (1ul << mwf::adc::CH_0)
   | (1ul << mwf::adc::CH_1)
   | (1ul << mwf::adc::CH_VCC));

// ADC 開始
mwf::the_adc->start(); // ワンショット
while(!mwf::the_adc->available()) {} // ポーリングで終了待ちを行う

// 値の取得
int16_t v_ch0 = mwf::the_adc->get_value_mv(mwf::adc::CH_0);
int16_t v_ch1 = mwf::the_adc->get_value_mv(mwf::adc::CH_1);
int16_t v_vcc = mwf::the_adc->get_value_mv(mwf::adc::CH_VCC);
  • ADCの開始(連続)
// チャネルの指定
mwf::the_adc->enable(
     (1ul << mwf::adc::CH_0)
   | (1ul << mwf::adc::CH_1)
   | (1ul << mwf::adc::CH_VCC));

// ADC 開始
mwf::the_adc->start(true); // 連続

// アプリケーションループ内で。
void loop() {
    if (mwf::the_adc->available()) {
        // 値の取得(周期的に実行する)
        int16_t v_ch0 = mwf::the_adc->get_value_mv(mwf::adc::CH_0);
        int16_t v_ch1 = mwf::the_adc->get_value_mv(mwf::adc::CH_1);
        int16_t v_vcc = mwf::the_adc->get_value_mv(mwf::adc::CH_VCC);

        ...
    }
}
  • 温度の測定
int32_t i32temp;
int16_t i16volt;

// 内部センサーの電源ON、安定化待ち処理、ADCの計測処理 (1回のみ)までを実行。
mwf::the_adc->temp_capture(i32temp, i16volt, 0);

// i32temp は温度℃の128倍値。i16volt はミリボルト
Serial << format("%dC %dmV", i32temp >> 7, i16volt);

class mwf::periph::adc

the_adc クラスオブジェクトの主要定義を記載します。

定数定義

static const uint8_t CH_MAX = 7;
static const uint8_t CH_0 = 0; // ADC0
static const uint8_t CH_1 = 1; // ADC1
static const uint8_t CH_2 = 2; // ADC2
static const uint8_t CH_3 = 3; // ADC3
static const uint8_t CH_4 = 4; // ADC4
static const uint8_t CH_5 = 5; // ADC5
static const uint8_t CH_VCC = 6; // VCC
static const uint8_t CH_TEMP = 7; // 内部温度センサー (通常のADとは取得方法が違います)

ADCチャネルについての設定定義です。

struct config

struct config {
  uint8_t prescale;
};

設定を行うための構造体。init()のパラメータとして渡す。

  • prescale : **《現バージョンでは DEFAULT_PRESCALE=6 のみに対応》**ADCの変換時間を決めるためのプリスケール値。fslライブラリで定義されるadc_config_t::clockDividerNumber(1ul << .prescale) を設定し::ADC_Init()を呼び出します。

global_init_adc_manager() global_deinit_adc_manager()

static void global_init_adc_manager();
static void global_deinit_adc_manager();

クラスオブジェクトthe_adc の生成と破棄を行う。

set_pin_as_adc()

static void set_pin_as_adc(uint8_t pin)

指定したピン番号pinをADC入力にする。

init() deinit()

void init(bool b_wait_init = true);
void deinit();

ADCを初期化します。

b_wait_initをFALSEに設定すると、ADCの安定化の待ち時間 (300ms) を省略します。待ち時間の扱いについてはis_periph_enabled()を参照してください。

内部温度センサー取得用に ADC を初期化または再初期化するには init_for_temp_volt()を呼び出します。すでに init() により初期化済みの場合は temp_capture()

is_periph_enabled()

bool is_periph_enabled()
void force_periph_enabled()
uint32_t get_init_freerun_tick()

ADCが初期化され必要な待ち時間を経過すると true を戻します。

  • the_wtimerで提供するFRWT(Free Running Wake Timer)が動作している場合は、is_periph_enabled()が適切な時期までfalseを戻します。init()が呼び出されたときのカウント値を得るには get_init_freerun_tick()を呼び出します。
  • FRWTが動作していない場合は初回のis_periph_enabled()の呼び出し時におよそ300usecの待ち時間が発生します。この待ち処理を行わないようにするためには init()呼び出し直後にforce_periph_enabled()を呼び出しておきます。この処理は内部状態を強制的に待ち時間が経過したものとして取り扱います。

enable()

void enable(uint32_t chmask);

ADCを動作可能な状態にします。chmaskは変換対象のチャネルのビットマスクで、ADC0 と ADC1 と VCC が対象の場合は (1ul << CH_0) | (1ul << CH_1) | (1ul << CH_VCC) と指定します。

start() stop()

void start(bool b_cont = false);
void stop();

enable() 実行後に start() を実行することで、ADCを開始します。b_cont == trueとした場合は、連続変換を行います。すでにstart()が呼び出されADCが実行中のときには、呼び出してはいけません。

連続変換時に変換を停止するには stop() を呼び出します。

変換が終了した時点で the_adc->available() の読み出しが true になります。

available()

bool available();

変換終了後に true を戻します。trueを読み出した後は再びfalseを戻します。

is_started()

bool is_started();

start()によりADCが実行中である場合trueを戻します。

get_value()

uint16_t get_value(uint8_t ch);

chで指定するチャネルのAD変換値(12bit)を取得する。AD変換終了後に呼び出す。

get_value_mv()

int16_t get_value_mv(uint8_t ch);

chで指定するチャネルのAD変換値をmvで取得する。AD変換終了後に呼び出す。

global_init_device() global_deinit_device()

static void global_init_device();
static void global_deinit_device();

ハードウェアの初期化と利用終了の手続きを行う。

※ コンストラクタ、デストラクタなどから内部的に呼び出され、ユーザアプリケーションから明示的に呼び出す必要はありません。

register_callback()

typedef void (*PFN_ADC_CALLBACK)(uint32_t, uint32_t);
void register_callback(PFN_ADC_CALLBACK pfn)

割り込みハンドラ内からのコールバック関数の指定。

コールバック関数の第一パラメータは kADC_ConvSeqAInterruptFlag, 第二パラメータは変換が行われたチャネルのビットマスクが渡されます。

温度センサー

temp_capture()

bool temp_capture(
    int32_t& temp128th,
    int16_t& volt_mv,
    uint8_t times_adc_scaler = 0,
    bool b_power_on_temp_sensor = true)

オンチップ温度センサーの値を取得する。副次的に電源電圧も計測する。

  • temp128thには、温度の計測結果を格納する変数を指定する。値は摂氏の128倍値になる。整数部は temp128th >> 7、小数点1桁部分は (10 * temp128th) >> 7 で計算できる。
  • volt_mvには、電圧の計測結果を格納する変数を指定する。値はミリボルト[mV]。
  • times_adc_scalerには、ADCの繰り返し回数に対応するスケーラ値を指定する。0..3まで指定でき、0の場合は1回、1は2回、2は4回、3は8回のAD変換を行ったのち、値を平均化処理する。
  • 戻り値は成功時にtrue,失敗時にfalseを戻す。

暗黙に以下の処理を行います。

  • 温度センサーがONになっていない場合は、センサーをONに設定し必要な待ち処理を行います。(temp_power_on()参照)
  • 実行後は温度センサーをOFFにします。
  • ADCの初期化(init())が行われていない場合は失敗します。
  • ADCの初期化後、デバイスが利用可能になっていない場合は、待ち処理を行います (is_periph_enabled()参照)。

temp_get_capt_tick()

uint32_t temp_get_capt_tick()

最後に温度を取得したときの FRWT のカウンタ値を返す。

temp_power_on(), temp_power_off()

void temp_power_on()
void temp_power_off()

明示的に温度センサーのON/OFFを行う。

FRWT が有効な場合に限り、カウント値をもとに待ち時間が完了しているかを判定するため、事前にON処理を行っておくことで待ち時間を短縮できる。

temp_computation()

int32_t temp_computation(
	uint16_t adcout_vbat_lsb_sum8,
	uint16_t tsens_adcout_T_sum8,
	uint8_t nb_samples_actual = 1)

内部的に利用します。ADC計測値から温度を計算します。

get_ctrl0_adc_reg_context()

class ctrl0_adc_reg;
ctrl0_adc_reg get_ctrl0_adc_reg_context(uint8_t mode, uint8_t tsamp)

//例
   	if (auto rc = get_ctrl0_adc_reg_context(
			  0x0
			, 0x14
	)) {
        ; // このスコープ内は (0x0, 0x14) の設定が有効。スコープを出ると元の値に戻す。
    }

内部的に利用します。一時的に ADCの設定パラメータを変更します。

class mwf::periph::adc (sys_ev_handler)

on_sleep()

ADCの停止処理を行います。

on_wakeup()

スリープ前に ADC が初期化されていた場合は、初期化手続き(init())を行います。enable(), start()は改めて実行する必要があります。

その他

連続モードでの動作について

変換周期はハードウェアによって決まっています。現バージョンではプリスケーラの値は固定です。

AHI, mwx での利用

AHI や mwx ライブラリの内部では mwf::the_adc を利用していますので、直接 mwf::the_adc を利用する場合は注意が必要です。

  • AHIライブラリを利用しかつ mwf::the_adc を利用する場合は、ADCに関連する一切の手続きを呼び出さないようにしてください (vAHI_ApConfigure(), vAHI_AdcEnable(), vAHI_AdcStartSample()など。App_Tweline 付属の adc.c)
  • mwx ライブラリを利用しかつ mwf::the_adc を利用する場合は、Analogue クラスオブジェクトに対して操作を行わないようにしてください(Analogue.setup() など)。

4 - mwf_periph_gint - GINT(GPIO)

mwf_periph_gint - GINT(GPIO)
汎用IOの入出力の設定、また GINT を用いたIO割り込みを実装しています。

mwf_periph_gint - GINT(GPIO)

汎用IOの入出力の設定、また GINT を用いたIO割り込みを実装しています。

TWENETでは、初期化、割り込み処理はTWENETライブラリ(TWENETcmpt)内で処理されます。ユーザプログラム内で本関数を呼び出すことは通常ありません。

include

#include "mwf_periph_gint.hpp"

class mwf::periph::gint

the_gint クラスオブジェクトの定義です。ピンを割り込み動作させる場合(スリープ割り込みも含む)、the_gintクラスオブジェクトの生成が必要です。実装の詳細は後述の「GINTを用いたDIO割り込み実装」を参照してください。

global_init_gint_manager() global_deinit_gint_manager()

static void global_init_gint_manager();
static void global_deinit_gint_manager();

クラスオブジェクトthe_gint の生成と破棄を行う。

init_int() deinit_int()

void init_int(tpf_gpio_int_handler pf_callback, void *p_data = nullptr);
void deinit_int();

GPIO 割り込みの初期化を行う。割り込みハンドラ(pf_callbackと割り込みハンドラに伝達されるパラメータ(p_data)を指定します。

GPIO 割り込みを停止するには deinit_int() を呼びます。

pf_callbackは、以下のように定義されます。

using tpf_gpio_int_handler = void(*)(uint32_t bm_now, uint32_t bm_changed, void *p_data);
  • bm_nowは、現時点でのピン状態に対応するビットマップ。
  • bm_changedは、変更のあったピンに対応するビットマップ。
  • p_dataは、init_int()で指定したp_dataです。

set_int_pins_bm()

void set_int_pins_bm(uint32_t u32mask_rising_edge, uint32_t u32mask_falling_edge);

割り込み対象のピンを指定します。

1番目のパラメータu32mask_rising_edgeは立ち上がりエッジの検出対象ピンのビットマップ、2番目のパラメータu32mask_falling_edgeは立ち下がりエッジの検出対象ピンのビットマップです。

立ち上がり、立ち下がり両方のエッジを設定することも可能です。

gint_poll()

void gint_poll();

割り込み時の処理と同じ処理を行う。

1msシステムタイマーなどから一定周期で呼び出すことで、後述の「GINTを用いたDIO割り込み実装」で解説する制限(割り込みハンドラ中で読み出した状態からポート状態が変化してそのままその変化が処理されない場合)を緩和できる場合があります。多くの場合はこの処理は必要ありません。

set|unset|get_opt_stop_int_when_changed()

void set_opt_stop_int_when_changed();
void unset_opt_stop_int_when_changed();
bool get_opt_stop_int_when_changed();

メカボタンのチャタリングなどの影響を緩和するために、状態変化検出後に当該ピンの割り込み動作を停止します。

具体的には、ピンの状態が変化し割り込みが発生し、かつ、その割り込みハンドラ中で変化があったと判定されたピン*について、割り込みピンから一時的に除外します。

*割り込み要因のピンはGINTの割り込み機構では知ることが出来ないため、割り込みハンドラが実行された直後にピンの状態を読み出し、直前の状態で比較することで変化を検出しています。

このオプションを設定した場合、ピンの変化が検出されたあとピンの状態の安定を待ってからreactivate_in_pins()を呼び出します。

reavtivate_int_pins()

void reavtivate_int_pins();

割り込みを一時停止したピンの割り込みを再開する。set_opt_stop_int_when_changed()のオプション設定参照。

get_gint_context()

gint_context& get_gint_context();

内部構造体にアクセスします。設定済みの立ち上がり立ち下がりピンのビットマップ(.bm_rise .bm_fall)や、スリープ起床時の起床要因のピン(.bm_wake)を得るために使用します。

_gint_update()

    std::tuple<uint32_t, uint32_t> _gint_update(
			  uint32_t u32mask_rising_edge = 0x80000000
			, uint32_t u32mask_falling_edge = 0x80000000);

(内部的に呼び出される関数でユーザプログラムからは使用しません)

1.割り込みピンの設定を行う。

2.ピンの状態変化を判定、更新する(u32mask_rising_edge, u32mask_falling_edge0x80000000の場合)。状態変化があれば init_int() で登録したコールバック関数を呼び出す。

gint_handler()

static void gint_handler();

(内部的に呼び出される関数でユーザプログラムからは使用しません)

GINTの割り込みハンドラ。

_gint_get_changed_by_specified_edge()

 uint32_t _gint_get_changed_by_specified_edge(uint32_t bm_cur, uint32_t bm_changed)

(内部的に呼び出される関数でユーザプログラムからは使用しません)

変化したピンのから、立ち上がり・立ち下がりの指定条件に合致するピンを抽出します。計算には、現在のビットマップ状態(bu_cur)と変化したピン(bm_changed)を用います。

class mwf::periph::gpio (sys_ev_handler)

on_sleep()

GINTが稼働中なら割り込みの停止を行います。

TWENETでは vAHI_DioOnSleep_MW() で、本ライブラリを経由(set_int_pins_bm())して設定した割り込み設定ピンをスリープ起床用として設定しています。なお、スリープ起床では立ち上がりまたは立下りのエッジの指定はできません。

on_wakeup()

GPIO割り込み起床した場合は、起床要因に対応するピン情報 (PMC->WAKEIOSOUCE) を保存します。

また、スリープ前に割り込みピンの指定があった場合は、改めて GINT による割り込みが動作するように再初期化します。

GINTを用いたDIO割り込み実装

PINT機能は利用数が最大4ポートまでの制限があるため、GINT(Group INT)の機能を用い類似の機能を実装してます。PINTのように特定のピンに注目した割り込み検出機構ではないため制限事項が存在します。TWENET ライブラリ中では PINT を用いていませんので、GINTによる実装の制限に問題がある場合は、PINT による実装も検討してください。

制限事項

  • ノイズや短いパルスといった状態変化後に短時間で再び状態が変化する信号の場合、期待しないふるまいになる場合があります(取りこぼしなど)。

    • 状態変化後、一定の間同じ状態が維持されることを想定します。
      • GINTの制約上、ごく短いパルスの場合GINT割り込みは検出できますが、変化したピンを得ることは出来ません。詳細は後述の「実装」を御覧ください。
      • 変化(エッジ)から約10usecの間状態が維持されれば、GINT のエッジ再設定が行えるため原理的には動作が期待できますが、安全を見て割り込みハンドラ1回の処理時間に相当する約30~50usecの間同じ状態が維持することを目安としてください。
    • GND状態で立ち下がりエッジを検出する、またその反対に VCC 状態で立ち上がりエッジを検出する場合は、原理上、取りこぼしが発生しやすくなります。
    • チャタリング・ノイズが含まれるものについては、初回割り込み発生時点で割り込み対象から外すオプション(vAHI_DioInterruptDisablePinsIntWhenChanged_MW(TRUE);またはmwf::the_gpio->set_opt_stop_int_when_changed();)を利用し、割り込み発生時点から一定時間待ってから、vAHI_DioInterruptReavtivate_MW(); または mwf::the_gpio->reavtivate_int_pins(); を呼び出してください。
    • 多くの場合必要ありませんがthe_gpio->gint_poll() を1ms単位のシステムティックなど一定周期で呼び出すことで、割り込みのオーバーヘッドが増えるものの、取りこぼしの影響を緩和できる場合があります。

    ※ 記載の数値は CPU が 32Mhz 動作した場合を前提としてます。

    ※ 半導体の機能をそのまま利用したい場合は、当ライブラリの初期化を行わず、GINT や PINT を直接利用してください。

実装

GINTは本来、複数のピンをグループとして扱い、全体として変化があった場合に割り込みを発生させるもので、個別のピンの状態を意識した機能ではありません。

以下のように実装しています。

  • 現在のピンの状態を読み出し、Hなら立ち下がり、Lなら立ち上がりエッジとして、GINTでの検出エッジの設定して、割り込みを有効にする。
  • GINT割り込み発生(いずれかのピンに変化し、割り込みハンドラが呼び出される)
    • 各ピンの状態を読み出し、変化のあったピンを検出する
    • GINTの検出エッジ設定を、読み出したピンの状態に合わせて再設定する
    • 変化のあったピンに対してアプリケーションに通知(コールバック)する

※ 割り込みハンドラは、直後にもう一度呼び出されます。

動作例

※ 記載中の数値などは、開発中のライブラリコード、検出対象ピンは2つ、マイコンは CPUは32MHzで駆動した場合です。

同時に2つのピンが L レベルになった時

割り込み発生から 1.5usec で割り込みハンドラが呼び出されます。割り込みの前段階の処理(ピンの読み出しと検出エッジの再設定)は、6.6usec後までかかります。その後、アプリケーション通知(割り込み時のコールバック)を行います(割り込み発生から 22usecまで)。

さらにもう一度割り込みが発生します(GINTのハードウェアの振る舞いと考えられます)。2回目の割り込みでは、多くの場合状態の変化は検出されないため値の確認のみですが、例外的な取りこぼしを抑制する場合があります。

  • 横軸 (10usec/DIV)
  • ピンク:割り込みハンドラの先頭から、GINTの検出エッジ再設定まで (1V/div)
  • シアン・イエロー:入力信号 (2V/div)

割り込みハンドラ中に他のピンが変化した場合1

この例では、割り込みハンドラの前半処理中に他のピン(シアン)が変化したため、最初のハンドラ中で矛盾なく処理できた例です。上述の同時変化と同じ振る舞いになります。最初の割り込みでイエローとシアン両方の変化がアプリケーションに伝達されます。

  • 横軸 (10usec/DIV)
  • ピンク:割り込みハンドラの先頭から、GINTの検出エッジ再設定まで (2V/div)
  • ブルー:割り込みハンドラの開始から終了まで (2V/div)
  • シアン・イエロー:入力信号 (5V/div)

割り込みハンドラ中に他のピンが変化した場合2

この例では、割り込みハンドラ中で他のピン(シアン)が変化していますが、検出エッジ再設定後の変化であるため、直後に割り込みが発生しています。2回目のハンドラ終了後に、更にもう一度ハンドラが実行されます。最初の割り込みでイエローの変化がアプリケーションに伝達され、2回目の割りr込みでシアンの変化が伝達されます。

  • 横軸 (10usec/DIV)
  • ピンク:割り込みハンドラの先頭から、GINTの検出エッジ再設定まで (2V/div)
  • ブルー:割り込みハンドラの開始から終了まで (2V/div)
  • シアン・イエロー:入力信号 (5V/div)

5 - mwf_periph_i2c - I2C

mwf_periph_i2c - I2C
I2Cバスを用いるための手続きをまとめたペリフェラルオブジェクトです。

mwf_periph_i2c - I2C

I2Cバスを用いるための手続きをまとめたペリフェラルオブジェクトです。

コード例

以下の例では mwf:: 名前空間を明示的に指定しています。省略する場合は using namespape mwf; を記述してください。

  • include
#include "mwf_periph_i2c.hpp"
  • 初期化
// create instance of the_i2c0.
if (!mwf::the_i2c0) {
  mwf::i2c::global_init_i2c0_manager();
}

// I2C device init
mwf::the_i2c0->init();

// write 2bytes (e.g. kick sensor capturing)
const uint8_t cmd1[] = { 0x60, 0x9C };
if (!mwf::the_i2c0->write_blocking(0x70, cmd1)) return false;

// wait (e.g. wait sensor data conversion.)
CLOCK_uDelay(1000*30); // wait some for sensor data conversion.

// read 6 bytes (e.g. read the sensor data.)
uint8_t data[6];
mwf::the_i2c0->read_blocking(0x70, data);
  • 読み出し(ブロッキング API)
// write 2bytes (e.g. kick sensor capturing)
const uint8_t cmd1[] = { 0x60, 0x9C };
if (!mwf::the_i2c0->write_blocking(0x70, cmd1)) return false;

// wait (e.g. wait sensor data conversion.)
CLOCK_uDelay(1000*30); // wait some for sensor data conversion.

// read 6 bytes (e.g. read the sensor data.)
uint8_t data[6];
mwf::the_i2c0->read_blocking(0x70, data);

この例では、センサーの取得開始コマンドを送付し、センサー動作時間待ち(センサーが必要とする時間)を経てから、データ取得を行なっています。

  • 読み出し(ノンブロッキング API)
// write 2bytes (e.g. kick sensor capturing)
const uint8_t cmd1[] = { 0x60, 0x9C };
if (!mwf::the_i2c0->write(0x70, cmd1)) return false;
while(!mwf::the_i2c0->available()); // waiting for completion of write operation.

// wait (e.g. wait sensor data conversion.)
CLOCK_uDelay(1000*30); // wait some for sensor data conversion.

// read 6 bytes (e.g. read the sensor data.)
uint8_t data[6];
mwf::the_i2c0->read(0x70, data);
while(!mwf::the_i2c0->available()); // waiting for completion of read operation.

ブロッキングAPIと同じwrite/readですが、ノンブロッキングAPIでは write()/read() 関数はデータ送信完了を待たず速やかに終了します。十分な時間を待つか the_i2c0->available()がtrueになるのを待ってから続く操作を行う必要があります(上記の例では、write/read直後にポーリング待ちを行っているので、ブロッキングAPIの利用と違いがありません)。

class mwf::periph::i2c

I2Cを利用するための手続きを記述しています。

※ 現状の実装では I2C0 を利用する the_i2c0 クラスオブジェクトのみが利用できます。

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>;

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

global_init_i2c0_manager(), global_deinit_i2c0_manager()

static void global_init_i2c0_manager(wE_PIN_CONF pin_conf = E_PIN_CONF::PRIMARY);
static void global_deinit_i2c0_manager();

the_i2c0クラスオブジェクトの生成と破棄を行います。

生成時にピン配置をpin_confE_PIN_CONF::PRIMARY 値:0(SCL=PIO10,SDA=PIO11)またはE_PIN_CONF::ALT 値:1(SCL=PIO15,SDA=PIO16)を指定します。ピンの初期化は init() 呼出時に行われる。

(eE_PIN_CONFenum class E_PIN_CONFのラッパクラスで、int型との代入比較のための定義を設けています)

init(), deinit()

void init(uint32_t clock_freq = 0, wE_PIN_CONF pin_conf = E_PIN_CONF::NODEF);
void deinit();

I2Cバスの初期化と利用終了手続きを行う。初期化時にはclock_freqをパラメータとして与え、0の場合は規定クロック100kHzが選択され、それ以外はclock_freq[Hz]を周波数として指定する。

pin_confを指定しない場合(E_PIN_CONF::NODEF 値:0)は、global_init_i2c0_manager()で指定したピンを用います。pin_confを指定した場合、そのピン設定を用いて初期化します。以降、本パラメータの省略時は最後に指定したピンを用います。

write_blocking(), write()

bool write_blocking(uint8_t addr, const uint8_t* buf, unsigned size);
template <unsigned N> bool write_blocking(uint8_t addr, const uint8_t (&buf)[N]);

bool write(uint8_t addr, const uint8_t* buf, unsigned size);
template <unsigned N> bool write(uint8_t addr, const uint8_t (&buf)[N]);

I2Cバスへデータを書き込む。

write_blocking()は書き込み完了まで待ち処理を行うブロッキング処理、write()は書き出し完了を待たずに関数を終了するノンブロッキング処理です。書き出しが完了すると .available()true になります。

addrはI2Cバスのアドレス(7bit)、bufは書き出すデータ、sizeは書き出すデータバイト数を指定します。bufがサイズNの固定配列の場合はNバイト書き出します。

read_blocking(), read()

bool read_blocking(uint8_t addr, uint8_t* buf, unsigned size);
template <unsigned N> bool read_blocking(uint8_t addr, uint8_t(&buf)[N]);

bool read(uint8_t addr, uint8_t* buf, unsigned size);
template <unsigned N> bool read(uint8_t addr, uint8_t(&buf)[N]);

I2Cバスからデータを読み込む。

read_blocking()は読み出し完了まで待ち処理を行うブロッキング処理、write()は読み出し完了を待たずに関数を終了するノンブロッキング処理です。読み出しが完了すると .available()true になります。

addrはI2Cバスのアドレス(7bit)、bufはデータ格納バッファ、sizeは読み出すデータバイト数を指定します。bufがサイズNの固定配列の場合はNバイト読み出します。

_transfer()

bool _transfer(OPT op, uint8_t addr, uint8_t* buf, unsigned size);

ノンブロッキング読み書きを行う処理関数。opは読み出しか書込みの指定、addrはI2Cバスのアドレス、bufは読み書きのためのバッファ、sizeは読み書きバイト数です。

_transfer_blocking(), _start_blockin(), _stop_blocking()

bool _transfer_blocking(OPT op, uint8_t* buf, unsigned size, bool sendStop = false)
bool _start_blocking(OPT op, uint8_t addr);
bool _stop_blocking();

mwxライブラリ向けに調整したブロッキング読み書きの手続き。_start_blocking()_transfer_blocking()を必要な回数、_stop_blocking()の順で呼び出す。サイトの転送で sendStop`をtrueに設定することで適切にSTOP信号を発光できる。

available()

bool available();

ノンブロッキングAPI利用時に、転送終了を判定する。転送終了するとtrueを戻す。

is_success()

bool is_success();

ノンブロッキングAPI利用時に、直前の転送が成功したかどうかを返す。trueなら転送が成功したことを示す。

class mwf::periph::i2c (sys_ev_handler)

on_sleep()

スリープ前の手続きとして I2C デバイスの利用終了手続きを行う。

on_wakeup()

スリープ時に初期化(init()呼出)済みの場合は、再度 init() の呼び出しを行い初期化する。

6 - mwf_periph_ntag - NTAG

mwf_periph_ntag - NTAG
チップ内蔵の近距離無線通信(NTAG)コントローラ(NT3H2211)のEEPROMを読み書きするための手続きです。

mwf_periph_ntag - NTAG

チップ内蔵の近距離無線通信(NTAG)コントローラ(NT3H2211)のEEPROMを読み書きするための手続きです。コントローラはI2C接続されていますがmwf::periph::i2cは用いません。

本手続きにより読み書きできるのは 1KB の領域(NT3H2211 の I2C block address 64-127)です。

コード例

#include "mwf_periph_ntag.hpp"

void func() {
    // create the_ntag class object.
    if (!mwf::the_ntag) {
      mwf::ntag::global_init_ntag_manager();
    }

    // initialize
    mwf::the_ntag->init();

    // write 128bytes
    uint8_t xfer1[128];
    for (unsigned i = 0; i < 128; i++) xfer1[i] = i;
    mwf::the_ntag->write_user_area(0x00, xfer1);

    // read 128bytes
    uint8_t xfer2[128];
    mwf::the_ntag->read_user_area(0x00, xfer2);
}

class mwf::periph::ntag

global_init_ntag_manager(), global_deinit_ntag_manager()

static void global_init_ntag_manager();
static void global_deinit_ntag_manager();

the_ntagクラスオブジェクトの生成と破棄を行います。

init(), deinit()

void init();
void deinit();

デバイスアクセスのための初期化と利用終了手続きを行います。初期化init()には300usecの待ち処理が含まれます。

write_user_area()

bool write_user_area(uint16_t addr, const uint8_t *p, uint16_t len);
template <unsigned N> bool write_user_area(uint8_t addr, const uint8_t (&buf)[N]);

EEPROMのユーザエリアにバイト列を書き込みます。

addrは開始アドレスで0..1023を指定します。pまたはbufは書込みデータのバッファです。lenまたはNはデータバイト数です。

read_user_area()

bool read_user_area(uint16_t addr, uint8_t *p, uint16_t len);
template <unsigned N> bool read_user_area(uint8_t addr, const uint8_t (&buf)[N]);

EEPROMのユーザエリアからバイト列を読み出します。

addrは開始アドレスで0..1023を指定します。pまたはbufは読み出し先のデータのバッファです。lenまたはNはデータバイト数です。

class mwf::periph::ntag (sys_ev_handler)

on_sleep()

スリープ前に利用終了の手続きを行います。

on_wakeup()

スリープ時に初期化済みの場合は、再度初期化します。再初期化が不要な場合は deinit() してからスリープしてください。

7 - mwf_periph_pwm - PWM, Timer

mwf_periph_pwm - PWM, Timer
PWM,タイマーを用いるための手続きをまとめたペリフェラルオブジェクトです。

mwf_periph_pwm - PWM, Timer

PWM,タイマーを用いるための手続きをまとめたペリフェラルオブジェクトです。

クラスオブジェクトthe_pwm[]を用いて操作します。クラスオブジェクトは配列として定義されていますがPWM0(the_pwm[0])からPWM9(the_pwm[9])まで利用できます。

PWM10は本ライブラリでは対応しません。

コード例

以下の例では mwf:: 名前空間を明示的に指定しています。省略する場合は using namespape mwf; を記述してください。

TWENETcmpt (AHI 互換関数) を利用する場合は、

#include "mwf_periph_pwm.hpp"

// in some func.
void func() {
	// create instance of PMW0.
	if (!the_pwm[0]) { // The class object of PMW0 is the_pwm[0].
		timer_n_pwm::global_init_pwm_manager(
		  0,   // PWM0
		  timer_n_pwm::PIN::ALT,
		       // The timer_n_pwm::PIN::PRIMARY will assign smaller PIO number PIO0 from PWM0,
		       // or conversely, timer_n_pwm::PIN::::ALT assigns PIO12.
		  true // set true to enable PWM output.
	  );
	}

	// set `x' as an alias of the_pwm[0].
	auto& x = the_pwm[0];

	// Init the device
	//x->init(); // not necessary, the constructor will call init() implicitly.

	// if needs INT, set true. (default: false)
	x->set_int_enabled(true);

	// set prescale
	x->set_prescale(6); // 0:32MHz 1:16Mhz 2:8Mhz ...

	// set polarity: if false, set HIGH while active state. (default: false)
	x->set_invert(false);

	// set cycle
	// note: 500Hz Duty 10% (Hi 0.2ms, Low 1.8ms)
	x->set_cycle(
		   100 // conut for an active state (HIGH)
		,  999 // count for a period (+1)
	);

	// start PWM out
	x->restart();
}

// INT handler (call set_int_enabled() before restart())
// note: if TWENETcmpt library is not linked, the IRQ handlers for PWM1..9 shall be defined.
extern "C" void PWM0_IRQHandler(void) {
  	... // some procedures.
 	PWM_ClearStatusFlags(PWM, kPWM_Pwm0);
}

class mwf::periph::timer_n_pwm

global_init_pwm_manager()

static void global_init_pwm_manager(
    		  uint8_t u8_pwm_id
			, uint8_t u8_pin_number
			, bool b_output_enabled = true
		 );

static void global_init_pwm_manager(
    		  uint8_t u8_pwm_id
    		, PIN e_pin
			, bool b_output_enabled = true
		);

クラスオブジェクトthe_pwm[]を構築します。構築時にPWM番号と対応するピンを指定します。

PWM番号は(u8_pwm_id)として指定すします。各PWMは利用可能なピンが2ピンあり(PWM5はPIO16のみ)、本APIではu8_pin_numberとして直接ピン番号を指定するか、指定可能なピンのうち若い番号(timer_n_pwm::PIN::PRIMARY)または別のピン番号(timer_n_pwm::PIN::ALT)を指定します。

矛盾する番号を指定した場合の動作は未定義です。

global_deinit_pwm_manager()

static void global_deinit_pwm_manager(uint8_t u8_pwm_id);

構築済みのthe_pwm[]クラスオブジェクトを破棄します。

set_pwm_output()

void set_pwm_output(bool_t b_enable);
bool get_pwm_output();

ピンの出力状態を変更します。b_enabletrueの場合は出力を有効にする指定でハードウェアのピンも設定変更されます。falseの場合はデフォルトのピン(conf::pin::conf_defautl())に設定します。

  • PWM出力中に呼び出すことが出来ます。
  • global_init_pwm_manager()のパラメータで出力設定している場合、改めて呼ぶ必要はありません。

set_int_enabled()

void set_int_enabled(bool_t b_enable);
bool get_int_enabled();

割り込みの有効・無効を設定します。b_enabletrueの場合は割り込みが有効、falseの場合は無効になります。

  • PWM出力中に呼び出すことが出来ます。
  • 後述の「割り込みハンドラ」を参照してください。

set_prescale(), set_divisor()

void set_prescale(uint8_t u8_prescale);
void set_divisor(uint16_t u16_div);

PWM制御のプリスケールを設定します。これによりPWM制御周波数が決まります。

  • PWM出力中に呼び出すことが出来ます。
  • set_prescale(u8_prescale)を指定した場合、制御周波数は0:32Mhz, 1:16Mhz, 2:8Mhz, …, 9: 62500Hz, 10: 31250Hz, 11以降は未定義(デバッグ時assert)です。
  • set_divisor(u16_div)を指定した場合, 制御周波数は (32Mhz / u16_div) です。値域は 1..1024 の範囲で、それ以外の値を指定した場合の振る舞いは未定義です。
  • PWM周期とDUTY比はset_cycle()のパラメータで決まります。
    • 例えば set_prescale(2) と指定した場合は制御周波数は fb=8Mhz です。この設定でset_cycle(2, 10) を指定すると PWM 周期は fbx10=800Khz で、パルス幅が 2x1/fb=1/8000000=250nsec になります。

set_cycle()

void set_cycle(uint16_t ct_comp, uint16_t ct_period);
uint16_t get_period_val(); // get total period count
uint16_t get_comp_val();   // get active region count

PWM1周期とその中でのアクティブ区間を決めるカウント値を指定します。アクティブ区間の間ピンの値が変化し、その終わりに割り込みが発生します。

ct_compまでの値がアクティブ、ct_periodが1周期のカウント数です。例えばct_comp100ct_period1000とした場合、PWM周期はPWM制御周波数で1000カウント分、set_invert(false)の条件で100カウント分がHIGH、残りの900カウントがLOWになる振る舞いをします。

  • PWM出力中に呼び出すことが出来ます。
  • ct_comp0からct_period-1までが有効です。アクティブが(ct_period-1/ct_period)の比率までが上限で100%に設定することが出来ません。set_duty()では100%の設定を考慮しています。
  • 1周期分のカウント値ct_periodについて、ハードウェアレジスタには ct_period - 1 として設定しています。本関数にはハードウェアレジスタ値を指定しないよう注意してください。

set_duty()

void set_duty(uint16_t u16duty, uint16_t u16duty_max = 1000);

PWMのDUTY比を設定します。

  • 事前に set_cycle() を用いて、PWMの1周期のカウント数を指定しておきます。左記の手続きを省略した場合 u16duty_max がPWM周期のカウント数として設定されます。
  • 1周期に対してu16_duty/u16duty_max の割合をアクティブ区間とします。例えば set_duty(100) と指定した場合はアクティブ区間は1周期に対して10%です。
  • u16dutyu16duty_maxと同じ値を指定した場合は、全区間がアクティブとなりデフォルトの反転しない波形出力set_invert(false)の場合HIGHレベルに設定します(ハードウェアの制約からアクティブ区間を全区間に設定できないため、内部的には波形出力レジスタを反転して、アクティブ区間を0に設定しています)。
    • このためset_duty()で100%設定した後にset_cycle()を呼び出すと波形が反転します。混用しないように注意してください。

set_invert()

void set_invert(bool_t b_invert);
bool get_invert();

出力波形を反転します。false(デフォルト)設定時はアクティブ区間がHIGHレベル、trueではLOWレベルです。

start(), stop()

void start();
void restart();
void stop();

PWM出力の開始、設定&開始(再開)、停止処理を行います。

  • 停止処理 stop() 時のピンの状態は、set_invert(false)(デフォルト)の場合 LOW レベル、set_invert(false)の場合HIGHレベルです。

class mwf::periph::timer_n_pwm (sys_ev_handler)

sys_ev_handlerはスリープ前後の手続きです。

on_sleep()

PWMの実行状態を保存した上で、スリープ時のピン状態をデフォルト設定に戻す。

on_wakeup()

スリープ前の状態した状態を復元する。

class mwf::periph::timer_n_pwm (sys_global_resource_handler)

sys_global_resouce_handler<T>(Ttimer_n_pwmクラス)は、複数のPWMクラスオブジェクトに対して、1度だけ必要な初期化処理、終了手続きを行うための手続きです。内部的に暗黙に利用されます。

  • コンストラクタやon_wakeup()sys_global_resource_handler<T>::init()を呼び出します。
    • 最初に作成されたインスタンスの場合は T::global_init() を呼び出します。
  • デストラクタやon_sleep()sys_global_resource_handler<T>::deinit()を呼び出します。
    • 最後に破棄されるインスタンスの場合は T::global_deinit() を呼び出します。

T::global_init()

::PWM_Init()を呼び出し、PWMを初期化します。

T::global_deinit()

::PWM_DeInit()を呼び出し、PWMの利用終了手続きを行います。

割り込み

set_int_enabled(true)を設定すると、アクティブ区間の終了で割り込みが発生します。割り込みハンドラはシステムで用意されたもので PWMn_IRWHandler() (nはPWMチャネル)です。


            割り込み発生         割り込み発生
            V                  V
Vcc    +----+             +----+
       |    |             |    |          t
GND----+    +-------------+    +--------  ->
       <----> アクティブ区間
       <------------------> PWM 1周期

割り込みハンドラを明示的に定義します。TWENETcmpt ライブラリをリンクするかどうかで要定義のハンドラ関数が変わります。

  • TWENETcmpt をリンク => 使用する PWM チャネルのみ定義する
  • TWENETcmpt をリンクしない => PWM0 から PWM9 チャネルまでの割り込みハンドラを割り込みを使用していなくても明示的に定義する

割り込みハンドラ

TWENET を利用する場合は、割り込み関数(cbToCoNet_u8HwInt())、イベント(cbToCoNet_vHwEvent())に変換されます。

独自の割り込みハンドラを定義する場合は PWNn_IRQHandler() を別途定義します。以下の例は PWM1 の定義例です。独自に定義する場合 TWENET の割り込み・イベントは発生しません。

// note: in c file, `extern "C"' should be remoded.
extern "C" void PWM1_IRQHandler(void) {
    PWM_ClearStatusFlags(PWM, kPWM_Pwm1);
}

8 - mwf_periph_rng - TRNG

mwf_periph_rng - TRNG
チップ内蔵の乱数生成ハードウェアを利用するため手続きをまとめたペリフェラルオブジェクトです。

mwf_periph_rng - TRNG

チップ内蔵の乱数生成ハードウェアを利用するため手続きをまとめたペリフェラルオブジェクトthe_rngを実装しています。

TWENET では、暗黙に利用しますので、ユーザプログラム上での初期化の手続きは不要です。

コード例

if (!mwf::the_rng) {
    mwf::rng::global_init_rng_manager();
    mwf::the_rng->init();
}

uint32_t val = mwf::the_rng->random();

class mwf::periph::rng

global_init_rng_manager(), global_deinit_rng_manager()

static void global_init_rng_manager();
static void global_deinit_rng_manager();

the_rngクラスオブジェクトの生成と破棄を行います。クラスオブジェクト生成時に自動的に初期化され、ランダム値の取得が可能になります。

random()

uint32_t random()

乱数値を戻します。

class mwf::periph::rng (sys_ev_handler)

on_sleep()

TRNGの停止処理を行います。

on_wakeup()

TRNGの始動処理を行います。

9 - 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 バスを利用できるように最初期化します。

10 - mwf_periph_wtimer - WTIMER, FRWT

mwf_periph_wtimer - WTIMER, FRWT
ウェイクアップタイマーを利用するため手続きをまとめたペリフェラルオブジェクトです。

mwf_periph_wtimer - WWDT, FRWT

ウェイクアップタイマーを利用するため手続きをまとめたペリフェラルオブジェクトthe_wtimerを実装しています。

TWENETでは暗黙に使用されますので、ユーザプログラムでの初期化は不要です。

ウェイクアップタイマーはモジュール内に内蔵する 32768Hz の水晶振動子に基づき減算カウントします。例えば32768からタイマーを開始した場合、1秒後にカウンタは0にり割り込みが発生します。通常はスリープ起床に用います。起床後もカウンター値は減算を継続するため、起床後にカウント値を読み出すことで、起床後からの経過時間を計算できます。

ウェイクアップタイマーは、2系統あり系統0は40bit(当ライブラリでは32bitカウンタとして利用)、系統1は28bitのカウンタを用います。

またウェイクアップタイマーを利用した FTWT (Free Running Wake Timer) の手続きが含まれます。スリープ時も低消費電流で動作できる特徴をいかし、2系統あるウェイクアップタイマーのうちの一つを常に動作させることで、実時間に対応するカウンタとして利用します。TWENETでは、特定の設定を行うことでFRWTが機能し、FRWTが動作している場合は ADC の初期化待ちなどを効率的に行えます。

TWENETでは系統0をFRWTとして利用し、系統1を通常の起床用タイマーとして利用します。

コード例

  • include
#include "mwf_periph_wtimer.hpp"

class mwf::periph::wtimer

global_init_wtimer_manager(), global_deinit_wtimer_manager()

static void global_init_wtimer_manager();
static void global_deinit_wtimer_manager();

the_wtimerクラスオブジェクトの生成と破棄を行います。

init(), deinit()

void init();
void deinit();

ウェイクアップタイマーを初期化または終了します。

  • 初期化時のパラメータu32msはタイムアウトをミリ秒(ms)で指定します。0または省略したときは4000msとなります。

start(), stop()

void start(uint8_t dev, uint32_t u32ct)
void stop(uint8_t dev)

ウェイクアップタイマーを開始または停止します。

  • devには、使用するウェイクアップタイマーのデバイス番号(WTIMER0_DEVICEまたはWTIMER1_DEVICE)を指定します。
  • u32ctには、開始時のカウント値を指定します。
  • FRWT が動作しているウェイクアップタイマーを指定した場合は、なにもしません。

read()

uint32_t read(uint8_t dev)

ウェイクアップタイマーのカウント値を読み出します。

  • devには、使用するウェイクアップタイマーのデバイス番号(WTIMER0_DEVICEまたはWTIMER1_DEVICE)を指定します。
  • FRWT が動作しているウェイクアップタイマーの値は読み出せません。

is_running()

bool is_running(uint8_t dev)

ウェイクアップタイマーが動作中かを判定します。

  • devには、使用するウェイクアップタイマーのデバイス番号(WTIMER0_DEVICEまたはWTIMER1_DEVICE)を指定します。
  • FRWT が動作しているウェイクアップタイマーを指定した場合は、falseを戻します。

set_interrupt()

void set_interrupt(uint8_t dev, bool b_enabled)

ウェイクアップタイマーが割り込みを発生させるかどうかを指定します。

  • devには、使用するウェイクアップタイマーのデバイス番号(WTIMER0_DEVICEまたはWTIMER1_DEVICE)を指定します。
  • b_enabledtrueに設定すると割り込みを発生させます。この指定がないと、スリープ起床時にも割り込みが発生しません。なお、いちどtrueを指定したウェイクアップタイマーに対してfalseを指定しても、割り込みを無効にすることはできません。
  • FRWT が動作しているウェイクアップタイマーを指定した場合は、なにもしません。

get_fired_status_on_wakeup()

uint8_t get_fired_status_on_wakeup()

スリープ起床後に呼び出し、その起床要因がウェイクアップタイマーであった場合は、デバイスに対応するビット (WTIMER0_DEVICE_MASKまたはWTIMER1_DEVICE_MASK)が設定される。

class mwf::periph::wtimer (sys_ev_handler)

on_sleep()

特別な処理はありません。

on_wakeup()

起床要因を確認し内部に情報を保存し、割り込み状態をクリアします。また、タイマーは停止しません。

FRWT関連

freerun_start(), freerun_stop()

void freerun_start(uint8_t dev)
void freerun_stop()

FRWTの開始と終了を行います。カウント値は開始時を0として、32768Hzで加算される値です。

  • devには、ウェイクアップタイマーのデバイス番号(WTIMER0_DEVICEまたはWTIMER1_DEVICE)を指定します。

freerun_is_running()

bool freerun_is_running()

FRWT が動作している場合に true を返す。

freerun_is_device()

bool freerun_is_device(uint8_t dev)

FRWT が動作しているデバイスなら true を返します。

  • devには、ウェイクアップタイマーのデバイス番号(WTIMER0_DEVICEまたはWTIMER1_DEVICE)を指定します。

freerun_ct_get()

uint32_t freerun_ct_get()

FRWTのカウント値を返します。FRWTのカウント値は、ウェイクアップタイマーの値そのものではなく、0から加算される値に変換されます(大まかには正負反転した値)。

カウント値計算関数

FRWTカウント値をミリ秒に変換したり、2つのカウント値の差を計算する関数です。

freerun_ct_convert_msec()

uint32_t freerun_ct_convert_msec(uint32_t ct, uint32_t* dec_part = nullptr)

FRWTのカウント値ctをミリ秒に変換します。dec_partを指定した場合は、1/10 の桁の値を 0..9 で設定します。

freerun_ct_diff()

int32_t freerun_ct_diff(uint32_t val_past, uint32_t val_now)

カウント値同士を差を計算します。基本的にはval_now - val_pastの値ですが、カウンタが最大値から0に戻った場合を考慮して計算します。カウンタの最大値の半分までの時間差が計算可能で、val_pastの方が古い場合は、正の値を戻します。

freerun_ct_diff_msec()

int32_t freerun_ct_diff_msec(int32 vdiff)

freerun_ct_diff()で得られるカウンタ差分vdiffをミリ秒に変換します。

freerun_ct_diff_usec()

int32_t freerun_ct_diff_usec(int32 vdiff)
int32_t freerun_ct_diff_usec(uint32_t val_past, uint32_t val_now)

freerun_ct_diff()で得られるカウンタ差分値vdiffまたはval_past,val_nowにより計算されるカウンタ差分をマイクロ秒に変換します。

  • 計算上int32_t型の計算による桁溢れが発生します(およそ2000秒を超えるような場合)。

11 - mwf_periph_wwdt - WWDT

mwf_periph_wwdt - WWDT
ウォッチドッグタイマーを利用するため手続きをまとめたペリフェラルオブジェクトです。

mwf_periph_wwdt - WWDT

ウォッチドッグタイマーを利用するため手続きをまとめたペリフェラルオブジェクトthe_wwdtを実装しています。

TWENETでは暗黙に使用されますので、ユーザプログラムでの初期化は不要です。

コード例

void setup_func() {
	mwf::gobal_init_wwdt_manager();
    the_wwdt.init(); // timeout in 4000ms approx.
}

// in some function called periodically (e.g. invoked by SysTick Timer.)
void do_every_tick() {
    the_wwdt.refresh();
}

class mwf::periph::wwdt

global_init_wwdt_manager(), global_deinit_wwdt_manager()

static void global_init_wwdt_manager();
static void global_deinit_wwdt_manager();

the_wwdtクラスオブジェクトの生成と破棄を行います。

init(), deinit()

void init(uint32_t u32ms = 0);
void deinit();

ウォッチドッグタイマーを初期化・停止(※1)します。

  • 初期化時のパラメータu32msはタイムアウトをミリ秒(ms)で指定します。0または省略したときは4000msとなります。
  • ※1 ハードウェアの制約上、一度実行したウォッチドッグタイマーは停止しません。deinit()はライブラリ手続きとして用意しています。(タイマーの再始動時などに deinit()を実行してから init()を再度呼び出す)

set_timeout()

void set_timeout(uint32_t u32ms);

ウォッチドッグタイマーのタイムアウトまでの時間を変更します。u32msにはタイムアウト時間をミリ秒(ms)で指定します。

  • u32msの妥当性の検証はしません。init()では0を規定値としていましたが、本関数で0を与えた場合の振る舞いは未定です。

refresh()

void refresh();

ウォッチドッグタイマーのタイムアウトまでに必ず呼び出すリフレッシュ関数です。

class mwf::periph::wwdt (sys_ev_handler)

on_sleep()

WWDTの停止処理を行います。

on_wakeup()

WWDTの始動処理を行います。

  • スリープ前に稼働状態の場合は、WWDTを再度稼働させます。

12 - class tick_counter - Stop Watch

class tick_counter - Stop Watch
msec, usec 領域のごく短い処理時間を計測するために用います。マイコンのハードウェアのカウント機能を用いています。

class tick_counter - Stop Watch

msec, usec 領域のごく短い処理時間を計測するために用います。マイコンのハードウェアのカウント機能を用いています。

本ライブラリコードについては、十分な確認の上、実験的な利用にとどめておくことを推奨します。最小30usec程度の単位での計測でよい場合は、ウェイクアップタイマーのカウント値が簡便です。

  • CoreDebug->DEMCR, DWTレジスタを制御します。

    • これらレジスタは一般に広く利用することを目的に紹介されているものではないと考えられます。開発中の一時的な時間計測等の利用では大きな問題を経験しないと考えられますが、最終的な運用段階でのファームウェアでの利用については推奨しません
  • 同時に複数のtick_counterオブジェクトを構築することが可能です

    • 利用するカウント機能は一つで、オブジェクト間で機能を共有します。
    • 最初のオブジェクト構築でカウント機能を動作させ、すべてのオブジェクト破棄時にカウント機能を停止させます。

例:

#include <mwf_stop_watch.hpp>

void some_func() {
    ...

    // 計測開始1
    mwf::periph::tick_counter sw;

    sw.lap(); // 計測開始1(直前の sw 構築時にも lap() は呼ばれるが、より厳密に処理の直前に lap() を呼び出す
    ...       // 計測したい処理
    sw.lap(); // 計測終了1

    // 値の表示(計測開始1~計測終了1)
    PRINTF("%dusec", sw.get_us());

    // 次の処理
    sw.lap(); // 計測開始2
    ... // 計測したい処理
    sw.lap(); // 計測終了2

    // 値の表示(計測開始2~計測終了2)
    PRINTF("%dusec", sw.get_us());
}

_start_counter(), _stop_counter()

static void _start_counter();
static void _stop_counter();

CoreDebug機能を用い、カウントタイマーの開始と停止を行います。

tick_counter()

コストラクタです。他に構築されたオブジェクトがなければカウンターを開始し、また、lap() を呼び出し計測を開始します。

~tick_couter()

デストラクタです。すべてのクラスオブジェクトが破棄された時点でカウンターを停止します。

lap()

直前のカウント値を退避し、呼び出された時点でのカウント値を保存します。

経過時間は get_us() により得ます。

13 - mwf-utils - utils

mwf-utils - utils
その他ユーティリティ。

mwf_utils

その他ユーティリティ。

prepare_object()

    template <class T>
    static inline std::unique_ptr<T>& prepare_object(std::unique_ptr<T>& spobj, bool b_construct_if_null = true) {
        if (!spobj && b_construct_if_null) {
            spobj.reset(new T());
        }
        return spobj;
    }

スマートポインタstd::unique_ptr<>のオブジェクトを参照します。オブジェクトが構築されていない場合は new T() により構築します。

get_value_if()

// 関数などから値を得て、その値を用いて処理をすすめる場合
int v = some_func();
if (v != -1) {
    // v の値を用いてなにか処理をする
    printf("%d", v);
}

// 以下のように書き換える
if (auto x = get_value_if::ne(some_func(), -1)) {
    printf("%d", x.value());
}

上記の例のように、関数の戻り値をある条件の場合に利用するときの記述を、if節中の変数宣言を用いて記述するためのユーティリティクラスです。

上記の例では get_value_if::ne() を用い、1つ目のパラメータは戻り値をもった関数呼び出し、2つ目のパラメータは比較する値を指定します。この場合 some_func()の戻り値が -1 でない場合に if 節の中が評価されます。1つ目のパラメータと2つ目のパラメータの型は同じでなければなりません。

判定式により eq, ne, lt, le, gt, ge が利用できます。

get_value_if::xx() (T は型)判定式
eq(T lhs, const T rhs)(lhs == rhs)値が同じであれば true
ne (T lhs, const T rhs)(lhs != rhs)値が違っていれば true
lt (T lhs, const T rhs)(lhs < rhs)値の比較、より小さい値なら true
le (T lhs, const T rhs)(lhs <= rhs)値の比較、以下なら true
gt (T lhs, const T rhs)(lhs > rhs)値の比較、より大きい値なら true
ge (T lhs, const T rhs)(lhs >= rhs)値の比較、以上なら true

Tは型を示します (template 構文の型パラメータ)