1. yosukek

    Posted

    yosukek
Changes in title
+nRF52でPPIを使ってGPIOTE EventでTIMER Taskを起動する
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,139 @@
+# 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関数を呼び、空ループに入る。
+
+```c: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サンプリングを開始
+するような書き方も出来る。