Raspberry Pi Picoに搭載されるRP2040は安価でPIOや264kBの大きなRAMと非常に魅力的なマイコンです。一方でSTM32マイコンやPICマイコンを使ったことがある経験者からすると、マイコン思想の違いからSTM32やPICと比べて思うように実装できないと感じることがあると思います。
今回はRP2040でRaspberry Pi Pico C/C++ SDKを使用した際の厳密なタイマ割込み(=ジッターが少なく、時間クリティカルな処理)を実現するために気を付けるべきポイントについて紹介します。
@タイマ実行コア
usec単位でのタイマ割込みを利用する際にadd_repeating_timer_usを使用することが多いと思います。ただ、add_repeating_timer_usはデフォルトでcore0で実行されるため、core1のタイマ割込みとしてadd_repeating_timer_usを使用するとcore0の処理の影響を受けてしまう可能性があります。例えば指定したusec単位での処理が間に合わないといった問題やジッターが生じて微小に割込みタイミングが前後するといった問題が生じます。
この問題を防ぐため、add_repeating_timer_usの代わりにalarm_pool_createとalarm_pool_add_repeating_timer_usを使用します。タイマを使用するコアからalarm_pool_create関数を実行することで、もう一方のコアの影響を受けずにタイマ割込みを行うことができます。
例えば、core1でタイマ割込みを利用する場合、multicore_launch_core1で呼び出す関数の処理の最初にalarm_pool_createを呼び出すことでタイマ割込みがcore1から実行されるようになります。
alarm_pool_t* core1Alarm = alarm_pool_create(0, 4);
alarm_pool_add_repeating_timer_us(core1Alarm, 100, timer_callback, NULL, &timer);
A関数RAM配置
RP2040はFlashを内蔵していないため、QSPI接続の外部Flashにアクセスしながら処理を実行します(XiP機能)。外部Flashは内蔵Flashに比べて速度が遅いため、usec単位でのタイマ割込みの処理中に外部Flashへのアクセスが発生すると大幅に処理が遅れます(1回で数10usec~)。Raspberry Pi Pico C/C++ SDKでは外部Flashへのアクセスを抑制するための手段が提供されています。外部Flashへのアクセスを抑制するため、usec単位でのタイマ割込みで処理する関数に__not_in_flash_funcマクロや__time_critical_funcマクロを使用します。
例えば void timer_callback(){・・・}という関数の場合、void __not_in_flash_func(timer_callback)(){・・・}という風に関数を書き換えることで関数をRAMに展開し、外部Flashへのアクセスを抑制することが可能です。詳細についてはここでは説明しませんが、platform.h内に当該マクロの定義と説明があります。
また、__not_in_flash_funcマクロや__time_critical_funcマクロの他にすべての関数をRAMに展開する方法もあります。ただ、RAMに入りきらない場合もあるため、すべてのケースで推奨される方法ではありません。すべての関数をRAMに展開するにはCMakeLists.txtの先頭から数行目に下記の設定を追加します。
set(PICO_COPY_TO_RAM,1)
BベクタテーブルRAM配置
割込みのベクタテーブルはデフォルトでRAM配置(PICO_NO_RAM_VECTOR_TABLE 0)となっているため、そのままの設定であれば注意する必要はありません。意図的にPICO_NO_RAM_VECTOR_TABLE 1に変更した際は割込み等で外部Flashへのアクセスが発生するため、意図せず遅れの原因になる可能性があるため、注意が必要です。
今回はRP2040で厳密なタイマ割込みを実現するために気を付けるべきポイントについて紹介しました。モータ制御や電流制御、音声処理等を行う場合、usec単位で細かくタイマ割込みを実現する必要があります。デュアルコアかつ外部FLASHから読み込みというRP2040固有の仕様からSTM32やPICとは違った注意が必要です。実際にSTM32から移植した際、デュアルコアにも関わらず、思ったようなパフォーマンスが出ないといった場面がありました。具体的にはあるモータ制御の処理を72MHzのSTM32F3マイコンでは100usec毎に処理を実行できていたにも関わらず、125MHzのRP2040では150usecに設定しないと処理が間に合わない状況でした。処理の実行時間をIO出力させてオシロで調べると最速で30usecで処理が終わっているものの、外部Flashへのアクセス等で時々100usecを超えてしまうことが分かりました。上記の設定を見直すことでRP2040のデュアルコアを生かして、STM32F3マイコンよりも高速に50usecで処理ができるようになりました。
他にもRP2040固有の気を付けるべきポイントがあるため、また別の機会に紹介したいと思います。
posted by Crescent at 00:00|
Comment(0)
|
TrackBack(0)
|
組込ソフト
|
|