2軸加速度センサーIIS2ICLXブレイクアウトをArduino(nRF52840)で動かす

144Labの入江田です。

今後スイッチサイエンスから発売する予定の傾斜センサブレイクアウトボードをnRF52840ボードとArduinoで駆動してみました。

STMicro社製の産業向け加速度センサIIS2ICLX「Tilt Sensor Module」(発売予定)

f:id:irieda:20210325173415j:plain

STMicroが公開しているサンプル

コード例はここにあります。 https://github.com/STMicroelectronics/STMems_Standard_C_drivers/tree/6788aa613bd11340767f691c77e306fc95c05555/iis2iclx_STdC

IIS2ICLXのスペックシートPDFはこちら。 https://www.st.com/resource/en/datasheet/iis2iclx.pdf

SparkFun Pro nRF52840 Mini(Arduino用ボード)

I2Cが使える環境なら何でも良いのですが、ピンの引き出しが容易な「SparkFun Pro nRF52840 Mini」を使って駆動させてみました。

結線について

トップ写真のようにシングルラインヘッダコネクタをつければ結線状況は以下のようになります。 f:id:irieda:20210325173418p:plain

信号名 向き ボードピン番号 コード内シンボル
SCL <- 29 SCL_PIN
SDA <-> 30 SDA_PIN
IO4 -> 31 INT_PIN
GND <- 3 GND_PIN
3.3V <- 2 P33_PIN

Arduinoプロジェクトの開始

ArduinoIDEの場合はFile->New->Saveにてプロジェクト名をつけて保存します。 すると、「~/Documents/Arduino/プロジェクト名/」というフォルダに「プロジェクト名.ino」が保存されます(Windowsユーザーは「/」を「\(バックスラッシュまたは¥)」に読み換えてください)。

STMicroが公開しているサンプルから「iis2iclx_reg.c」「iis2iclx_reg.h」をダウンロードして、「~/Documents/Arduino/プロジェクト名/」フォルダに保存します。(つまりプロジェクト名.inoと同じフォルダに置きます)

arduino-cliを使う場合は任意の作業フォルダに「プロジェクト名/プロジェクト名.ino」ファイルを作製して「プロジェクト名/」フォルダに「iis2iclx_reg.c」「iis2iclx_reg.h」を保存してください。

「プロジェクト名.ino」の内容

ボード依存なコードは「platform_write」「platform_read」関数に集約され、それを「stmdev_ctx_t ctx」に関数ポインタをセットすることでセットアップする仕掛けになっています。

P33_PINを出力にしてHighレベル出力、GND_PINも出力にしてLowレベル出力することでこの加速度センサーの電源として利用します。

その他はSTMicroの公開しているexampleそのままです。

#include <Wire.h>
#include <stdint.h>

#include "iis2iclx_reg.h"

#define P33_PIN 2
#define GND_PIN 3
#define INT_PIN 31
#define SDA_PIN 30
#define SCL_PIN 29

#define II2ICLX_ADDR (IIS2ICLX_I2C_ADD_L >> 1)

TwoWire wire(NRF_TWIM1, NRF_TWIS1, SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQn,
             SDA_PIN, SCL_PIN);

static int32_t platform_write(void *handle, uint8_t reg, uint8_t *bufp,
                              uint16_t len) {
  wire.beginTransmission(II2ICLX_ADDR);
  wire.write(reg);
  wire.write(bufp, len);
  return wire.endTransmission(false);
}

static int32_t platform_read(void *handle, uint8_t reg, uint8_t *bufp,
                             uint16_t len) {
  byte rc;
  uint8_t cnt;

  wire.beginTransmission(II2ICLX_ADDR);
  wire.write(reg);
  rc = wire.endTransmission(false);
  if (rc == 0) {
    wire.requestFrom((int32_t)II2ICLX_ADDR, (int32_t)len, true);
    cnt = 0;
    while (wire.available()) {
      bufp[cnt] = wire.read();
      cnt++;
    }
    if (cnt < len) {
      rc = 4;
    }
  }
  return rc;
}

stmdev_ctx_t ctx = stmdev_ctx_t{
    .write_reg = platform_write, .read_reg = platform_read};

void setup() {
  pinMode(P33_PIN, OUTPUT);  // 3.3V
  digitalWrite(P33_PIN, 1);
  pinMode(GND_PIN, OUTPUT);  // GND
  digitalWrite(GND_PIN, 0);

  Serial.begin(115200);

  wire.begin();
  wire.setClock(100000);
  delay(100);

  iis2iclx_bus_mode_set(&ctx, IIS2ICLX_SEL_BY_HW);
  uint8_t whoamI;
  iis2iclx_device_id_get(&ctx, &whoamI);
  Serial.print("whoamI: ");
  Serial.printBuffer(&whoamI, 1);
  Serial.println("");
  iis2iclx_reset_set(&ctx, PROPERTY_ENABLE);
  uint8_t rst = 1;
  while (rst) {
    iis2iclx_reset_get(&ctx, &rst);
    delay(20);
  }
  /* Enable Block Data Update */
  iis2iclx_block_data_update_set(&ctx, PROPERTY_ENABLE);
  /* Set Output Data Rate */
  iis2iclx_xl_data_rate_set(&ctx, IIS2ICLX_XL_ODR_12Hz5);
  /* Set full scale */
  iis2iclx_xl_full_scale_set(&ctx, IIS2ICLX_2g);
  /* Configure filtering chain(No aux interface)
   * Accelerometer - LPF1 + LPF2 path
   */
  iis2iclx_xl_hp_path_on_out_set(&ctx, IIS2ICLX_LP_ODR_DIV_100);
  iis2iclx_xl_filter_lp2_set(&ctx, PROPERTY_ENABLE);
  Serial.println("setup completed");
}

void loop() {
  uint8_t reg;
  float x = 0;
  float y = 0;
  float temperature = 0;
  iis2iclx_xl_flag_data_ready_get(&ctx, &reg);
  if (reg) {
    /* Read acceleration field data */
    int16_t accel[2];
    iis2iclx_acceleration_raw_get(&ctx, &accel[0]);
    x = iis2iclx_from_fs2g_to_mg(accel[0]);
    y = iis2iclx_from_fs2g_to_mg(accel[1]);
  }
  iis2iclx_temp_flag_data_ready_get(&ctx, &reg);
  if (reg) {
    /* Read temperature data */
    int16_t tmp;
    iis2iclx_temperature_raw_get(&ctx, &tmp);
    temperature = iis2iclx_from_lsb_to_celsius(tmp);
  }
  Serial.printf("Accel: %6.1f, %6.1f Temp.: %5.2f\n", x, y, temperature);
  delay(100);
}

Arduinoボード関連設定

「Adafruit nRF52」ボードサポート

ArduinoIDEもarduino-cliも以下の手順で「Adafruit nRF52」ボードサポートをインストールします。

Additional boards manager URLsに以下のURLを追加します。

https://www.adafruit.com/package_adafruit_index.json

「Adafruit nRF52(v0.21.0以降)」のボードサポートをインストールしてください。

以下はarduino-cliでボードサポートをインストールする方法です。

arduino-cli core update-index && arduino-cli core install adafruit:nrf52

ボード選択

ArduinoIDEでは以下のボードを選んでください。

f:id:irieda:20210325173516p:plain

arduino-cli では「FQBN=adafruit:nrf52:pca10056」とします。 コンパイルとボードへのアップロードは以下のコマンドで

arduino-cli compile -b adafruit:nrf52:pca10056 プロジェクト名
arduino-cli upload -b adafruit:nrf52:pca10056 -p シリアルポート名 プロジェクト名

出力例

pip3 install pyserialするとpyserial-minitermというツールが使えます。 pyserial-miniterm ポート名 115200するとターゲットのログ出力が見れます。 ArduinoIDEの場合はSerial Monitorで。

whoamI: 6B
setup completed
Accel:    0.0,    0.0 Temp.: 22.21
Accel:   23.7,    1.2 Temp.: 20.54
Accel:   30.2,    0.1 Temp.: 20.68
Accel:  143.7,    0.2 Temp.: 20.64
Accel:  195.1,    0.3 Temp.: 20.66
Accel:  243.3,    0.4 Temp.: 20.69
Accel:  331.0,    0.5 Temp.: 20.66
Accel:  370.8,    0.6 Temp.: 20.66
Accel:  408.0,    0.7 Temp.: 20.71
Accel:  475.7,    0.7 Temp.: 20.69
Accel:  506.4,    0.8 Temp.: 20.70
Accel:  535.2,    0.9 Temp.: 20.68
Accel:  587.5,    0.9 Temp.: 20.70
Accel:  611.2,    1.0 Temp.: 20.68
Accel:  633.4,    1.0 Temp.: 20.68

まとめ

IIS2ILXシリーズは内部にフィルタ処理を持ちノイズが少なく、温度変動が少ない、動作可能温度範囲が広いなど産業用途に向いた特徴を持っています。温度も測れるため温度変動の補正もやろうと思えばできます。platform_??関数さえ環境に応じた実装を書けばいろんな環境で動作させられます。

nRF52840シリーズの乗ったブレイクアウトボードはUSB機能やBluetooth5.0機能および任意のピンをI2Cとして利用可能なのでこういった実験をするのに向いています。

ひとつのハマりポイントを紹介しておくと、ArduinoのI2Cは7bitアドレス表記を期待していて、STMicroのドライバは8bitアドレス表記になっているところです。

なのでコードの冒頭で1bit左シフトした値を再定義しています。

#define II2ICLX_ADDR (IIS2ICLX_I2C_ADD_L >> 1)