PPIとは
今回は珍しく旧SDK(nRF5 SDK)の話です。(もちろんnRF Connect SDKにもありますがそれは後ほど)
PPIというのはProgrammable Peripheral Interconnectの略です。具体的にはペリフェラル同士の割り込みを結び付けてCPUを介さずにペリフェラルを動かすというもので、この程度の説明はたしかマニュアルにも書かれていたような気がするのですが、ぶっちゃけ何のことかさっぱり分かっていませんでした。色んなCPUを触っていますが、おそらく他のCPUにはこんな機能はないと思います。
他のCPUにないというのが何のことか理解できなかった理由ということで・・・
でも・・・
そうは言ってみたところで、正直なところ具体的に何に使えばいいのか分からない・・・そりゃそうですよね。他のCPUではそんな機能がないのでそんなのすぐに使えって言っても無理があります。
と思ったところでそういえば誰かが過去にPPIのことを書いているのでは?と思って調べてみたら・・・ありました。
まさにこれです。ここではGPIO(入力)→TIMER(出力)ですが、これはなんでもかまいません。例えば私が作ったサンプルだと以下のようにTIMER(入力)→GPIO(出力)です。
// Timer
ret_code_t err_code;
uint32_t time_ticks;
nrfx_timer_config_t timer_cfg = NRFX_TIMER_DEFAULT_CONFIG;
// Configure timer1
err_code = nrfx_timer_init(&m_timer1, &timer_cfg, timer_event_handler);
APP_ERROR_CHECK(err_code);
// Set timer interval
time_ticks = nrfx_timer_ms_to_ticks(&m_timer1, 100);
nrfx_timer_extended_compare(&m_timer1, NRF_TIMER_CC_CHANNEL1, time_ticks, NRF_TIMER_SHORT_COMPARE1_CLEAR_MASK, true);
// GPIOTE Handler
if (!nrfx_gpiote_is_init())
{
err_code = nrfx_gpiote_init();
APP_ERROR_CHECK(err_code);
}
// Output
nrfx_gpiote_out_config_t const out_config = {
.action = NRF_GPIOTE_POLARITY_TOGGLE,
.init_state = 1,
.task_pin = true,
};
err_code = nrfx_gpiote_out_init(BSP_LED_0, &out_config);
APP_ERROR_CHECK(err_code);
nrfx_gpiote_out_task_enable(BSP_LED_0);
// PPI
err_code = nrf_drv_ppi_init();
APP_ERROR_CHECK(err_code);
nrf_ppi_channel_t channel;
err_code = nrfx_ppi_channel_alloc(&channel);
APP_ERROR_CHECK(err_code);
err_code = nrfx_ppi_channel_assign(channel,
nrfx_timer_compare_event_address_get(&m_timer1, NRF_TIMER_CC_CHANNEL1),
nrfx_gpiote_out_task_addr_get(BSP_LED_0));
APP_ERROR_CHECK(err_code);
/* Enable (D)PPI channel. */
err_code = nrfx_ppi_channel_enable(channel);
APP_ERROR_CHECK(err_code);
nrfx_timer_enable(&m_timer1);
上記のサンプル(メイン部分だけ抜粋)を動かすと500ミリ秒毎にLEDが点いたり消えたりします。飛び先の関数としてtimer_event_handlerを指定していますが実際に飛ばす必要はありませんし、実際に飛んだ先の関数内には何も記述していません。(ので記載を省略しています)
マイクロオーダーのタイマーイベントでI/Oを制御しようとすると割り込み待ちでずれてしまうことも多々あります。そういう場合にCPUを介さずに制御することでそういった遅延をなくすことができます。また、おそらくですが消費電力も少なくなります。
実はPPIのサンプルは存在している
ちゃんと理解せずに使っていたので気が付きませんでしたが、実はPPIを使ったサンプルというのは最初から用意されています。A/D変換(saadc)のサンプルです。しっかり読むとPPIを使ってTIMER(入力)→SAADC(出力)という制御をしています。
コピペで使っていたので何をしているのか全く理解していなかったのさ。てへぺろ
まとめ
操作して動かす場合はGPIOによるPPIを、一定間隔で繰り返すものはTIMERでのPPIを組んで積極的にCPU負荷(と消費電力)を減らしていきましょう。