6軸IMUセンサBMI160

6軸IMUセンサ(3軸加速度+3軸ジャイロセンサ)と言えば、InvenSense(現TDK)のMPU-6050やSTマイクロのLSM6DS3が電子工作界隈ではメジャーですが、BOSCHのBMI160もがなかなか良いです。BOSCHといえば気圧・温湿度センサBMP280/BME280がすごく流行りましたが、こちらも流行ってほしいです。

f:id:licheng:20190805200519j:plain

ブレークアウト基板

今のところブレークアウト基板はAmazonで売ってる紫色のやつがいちばん入手性がいいかな? 中華な怪しさが漂います。残念ながらこういうBMI160単品の汎用ブレークアウト基板はスイッチサイエンスとか秋月とかではまだ取り扱いがありません。SpurkfunかAdafruitあたりが基板出してスイッチサイエンスで買えるようになってほしい。せめてHiLetgoあたりが出してたら多少は安心感?があるのですが。

性能

BMI160もMPU-6050もLSM6DS3も似たり寄ったりの仕様ですが、BMI160は特にジャイロのオフセットが小さいのが好印象です。まあ、ガチで使うときはどのみちマイコンでキャリブしますけどね。

チップ ジャイロのオフセット[deg/sec]
BMI160 ±3
LSM6DS3 ±10
MPU-6050 ±20

Arduinoで使う

下記のライブラリを使うとよいでしょう。
github.com

チップ単価

基板をおこす場合、DigiKeyRSコンポーネンツでの単価の比較は下記のとおり。いずれも1個買いの場合の価格です。(2019/08/05現在)

チップ DigiKey価格[円] RSコンポーネンツ価格[円]
LSM6DS3 347 357
BMI160 624 取り扱いなし
MPU-6050 961 1074

PSoC注意点メモ

f:id:licheng:20190709143909j:plain:w500

PSoC 5LP Prototyping Kitの注意点

  • PSoC 5LP Prototyping KitのP0_2, P0_3, P0_4, P3_2にはでかいコンデンサ(1uF)がついてるので要注意。とくにOPアンプで使うときに不都合。(不都合なときはC12, C13, C9, C7をはずす。)
  • P1_0, P1_1もデバッガ用ピンなので使えない。
  • P2_1にLED、P2_2にSWが付いていることにも注意。
  • PSoC 5LP Prototyping Kitは5V動作である。PSoCじたいは3.3Vでも動作するが、デバッガ部から5Vが供給されてしまう。
  • デバッガ部を首ちょんぱして5Vは接続せず、GNDは接続、その他の信号は抵抗をはさんで接続し、ターゲット部のVDDに3.3Vを供給すれば3.3V動作でデバッグもいちおうできる。
  • ターゲット部のUSBコネクタを接続するとやはり5Vが給電されてしまう。R20をはずせばカットできるはず。
  • 首ちょんぱしたデバッガ部でもじゅうぶんPSoC用デバッガとして使えるが、あえてMiniProgを買うならMiniProg3かMiniProg4! (秋月にはMiniProg1があるけどPSoC1用なので不可)

PSoC Creatorの注意点

  • Vrefは精度重視でドライブ力は無い。配線の抵抗も無視できない。ボルテージフォロワなどで受けて使うのが基本。(と中の人が言ってた。)
  • Tools > Options > Design Entry > Component Catalog で 「Show Hidden Components」にチェックすると、コンポーネントカタログに隠しコンポーネント(笑)が表示される。PSoCのハードウェアを余さず活用できるが、ライブラリが整備されてないのですこぶる使いづらい。まあ通常は必要ないだろう。
  • 依存するライブラリ(たとえば自作コンポーネントのライブラリ)の指定は、Project > Properties > General > Dependencies をクリックして、さらに「...」をクリックすると設定画面が現れるので「User Dependencies」に追加する。(分かりにくい!)

BME280とBMP280の仕様の違い

f:id:licheng:20190618173924j:plain:w400

BOSCHの気圧・温度センサBME280とBMP280の差は、基本的には湿度センサの有無ですが、configレジスタのt_sbビットの解釈も一部異なっているので要注意。t_sbビットはセンサ測定値の更新周期に影響する tstandby を設定します。

tstandby[msec]の設定

t_sb[2:0] BME280 BMP280
000 0.5 0.5
001 62.5 62.5
010 125 125
011 250 250
100 500 500
101 1000 1000
110 10 2000
111 20 4000

例えば、BME280をBMP280に置き換えたら tstandby=10msecに設定したつもりが2000msecになってしまいます。これはセンサ測定値の更新周期が2秒以上になることを意味します。

PSoC CreaterでVerilogのコンポーネント作成

手順メモ。

ワークスペースにライブラリプロジェクトを追加

  • 左ペインのWorkSpace ExploerでWorkspaceを右クリックして「Add」>「New Project」
  • Select project typeで「Library project」を選択
  • ライブラリの場所と名前を指定。ここではプロジェクト名を「MyLibrary」にしたとする

ライブラリプロジェクトにコンポーネントを追加

  • WorkSpace ExploerのComponentsタブで「MyLibrary」を右クリックして「Add Component Item」
  • 「Symbol Wizard」を選択し、コンポーネント名を指定して「Create New」
  • コンポーネント名には、バージョンを示す「_vX_Y」タグをつける

シンボルウィザードでシンボル作成

  • Symbol Creation Wizardで入出力の端子名と種別(Digital Input, Digital Output, Clock Input)を指定
  • Title colorで緑(Digital)を選択
  • 「OK」でシンボルが作成される
  • コンポーネント.cysymというファイル名でシンボル図のファイルができるので外観を適宜編集

カタログでの分類名を指定

  • シンボル図の空きスペースで右クリックして「Properties」を開く
  • SymbolのDoc.CatalogPlacementで(コレクション)を開く
  • カタログでの分類名を指定する。
  • ここでは「Community/Digital/Logic/コンポーネント (バージョンは付けない)」にしたとする

パラメータを作成

  • シンボル図の空きスペースで右クリックして「Symbol Parameters」を開く
  • パラメータの名前、種別、既定値を設定

Verilogソースを生成

  • シンボル図の空きスペースで右クリックして「Generate Verilog
  • コンポーネント.v というVerilogソースファイルが生成される
  • Verilogソースを編集。「do not edit this line」と書かれた行は編集しないこと
  • 「Build」>「Build All Projects」でビルドする

コンポーネントの使い方

  • 回路図(TopDesign.cysch)を開く
  • 右ペインのComponent Catalogでコンポーネントを探す
  • 上記の例では、「Community」タブの「Digital/Logic/コンポーネント名[バージョン]
  • 回路図にドラッグ&ドロップする

gitのベアリポジトリ、ノンベアリポジトリとは?

  • ベアリポジトリ(bare repository) = 作業コピーを含まないリポジトリ
  • ノンベアリポジトリ(non-bare repository) = 作業コピーを含むリポジトリ
  • ベアリポジトリは集中管理用
  • つまり、リモートリポジトリはベア、ローカルリポジトリがノンベアが基本
  • ノンベアリポジトリからもcloneすることはできる。
  • しかし、ノンベアリポジトリにpushすると通常はエラーになる。
  • 作業コピーとインデックスに不整合が生じるためである。
  • 下記コマンドを実行すればノンベアリポジトリでもpushを受け付けるようになる。
  • SourceTreeの場合、右上の「ターミナル」ボタンでターミナルを開いてコマンドを実行する。
  • ただしこれは非推奨である。一人で開発する分にはまあいいけども。
git config receive.denyCurrentBranch ignore 
  • ベアリポジトリは下記のコマンドで新規作成できる。
  • SourceTreeの場合、GUIからは作成できないのでターミナルでコマンドを実行する。
git init --bare
git clone --bare ノンベアリポジトリの場所

今さらLPCXpressoメモ (2)

割り込み待ち

割り込み待ち命令の組込み関数は、__WFI()

クロック出力

LPC812 Xpressoの場合、P0_1ピンにクロック出力が設定されている。
設定箇所は、lpc_board_nxp_lpcxpresso_812(ボードライブラリのプロジェクト) の board_sysinit.c の Board_SetupMuxing()

I2Cピン

LPC812の場合、I2Cバスが割り当てられているP0_10とP0_11は、GPIOとして使う場合は出力に設定できない。またプルアップも設定できない。

LPC8xxとLPC11xx

どちらもARM Cortex-M0(+)のローエンドマイコンだが、ペリフェラルの仕様がぜんぜん違う。そして、LPCOpenライブラリはその差を吸収してくれない。(API関数が異なる。)

LPC1114 Xpresso用のチップライブラリとボードライブラリ

下記のものを使用する。

  • チップライブラリ : lpc_chip_11cxx_lib
  • ボードライブラリ : nxp_lpcxpresso_11c24_board_lib

Chip_UART_SetBaudFDR関数

lpc_chip_11cxx_lib (LPC11xx用のチップライブラリ) の Chip_UART_SetBaudFDR関数はいい加減な実装で使い物にならない。通常のChip_UART_SetBaud関数で設定できない(誤差が大きくなる)ような高いボーレートを設定したい場合は、LPC111x/LPC11C1x ユーザーマニュアルの「9.6.15 UART 分数分周器レジスタ(U0FDR)」を参照してDL、DIVADDVAL、MULVALの値を設定すること。

固定小数点計算ふたたび

前回の 固定小数点の再発明 - 滴了庵日録 ではROMサイズがかえって増えるという残念な結果になったので、C++でクラス化することはあきらめてC言語で書きなおした。

fixed24.h

#ifndef _FIXED24_H
#define _FIXED24_H

#include<stdint.h>

typedef int32_t fixed24;

#define FIXED24(x, y) (fixed24)(((int64_t)(x) << 24)/(int64_t)(y)) 

fixed24 int_toFixed24(int32_t x, int32_t y);
fixed24 fixed24_mul(fixed24 x, fixed24 y);
fixed24 fixed24_div(fixed24 x, fixed24 y);
int     fixed24_toInt(fixed24 x);
double  fixed24_toDbl(fixed24 x);

#endif

fixed24.c

#include "fixed24.h"

fixed24 int_toFixed24(int32_t x, int32_t y) {
	return (fixed24)(((int64_t)x << 24) / (int64_t)y);
}
fixed24 fixed24_mul(fixed24 x, fixed24 y) {
	return (int32_t)(((int64_t)(x) * (int64_t)(y)) >> 24);
}
fixed24 fixed24_div(fixed24 x, fixed24 y) {
	return (int32_t)((((int64_t)(x) << 32) / (int64_t)(y)) >> 8);
}
int fixed24_toInt(fixed24 x) {
	return (int)((x) >> 24);
}
double fixed24_toDbl(fixed24 x) {
	return (double)x / (double)0x01000000;
}

テスト

#include <stdio.h>
#include <stdlib.h>

#include "fixed24.h"

int main(void)
{
    fixed24 x = FIXED24(10, 1);         // 10/1 = 10
    fixed24 y = int_toFixed24(20, 100); // 20/100 = 0.20
    fixed24 z = 0x01000000 / 2;         // 1/2 = 0.5

    printf("x = %d (%08X)\n", fixed24_toInt(x), x);
    printf("y = %f (%08X)\n", fixed24_toDbl(y), y);
    printf("z = %f (%08X)\n", fixed24_toDbl(z), z);

    z = x + y;
    printf("%f + %f = %f (%08X)\n",
        fixed24_toDbl(x), fixed24_toDbl(y), fixed24_toDbl(z), z);
    z = x - y;
    printf("%f - %f = %f (%08X)\n",
        fixed24_toDbl(x), fixed24_toDbl(y), fixed24_toDbl(z), z);
    z = fixed24_mul(x, y);
    printf("%f * %f = %f (%08X)\n",
        fixed24_toDbl(x), fixed24_toDbl(y), fixed24_toDbl(z), z);
    z = fixed24_div(x, y);
    printf("%f / %f = %f (%08X)\n",
        fixed24_toDbl(x), fixed24_toDbl(y), fixed24_toDbl(z), z);
    z = x * 2;
    printf("%f * 2 = %f (%08X)\n", fixed24_toDbl(x), fixed24_toDbl(z), z);
    z = x / 2;
    printf("%f / 2 = %f (%08X)\n", fixed24_toDbl(x), fixed24_toDbl(z), z);

    x = FIXED24(1, 1);
    y = FIXED24(1, 1);
    printf("%f == %f : %s\n",
        fixed24_toDbl(x), fixed24_toDbl(y), (x == y) ? "TRUE" : "FALSE");
    printf("%f != %f : %s\n",
        fixed24_toDbl(x), fixed24_toDbl(y), (x != y) ? "TRUE" : "FALSE");
    y = FIXED24(2, 1);
    printf("%f == %f : %s\n",
        fixed24_toDbl(x), fixed24_toDbl(y), (x == y) ? "TRUE" : "FALSE");
    printf("%f != %f : %s\n",
        fixed24_toDbl(x), fixed24_toDbl(y), (x != y) ? "TRUE" : "FALSE");

    return 0;
}