【Arduino】XIAO nRF52840/XIAO nRF52840 Senseを使う

it

SeeedStudioのXIAO nRF52840とXIAO nRF52840 Senseを使ってみました。
XIAOシリーズでノルディックを搭載しています。
基本的なGPIOと通信の使い方の他、6軸IMU、PDM Microphone、無線機能をを使いました。

XIAO nRF52840 / XIAO nRF52840 Sense

簡単紹介

Seeedstudio のXIAO規格にnRF52840を搭載した基板。
無線機能他、XIAO nRF52840 Senseには、IMU 6軸センサ、PMD Picrophoneを搭載。

メーカーホームページ : Getting Started with Seeed Studio XIAO nRF52840 Series | Seeed Studio Wiki

◆入手

国内電子部品販売店サイト、AliExpressで入手できます。
XIAO ESP32S3 \1,500(送料別)
XIAO EsP32S3 Sense \2,700(送料別)が目安。

◆XIAOシリーズの記事

XIAO SAMD21XIAO SAMD21を使った記事。
基本的なGPIOの操作とDAC出力、書き込み時のトラブルについてまとめた記事です。
XIAO RP2040XIAO RP2040を使った記事。
使っている時に発生したI2CのWireとWire1問題、WS2812の点灯などトラブルを中心に記載しました。
XIAO ESP32-C3XIAO ESP32-C3を使った記事。
GPIOを使った基本スケッチ、BLE UARTを使った内容を記事にしました。
XIAO ESP32-S3XIAO ESP32-S3/XIAO ESP32-S3 Sense を使った記事。
GPIOを使った基本スケッチの他静電容量タッチセンサ、カメラWebサーバーを使った内容を記事にしました。
XIAO nRF52840XIAO nRF52840/XIAO nRF52840 Senseを使った記事。
GPIOを使った基本スケッチ、BLE UART他、XIAO nRF52840 SenseのIMU 6軸センサ、PDM Microphoneを使った内容を記事にしました。
XIAO RA4M1XIAO RA4M1を使った記事。
基板特有のトラブルと基本的なGPIOの操作について記事にしました。
XIAO RP2350XIAO RP2350を使った記事。
XIAO RP2040との比較を中心に搭載機能を使った内容を記事しました。
XIAO ESP32C6XIAO ESP32C6を使った記事。
基本的なGPIOの使い方からWiFiServerにして読み取ったDA値を表示してみた内容を記事にしました。

ピン配置

外観

◆XIAO nRF52840

◆XIAO nRF52840 Sense

使ってみた

◆開発

Arduino環境で開発します。
ボードライブラリにはSeeed Studioの「Seeed XIAO nRF52840」と「Seeed XIAO nRF52840 Sense」を使いました。

書き込みを行うとシリアルポートが認識されなくなる。
認識はされていなくても書き込みはできるが不安になります。

GPIOのLOW/HIGHを繰り返す簡単なスケッチのコンパイル時間を計測した結果は約10秒です。
Arduino nano 328pの3秒ほどではありませんがまずまずの速さです。

◆XIAO ESP32-S3とXIAO ESP32-S3-Sense

無線を使用できるマイコンモジュールで、アンテナ不要で完成形です。
XIAOシリーズでアンテナを取り付けずに無線が使えます。

◆性能評価

搭載されているCPUはnRF52840です。
GPIOのLowとHighを繰り返す単純ループの結果はCPUクロックに対してまずまずの速度でした。

基板名CPUクロック(MHz)結果(周期 MHz)
ESP32 DevkitC V4Xtensa LX62404.2
XIAO nRF52840Nordic nRF52840641.13
XIAO ESP32-S3Xtensa LX72400.98

◆ユーティリティ

とても小さなResetボタンが実装されています。
指先で押すのは難しく、タッチパネルの樹脂ペンなどでようやく押せるレベルです。

シリアル認識しなくなりスケッチが書き込めなるなるとResetボタンを2回押しする作業が必要になりますが、このサイズのボタンでは作業しにくい。

◆6軸IMU

Seeedの「Seeed Arduino LSM6DS3」ライブラリを使うことで簡単に使用できますが、ボードライブラリのボード名が「Seeed XIAO nRF52840 Sense」だと動作しないので注意です。

XIAO nRF52840 Senseの向きに対するセンサーの読み取り値をグラフにしました。
手で角度を変えていたのできれいに変化できていないところがあります。
センサーは敏感で振動でも読み取った値に現れます。

◆PDM Microphone

ボードライブラリのサンプルスケッチ
「Examples > nRF52840 PDM – Adafruit Fork > PDMSerialPlotter」を使いました。
サンプリング周期が安定していませんが、一般的な可聴範囲10kHz~20kHzは十分カバーできそうです。
振幅は音量に依存しているようです。

まとめ

程よく性能があり、コンパイル時間も速いです。
小型でアンテナを別装備することなく無線を使えます。

XIAO nRF52840 Senseでは6軸IMUを装備、PDM Microphoneが実装されているので、狭小か所への組み込みには有利です。

書き込みを行うたびにCOMポートが消える他、COM認識させるためのRSTボタンが小さくて操作が難しい問題があります。
簡単なBLE UARTも結構なコードが必要なため気軽さはありません。
少し高価なところも気安く使いにくいと思います。

準備

Arduino環境の作成

◆開発環境

当記事ではArduino環境を使って開発します。
Arduino環境の準備はこちらの記事で紹介しています。

◆ボードライブラリ

Arduino IDEのボードマネージャからESP32用のライブラリのインストールとボードの選択をします。

ボードマネージャのURLhttps://sandeepmistry.github.io/arduino-nRF5/package_nRF5_boards_index.json
検索nrf52840
ボードライブラリSeeed nRF52 Boards by Seeed Studio バージョン x.x.x
選択するボード
(XIAO nRF52840)
Seeed nRF52 Boards > Seeed XIAO nRF52840
選択するボード
(XIAO nRF52840 Sense)
Seeed nRF52 Boards > Seeed XIAO nRF52840 sense
※ x.x.x 動作確認時のバージョン1.1.9

◆モジュールライブラリ

モジュールや機能を使用しない場合はモジュールライブラリのインストールは不要です。

SSD1306

ライブラリ名検索確認時のバージョン
Adafruit SSD1306 by AdafruitSSD13062.5.11
Adafruit GFX Library by AdafruitGFX1.11.10

ILI9341

ライブラリ名検索確認時のバージョン
Adafruit ILI9341 by AdafruitILI93411.6.1
Adafruit GFX Library by AdafruitGFX1.11.10

6軸IMU(LSM6DS3)

XIAO nRF52840 Senseで6軸IMUを使用する場合にインストールが必要です。
ライブラリを以下のサイトからダウンロードし、以下画像手順に従ってインストールします。

外部サイト : GitHub – Seeed-Studio/Seeed_Arduino_LSM6DS3: Grove sensor 6 Axis Accelerometer&Gyroscope using LSM6DS3

Bluetoothのペアリング

Bluetoothを使ったスケッチを動作させるときにnRF52840とBluetoothホスト側とペアリングします。
ペアリングはnRF52840にスケッチを書き込み起動した状態で行います。

こちらはXIAO nRF52840とスマートフォンのペアリング操作一例です。
使用するスマートフォンにより操作が違うので、差異は各スマートフォンのマニュアルを参照します。
Androidの「設定>接続済みの端末」へ進み、ペアリングするモジュールの検索とペアリングをします。

スケッチ : XIAO nRF52840 / XIAO nRF52840 Sense共通

デジタル出力

説明

GPIOのデジタル出力を使い信号の出力をモニタします。
GPIO出力のLowとHighの繰り返し速度の計測をします。

GPIO D0(GPIO0)とGNDをオシロスコープ(HDS272)でプローブし、信号間の時間を計測します。

配線

配線不要。
GPIO D0(GPIO0)とGNDをオシロスコープでプローブします。

スケッチ

#define SIGNAL_PIN (D0)

void setup()
{
  pinMode(D0, OUTPUT);
}

void loop()
{
  while(1)
  {
    digitalWrite(D0, HIGH);
    digitalWrite(D0, LOW);
  }
}

結果

このスケッチのコンパイル時間は約10秒でした。
オシロスコープ(HDS272)でGPIOのLow/High時間を計測しました。
信号の間隔は880ns、1秒間に繰り返す周期は1.136MHzでした。

デジタル出力(ユーザRGB LED)

説明

XIAO nRF52840 のユーザLED(RGB LED)を使います。

LEDは3色発光(赤、緑、青)で、Negative(信号をLOWにすると発光)です。

各色の発光と輝度を組み合わせてフルカラーを表現します。
このスケッチでは、赤、緑、黄、青、紫、水、白の順に発光します。

配線

配線不要

スケッチ

void setup()
{
  pinMode(LED_RED, OUTPUT);
  pinMode(LED_GREEN, OUTPUT);
  pinMode(LED_BLUE, OUTPUT);

  while(1)
  {
    for(int16_t i = 0; i < 8; i ++)
    {
      switch(i)
      {
        case 0:
          digitalWrite(LED_RED, HIGH);
          digitalWrite(LED_GREEN, HIGH);
          digitalWrite(LED_BLUE, HIGH);
          break;

        case 1:
          digitalWrite(LED_RED, LOW);
          digitalWrite(LED_GREEN, HIGH);
          digitalWrite(LED_BLUE, HIGH);
          break;

        case 2:
          digitalWrite(LED_RED, HIGH);
          digitalWrite(LED_GREEN, LOW);
          digitalWrite(LED_BLUE, HIGH);
          break;

        case 3:
          digitalWrite(LED_RED, LOW);
          digitalWrite(LED_GREEN, LOW);
          digitalWrite(LED_BLUE, HIGH);
          break;

        case 4:
          digitalWrite(LED_RED, HIGH);
          digitalWrite(LED_GREEN, HIGH);
          digitalWrite(LED_BLUE, LOW);
          break;

        case 5:
          digitalWrite(LED_RED, LOW);
          digitalWrite(LED_GREEN, HIGH);
          digitalWrite(LED_BLUE, LOW);
          break;

        case 6:
          digitalWrite(LED_RED, HIGH);
          digitalWrite(LED_GREEN, LOW);
          digitalWrite(LED_BLUE, LOW);
          break;

        case 7:
          digitalWrite(LED_RED, LOW);
          digitalWrite(LED_GREEN, LOW);
          digitalWrite(LED_BLUE, LOW);
          break;
      }      
      delay(1000);
    }
  }
}

void loop()
{
}

結果

順に色を変えながら発光しました。
発光の様子です。
画像ではわかりにくいがそれほど混色してなく各色の発光状態がわかってしまいます。
紫と白の混ざりが悪く見えます。

GPIOデジタル入出力(ボタンLED)

説明

XIAO nRF52840のデジタル入力とデジタル出力を使います。

ボタンを押している間LEDを点灯させます。
ボタンの入力はINPUT_PULLDOWNによりプルダウン設定をします。

配線

スケッチ

#define LED_PIN     (D0)
#define BUTTON_PIN  (D1)

void setup()
{
  pinMode(LED_PIN, OUTPUT);
  pinMode(BUTTON_PIN, INPUT_PULLDOWN);
}

void loop()
{
  int iStat = digitalRead(BUTTON_PIN);
  digitalWrite(LED_PIN, iStat);
}

結果

ボタンを押下するとLEDが点灯しました。
ボタンを離すとLEDが消灯しました。

ADC

説明

XIAO ESP32-S3のADCを使います。

電圧はXIAO SAMD21のDACを使い0 ~ 3.3Vを入力します。
XIAO ESP32-S3のADCで読み取った値はシリアル(COM)出力します。

配線

サンプルスケッチ

#include <Adafruit_TinyUSB.h>

#define ADC_PIN   (A0)

void setup()
{
  Serial.begin(115200);
  pinMode(ADC_PIN, INPUT);
}

void loop()
{
  int iADC = 0;

  iADC = analogRead(ADC_PIN);
  Serial.printf("(ADC) = %d\r\n", iADC);
  delay(2);
}

結果

左下はXIAO SAMD21から入力した電圧をオシロスコープ(HDS272)で読み取ったものです。
右下は読み取った値をプロットしてグラフにしました。

読み取った値はノイズもなくリニアに変化しています。
最大値は935(AD)で折り返しました。
入力電圧3.3Vに対して1割程度小さな値でした。

PWM

説明

XIAO nRF52840のPWM信号をモニタします。
GPIO0(D0)を使い、Dutyを1, 50, 99%に設定します。

配線

配線不要。
GPIO0(D0)とGNDにオシロスコープのプローブをあてます。

サンプルスケッチ

#define PWM_PIN   (D0)

int16_t tblPWM[] = {1 ,128 ,254};

void setup() 
{
  int16_t tblMax = sizeof(tblPWM) / sizeof(int16_t);

  while(1)
  {
    for(int16_t i = 0; i < tblMax; i ++)
    {
      analogWrite(PWM_PIN, tblPWM[i]);
      delay(3000);
    }
  }
}

void loop()
{
}

結果

PWMの信号出力の波形をオシロスコープ(HDS272)で読み取りました。
PWMの周期は62.5kHzで高い周波数でした。

Duty1% と 99%の信号を拡大してみましたが、信号波形がつぶれることなくフラットトップ(ボトムが)確認できました。

UART通信

UART

XIAO nRF52840 でUARTを使用する場合「Adafruit_TinyUSB.h」をIncludeします。
XIAO nRF52840では、USBシリアルとUARTは別々のオブジェクトを使用します。
UARTで使用するピン変更はできません。

ポート(仮称)オブジェクト名UARTピン
USBシリアルSerial
UARTSerial1TX(6), RX(7)

説明

XIAO nRF52840のUSBシリアルとUARTを使います。

USBシリアルからの入力はUARTのTXに送信します。
UARTのRXからの入力はUSBシリアルに送信します。

配線

スケッチ

#include <Adafruit_TinyUSB.h>

void setup()
{
  Serial.begin(115200);
  Serial1.begin(115200);
}

void loop() 
{
  if(Serial.available() != 0)
  {
    Serial1.write(Serial.read());
  }

  if(Serial1.available() != 0)
  {
    Serial.write(Serial1.read());
  }
}

結果

USBシリアルとUART通信の様子です。

Teratermを2つ起動します。
ローカルエコーは有効です。
画像左下のTeratermはXIAO nRF52840のUSBシリアルでCOM31で認識されました。
画像右下のTeratermはUARTでCOM8で認識されました。

COM31側から「tamanegi」と入力すると、COM8側にも「tamanegi」と表示されました。
COM8側から「xiao」と入力すると、COM31側にも「xiao」と表示されました。

I2C(SSD1306)

説明

I2Cを使ってSSD1306(OLED 0.96inch)モニタを表示制御します。
SSD1306の表示制御にはAdafruit製の「Adafruit SSD1306 by Adafruit」を使いました。

この描画サンプルは円周上の3点を直線で結んで3角形が回転しているように見せています。

描画サンプルはAdafruit SSD1306 のサンプルスケッチを参考にしました。
File > Examples > Adafruit SSD1306 > ssd1306_128x64_i2c

配線

スケッチ

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH    (128)
#define SCREEN_HEIGHT   (64)

#define OLED_RESET      (-1)
#define SCREEN_ADDRESS  (0x3C)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

void setup()
{

  Serial.begin(115200);
  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    for(;;);
  }
  display.clearDisplay();
}

void loop()
{
  int16_t arrayMap[] = {0, 120, 240};
  int16_t mapSize = sizeof(arrayMap) / sizeof(int16_t);

  const int16_t r = 20;
  const int16_t offsetX = 50;
  const int16_t offsetY = 30;
  int16_t x1, y1;
  int16_t x0, y0; 
  for (int angle = 0; angle < 360; angle++)
  {
    display.clearDisplay();
    for(int16_t mIndex = 0; mIndex < mapSize; mIndex ++)
    {
      int16_t a = (arrayMap[mIndex] + angle) % 360;
      int x = offsetX + r * cos(radians(a));
      int y = offsetY + r * sin(radians(a));

      if(mIndex == 0)
      {
        x0 = x;
        y0 = y;
      }
      else if(mIndex < (mapSize - 1))
      {
        display.drawLine(x1, y1, x, y, 1);
      }
      else
      {
        display.drawLine(x1, y1, x, y, 1);
        display.drawLine(x, y, x0, y0, 1);
      }
      x1 = x;
      y1 = y;
    }
    display.display();
    delay(5);
  }
}

結果

三角形がゆっくり回転している描画ができました。

SPI(ILI9341)

説明

SPIを使ってILI9341(LCD 2.4inch)とタッチパネルを使います。

LCDにはタッチした座標にポイントを描画し簡単なペイントモジュールにします。
LCDの解像度とタッチパネルの分解能には差があるのでスケール調整をしています。
タッチ座標の位置ずれを補正しています。

参考にしたILI9341の描画サンプルです。
File > Examples > Adafruit ILI9341 > graphicstest

配線

スケッチ

#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include <XPT2046_Touchscreen.h>
#include <SPI.h>

#define LCD_WIDTH           (320)
#define LCD_HEIGHT          (240)
#define TOUCH_WIDTH_ADJUST  (300)
#define TOUCH_HEIGHT_ADJUST (300)
#define TOUCH_WIDTH         (4000 - TOUCH_WIDTH_ADJUST)
#define TOUCH_HEIGHT        (4000 - TOUCH_HEIGHT_ADJUST)
#define TOUCH_OFFSET_X      (150)
#define TOUCH_OFFSET_Y      (150)
#define RADIUS              (2)

#define TFT_CS              (D0)
#define TFT_RST             (D1)
#define TFT_DC              (D2)

#define TOUCH_CS            (D3)

XPT2046_Touchscreen ts(TOUCH_CS);
Adafruit_ILI9341 tft = Adafruit_ILI9341(&SPI, TFT_DC, TFT_CS, TFT_RST);

void setup()
{
  tft.begin();
  tft.setRotation(1);
  tft.setTextSize(2);
  tft.fillScreen(ILI9341_BLACK);

  ts.begin(SPI);
  ts.setRotation(3);
}

void loop()
{
  boolean bTouch = ts.touched();
  const float RateX = (float)LCD_WIDTH / (TOUCH_WIDTH - TOUCH_OFFSET_X);
  const float RateY = (float)LCD_HEIGHT / (TOUCH_HEIGHT - TOUCH_OFFSET_Y);

  if (ts.touched() == true)
  {
    TS_Point tPoint = ts.getPoint();

    int16_t x = (float)(tPoint.x - TOUCH_OFFSET_X) * RateX;
    int16_t y = (float)(tPoint.y - TOUCH_OFFSET_Y) * RateY;
    tft.fillCircle(x, y, RADIUS, ILI9341_WHITE);
  }
  delay(10);
}

結果

座標ばらつきが見られますがタッチしたポイントにドット描画できました。
座標ばらつきはモジュールによるもので、別のモジュールを選定するか座標情報に移動平均することで緩和できます。

BLE-HID(マウス)

サンプルスケッチ

XIAO nRF52840のBLEを使ったHIDマウスを作ります。

BLEマウスはサンプル参考にして修正しています。
Examples > Adafruit Bluefruit nRF52 Libraries > Peripheral > blehid_mouse

オリジナルのサンプルからの修正点は、ボタンに使用するGPIOの定義と設定、loop()内の処理です。

GPIO 0(D0)に接続したボタンをPULL_DOWN設定にしてボタンのOff/On状態を読み取ります。
ボタンが押されていればマウスカーソルを画面の左上に移動します。

ボタンの移動を複数回行うのは1回に移動できる幅に上限があり、複数回移動を実施することで画面の解像度分を補いました。

配線

スケッチ

#include <bluefruit.h>

BLEDis bledis;
BLEHidAdafruit blehid;

#define BUTTON_PIN  (D0)

void setup() 
{
  Serial.begin(115200);

  Bluefruit.begin();
  Bluefruit.Periph.setConnInterval(9, 16);
  Bluefruit.setTxPower(4);
  
  bledis.setManufacturer("Adafruit Industries");
  bledis.setModel("Bluefruit Feather 52");
  bledis.begin();

  blehid.begin();

  pinMode(BUTTON_PIN, INPUT_PULLDOWN);
  startAdv();
}

void startAdv(void)
{  
  // Advertising packet
  Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
  Bluefruit.Advertising.addTxPower();
  Bluefruit.Advertising.addAppearance(BLE_APPEARANCE_HID_MOUSE);
  
  // Include BLE HID service
  Bluefruit.Advertising.addService(blehid);

  // There is enough room for 'Name' in the advertising packet
  Bluefruit.Advertising.addName();
  
  /* Start Advertising
   * - Enable auto advertising if disconnected
   * - Interval:  fast mode = 20 ms, slow mode = 152.5 ms
   * - Timeout for fast mode is 30 seconds
   * - Start(timeout) with timeout = 0 will advertise forever (until connected)
   * 
   * For recommended advertising interval
   * https://developer.apple.com/library/content/qa/qa1931/_index.html   
   */
  Bluefruit.Advertising.restartOnDisconnect(true);
  Bluefruit.Advertising.setInterval(32, 244);    // in unit of 0.625 ms
  Bluefruit.Advertising.setFastTimeout(30);      // number of seconds in fast mode
  Bluefruit.Advertising.start(0);                // 0 = Don't stop advertising after n seconds  
}

void loop() 
{
  if(digitalRead(BUTTON_PIN) == HIGH)
  {
    for(int16_t i = 0; i < 20; i ++)
    {
      blehid.mouseMove(-127, -127);
    }
    delay(100);
  }
}

結果

BLEマウスとしての動作をします。
ボタンを押すとマウスカーソルが画面の左上に移動します。
複数回の移動を行うため移動の軌跡が見えることがあります。

マウスカーソルが迷子になったとき、ボタンを押すと左上に移動してくれるガジェットです。
動画でもわかりにくいですが、ボタンを押すと画面左上にマウスカーソルが移動しています。

BLE-HID(キーボード)

説明

XIAO nRF52840のBLEを使ったHIDキーボードを作ります。

BLEキーボードはサンプル参考にして修正しています。
Examples > Adafruit Bluefruit nRF52 Libraries > Peripheral > blehid_keyboard

オリジナルのサンプルからの修正点は、ボタンに使用するGPIOの定義と設定、loop()内の処理です。

GPIO 0(D0)に接続したボタンをPULL_DOWN設定にしてボタンのOff/On状態を読み取ります。
ボタンが押されていれば”password”とキーボード出力します。

配線

サンプルスケッチ

サンプルスケッチライブラリの参照元

#include <bluefruit.h>

BLEDis bledis;
BLEHidAdafruit blehid;

#define BUTTON_PIN        (D0)
#define KEY_LEFT_GUI      0x83

const char strKey[] = "password";
bool flagOn = false;

void setup() 
{
  pinMode(BUTTON_PIN, INPUT_PULLDOWN);

  Bluefruit.begin();
  Bluefruit.setTxPower(4);    // Check bluefruit.h for supported values

  // Configure and Start Device Information Service
  bledis.setManufacturer("Adafruit Industries");
  bledis.setModel("Bluefruit Feather 52");
  bledis.begin();

  /* Start BLE HID
   * Note: Apple requires BLE device must have min connection interval >= 20m
   * ( The smaller the connection interval the faster we could send data).
   * However for HID and MIDI device, Apple could accept min connection interval 
   * up to 11.25 ms. Therefore BLEHidAdafruit::begin() will try to set the min and max
   * connection interval to 11.25  ms and 15 ms respectively for best performance.
   */
  blehid.begin();

  // Set callback for set LED from central
//  blehid.setKeyboardLedCallback(set_keyboard_led);

  /* Set connection interval (min, max) to your perferred value.
   * Note: It is already set by BLEHidAdafruit::begin() to 11.25ms - 15ms
   * min = 9*1.25=11.25 ms, max = 12*1.25= 15 ms 
   */
  /* Bluefruit.Periph.setConnInterval(9, 12); */

  // Set up and start advertising
  startAdv();
}

void startAdv(void)
{  
  // Advertising packet
  Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
  Bluefruit.Advertising.addTxPower();
  Bluefruit.Advertising.addAppearance(BLE_APPEARANCE_HID_KEYBOARD);
  
  // Include BLE HID service
  Bluefruit.Advertising.addService(blehid);

  // There is enough room for the dev name in the advertising packet
  Bluefruit.Advertising.addName();
  
  /* Start Advertising
   * - Enable auto advertising if disconnected
   * - Interval:  fast mode = 20 ms, slow mode = 152.5 ms
   * - Timeout for fast mode is 30 seconds
   * - Start(timeout) with timeout = 0 will advertise forever (until connected)
   * 
   * For recommended advertising interval
   * https://developer.apple.com/library/content/qa/qa1931/_index.html   
   */
  Bluefruit.Advertising.restartOnDisconnect(true);
  Bluefruit.Advertising.setInterval(32, 244);    // in unit of 0.625 ms
  Bluefruit.Advertising.setFastTimeout(30);      // number of seconds in fast mode
  Bluefruit.Advertising.start(0);                // 0 = Don't stop advertising after n seconds
}

void loop() 
{
  if(digitalRead(BUTTON_PIN) == HIGH)
  {
    delay(10);
    if(digitalRead(BUTTON_PIN) == HIGH)
    {
      if(flagOn == false)
      {
        for(int i = i; i < strlen(strKey); i ++)
        {
          blehid.keyPress(strKey[i]);
          blehid.keyRelease();
        }
        flagOn = true;
      }
    }
  }
  else
  {
    flagOn = false;
  }
}

結果

BLEキーボードとしての動作をしました。
ボタンを一回押すと”password”と入力されます。

ノートパソコンとSeeed XIAO BLE nRF52840 はBLEペアリング済みです。

BLE-UART

準備

XIAO nRF52840とスマートフォンでBLE UARTします。

この作業には手順があります。
1.スケッチをXIAO nRF52840に書き込む。
2.スケッチが動き出したらXIAO nRF52840とスマートフォンをペアリングする。
3.スマートフォンのBluetooth通信アプリ「Serial Bluetooth Terminal」を起動し通信を開始する。

「Serial Bluetooth Terminal」を使いXIAO nRF52840とBLE-UART接続の操作です。
「メニュー>Devices」へ進み、Bluetooth LEのリストから接続するモジュールを選択します。


サンプルスケッチ

BLE-UARTは、nRF52840 ボードライブラリのサンプルを使用しました。
Examples > Adafruit Bluefruit nRF52 Libraries > Peripheral > bleuart

結果

XIAO nRF52840のシリアル通信にはArduino IDEのシリアルモニタを使いました。

BLE-UART接続したらアプリケーション下部入力ボックスから”XIAO BLEUART”と入力して送信ボタン(紙飛行機アイコン)をタップします。
シリアルモニタに”XIAO BLEUART”の文字列が表示されました。

シリアルモニタから”hello world!!”と入力しEnterキーを押すとアプリケーションの送受信履歴に”hello world!!”と表示されました。

スケッチ : XIAO nRF52840 Sense のみ

6軸IMU

説明

XIAO nRF52840 Senseの6軸IMUセンサを使います。

モジュールライブラリは「Seeed Arduino LSM6DS3」を使用しました。
「Examples > Seeed Arduino LSM6DS3 > LowLevelExample」を参考にしました。

X, Y, Z軸の情報を読み取りシリアル出力します。
角度は手で動かしました。
各軸5秒程度で180°回転させる目標で作業しています。

注意

モジュールライブラリ「Seeed Arduino LSM6DS3」を使い6軸IMUを使う場合は、ボードライブラリ「Seeed nRF52 Boards」の「Seeed XIAO nRF52840 Sense」を選択します。
「Seeed XIAO nRF52840」ではコンパイルと書き込みができますが6軸IMUは使えません。

スケッチ

#include "LSM6DS3.h"
#include "Wire.h"

uint16_t errorsAndWarnings = 0;

LSM6DS3Core myIMU(I2C_MODE, 0x6A);

void setup()
{

    Serial.begin(9600);
    while (!Serial);

    if (myIMU.beginCore() != 0) {
        Serial.print("\nDevice Error.\n");
    } else {
        Serial.print("\nDevice OK.\n");
    }

    uint8_t dataToWrite = 0;
    
    dataToWrite = 0;
    dataToWrite |= LSM6DS3_ACC_GYRO_BW_XL_100Hz;
    dataToWrite |= LSM6DS3_ACC_GYRO_FS_XL_8g;
    dataToWrite |= LSM6DS3_ACC_GYRO_ODR_XL_104Hz;

    errorsAndWarnings += myIMU.writeRegister(LSM6DS3_ACC_GYRO_CTRL1_XL, dataToWrite);

    errorsAndWarnings += myIMU.readRegister(&dataToWrite, LSM6DS3_ACC_GYRO_CTRL4_C);
    dataToWrite &= ~((uint8_t)LSM6DS3_ACC_GYRO_BW_SCAL_ODR_ENABLED);

}

void loop()
{
    int16_t axisX, axisY, axisZ;

    if (myIMU.readRegisterInt16(&axisX, LSM6DS3_ACC_GYRO_OUTX_L_XL) != 0)
    {
        errorsAndWarnings++;
    }

    if (myIMU.readRegisterInt16(&axisY, LSM6DS3_ACC_GYRO_OUTY_L_XL) != 0) 
    {
        errorsAndWarnings++;
    }

    if (myIMU.readRegisterInt16(&axisZ, LSM6DS3_ACC_GYRO_OUTZ_L_XL) != 0)
    {
        errorsAndWarnings++;
    }
    Serial.printf("x, y, z = %d, %d, %d\r\n", axisX, axisY, axisZ);
    delay(100);
}

結果

モジュールの角度状態と読み取った結果をグラフにしました。
手で角度を変えているのでなめらかな値を読み取ることはできませんでしたが十分判断できます。
状態はモジュールに対して横からの視点です。

読み取り値にはバラつきがあり、静止状態でのバラつきの幅は5~10程度でした。

PDM Microphone

説明

XIAO nRF52840 SenseのPDM Microphoneを使います。

XIAO nRF52840 ボードライブラリ「Seeed nRF52 Boards by Seeed Studio」のサンプルスケッチ
「Examples > nRF52840 PDM – Adafruit Fork > PDMSerialPlotter」
を使います。

実行すると検出した音情報をUSBシリアルに出力します。

スケッチ

Examples > nRF52840 PDM – Adafruit Fork > PDMSerialPlotter

結果

シリアル出力中に圧電ブザーの音量を徐々に上げました。
読み取った結果をグラフにしました。

振幅は音量に依存しているようです。
一部(30,000 ~ 30,300ポイント間)を拡大しました。
一定の周期で振幅しています。

コメント

  1. 増谷 直人 より:

    いつも参考にさせていただいております。貴重な情報をありがとうございます。

    現在、スマホ関連のガジェットに興味があり、BLE(Bluetooth Low Energy)を使ってスマホの音量調整ができないか模索中です。
    UART接続の例はよく見かけますが、「スマホのアプリに入り込む」と言ったら大袈裟なのですが、一歩踏み込んだ制御ができないかと考えています。

    ワイヤレスイヤホンを使えば簡単に操作できますが、そこはあえて自作にこだわりたいところです。

    たとえば、「手を上げると音量が上がり、下げると音量が下がる」といった操作ができれば面白いと思っています。「それ、何に使うの?」と周囲からはツッコミが入りそうです(笑)。

    といった具合に「なんか面白いことできないかな…」という気持ちで模索中です。

    • tamanegi より:

      コメントありがとうございます。
      XIAO nRF52840 Senseを使うと、無線やセンサーが小さなマイコン基板で完結できていいですよね。
      モノづくりやDIYは必要な機能を満たす以外に、楽しい気持ちになりますよね。

タイトルとURLをコピーしました