TWELITE CUEを小型無線リモコンとして使えないかなと考えてみた。ボタン電池駆動は消費電力が非常に気になるし1個のアクションだけ実行できれば良いのでボタンSWがあるといいかもと思ったが調べてみるとCUEに内蔵されている加速度センサー(MC3630)はマイクロアンペア未満という超低消費電力で動作するため振ることでボタンSWの代わりになりそうだ。CUEは動きを検出したら無線送信するための製品なので本来の使い方そのものとも言える。
MC36XXシリーズ用のドライバーが製造元のmCube社から公開されているが、MC36XXシリーズの製品毎に微妙に異なる仕様に対応するためなのか基本的な共通機能のみとなっていることに加えて余計なコードが入っているために雑然としていてなんとなく使う気にはならなかった。さらに調べてみると...製品は有名そうなのに独自ドライバーを書いてる人がいない...
モノワイヤレス社のコードには”おまじない”という言葉とともに苦労した様子も伺える...なんだか不吉な予感...あとで的中!(笑)
ドキュメント通りに作ってみると...ピクリともしない。初期化処理が駄目みたいでうんともすんとも言わないのだ。これには複数の原因があったのでまたまた大ハマりしてしまった。最近、ハマることがほんとに多すぎる。(笑)
MC3630は読み書きするレジスタ・アドレスを指定しレジスタ・ビットを操作するタイプのデバイスであるがレジスタ数が多くビット割当てされた機能も結構あったりして対応はそれなりに大変だ。そして、普通の人ならビット操作のためにレジスタを読んでビットをAND/ORして書き戻すというコードを書いてしまうだろう。
だが普通じゃ面白くないので高速化のためにデバイスのレジスタ・マップと同じ構造のバッファ変数によりレジスタ・リードを省略可能にしてみたり、簡略化のためにビットフィールドを使い繁雑なビット操作はコンパイラーにお任せするようにしてみた。
但し、ビットフィールド毎にAND/ORしてしまうので複数ビットをまとめてAND/ORするよりも非効率かつ巨大なコードになりやすく非力なCPUでの使用には注意する必要もある。ビットフィールドの非互換性の理由は知らなかったが知識だけはあったので注意しなきゃなと思いつつもコードが完成する頃にはすっかり忘れてしまっていたのが敗因の一つだ。あとでわかったことではあるがバイト・エンディアンではなくビット・エンディアンなる言葉があるなんて生まれて初めて知ったのだがハマってるときの原因というのは無知或いは正しいと思ってる部分にあることが多く解決するのは本当に難しい。(-_-;)
大ハマりの最大の原因は”おまじない”。”おまじない”と書かれてるドキュメントなど見たこともないが”おまじない”が書かれていないドキュメント通りにしても動かないので”おまじない”は必要なものらしい。
再度、製造元のドライバーのコードを確認してみると...しっかり”おまじない”してるやん! orz
今回は、TWELITE CUEに内蔵されている各周辺チップに対応したボード・クラスも作ってみた。ボード・クラスを使うとLED制御やウォッチドッグ(TPL5010)、磁気センサー(DRV5032FD)、加速度センサー(MC3630)などを簡単に扱えるので便利かも。
※Board::handle()の呼び出しがないと約100秒後にリセットがかかるので注意しよう!
↑
※yield()からの呼び出すようにしたので普段は意識しなくても良い。
mc3630.h/mc3630.cppは汎用的に使えるようにしたつもり。JN516xだとvirtualが使えないので苦肉の策でC言語のように関数アドレスを構造体渡ししているがvirtualが使える開発環境なら継承クラス側でvirtual宣言された4個のメソッドをオーバーライド実装すればOKだ。
【サンプル・コード】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
#include "device.h" static Alarm alarm; void task0(void) { while (1) { System::delay(1000); Debug::printf("Task0\n"); } } void task1(void) { while (1) { System::delay(1000); Debug::printf("Task1\n"); } } void WPanRecieveCallback(uint16 u16Addr, const uint8 *pu8Data, uint8 u8Len) { Debug::printf("receive(%s), %d byte (%d)\n", pu8Data, u8Len, u16Addr); /* Node 0 --> Node 1 or 2 */ if (u16Addr) WPan::transmit(u16Addr, pu8Data, u8Len); } void setup(void) { Debug::begin(); #if 1 /* 現在のスタック領域を刻んで利用 */ Task::start(task0, -TASK_DEFAULT_STACK_SIZE); Task::start(task1, -TASK_DEFAULT_STACK_SIZE); #else /* 変数領域をスタック領域とする */ static uint32 stacks[2][TASK_DEFAULT_STACK_SIZE / sizeof(uint32)]; Task::start(task0, sizeof(stacks[0]), stacks[0]); Task::start(task1, sizeof(stacks[1]), stacks[1]); #endif /* Node 0 */ WPan::begin(0); /* Node 1 */ // WPan::begin(1); /* Node 2 */ // WPan::begin(2); alarm.interval(1000000); } void loop(void) { if (alarm.expire()) { /* Node 1 or 2 --> Node 0 */ if (WPan::address()) { static const char msg[] = "1234567890"; WPan::transmit(0, (uint8 *)msg, sizeof(msg)); } /* Sniff wakeup sample */ #if 0 ★ Board::startSniff(6); ★ System::sleep(System::SLEEP_OSCOFF_RAMOFF); #endif } } |
【修正履歴】
2022-06-01
前回の修正が正しく動作するには割り込みを排他制御する必要がありその対応をしたとしてもメリットよりもデメリットのほうが大きいと判断し元に戻すことにした。wake割り込みが発生する最短のタイミングはstartSniff()呼び出しから規定レートで166ms以降、最高レートでは770us以降となるので注意してほしい。startSniff()~sleep()の間に余計なコードを入れない限り問題はないはず。
2022-05-29
サンプルの★の間でWake割り込みが発生してしまうと二度と生き返らなくなってしまうので対策を行った。宝くじが当たるよりも確率は低いと思うけど念の為。
【ライブラリ(BLUE/RED共通)】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
/* twelite_cue.h - Board Library for MONOWIRESS TWELITE CUE Copyright (c) 2022 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #pragma once #include "gpio.h" #include "led.h" #include "mc3630_jn516x.h" // MC3630_IO class Board { public: static const Gpio::PIN PIN_LED = Gpio::DIO5; static const Gpio::PIN PIN_WDTOUT = Gpio::DIO13; static const Gpio::PIN PIN_SNS_INT = Gpio::DIO17; static const Gpio::PIN PIN_SNS_OUT1 = Gpio::DIO16; static const Gpio::PIN PIN_SNS_OUT2 = Gpio::DIO8; static const Gpio::PIN PIN_SW_SET = Gpio::DIO1; static void begin(void) { /* Setup LED */ LED::setup(0, PIN_LED, HIGH); /* Setup GPIO */ Gpio::pinMode(PIN_WDTOUT , Gpio::OUTPUT); Gpio::pinMode(PIN_SW_SET , Gpio::INPUT_PULLUP); Gpio::pinMode(PIN_SNS_OUT1, Gpio::INPUT); Gpio::pinMode(PIN_SNS_OUT2, Gpio::INPUT); Gpio::pinMode(PIN_SNS_INT , Gpio::INPUT_PULLUP); Gpio::wake(PIN_SNS_INT, Gpio::FALLING, empty); /* Setup MC3630 */ _mc3630.begin(MC3630::IFMODE_SPI, MC3630_IO::begin(MC3630::IFMODE_SPI)); _mc3630.setInterrupt(MC3630::INTE_WAKE); _mc3630.setWakeConfig(MC3630::RATE_ULP_SLOW, MC3630::RANGE_12G, MC3630::RES_12BIT); _mc3630.setSniffConfig(MC3630::SNIFF_RATE_ULP_DEFAULT); } static void startSniff(uint8 threshold, uint8 count = 0) { _mc3630.setMode(MC3630::MODE_STANDBY); _mc3630.clearInterrupt(); _mc3630.setSniffThreshold(MC3630::THADR_THRESHOLD_X, threshold); _mc3630.setSniffThreshold(MC3630::THADR_THRESHOLD_Y, threshold); _mc3630.setSniffThreshold(MC3630::THADR_THRESHOLD_Z, threshold); _mc3630.setSniffThreshold(MC3630::THADR_COUNT_X, count); _mc3630.setSniffThreshold(MC3630::THADR_COUNT_Y, count); _mc3630.setSniffThreshold(MC3630::THADR_COUNT_Z, count); _mc3630.setMode(MC3630::MODE_SNIFF); } static void startCWake(void) { _mc3630.setMode(MC3630::MODE_STANDBY); _mc3630.clearInterrupt(); _mc3630.setMode(MC3630::MODE_CWAKE); } static uint8_t readSW(void) { return Gpio::digitalRead(PIN_SW_SET); } static uint8_t readMagneticSensor(void) { return (Gpio::digitalRead(PIN_SNS_OUT1) << 0) | (Gpio::digitalRead(PIN_SNS_OUT2) << 1); } static MC3630& getAccelerometer(void) { return _mc3630; } static void handle(void) { Gpio::digitalWrite(PIN_WDTOUT, HIGH); Gpio::digitalWrite(PIN_WDTOUT, LOW); } private: static MC3630 _mc3630; }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/* twelite_cue.cpp - Board Library for MONOWIRESS TWELITE CUE Copyright (c) 2022 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "twelite_cue.h" MC3630 Board::_mc3630; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
/* mc3630_jn516x.h - MC3630 IO Library for NXP JN516x Series Copyright (c) 2022 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #pragma once #include "device.h" #include "mc3630.h" class MC3630_IO { public: static MC3630::IOMETHOD *begin(MC3630::IFMODE mode = MC3630::IFMODE_SPI, uint8_t slave = Spi::SEL_0) { _slave = slave; _mode = mode; if (_mode & MC3630::IFMODE_I2C) Wire::begin(Wire::SPEED_800KHZ); else { _spiconfig.mode(SpiConfig::MODE_3); _spiconfig.speed(SpiConfig::SPEED_2MHZ); } _iomethod.writeIO = writeIO; _iomethod.readIO = readIO; _iomethod.setSpiHsModeIO = setSpiHsModeIO; _iomethod.delayMicroseconds = delayMicroseconds; return &_iomethod; } static void writeIO(uint8_t cmd, const uint8_t *buf, uint8_t len) { if (_mode & MC3630::IFMODE_I2C) Wire::write(_slave, cmd, buf, len); else { _spiconfig.beginTransaction(); Spi::write(_slave, cmd, buf, len); _spiconfig.endTransaction(); } } static void readIO(uint8_t cmd, uint8_t *buf, uint8_t len) { if (_mode & MC3630::IFMODE_I2C) Wire::writeAndRead(_slave, &cmd, sizeof(cmd), buf, len); else { _spiconfig.beginTransaction(); Spi::writeAndRead(_slave, &cmd, sizeof(cmd), buf, len); _spiconfig.endTransaction(); } } static void setSpiHsModeIO(void) { _spiconfig.speed(SpiConfig::SPEED_8MHZ); }; static void delayMicroseconds(uint32 us) { System::delayMicroseconds(us); } private: static MC3630::IFMODE _mode; static MC3630::IOMETHOD _iomethod; static uint8_t _slave; static SpiConfig _spiconfig; }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
/* mc3630_jn516x.cpp - MC3630 IO Library for NXP JN516x Series Copyright (c) 2022 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "mc3630_jn516x.h" MC3630::IFMODE MC3630_IO::_mode; MC3630::IOMETHOD MC3630_IO::_iomethod; uint8_t MC3630_IO::_slave; SpiConfig MC3630_IO::_spiconfig; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 |
/* mc3630.h - 3-Axis Accelerometer Sensor Library for mCube - MC3630 Copyright (c) 2022 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #pragma once #include "stdint.h" #include "stdbool.h" #define MC3630_I2C_SLAVE_0 0x4C // DOUT_A1 = GND #define MC3630_I2C_SLAVE_1 0x6C // DOUT_A1 = VDD #define MC3630_NUMBER_OF_AXIS 3 #if defined(JENNIC_CHIP_FAMILY_JN516x) #undef _BIT_FIELDS_HTOL #define _BIT_FIELDS_HTOL #define virtual /* do not removed */ #endif class MC3630 { private: typedef enum { // CWAKE, SWAKE Power Mode CSPM_LP_MODE = 0b000, // Low Power Mode (nominal noise levels) (default) CSPM_ULP_MODE = 0b011, // Ultra-Low Power Mode (highest noise levels) CSPM_PR_MODE = 0b100, // Precision Mode (lowest noise levels) } CSPM; typedef enum { // SNIFF Power Mode SPM_LP_MODE = 0b000, // Low Power Mode (nominal noise levels) (default) SPM_ULP_MODE = 0b011, // Ultra-Low Power Mode (highest noise levels) SPM_PR_MODE = 0b100, // Precision Mode (lowest noise levels) } SPM; public: typedef struct { void (*writeIO)(uint8_t cmd, const uint8_t *buf, uint8_t len); void (*readIO)(uint8_t cmd, uint8_t *buf, uint8_t len); void (*setSpiHsModeIO)(void); void (*delayMicroseconds)(uint32 us); } IOMETHOD; typedef enum { IFMODE_SPI3 = 1, IFMODE_I2C = 2, IFMODE_SPI = 4, } IFMODE; typedef enum { AXIS_X = 0, AXIS_Y = 1, AXIS_Z = 2, } AXIS; typedef enum { MODE_SLEEP = 0b000, MODE_STANDBY = 0b001, MODE_SNIFF = 0b010, MODE_CWAKE = 0b101, MODE_SWAKE = 0b110, MODE_TRIGGER = 0b111, } MODE; typedef enum { RES_6BIT = 0b000, // 6 bits RES_7BIT = 0b001, // 7 bits RES_8BIT = 0b010, // 8 bits RES_10BIT = 0b011, // 10 bits RES_12BIT = 0b100, // 12 bits RES_14BIT = 0b101, // 14 bits (only 12-bits if FIFO enabled) } RES; typedef enum { RANGE_2G = 0b000, // ±2g RANGE_4G = 0b001, // ±4g RANGE_8G = 0b010, // ±8g RANGE_16G = 0b011, // ±16g RANGE_12G = 0b100, // ±12g } RANGE; typedef enum { MOTION_DISABLE = 0, MOTION_POSITIVE = 1, MOTION_NEGATIVE = 2, MOTION_BOTH = 3, } MOTION; typedef enum { /* Ultra-Low Power */ RATE_ULP_25Hz = 0x06 | (CSPM_ULP_MODE << 4), // 0.9uA RATE_ULP_50Hz = 0x07 | (CSPM_ULP_MODE << 4), // 1.6uA RATE_ULP_100Hz = 0x08 | (CSPM_ULP_MODE << 4), // 2.8uA RATE_ULP_190Hz = 0x09 | (CSPM_ULP_MODE << 4), // 5.5uA RATE_ULP_380Hz = 0x0A | (CSPM_ULP_MODE << 4), // 10.0uA RATE_ULP_750Hz = 0x0B | (CSPM_ULP_MODE << 4), // 18.0uA RATE_ULP_1100Hz = 0x0C | (CSPM_ULP_MODE << 4), // 26.0uA RATE_ULP_1300Hz = 0x0F | (CSPM_ULP_MODE << 4), // 36.0uA RATE_ULP_SLOW = RATE_ULP_25Hz, RATE_ULP_FAST = RATE_ULP_1300Hz, RATE_ULP_MANUAL = RATE_ULP_1300Hz, // setManualRate() /* Low Power */ RATE_LP_14Hz = 0x05 | (CSPM_LP_MODE << 4), // 1.0uA RATE_LP_28Hz = 0x06 | (CSPM_LP_MODE << 4), // 1.6uA RATE_LP_54Hz = 0x07 | (CSPM_LP_MODE << 4), // 2.7uA RATE_LP_105Hz = 0x08 | (CSPM_LP_MODE << 4), // 5.0uA RATE_LP_210Hz = 0x09 | (CSPM_LP_MODE << 4), // 11.0uA RATE_LP_400Hz = 0x0A | (CSPM_LP_MODE << 4), // 19.0uA RATE_LP_600Hz = 0x0B | (CSPM_LP_MODE << 4), // 26.0uA RATE_LP_750Hz = 0x0F | (CSPM_LP_MODE << 4), // 36.0uA RATE_LP_SLOW = RATE_LP_14Hz, RATE_LP_FAST = RATE_LP_750Hz, RATE_LP_MANUAL = RATE_LP_750Hz, // setManualRate() /* Precision */ RATE_PR_14Hz = 0x05 | (CSPM_PR_MODE << 4), // 5.0uA RATE_PR_28Hz = 0x06 | (CSPM_PR_MODE << 4), // 10.0uA RATE_PR_55Hz = 0x07 | (CSPM_PR_MODE << 4), // 18.0uA RATE_PR_80Hz = 0x08 | (CSPM_PR_MODE << 4), // 25.0uA RATE_PR_100Hz = 0x0F | (CSPM_PR_MODE << 4), // 36.0uA RATE_PR_SLOW = RATE_PR_14Hz, RATE_PR_FAST = RATE_PR_100Hz, RATE_PR_MANUAL = RATE_PR_100Hz, // setManualRate() } RATE; typedef enum { MAN_SEL_DISABLE = 0b000, // Manual rate mode disabled. Normal operation MAN_SEL_RATE_IBTHC = 0b001, // {SNIFF_RATE_IBTHC[3:0], WAKE_RATE_IBTHC[3:0]} MAN_SEL_WAKE_RATE_FPICK = 0b010, // {0,0,0, WAKE_RATE_FPICK[4:0]} MAN_SEL_SNIFF_RATE_FPICK = 0b011, // {0,0,0, SNIFF_RATE_FPICK[4:0]} MAN_SEL_WAKE_RATE_LSB = 0b100, // {WAKE_RATE_CLK_COUNT_LSB[7:0]} MAN_SEL_WAKE_RATE_MSB = 0b101, // {WAKE_RATE_CLK_COUNT_MSB[15:8]} MAN_SEL_SNIFF_RATE_LSB = 0b110, // {SNIFF_RATE_CLK_COUNT_LSB[7:0]} MAN_SEL_SNIFF_RATE_MSB = 0b111, // {SNIFF_RATE_CLK_COUNT_MSB[15:8]} } MAN_SEL; typedef enum { /* Ultra-Low Power */ SNIFF_RATE_ULP_DEFAULT = 0x00 | (SPM_ULP_MODE << 4), // 6Hz 0.4uA SNIFF_RATE_ULP_0p4Hz = 0x01 | (SPM_ULP_MODE << 4), SNIFF_RATE_ULP_0p8Hz = 0x02 | (SPM_ULP_MODE << 4), SNIFF_RATE_ULP_1p5Hz = 0x03 | (SPM_ULP_MODE << 4), SNIFF_RATE_ULP_6Hz = 0x04 | (SPM_ULP_MODE << 4), SNIFF_RATE_ULP_13Hz = 0x05 | (SPM_ULP_MODE << 4), SNIFF_RATE_ULP_25Hz = 0x06 | (SPM_ULP_MODE << 4), SNIFF_RATE_ULP_50Hz = 0x07 | (SPM_ULP_MODE << 4), SNIFF_RATE_ULP_100Hz = 0x08 | (SPM_ULP_MODE << 4), SNIFF_RATE_ULP_190Hz = 0x09 | (SPM_ULP_MODE << 4), SNIFF_RATE_ULP_380Hz = 0x0A | (SPM_ULP_MODE << 4), SNIFF_RATE_ULP_750Hz = 0x0B | (SPM_ULP_MODE << 4), SNIFF_RATE_ULP_1100Hz = 0x0C | (SPM_ULP_MODE << 4), SNIFF_RATE_ULP_1300Hz = 0x0F | (SPM_ULP_MODE << 4), SNIFF_RATE_ULP_SLOW = SNIFF_RATE_ULP_0p4Hz, SNIFF_RATE_ULP_FAST = SNIFF_RATE_ULP_1300Hz, /* Low Power */ SNIFF_RATE_LP_DEFAULT = 0x00 | (SPM_LP_MODE << 4), // 7Hz SNIFF_RATE_LP_0p4Hz = 0x01 | (SPM_LP_MODE << 4), SNIFF_RATE_LP_0p8Hz = 0x02 | (SPM_LP_MODE << 4), SNIFF_RATE_LP_1p5Hz = 0x03 | (SPM_LP_MODE << 4), SNIFF_RATE_LP_7Hz = 0x04 | (SPM_LP_MODE << 4), SNIFF_RATE_LP_14Hz = 0x05 | (SPM_LP_MODE << 4), SNIFF_RATE_LP_28Hz = 0x06 | (SPM_LP_MODE << 4), SNIFF_RATE_LP_54Hz = 0x07 | (SPM_LP_MODE << 4), SNIFF_RATE_LP_105Hz = 0x08 | (SPM_LP_MODE << 4), SNIFF_RATE_LP_210Hz = 0x09 | (SPM_LP_MODE << 4), SNIFF_RATE_LP_400Hz = 0x0A | (SPM_LP_MODE << 4), SNIFF_RATE_LP_600Hz = 0x0B | (SPM_LP_MODE << 4), SNIFF_RATE_LP_750Hz = 0x0F | (SPM_LP_MODE << 4), SNIFF_RATE_LP_SLOW = SNIFF_RATE_LP_0p4Hz, SNIFF_RATE_LP_FAST = SNIFF_RATE_LP_750Hz, /* Precision */ SNIFF_RATE_PR_DEFAULT = 0x00 | (SPM_PR_MODE << 4), // 7Hz SNIFF_RATE_PR_0p2Hz = 0x01 | (SPM_PR_MODE << 4), SNIFF_RATE_PR_0p4Hz = 0x02 | (SPM_PR_MODE << 4), SNIFF_RATE_PR_0p9Hz = 0x03 | (SPM_PR_MODE << 4), SNIFF_RATE_PR_7Hz = 0x04 | (SPM_PR_MODE << 4), SNIFF_RATE_PR_14Hz = 0x05 | (SPM_PR_MODE << 4), SNIFF_RATE_PR_28Hz = 0x06 | (SPM_PR_MODE << 4), SNIFF_RATE_PR_55Hz = 0x07 | (SPM_PR_MODE << 4), SNIFF_RATE_PR_80Hz = 0x08 | (SPM_PR_MODE << 4), SNIFF_RATE_PR_100Hz = 0x0F | (SPM_PR_MODE << 4), SNIFF_RATE_PR_SLOW = SNIFF_RATE_PR_0p2Hz, SNIFF_RATE_PR_FAST = SNIFF_RATE_PR_100Hz, } SNIFF_RATE; typedef enum { /* Ultra-Low Power */ STB_RATE_ULP_1Hz = 0x00 | (SPM_ULP_MODE << 4), STB_RATE_ULP_3Hz = 0x01 | (SPM_ULP_MODE << 4), STB_RATE_ULP_5Hz = 0x02 | (SPM_ULP_MODE << 4), STB_RATE_ULP_10Hz = 0x03 | (SPM_ULP_MODE << 4), STB_RATE_ULP_23Hz = 0x04 | (SPM_ULP_MODE << 4), STB_RATE_ULP_45Hz = 0x05 | (SPM_ULP_MODE << 4), STB_RATE_ULP_90Hz = 0x06 | (SPM_ULP_MODE << 4), STB_RATE_ULP_180Hz = 0x07 | (SPM_ULP_MODE << 4), STB_RATE_ULP_SLOW = STB_RATE_ULP_1Hz, STB_RATE_ULP_FAST = STB_RATE_ULP_180Hz, /* Low Power */ STB_RATE_LP_0p5Hz = 0x00 | (SPM_LP_MODE << 4), STB_RATE_LP_1Hz = 0x01 | (SPM_LP_MODE << 4), STB_RATE_LP_3Hz = 0x02 | (SPM_LP_MODE << 4), STB_RATE_LP_6Hz = 0x03 | (SPM_LP_MODE << 4), STB_RATE_LP_12Hz = 0x04 | (SPM_LP_MODE << 4), STB_RATE_LP_24Hz = 0x05 | (SPM_LP_MODE << 4), STB_RATE_LP_48Hz = 0x06 | (SPM_LP_MODE << 4), STB_RATE_LP_100Hz = 0x07 | (SPM_LP_MODE << 4), STB_RATE_LP_SLOW = STB_RATE_LP_0p5Hz, STB_RATE_LP_FAST = STB_RATE_LP_100Hz, /* Precision */ STB_RATE_PR_0p1Hz = 0x00 | (SPM_PR_MODE << 4), STB_RATE_PR_0p2Hz = 0x01 | (SPM_PR_MODE << 4), STB_RATE_PR_0p4Hz = 0x02 | (SPM_PR_MODE << 4), STB_RATE_PR_0p8Hz = 0x03 | (SPM_PR_MODE << 4), STB_RATE_PR_1p5Hz = 0x04 | (SPM_PR_MODE << 4), STB_RATE_PR_3Hz = 0x05 | (SPM_PR_MODE << 4), STB_RATE_PR_5Hz = 0x06 | (SPM_PR_MODE << 4), STB_RATE_PR_10Hz = 0x07 | (SPM_PR_MODE << 4), STB_RATE_PR_SLOW = STB_RATE_PR_0p1Hz, STB_RATE_PR_FAST = STB_RATE_PR_10Hz, } STB_RATE; typedef enum { THADR_NONE = 0b000, THADR_THRESHOLD_X = 0b001, THADR_THRESHOLD_Y = 0b010, THADR_THRESHOLD_Z = 0b011, THADR_COUNT_X = 0b101, THADR_COUNT_Y = 0b110, THADR_COUNT_Z = 0b111, } THADR; typedef enum { MUX_DELTA_5_0 = 0b000, MUX_DELTA_6_1 = 0b001, MUX_DELTA_7_2 = 0b010, MUX_DELTA_8_3 = 0b011, MUX_DELTA_9_4 = 0b100, MUX_DELTA_10_5 = 0b101, } MUX_DELTA; typedef enum { FIFO_OPT_WATERMARK = 0x01, FIFO_OPT_FREEZE = 0x02, FIFO_OPT_BURST = 0x04, FIFO_OPT_STREAM = 0x08, } FIFO_OPT; // bit combination typedef enum { INTE_WAKE = 0x01, INTE_ACQ = 0x02, INTE_FIFO_EMPTY = 0x04, INTE_FIFO_FULL = 0x08, INTE_FIFO_THRESH = 0x10, INTE_SWAKE = 0x20, } INTE; // bit combination typedef union __attribute__((packed)) { struct __attribute__((packed)) { #if defined(_BIT_FIELDS_HTOL) uint8_t __RSV1__ : 4; uint8_t I2C_AD0_BIT : 1; uint8_t __RSV0__ : 3; #else uint8_t __RSV0__ : 3; uint8_t I2C_AD0_BIT : 1; uint8_t __RSV1__ : 4; #endif } bit; uint8_t reg; } EXT_STAT_1; typedef union __attribute__((packed)) { struct __attribute__((packed)) { #if defined(_BIT_FIELDS_HTOL) uint8_t SNIFF_DETECT: 1; uint8_t SNIFF_EN : 1; uint8_t OTP_BUSY : 1; uint8_t __RSV0__ : 3; uint8_t PD_CLK_STAT : 1; uint8_t OVR_DATA : 1; #else uint8_t OVR_DATA : 1; uint8_t PD_CLK_STAT : 1; uint8_t __RSV0__ : 3; uint8_t OTP_BUSY : 1; uint8_t SNIFF_EN : 1; uint8_t SNIFF_DETECT: 1; #endif } bit; uint8_t reg; } EXT_STAT_2; typedef union __attribute__((packed)) { struct __attribute__((packed)) { #if defined(_BIT_FIELDS_HTOL) uint8_t INT_PEND : 1; uint8_t FIFO_THRESH: 1; uint8_t FIFO_FULL : 1; uint8_t FIFO_EMPTY : 1; uint8_t NEW_DATA : 1; uint8_t MODE : 3; #else uint8_t MODE : 3; uint8_t NEW_DATA : 1; uint8_t FIFO_EMPTY : 1; uint8_t FIFO_FULL : 1; uint8_t FIFO_THRESH: 1; uint8_t INT_PEND : 1; #endif } bit; uint8_t reg; } STATUS_1; typedef union __attribute__((packed)) { struct __attribute__((packed)) { #if defined(_BIT_FIELDS_HTOL) uint8_t INT_SWAKE : 1; uint8_t INT_FIFO_THRESH: 1; uint8_t INT_FIFO_FULL : 1; uint8_t INT_FIFO_EMPTY : 1; uint8_t INT_ACQ : 1; uint8_t INT_WAKE : 1; uint8_t __RSV0__ : 2; #else uint8_t __RSV0__ : 2; uint8_t INT_WAKE : 1; uint8_t INT_ACQ : 1; uint8_t INT_FIFO_EMPTY : 1; uint8_t INT_FIFO_FULL : 1; uint8_t INT_FIFO_THRESH: 1; uint8_t INT_SWAKE : 1; #endif } bit; uint8_t reg; } STATUS_2; bool begin(IFMODE mode, IOMETHOD *iomethod = 0); EXT_STAT_1 getExtStatus1(void); EXT_STAT_2 getExtStatus2(void); STATUS_1 getStatus1(void); STATUS_2 getStatus2(void); void getOutput(int16_t axis[MC3630_NUMBER_OF_AXIS]); void setOffset(const int16_t axis[MC3630_NUMBER_OF_AXIS]); void setGain(const int16_t axis[MC3630_NUMBER_OF_AXIS]); void disableDriveMotion(const MOTION axis[MC3630_NUMBER_OF_AXIS]); void setSniffSWakeRearm(bool enable); void setSpiStatus(bool enable); void disableAxis(uint16_t mask); void setMode(MODE mode); MODE getMode(void); void trigger(void); void setTriggerConfig(STB_RATE rate, uint8_t count = 1); void setExtTrigger(bool enable, bool polarity); void setFifoStatus(bool enable); void setFifoMode(bool enable, uint8_t threshold, FIFO_OPT option); void resetFifo(void); void setSniffConfig(SNIFF_RATE rate, bool andMode = false, bool c2b = false); void setSniffThreshold(THADR addr, uint8_t value, MUX_DELTA mux = MUX_DELTA_5_0); void resetSniff(void); void setWakeConfig(RATE rate, RANGE range, RES res); void setManualRate(MAN_SEL sel, uint8_t val); void setInterrupt(INTE enable, bool ipp = false, bool iah = false); void clearInterrupt(void); uint8_t getChipID(void); void setScratch(uint8_t value); uint8_t getScratch(void); private: typedef union __attribute__((packed)) { struct __attribute__((packed)) { #if defined(_BIT_FIELDS_HTOL) uint8_t IFMODE : 3; uint8_t INTSC_EN: 1; uint8_t FREEZE : 1; uint8_t ZERO : 3; #else uint8_t ZERO : 3; uint8_t FREEZE : 1; uint8_t INTSC_EN: 1; uint8_t IFMODE : 3; #endif } bit; uint8_t reg; } FREG_1; typedef union __attribute__((packed)) { struct __attribute__((packed)) { #if defined(_BIT_FIELDS_HTOL) uint8_t EXT_TRIG_EN : 1; uint8_t EXT_TRIG_POL : 1; uint8_t FIFO_STREAM : 1; uint8_t I2CINT_WRCLRE: 1; uint8_t FIFO_STAT_EN : 1; uint8_t SPI_STAT_EN : 1; uint8_t FIFO_BURST : 1; uint8_t WRAPA : 1; #else uint8_t WRAPA : 1; uint8_t FIFO_BURST : 1; uint8_t SPI_STAT_EN : 1; uint8_t FIFO_STAT_EN : 1; uint8_t I2CINT_WRCLRE: 1; uint8_t FIFO_STREAM : 1; uint8_t EXT_TRIG_POL : 1; uint8_t EXT_TRIG_EN : 1; #endif } bit; uint8_t reg; } FREG_2; typedef union __attribute__((packed)) { struct __attribute__((packed)) { #if defined(_BIT_FIELDS_HTOL) uint8_t TRIG_CMD : 1; uint8_t Z_AXIS_PD: 1; uint8_t Y_AXIS_PD: 1; uint8_t X_AXIS_PD: 1; uint8_t __RSV0__ : 1; uint8_t MCTRL : 3; #else uint8_t MCTRL : 3; uint8_t __RSV0__ : 1; uint8_t X_AXIS_PD: 1; uint8_t Y_AXIS_PD: 1; uint8_t Z_AXIS_PD: 1; uint8_t TRIG_CMD : 1; #endif } bit; uint8_t reg; } MODE_C; typedef union __attribute__((packed)) { struct __attribute__((packed)) { #if defined(_BIT_FIELDS_HTOL) uint8_t __RSV0__: 1; uint8_t MAN_SEL : 3; uint8_t WR : 4; #else uint8_t WR : 4; uint8_t MAN_SEL : 3; uint8_t __RSV0__: 1; #endif } bit; uint8_t reg; } RATE_1; typedef union __attribute__((packed)) { struct __attribute__((packed)) { #if defined(_BIT_FIELDS_HTOL) uint8_t STB_RATE: 3; uint8_t ZERO : 1; uint8_t SR : 4; #else uint8_t SR : 4; uint8_t ZERO : 1; uint8_t STB_RATE: 3; #endif } bit; uint8_t reg; } SNIFF_C; typedef union __attribute__((packed)) { struct __attribute__((packed)) { #if defined(_BIT_FIELDS_HTOL) uint8_t MODE : 1; uint8_t AND_OR: 1; uint8_t TH : 6; #else uint8_t TH : 6; uint8_t AND_OR: 1; uint8_t MODE : 1; #endif } bit; uint8_t reg; } SNIFFTH_C; typedef union __attribute__((packed)) { struct __attribute__((packed)) { #if defined(_BIT_FIELDS_HTOL) uint8_t RESET: 1; uint8_t MUX : 3; uint8_t CNTEN: 1; uint8_t THADR: 3; #else uint8_t THADR: 3; uint8_t CNTEN: 1; uint8_t MUX : 3; uint8_t RESET: 1; #endif } bit; uint8_t reg; } SNIFFCF_C; typedef union __attribute__((packed)) { struct __attribute__((packed)) { #if defined(_BIT_FIELDS_HTOL) uint8_t __RSV1__: 1; uint8_t RANGE : 3; uint8_t __RSV0__: 1; uint8_t RES : 3; #else uint8_t RES : 3; uint8_t __RSV0__: 1; uint8_t RANGE : 3; uint8_t __RSV1__: 1; #endif } bit; uint8_t reg; } RANGE_C; typedef union __attribute__((packed)) { struct __attribute__((packed)) { #if defined(_BIT_FIELDS_HTOL) uint8_t RESET: 1; uint8_t EN : 1; uint8_t MODE : 1; uint8_t TH : 5; #else uint8_t TH : 5; uint8_t MODE : 1; uint8_t EN : 1; uint8_t RESET: 1; #endif } bit; uint8_t reg; } FIFO_C; typedef union __attribute__((packed)) { struct __attribute__((packed)) { #if defined(_BIT_FIELDS_HTOL) uint8_t INT_SWAKE : 1; uint8_t INT_FIFO_THRESH: 1; uint8_t INT_FIFO_FULL : 1; uint8_t INT_FIFO_EMPTY : 1; uint8_t INT_ACQ : 1; uint8_t INT_WAKE : 1; uint8_t IAH : 1; uint8_t IPP : 1; #else uint8_t IPP : 1; uint8_t IAH : 1; uint8_t INT_WAKE : 1; uint8_t INT_ACQ : 1; uint8_t INT_FIFO_EMPTY : 1; uint8_t INT_FIFO_FULL : 1; uint8_t INT_FIFO_THRESH: 1; uint8_t INT_SWAKE : 1; #endif } bit; uint8_t reg; } INTR_C; typedef union __attribute__((packed)) { struct __attribute__((packed)) { #if defined(_BIT_FIELDS_HTOL) uint8_t SPI_HS_EN: 1; uint8_t SPM : 3; uint8_t __RSV0__ : 1; uint8_t CSPM : 3; #else uint8_t CSPM : 3; uint8_t __RSV0__ : 1; uint8_t SPM : 3; uint8_t SPI_HS_EN: 1; #endif } bit; uint8_t reg; } PMCR; typedef union __attribute__((packed)) { struct __attribute__((packed)) { #if defined(_BIT_FIELDS_HTOL) uint8_t __RSV1__: 4; uint8_t DN : 1; uint8_t DP : 1; uint8_t __RSV0__: 2; #else uint8_t __RSV0__: 2; uint8_t DP : 1; uint8_t DN : 1; uint8_t __RSV1__: 4; #endif } bit; uint8_t reg; } DM; typedef union __attribute__((packed)) { struct __attribute__((packed)) { #if defined(_BIT_FIELDS_HTOL) uint8_t RELOAD : 1; uint8_t RESET : 1; uint8_t __RSV0__: 6; #else uint8_t __RSV0__: 6; uint8_t RESET : 1; uint8_t RELOAD : 1; #endif } bit; uint8_t reg; } RESET; typedef union __attribute__((packed)) { struct __attribute__((packed)) { uint8_t L; #if defined(_BIT_FIELDS_HTOL) uint8_t GAIN8: 1; uint8_t H : 7; #else uint8_t H : 7; uint8_t GAIN8: 1; #endif } bit; struct __attribute__((packed)) { uint8_t L; uint8_t H; } reg; } OFFSET; typedef union __attribute__((packed)) { struct __attribute__((packed)) { uint8_t L; uint8_t H; } reg; } OUTPUT; typedef struct __attribute__((packed)) { EXT_STAT_1 ext_stat_1; // 0x00 R EXT_STAT_2 ext_stat_2; // 0x01 R OUTPUT output[MC3630_NUMBER_OF_AXIS]; // 0x02 R STATUS_1 status_1; // 0x08 R STATUS_2 status_2; // 0x09 R uint8_t __rsv0__[3]; FREG_1 freg_1; // 0x0D W FREG_2 freg_2; // 0x0E W uint8_t init_1; // 0x0F WO MODE_C mode; // 0x10 W RATE_1 rate; // 0x11 W SNIFF_C sniff; // 0x12 W SNIFFTH_C sniffth; // 0x13 WS SNIFFCF_C sniffcf; // 0x14 W RANGE_C range; // 0x15 W FIFO_C fifo; // 0x16 W INTR_C intr; // 0x17 R uint8_t chip_id; // 0x18 R uint8_t __rsv1__; uint8_t init_3; // 0x1A RW uint8_t scratch; // 0x1B RW PMCR pmcr; // 0x1C W uint8_t __rsv2__[3]; DM dm[3]; // 0x20 W uint8_t __rsv3__; RESET reset; // 0x24 W uint8_t __rsv4__[3]; uint8_t init_2; // 0x28 W uint8_t trigc; // 0x29 W OFFSET offset[MC3630_NUMBER_OF_AXIS]; // 0x2A W uint8_t gain[MC3630_NUMBER_OF_AXIS]; // 0x30 W } REGISTERS; IOMETHOD *_iomethod; bool _enable; REGISTERS _registers; uint8 _spm_sniff; uint8 _spm_trigc; void setInterface(IFMODE mode); IFMODE getInterface(void); void setWrapAddress9(bool enable); void setI2CWrClear(bool enable); void setSpiHsMode(void); void reset(bool reset, bool reload = false); void setSniffPowerMode(uint8 spm); void initDriveMotion(void); void init1(void); void init2(void); void init3(void); void writeReg(const void *reg, uint8_t len); void readReg(void *reg, uint8_t len); void initialize(void); protected: virtual void writeIO(uint8_t cmd, const uint8_t *buf, uint8_t len); virtual void readIO(uint8_t cmd, uint8_t *buf, uint8_t len); virtual void setSpiHsModeIO(void); virtual void delayMicroseconds(uint32 us); }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 |
/* mc3630.cpp - 3-Axis Accelerometer Sensor Library for mCube - MC3630 Copyright (c) 2022 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "system.h" #include "mc3630.h" bool MC3630::begin(IFMODE mode, IOMETHOD *iomethod) { _iomethod = iomethod; initialize(); if (mode & IFMODE_I2C) { setInterface(mode); setI2CWrClear(true); // Write clear interrupt } else { setInterface(mode); setSpiHsMode(); // Change SPI HS Mode (8MHz) } _registers.status_1.bit.FIFO_EMPTY = 1; return _enable = (getChipID() == 0x71); } MC3630::EXT_STAT_1 MC3630::getExtStatus1(void) { if (_enable) readReg(&_registers.ext_stat_1, sizeof(_registers.ext_stat_1)); return (EXT_STAT_1)_registers.ext_stat_1; } MC3630::EXT_STAT_2 MC3630::getExtStatus2(void) { if (_enable) readReg(&_registers.ext_stat_2, sizeof(_registers.ext_stat_2)); return (EXT_STAT_2)_registers.ext_stat_2; } MC3630::STATUS_1 MC3630::getStatus1(void) { if (_enable) readReg(&_registers.status_1, sizeof(_registers.status_1)); return (STATUS_1)_registers.status_1; } MC3630::STATUS_2 MC3630::getStatus2(void) { if (_enable) readReg(&_registers.status_2, sizeof(_registers.status_2)); return (STATUS_2)_registers.status_2; } void MC3630::getOutput(int16_t axis[MC3630_NUMBER_OF_AXIS]) { if (_enable) { STATUS_1 status = getStatus1(); if (status.bit.NEW_DATA || !status.bit.FIFO_EMPTY) readReg(_registers.output, sizeof(_registers.output)); for (uint8_t i = 0; i < MC3630_NUMBER_OF_AXIS; ++i) axis[i] = ((uint16_t)_registers.output[i].reg.H << 8) | _registers.output[i].reg.L; } } void MC3630::setOffset(const int16_t axis[MC3630_NUMBER_OF_AXIS]) { for (uint8_t i = 0; i < MC3630_NUMBER_OF_AXIS; ++i) { _registers.offset[i].bit.L = (uint8_t)(axis[i] >> 0); _registers.offset[i].bit.H = (uint8_t)(axis[i] >> 8); } writeReg(_registers.offset, sizeof(_registers.offset)); } void MC3630::setGain(const int16_t axis[MC3630_NUMBER_OF_AXIS]) { for (uint8_t i = 0; i < MC3630_NUMBER_OF_AXIS; ++i) { uint16_t val = (axis[i] < 0x01FF ? axis[i] : 0x01FF); _registers.gain [i] = (uint8_t)(val >> 0); _registers.offset[i].bit.GAIN8 = (uint8_t)(val >> 8); } writeReg(_registers.offset, sizeof(_registers.offset) + sizeof(_registers.gain)); } void MC3630::disableDriveMotion(const MOTION axis[MC3630_NUMBER_OF_AXIS]) { for (uint8_t i = 0; i < MC3630_NUMBER_OF_AXIS; ++i) { _registers.dm[i].bit.DP = (axis[i] & MOTION_POSITIVE ? 1 : 0); _registers.dm[i].bit.DN = (axis[i] & MOTION_NEGATIVE ? 1 : 0); } writeReg(_registers.dm, sizeof(_registers.dm)); } void MC3630::setInterface(IFMODE mode) { _registers.freg_1.bit.IFMODE = mode; writeReg(&_registers.freg_1, sizeof(_registers.freg_1)); } MC3630::IFMODE MC3630::getInterface(void) { readReg(&_registers.freg_1, sizeof(_registers.freg_1)); return (IFMODE)_registers.freg_1.bit.IFMODE; } void MC3630::setWrapAddress9(bool enable) { _registers.freg_2.bit.WRAPA = enable; writeReg(&_registers.freg_2, sizeof(_registers.freg_2)); } void MC3630::setSniffSWakeRearm(bool enable) { _registers.freg_1.bit.INTSC_EN = enable; writeReg(&_registers.freg_1, sizeof(_registers.freg_1)); } void MC3630::setSpiStatus(bool enable) { if (_registers.freg_1.bit.IFMODE & (IFMODE_SPI | IFMODE_SPI3)) { _registers.freg_2.bit.SPI_STAT_EN = enable; writeReg(&_registers.freg_2, sizeof(_registers.freg_2)); } } void MC3630::setI2CWrClear(bool enable) { if (_registers.freg_1.bit.IFMODE & IFMODE_I2C) { _registers.freg_2.bit.I2CINT_WRCLRE = enable; writeReg(&_registers.freg_2, sizeof(_registers.freg_2)); } } void MC3630::setExtTrigger(bool enable, bool polarity) { _registers.freg_2.bit.EXT_TRIG_EN = enable; _registers.freg_2.bit.EXT_TRIG_POL = polarity; writeReg(&_registers.freg_2, sizeof(_registers.freg_2)); } void MC3630::setFifoStatus(bool enable) { _registers.freg_2.bit.FIFO_STAT_EN = enable; writeReg(&_registers.freg_2, sizeof(_registers.freg_2)); } void MC3630::setFifoMode(bool enable, uint8_t threshold, FIFO_OPT option) { _registers.fifo.bit.TH = (threshold < 31 ? threshold : 31); _registers.fifo.bit.MODE = (option & FIFO_OPT_WATERMARK) != 0; _registers.fifo.bit.EN = enable; writeReg(&_registers.fifo, sizeof(_registers.fifo)); _registers.freg_1.bit.FREEZE = (option & FIFO_OPT_FREEZE) != 0; _registers.freg_2.bit.FIFO_BURST = (option & FIFO_OPT_BURST) != 0; _registers.freg_2.bit.FIFO_STREAM = (option & FIFO_OPT_STREAM) != 0; writeReg(&_registers.freg_1, sizeof(_registers.freg_1) + sizeof(_registers.freg_2)); } void MC3630::resetFifo(void) { _registers.fifo.bit.RESET = true; writeReg(&_registers.fifo, sizeof(_registers.fifo)); _registers.fifo.bit.RESET = false; } void MC3630::disableAxis(uint16_t mask) { _registers.mode.bit.X_AXIS_PD = (mask & (1 << AXIS_X)) != 0; _registers.mode.bit.Y_AXIS_PD = (mask & (1 << AXIS_Y)) != 0; _registers.mode.bit.Z_AXIS_PD = (mask & (1 << AXIS_Z)) != 0; writeReg(&_registers.mode, sizeof(_registers.mode)); } void MC3630::setMode(MODE mode) { if ((mode > MODE_STANDBY) && (_registers.mode.bit.MCTRL > MODE_STANDBY)) setMode(MODE_STANDBY); if (mode == MODE_SNIFF) setSniffPowerMode(_spm_sniff); if (mode == MODE_TRIGGER) setSniffPowerMode(_spm_trigc); _registers.mode.bit.MCTRL = mode; _registers.mode.bit.TRIG_CMD = false; writeReg(&_registers.mode, sizeof(_registers.mode)); } MC3630::MODE MC3630::getMode(void) { readReg(&_registers.mode, sizeof(_registers.mode)); return (MODE)_registers.mode.bit.MCTRL; } void MC3630::trigger(void) { if (_registers.mode.bit.MCTRL == MODE_TRIGGER) { _registers.mode.bit.TRIG_CMD = true; writeReg(&_registers.mode, sizeof(_registers.mode)); } } void MC3630::setTriggerConfig(STB_RATE rate, uint8_t count) { _spm_trigc = rate >> 4; _registers.sniff.bit.STB_RATE = rate & 0x0F; writeReg(&_registers.sniff, sizeof(_registers.sniff)); if (_registers.rate.bit.MAN_SEL != MAN_SEL_DISABLE) setManualRate(MAN_SEL_DISABLE, 0); _registers.trigc = count; writeReg(&_registers.trigc, sizeof(_registers.trigc)); } void MC3630::setSniffPowerMode(uint8 spm) { if (_registers.pmcr.bit.SPM != spm) { _registers.pmcr.bit.SPM = spm; writeReg(&_registers.pmcr, sizeof(_registers.pmcr)); } } void MC3630::setSniffConfig(SNIFF_RATE rate, bool andMode, bool c2b) { _spm_sniff = rate >> 4; _registers.sniff.bit.SR = rate & 0x0F; writeReg(&_registers.sniff, sizeof(_registers.sniff)); _registers.sniffth.bit.AND_OR = andMode; _registers.sniffth.bit.MODE = c2b; writeReg(&_registers.sniffth, sizeof(_registers.sniffth)); } void MC3630::setSniffThreshold(THADR addr, uint8_t value, MUX_DELTA mux) { if (addr >= THADR_COUNT_X) { if (value-- == 0) return; _registers.sniffcf.bit.CNTEN = true; } _registers.sniffcf.bit.THADR = addr; _registers.sniffcf.bit.MUX = mux; writeReg(&_registers.sniffcf, sizeof(_registers.sniffcf)); _registers.sniffth.bit.TH = (value < 63 ? value : 63); writeReg(&_registers.sniffth, sizeof(_registers.sniffth)); } void MC3630::resetSniff(void) { _registers.sniffcf.bit.RESET = true; writeReg(&_registers.sniffcf, sizeof(_registers.sniffcf)); _registers.sniffcf.bit.RESET = false; } void MC3630::setWakeConfig(RATE rate, RANGE range, RES res) { _registers.pmcr.bit.CSPM = rate >> 4; writeReg(&_registers.pmcr, sizeof(_registers.pmcr)); _registers.rate.bit.WR = rate & 0x0F; writeReg(&_registers.rate, sizeof(_registers.rate)); _registers.range.bit.RANGE = range; _registers.range.bit.RES = res; writeReg(&_registers.range, sizeof(_registers.range)); } void MC3630::setManualRate(MAN_SEL sel, uint8_t val) { _registers.rate.bit.MAN_SEL = sel; writeReg(&_registers.rate, sizeof(_registers.rate)); if (sel != MAN_SEL_DISABLE) { _registers.trigc = val; writeReg(&_registers.trigc, sizeof(_registers.trigc)); } } void MC3630::setInterrupt(INTE enable, bool ipp, bool iah) { _registers.intr.bit.IPP = ipp; _registers.intr.bit.IAH = iah; _registers.intr.bit.INT_WAKE = (enable & INTE_WAKE) != 0; _registers.intr.bit.INT_ACQ = (enable & INTE_ACQ) != 0; _registers.intr.bit.INT_FIFO_EMPTY = (enable & INTE_FIFO_EMPTY) != 0; _registers.intr.bit.INT_FIFO_FULL = (enable & INTE_FIFO_FULL) != 0; _registers.intr.bit.INT_FIFO_THRESH = (enable & INTE_FIFO_THRESH) != 0; _registers.intr.bit.INT_SWAKE = (enable & INTE_SWAKE) != 0; writeReg(&_registers.intr, sizeof(_registers.intr)); } void MC3630::clearInterrupt(void) { writeReg(&_registers.status_2, sizeof(_registers.status_2)); } uint8_t MC3630::getChipID(void) { readReg(&_registers.chip_id, sizeof(_registers.chip_id)); return _registers.chip_id; } void MC3630::setScratch(uint8_t value) { _registers.scratch = value; writeReg(&_registers.scratch, sizeof(_registers.scratch)); } uint8_t MC3630::getScratch(void) { readReg(&_registers.scratch, sizeof(_registers.scratch)); return _registers.scratch; } void MC3630::setSpiHsMode(void) { if (_registers.freg_1.bit.IFMODE & (IFMODE_SPI | IFMODE_SPI3)) { _registers.pmcr.bit.SPI_HS_EN = true; writeReg(&_registers.pmcr, sizeof(_registers.pmcr)); setSpiHsModeIO(); } } void MC3630::reset(bool reset, bool reload) { _registers.reset.bit.RESET = reset; _registers.reset.bit.RELOAD = reload; writeReg(&_registers.reset, sizeof(_registers.reset)); } void MC3630::init1(void) { _registers.init_1 = 0x42; writeReg(&_registers.init_1, sizeof(_registers.init_1)); } void MC3630::init2(void) { _registers.init_2 = 0x00; writeReg(&_registers.init_2, sizeof(_registers.init_2)); } void MC3630::init3(void) { _registers.init_3 = 0x00; writeReg(&_registers.init_3, sizeof(_registers.init_3)); } void MC3630::initDriveMotion(void) { _registers.dm[AXIS_X].reg = 0x01; writeReg(&_registers.dm[AXIS_X], sizeof(_registers.dm[AXIS_X])); _registers.dm[AXIS_Y].reg = 0x80; writeReg(&_registers.dm[AXIS_Y], sizeof(_registers.dm[AXIS_Y])); } void MC3630::writeReg(const void *reg, uint8_t len) { const uint8_t *buf = (const uint8_t *)reg; uint8_t cmd = buf - (uint8_t *)&_registers; if (_registers.freg_1.bit.IFMODE & (IFMODE_SPI | IFMODE_SPI3)) cmd |= 0x40; writeIO(cmd, buf, len); } void MC3630::readReg(void *reg, uint8_t len) { uint8_t *buf = (uint8_t *)reg; uint8_t cmd = buf - (uint8_t *)&_registers; if (_registers.freg_1.bit.IFMODE & (IFMODE_SPI | IFMODE_SPI3)) cmd |= 0xC0; readIO(cmd, buf, len); } void MC3630::initialize(void) { setMode(MODE_STANDBY); // Go to Standby reset(true); // Reset (or Power-On) delayMicroseconds(1000); // Wait for reset to complete clearInterrupt(); // !! good luck charm !! delayMicroseconds(1000); // Wait for state machine init1(); // Initialization initDriveMotion(); // Initialization init2(); // Initialization init3(); // Initialization } void MC3630::writeIO(uint8_t cmd, const uint8_t *buf, uint8_t len) { _iomethod->writeIO(cmd, buf, len); } void MC3630::readIO(uint8_t cmd, uint8_t *buf, uint8_t len) { _iomethod->readIO(cmd, buf, len); } void MC3630::setSpiHsModeIO(void) { _iomethod->setSpiHsModeIO(); } void MC3630::delayMicroseconds(uint32 us) { _iomethod->delayMicroseconds(us); } |
【関連投稿】
NXP JN516X (TWELITE) をプログラミングする(開発環境の構築)
NXP JN516X (TWELITE) をプログラミングする(メイン・ルーチン)
NXP JN516X (TWELITE) をプログラミングする(TICKTIMER)
NXP JN516X (TWELITE) をプログラミングする(UART)
NXP JN516X (TWELITE) をプログラミングする(SYSTEM)
NXP JN516X (TWELITE) をプログラミングする(GPIO)
NXP JN516X (TWELITE) をプログラミングする(TIMER)
NXP JN516X (TWELITE) をプログラミングする(ALARM)
NXP JN516X (TWELITE) をプログラミングする(WAKETIMER)
NXP JN516X (TWELITE) をプログラミングする(WATCHDOG)
NXP JN516X (TWELITE) をプログラミングする(I2C)
NXP JN516X (TWELITE) をプログラミングする(SPI)
NXP JN516X (TWELITE) をプログラミングする(ADC)
NXP JN516X (TWELITE) をプログラミングする(COMPARATOR)
NXP JN516X (TWELITE) をプログラミングする(CLOCK)
NXP JN516X (TWELITE) をプログラミングする(BROWNOUT)
NXP JN516X (TWELITE) をプログラミングする(PULSCOUNTER)
NXP JN516X (TWELITE) をプログラミングする(INFRARED)
NXP JN516X (TWELITE) をプログラミングする(RANDOM-GENERATOR)
NXP JN516X (TWELITE) をプログラミングする(FLASH)
NXP JN516X (TWELITE) をプログラミングする(EEPROM)
NXP JN516X (TWELITE) をプログラミングする(WPAN)
NXP JN516X (TWELITE) をプログラミングする(Eclipse-CDT+MWSTAGE)
NXP JN516X (TWELITE) をプログラミングする(乗算と除算)
NXP JN516X (TWELITE) をプログラミングする(マルチタスク)
NXP JN516X (TWELITE) をプログラミングする(フラッシュ・プログラマー)
NXP JN516X (TWELITE) をプログラミングする(OTA UPDATE)
NXP JN516X (TWELITE) をプログラミングする(TWELITE CUE/MC3630)
NXP JN516X (TWELITE) をプログラミングする(LED)
NXP JN516X (TWELITE) をプログラミングする(AES)
NXP JN516X (TWELITE) をプログラミングする(Downloads)