[TWE-Lite]TIMERを使う編


# TWE-Liteのタイマ

- TWE-Liteに搭載されているマイコンJN5164には通常のタイマと高精度タイマ(TickTimer)が搭載されている
- **通常のタイマとTickTimer，どれくらい差があるのか**気になるので見てみた
- ただし，使用した機材は**ToCoStick**

# 目的

- **TIMER割り込みを使えるようにする．**
- ついでにTickTimerとの誤差もみる．



# 検証用プログラム

```c:main.c
#include <AppHardwareApi.h>
#include "utils.h"
#include "serial.h"
#include "sprintf.h"
#include "ToCoNet.h"
#include <string.h>

#define UART_BAUD 115200 // シリアルのボーレート


static tsFILE sSerStream;          // シリアル用ストリーム
static tsSerialPortSetup sSerPort; // シリアルポートデスクリプタ

static tsTimerContext timer0;


// デバッグメッセージ出力用
#define DBG
#ifdef DBG
#define dbg(...) vfPrintf(&sSerStream, LB __VA_ARGS__)
#else
#define dbg(...)
#endif

// デバッグ出力用に UART を初期化
static void vSerialInit() {
    static uint8 au8SerialTxBuffer[96];
    static uint8 au8SerialRxBuffer[32];

    sSerPort.pu8SerialRxQueueBuffer = au8SerialRxBuffer;
    sSerPort.pu8SerialTxQueueBuffer = au8SerialTxBuffer;
    sSerPort.u32BaudRate = UART_BAUD;
    sSerPort.u16AHI_UART_RTS_LOW = 0xffff;
    sSerPort.u16AHI_UART_RTS_HIGH = 0xffff;
    sSerPort.u16SerialRxQueueSize = sizeof(au8SerialRxBuffer);
    sSerPort.u16SerialTxQueueSize = sizeof(au8SerialTxBuffer);
    sSerPort.u8SerialPort = E_AHI_UART_0;
    sSerPort.u8RX_FIFO_LEVEL = E_AHI_UART_FIFO_LEVEL_1;
    SERIAL_vInit(&sSerPort);

    sSerStream.bPutChar = SERIAL_bTxChar;
    sSerStream.u8Device = E_AHI_UART_0;
}


static void vInitTimer()
{
	memset(&timer0, 0, sizeof(tsTimerContext));
	timer0.u8Device = E_AHI_DEVICE_TIMER0; // timer0使用

	timer0.u16Hz = 1000;        // 1000Hz
	timer0.u8PreScale = 1;      // プリスケーラ1/2
	timer0.bDisableInt = FALSE; // 割り込み禁止


	vTimerConfig(&timer0); // タイマ設定書き込み
	vTimerStart(&timer0);  // タイマスタート

}


// ハードウェア初期化
static void vInitHardware()
{
    vSerialInit();						//	シリアル通信の設定
    ToCoNet_vDebugInit(&sSerStream);
    ToCoNet_vDebugLevel(0);
}

static int sum = 0;

// ユーザ定義のイベントハンドラ
static void vProcessEvCore(tsEvent *pEv, teEvent eEvent, uint32 u32evarg)
{

    // 1 秒周期のシステムタイマ通知
   if(eEvent == E_EVENT_TICK_SECOND)
   {
		dbg("%d\t%d",u32TickCount_ms,sum);		//	Tickタイマが数えてる（らしい）msと，TIMER0によるmsを出力
   }

    return;
}


void cbToCoNet_vMain(void)
{
    return;
}


void cbToCoNet_vRxEvent(tsRxDataApp *pRx)
{
    return;
}


void cbToCoNet_vTxEvent(uint8 u8CbId, uint8 bStatus)
{
    return;
}


void cbToCoNet_vNwkEvent(teEvent eEvent, uint32 u32arg)
{
    return;
}

// ハードウェア割り込みの遅延実行部
void cbToCoNet_vHwEvent(uint32 u32DeviceId, uint32 u32ItemBitmap)
{
	if(u32DeviceId == E_AHI_DEVICE_TIMER0)	//	TIMER0で割り込まれたら
	{
		sum++;
	}
    return;
}

// ハードウェア割り込み発生時
uint8 cbToCoNet_u8HwInt(uint32 u32DeviceId, uint32 u32ItemBitmap)
{

    return FALSE;
}

// コールドスタート時
void cbAppColdStart(bool_t bAfterAhiInit)
{

    sToCoNet_AppContext.u8CPUClk = 3;		//	CPUクロックは最高の32MHz
    sToCoNet_AppContext.u16TickHz = 250;	//	TickTimerはデフォルトの250Hz
    ToCoNet_vRfConfig();					//	設定適用．無くてもいい気がする（未検証）
    if (!bAfterAhiInit) {
    } else {
        // ユーザ定義のイベントハンドラを登録
        ToCoNet_Event_Register_State_Machine(vProcessEvCore);
        vInitHardware();
        vInitTimer();
    }
}

// ウォームスタート時
void cbAppWarmStart(bool_t bAfterAhiInit)
{
    return;
}


```

- TIMER0で1000Hzの割り込みをかけて，割り込み時にカウントアップしていく．
- １秒おきに，TickTimerが数えてる（らしき）1msカウンタとTIMER0でカウントした数値を比較
- **1秒の誤差**が出るまでひたすら待つ
- シリアル通信部については，[こちらのklab様の記事](http://dsas.blog.klab.org/archives/52201101.html)
を参考にさせていただきました．ありがとうございました．

# 動いてるとこ

![スクリーンショット 2016-01-21 15.10.48.png](https://qiita-image-store.s3.amazonaws.com/0/81908/dd70f9b5-47bf-c750-49e5-fc28d60766c3.png)

# 結果

- TIMER0はTickTimerに比べ，**64024秒に1秒**の遅れがありましたとさ．
- どっちのが精度いいのかわからないけど，公式文書（マイコンの方）を読む限りはTickTimerのが良いっぽい.
- ただしToCoNetを利用するなら，TickTimerは抑えられている（一応割り込み周期の変更はできる）



### 後記

- TWE-Lite，面白いのにあんまり流行ってない気がする．
    - Cしか使えないのが結構痛い．C++が使えたららなあ…．
    - というか公式のマニュアルも結構雑＆保護のせいで使いづらい
    - Bluetoothと違って色んな物に繋げないのも原因のひとつか
    - 通信モジュールとしての性能も見ていきたい