Help us understand the problem. What is going on with this article?

nRF52でPPIを使ってGPIOTE EventでTIMER Taskを起動する

More than 1 year has passed since last update.

GPIOTE EventでTIMER Taskを起動する

Nordic SDK 14.20のサンプルプロジェクトpin_change_intとppiを参考に
PPIを使って、GPIOTEのIO変化を契機にTIMERを開始するサンプルを書いてみた。
以下にコードと各関数の処理概要を記す。

input_sampling_event_init関数では、GPIOTEとTIMER、PPIの初期設定を行う。
GPIOTEは、PIN_IN(DK Boardのボタン1)のH→L変化を捉えて、in_pin_handlerが呼ばれる。
TIMER0は、1ms毎にtimer_handlerが呼ばれる。
PPIで、GPIOTEとTIMER0を連携する。

input_sampling_event_enable関数では、input_sampling_event_init関数で設定したPPIを有効化する。これで、GPIOTEによるEventでTIMER0のTaskが起動する。
なお、今サンプルでは、TIEMR0のTaskは開始するが停止については書いていない。

main関数では、input_sampling_event_init関数とinput_sampling_event_enable関数を呼び、空ループに入る。

main.c
#include <stdbool.h>
#include "nrf.h"
#include "nrf_drv_gpiote.h"
#include "nrf_drv_ppi.h"
#include "nrf_drv_timer.h"
#include "app_error.h"
#include "boards.h"

#ifdef BSP_BUTTON_0
    #define PIN_IN BSP_BUTTON_0
#endif
#ifndef PIN_IN
    #error "Please indicate input pin"
#endif

#ifdef BSP_LED_0
    #define PIN_OUT BSP_LED_0
#endif
#ifndef PIN_OUT
    #error "Please indicate output pin"
#endif


static const nrf_drv_timer_t m_timer = NRF_DRV_TIMER_INSTANCE(0);
static nrf_ppi_channel_t     m_ppi_channel;

static uint32_t m_counter = 0;


void timer_handler(nrf_timer_event_t event_type, void * p_context)
{
    m_counter++;
}


void in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
    m_counter = 0;
}


static void input_sampling_event_init(void)
{
    ret_code_t err_code;

    err_code = nrf_drv_ppi_init();
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_gpiote_init();
    APP_ERROR_CHECK(err_code);

    nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(true);
    in_config.pull = NRF_GPIO_PIN_PULLUP;
    in_config.hi_accuracy = false;
    err_code = nrf_drv_gpiote_in_init(PIN_IN, &in_config, in_pin_handler);
    APP_ERROR_CHECK(err_code);


    nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
    timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_32;

    err_code = nrf_drv_timer_init(&m_timer, &timer_cfg, timer_handler);
    APP_ERROR_CHECK(err_code);

    /* setup m_timer for compare event every 1ms */
    uint32_t ticks = nrf_drv_timer_ms_to_ticks(&m_timer, 1);
    nrf_drv_timer_extended_compare(&m_timer,
                                   NRF_TIMER_CC_CHANNEL0,
                                   ticks,
                                   NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
                                   true);

    err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel);
    APP_ERROR_CHECK(err_code);

    uint32_t gpiote_in_event_addr = nrf_drv_gpiote_in_event_addr_get(PIN_IN);
    uint32_t timer_task_addr      = nrf_drv_timer_task_address_get(&m_timer, NRF_TIMER_TASK_START);

    err_code = nrf_drv_ppi_channel_assign(m_ppi_channel,
                                          gpiote_in_event_addr,
                                          timer_task_addr);
    APP_ERROR_CHECK(err_code);


    nrf_drv_gpiote_in_event_enable(PIN_IN, true);

}


void input_sampling_event_enable(void)
{
    ret_code_t err_code = nrf_drv_ppi_channel_enable(m_ppi_channel);

    APP_ERROR_CHECK(err_code);
}


/**
 * @brief Function for application main entry.
 */
int main(void)
{
    input_sampling_event_init();
    input_sampling_event_enable();

    while (true)
    {
        // Do nothing.
    }
}


/** @} */

実は少し前、pin_change_intを参考に、IO変化のコールバック関数内でTIMERの開始を行うコードを書いていたのだが、ふとPPIを使っても出来ると思ったのでやってみた。
積極的にPPI(ハードウェア処理)に任せていくのがいいのだと思う。

応用すれば、GPIOTE(Event)→PPI→TIMER(Task/Event)→PPI→SAADC(Task)
のような数珠繋ぎにして、スイッチを押したら定期ADサンプリングを開始
するような書き方も出来る。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away