JN516xで時間計測する方法は複数ある。
・Timer(XTAL)
・TickTimer(XTAL)
・WakeTimer(RC)
・Watchdog(RC)
それぞれ長短あるが正確なのはXTALクロック駆動のTimerとTickTimerだ。どちらもマイクロ秒未満を測ることも可能だ。
16MHz駆動の場合、Timerは16bitなので4,096us、TickTimerは32bitなのだがreference-countが28bitなので16,777,215usまで測れることになる。それ以上を計測するにはオーバーフロー処理すれば良いが計測中にタイマーカウンターを変更したり止めたりすると誤差が生じるため動かし続けることが重要である。
で、どちらを使うかであるが多機能なTimerは残しておきたいと考えるのが普通?だとすると残るはTickTimerのみだ。28bitもあるのでオーバーフロー処理のオーバーヘッドを気にしなくても良いというメリットもある。それとマイクロ秒未満を出来るだけ簡単に計算できるようカウンターは32bitフルで使いたいのでreference-countの28bitに制限されない方法を考えてみた。
32bit以上を計測するにはカウンター(32bit)がゼロになったときにオーバーフロー処理を行う必要があるのでreference-count(28bit)の設定はゼロになる。但し、カウンターが一回りする間に16回マッチしてしまうためオーバーフロー処理は16回毎に行う必要がある。
【TickTimerの初期化】
TickTimerのカウンターとreference-countをゼロ設定しコンティニューモードでスタートすると即座に割り込みが発生し誤動作してしまう。そのためタイマーを先にスタートさせカウンターがゼロ以外になってから割り込み許可するようAPIの実行順で調整している。
1 2 3 4 5 6 7 8 |
vAHI_TickTimerIntEnable(false); vAHI_TickTimerConfigure(E_AHI_TICK_TIMER_DISABLE); vAHI_TickTimerRegisterCallback(TickTimerCallback); vAHI_TickTimerInterval(0); vAHI_TickTimerWrite(_overflow = 0); vAHI_TickTimerConfigure(E_AHI_TICK_TIMER_CONT); vAHI_TickTimerIntPendClr(); vAHI_TickTimerIntEnable(true); |
【オーバーフロー処理】
16回毎のオーバーフロー処理を割り込み毎に1/16ずつ加算することで単純化している。シンプルイズベスト!だ。
1 2 3 4 |
void TickTimerCallback(uint32 u32Device, uint32 u32ItemBitmap) { _overflow += INTERVAL >> 4; } |
【修正履歴】
2022-05-03
オーバーフロー・マスク値のキャスト・ミスによりmicros64()の戻り値の上位32bitが常にゼロになっていたのを修正。基本的な検証ミス。約71分後にならないと現象確認できないのに性格の問題によりそこまで待てなかったのが敗因か。(-_-;)
【ライブラリ】
64bitのマイクロ秒時間(micros64)、マイクロ秒未満の計測のための16MHzクロックカウントの取得(read)、割り込み禁止状態からのmicros64呼び出しに対応。
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 |
/* ticktimer.h - Tick Timer Library for NXP-JN516x 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 <jendefs.h> #include <AppHardwareApi.h> class TickTimer { public: static void begin(void) { vAHI_TickTimerIntEnable(false); vAHI_TickTimerConfigure(E_AHI_TICK_TIMER_DISABLE); vAHI_TickTimerRegisterCallback(TickTimerCallback); vAHI_TickTimerInterval(0); vAHI_TickTimerWrite(_overflow = 0); vAHI_TickTimerConfigure(E_AHI_TICK_TIMER_CONT); vAHI_TickTimerIntPendClr(); vAHI_TickTimerIntEnable(true); } static uint32 read(void) { return u32AHI_TickTimerRead(); } static uint64 micros64(void) { uint64 h;が uint32 l; do { // Check twice because the status can be confirmed even if interrupt is enabled. if (bAHI_TickTimerIntStatus() && bAHI_TickTimerIntStatus()) { vAHI_TickTimerIntPendClr(); _overflow += INTERVAL >> 4; } h = _overflow; l = read(); } while (bAHI_TickTimerIntStatus() || ((uint32)h != (uint32)_overflow)); return (l >> 4) | (h & ~(uint64)(INTERVAL - 1)); } private: static void TickTimerCallback(uint32 u32Device, uint32 u32ItemBitmap) { (void)u32Device; // E_AHI_DEVICE_TICK_TIMER (void)u32ItemBitmap; // 1 _overflow += INTERVAL >> 4; } static const uint32 INTERVAL = 1 << 28; static volatile uint64 _overflow; }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/* ticktimer.cpp - Tick Timer Library for NXP-JN516x 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 "ticktimer.h" volatile uint64 TickTimer::_overflow; |
【Lチカ再挑戦】
時間計測ができるようになったので前回のLチカを1秒おきに点滅するようにしてみよう。
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 |
#include <jendefs.h> #include <AppHardwareApi.h> #include "ticktimer.h" #ifdef __cplusplus #undef PUBLIC #define PUBLIC extern "C" #endif #define LED 18 /* 普通に起動したときのメイン・ルーチン */ PUBLIC void AppColdStart(void) { uint64 i; /* SDK-APIの初期化 */ u32AHI_Init(); /* LEDピンの出力に設定にする */ vAHI_DioSetDirection(0, 1 << LED); /* TickTimerの初期化*/ TickTimer::begin(); /* メイン・ループ */ while (1) { /* LEDピンをHIGHにする */ vAHI_DioSetOutput(1 << LED, 0); /* 一秒待つ */ for (i = TickTimer::micros64(); TickTimer::micros64() - i < 1000000; ) continue; /* LEDピンをLOWにする */ vAHI_DioSetOutput(0, 1 << LED); /* 一秒待つ */ for (i = TickTimer::micros64(); TickTimer::micros64() - i < 1000000; ) continue; } } /* ウェイクアップ・イベントで起動したときのメイン・ルーチン */ PUBLIC void AppWarmStart(void) { /* u32AHI_Init()の前に行う処理を記述する */ /* コールドスタートを呼び出す */ AppColdStart(); } |
前回の超高速Lチカの点滅は見えなかったが今回は見えるぞ。(笑)
次回は、UART及びUART用のデバッグライブラリを説明する予定。
【関連投稿】
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)