nRF Connect SDK:タイマー(改版)

# 以前の記事
以前にもタイマーに関連する記事を書きました。

https://qiita.com/yoshihiro0709/items/5d31d9a3c3d69f1a0d3f

ちなみにこの時にはnRFXタイマーは使えないと書いています。
# nRFXタイマーは使える
でもふと疑問に思ったのです。その後PPIを使えるようにしたのですが、nRFXタイマーが使えないとしたらPPIをどうやって使えばいいんだ・・・？もちろんPPIはタイマー以外のペリフェラル結合でも使えますが、PPIで一番使いたいのはタイマーじゃないのかな、と。
## 以前はIRQ_CONNECTが足りていなかった
当時、何がダメでnRFXタイマーが動かないと判断したのか、実は覚えていません。調べた順番の前後も覚えていないのでもしかしたらタイマーの前にTWIMやSPIMを動かしているかも知れないのですが、当時足りていなかったのはおそらくIRQ_CONNECTではないかと思います。
## 改めて動作確認
せっかく動作確認するのだからタイマー0から4まで全部動かしてみようと思います。
``` main.c
/*
 * Copyright (c) 2012-2014 Wind River Systems, Inc.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr/zephyr.h>
#include <nrfx_timer.h>

static const nrfx_timer_t m_timer0 = NRFX_TIMER_INSTANCE(0);
static const nrfx_timer_t m_timer1 = NRFX_TIMER_INSTANCE(1);
static const nrfx_timer_t m_timer2 = NRFX_TIMER_INSTANCE(2);
static const nrfx_timer_t m_timer3 = NRFX_TIMER_INSTANCE(3);
static const nrfx_timer_t m_timer4 = NRFX_TIMER_INSTANCE(4);

static void timer_event_handler(nrf_timer_event_t event_type, void * context)
{
    switch (event_type)
    {
        case NRF_TIMER_EVENT_COMPARE0:
    		printk("timer 0\n");
            break;

        case NRF_TIMER_EVENT_COMPARE1:
    		printk("timer 1\n");
            break;

        case NRF_TIMER_EVENT_COMPARE2:
    		printk("timer 2\n");
            break;

        case NRF_TIMER_EVENT_COMPARE3:
    		printk("timer 3\n");
            break;

        case NRF_TIMER_EVENT_COMPARE4:
    		printk("timer 4\n");
            break;

        default:
    		printk("timer Other\n");
            break;
	}
}

void main(void)
{
	nrfx_err_t err;
    uint32_t time_ticks;
	nrfx_timer_config_t timer_cfg = {
		.frequency = NRF_TIMER_FREQ_16MHz,
		.mode      = NRF_TIMER_MODE_TIMER,
		.bit_width = NRF_TIMER_BIT_WIDTH_32,
	};

    // Configure timer driver
    err = nrfx_timer_init(&m_timer0, &timer_cfg, timer_event_handler);
	IRQ_CONNECT(TIMER0_IRQn, IRQ_PRIO_LOWEST, nrfx_timer_0_irq_handler, NULL, 0);
    time_ticks = nrfx_timer_ms_to_ticks(&m_timer0, 1000);
    nrfx_timer_extended_compare(&m_timer0, NRF_TIMER_CC_CHANNEL0, time_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);

    err = nrfx_timer_init(&m_timer1, &timer_cfg, timer_event_handler);
	IRQ_CONNECT(TIMER1_IRQn, IRQ_PRIO_LOWEST, nrfx_timer_1_irq_handler, NULL, 0);
    time_ticks = nrfx_timer_ms_to_ticks(&m_timer1, 2000);
    nrfx_timer_extended_compare(&m_timer1, NRF_TIMER_CC_CHANNEL1, time_ticks, NRF_TIMER_SHORT_COMPARE1_CLEAR_MASK, true);

    err = nrfx_timer_init(&m_timer2, &timer_cfg, timer_event_handler);
	IRQ_CONNECT(TIMER2_IRQn, IRQ_PRIO_LOWEST, nrfx_timer_2_irq_handler, NULL, 0);
    time_ticks = nrfx_timer_ms_to_ticks(&m_timer2, 3000);
    nrfx_timer_extended_compare(&m_timer2, NRF_TIMER_CC_CHANNEL2, time_ticks, NRF_TIMER_SHORT_COMPARE2_CLEAR_MASK, true);

    err = nrfx_timer_init(&m_timer3, &timer_cfg, timer_event_handler);
	IRQ_CONNECT(TIMER3_IRQn, IRQ_PRIO_LOWEST, nrfx_timer_3_irq_handler, NULL, 0);
    time_ticks = nrfx_timer_ms_to_ticks(&m_timer3, 4000);
    nrfx_timer_extended_compare(&m_timer3, NRF_TIMER_CC_CHANNEL3, time_ticks, NRF_TIMER_SHORT_COMPARE3_CLEAR_MASK, true);

    err = nrfx_timer_init(&m_timer4, &timer_cfg, timer_event_handler);
	IRQ_CONNECT(TIMER4_IRQn, IRQ_PRIO_LOWEST, nrfx_timer_4_irq_handler, NULL, 0);
    time_ticks = nrfx_timer_ms_to_ticks(&m_timer4, 5000);
    nrfx_timer_extended_compare(&m_timer4, NRF_TIMER_CC_CHANNEL4, time_ticks, NRF_TIMER_SHORT_COMPARE4_CLEAR_MASK, true);

    // Enable timer driver
	nrfx_timer_enable(&m_timer0);
	nrfx_timer_enable(&m_timer1);
	nrfx_timer_enable(&m_timer2);
	nrfx_timer_enable(&m_timer3);
	nrfx_timer_enable(&m_timer4);
}
```
## コンフィギュレーション
``` prj.conf
CONFIG_NRFX_TIMER0=y
CONFIG_NRFX_TIMER1=y
CONFIG_NRFX_TIMER2=y
CONFIG_NRFX_TIMER3=y
CONFIG_NRFX_TIMER4=y
CONFIG_DEBUG_THREAD_INFO=y
CONFIG_DEBUG_OPTIMIZATIONS=y
```
余談ですが、VSCodeになってからはprj.confはKconfigの設定画面を使うと楽にできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340602/edd5ea4c-4779-d076-76d1-fe832adf89bd.png)
## タイマー0も使える
もしかしたらBluetoothを使っていないから解放されているだけかも知れませんが、タイマー0も普通に使えるみたいです。
ていうか、じゃあZephyrのタイムスライスっていったい誰がやっているんでしょう・・・？もしかしてLFCLKベースなのでしょうか？

::: note
nRF SDKではAPP TIMERと呼ばれていたタイマーのことです。
:::