##はじめに
電子工作界隈で話題になっているCortex-M0+をコアにもつRP2040を搭載したRaspberry Pi Pico(以後、ラズパイPico)ですが、公式に提供されているPico-SDKの初期化では動作クロックが125MHzになっています。ただし、チップとしては133MHzまで使えることになっているので、インターフェース誌 2021年8月号で私が紹介したFreeRTOSの動作クロックを変更してみました。
・インターフェース誌 2021年8月号
https://interface.cqpub.co.jp/magazine/202108/
FreeRTOSの記事のサンプル
https://interface.cqpub.co.jp/wp-content/uploads/if2108_103.pdf
##FreeRTOSとSDKの関係
インターフェース誌で紹介したラズパイPico用のFreeRTOSは以下の3つのプログラムで構成されています。
・https://github.com/PicoCPP/RPI-pico-FreeRTOS
FreeRTOS本体とPico-SDKを組み合わせるための定義やサンプルプログラム
・https://github.com/FreeRTOS/FreeRTOS-Kernel
FreeRTOS本体
・https://github.com/raspberrypi/pico-sdk.git
Pico-SDK
|--RPI-pico-FreeRTOS
| | →https://github.com/PicoCPP/RPI-pico-FreeRTOS
| |--.git
| |--.gitignore
| |--.gitmodules
| |--CMakeLists.txt
| |--Dockerfile
| |--FreeRTOS-Kernel
| | → https://github.com/FreeRTOS/FreeRTOS-Kernel
| |--README.md
| |--include
| |--pico-cpp
| |--pico-sdk
| | →https://github.com/raspberrypi/pico-sdk.git
| |--src
SDKで提供されるベクタテーブルのリセットハンドラから以下のような流れでFreeRTOSの起動していきます。
pico-sdk/src/rp2_common/pico_standard_link/crt0.S
_reset_handler:
↓
pico-sdk/src/rp2_common/pico_runtime/runtime.c
runtime_init()
↓
pico-sdk/src/rp2_common/hardware_clocks/clocks.c
clocks_init()
↓
RPI-pico-FreeRTOS/src/main.cpp
main
↓
xTaskCreate()
vTaskStartScheduler()
FreeRTOSはライブラリとして提供されmain関数内でタスクの生成やスケジューラーが起動されます。
##クロックの設定
起動処理中にラズパイPicoのクロックはclocks_init関数の中で設定されています。
145 /// \tag::pll_settings[]
146 // Configure PLLs
147 // REF FBDIV VCO POSTDIV
148 // PLL SYS: 12 / 1 = 12MHz * 125 = 1500MHZ / 6 / 2 = 125MHz
149 // PLL USB: 12 / 1 = 12MHz * 40 = 480 MHz / 5 / 2 = 48MHz
150 /// \end::pll_settings[]
151
152 reset_block(RESETS_RESET_PLL_SYS_BITS | RESETS_RESET_PLL_USB_BITS);
153 unreset_block_wait(RESETS_RESET_PLL_SYS_BITS | RESETS_RESET_PLL_USB_BITS);
154
155 /// \tag::pll_init[]
156 pll_init(pll_sys, 1, 1500 * MHZ, 6, 2); ・・・(1)
157 pll_init(pll_usb, 1, 480 * MHZ, 5, 2); ・・・(2)
158 /// \end::pll_init[]
この中の**(1)**の部分でシステムクロックが設定されています。
1500MHZ / 6 / 2 = 125MHz
RP2040の最高周波数 133MHzにするには、この式の「1500」を設定することで変更できます。
133 * 6 * 2 = 1596
133MHzにするには**(1)**の行の「1500」を「1596」へ変更します。
pll_init(pll_sys, 1, 1596 * MHZ, 6, 2);
ここでシステムクロックが 125MHzから133HMzへ変更したため、125MHzを期待して作られている処理を変更する必要があります。
変更箇所は、clocks_init関数の以下の箇所になります。
・システムのクロック値
169 // CLK SYS = PLL SYS (125MHz) / 1 = 125MHz
170 clock_configure(clk_sys,
171 CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX,
172 CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS,
173 125 * MHZ,
174 125 * MHZ);
↓
169 // CLK SYS = PLL SYS (133MHz) / 1 = 133MHz
170 clock_configure(clk_sys,
171 CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX,
172 CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS,
173 133 * MHZ,
174 133 * MHZ);
・ペリフェラルのクロック値
198 // CLK PERI = clk_sys. Used as reference clock for Peripherals. No dividers so just select and enable
199 // Normally choose clk_sys or clk_usb
200 clock_configure(clk_peri,
201 0,
202 CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS,
203 125 * MHZ,
204 125 * MHZ);
↓
198 // CLK PERI = clk_sys. Used as reference clock for Peripherals. No dividers so just select and enable
199 // Normally choose clk_sys or clk_usb
200 clock_configure(clk_peri,
201 0,
202 CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS,
203 133 * MHZ,
204 133 * MHZ);
##FreeRTOSのタイマ設定
OSはタイマー割込みを使って単位時間を決めている。FreeRTOSも同様でタスクの待ち時間などの単位時間として用いられます。
RP2040では **Cortex-M0+**が内蔵する systickタイマを使っているのでシステムクロックsystickタイマの入力となり、システム周波数がタイマの動作周波数となっています。
FreeRTOSは1ミリ秒を単位時間としているのでシステムクロックの 1/1000をタイマのカウント値としています。
実際には include/FreeRTOSConfig.h内で定義されている。
システムクロックが133MHzになるので、タイマのカウント値も以下のように変更します。
8 #define configCPU_CLOCK_HZ 125000000/* Looking at runtime.c in the RPI 2040 SDK, the sys clock frequency is 125MHz */
↓
8 #define configCPU_CLOCK_HZ 133000000/* Looking at runtime.c in the RPI 2040 SDK, the sys clock frequency is 133MHz */
##検証
Pico-SDKとFreeRTOSの設定の変更前後でRP2040の動作速度がどのように変わるか確認します。
RP2040の動作速度がわかるように以下の何も処理しないループ(ビジーループ)を作成します。125MHz設定で1回の呼び出しで100マイクロ秒となるよう調整してループ回数を決めてあります。命令の実行時間が125MHz(1/125M 秒)単位となるので、ループ回数が1250回となったようです。ちなみにコンパイラの最適化により処理が消されないようループに用いる変数をvolatile宣言してあります。
volatile int conter1;
static inline void test_delay( void )
{
for( conter1=0; conter1<1250 ; conter1++ ) {
}
}
先に作成したtest_delay()の呼び出し前後でGPIOを H/L (1/0)する処理を入れ、それを延々と繰り返すようにしました。
この GPIOをロジアナなどで観察さればRP2040の動作速度がわかります。
void vTaskCode( void * pvParameters )
{
:
for( ;; )
{
int i;
gpio_put(PIN_ONLED,1);
for( i=0 ; i<500 ; i++ ) {
gpio_put(PIN_GPIO0,1);
test_delay();
gpio_put(PIN_GPIO0,0);
test_delay();
}
gpio_put(PIN_ONLED,0);
for( i=0 ; i<500 ; i++ ) {
gpio_put(PIN_GPIO0,1);
test_delay();
gpio_put(PIN_GPIO0,0);
test_delay();
}
}
ロジアナの測定結果は以下のようになりました。
・133MHz設定時の test_delay()の測定結果(基準線は125MHz時)
・133MHz設定時の test_delay()の測定結果(基準線は133MHz時)
##結果
ロジアナの結果からも 125MHzから133MHz設定へ変更したことで同じ処理(命令)の動作時間が早くなったことが確認できました。
ロジアナの結果ではタイマ割込みなどの影響からか多少の変化が出ますが、おおむね**106%**程度の速度の向上が見られました。これは動作周波数の違いと同等になることから、125MHzから 133MHzへの設定変更ができたと考えます。
100 / 94 * 100 ≒ 106.38 [%]
133 / 125 * 100 ≒ 106.40 [%]
##さいごに
今回はインターフェース誌で紹介した FreeRTOSで試しましたが、RP2040の初期化処理にPico-SDKを使ったプログラムであれば、
clocks.cの**clocks_init()**内の設定値を変更することで性能の向上が見込めます。
ただし、ハードウェアのアクセスや通信速度などで 125MHzのシステムクロックを期待している処理の場合、誤動作の原因となるので注意が必要です。
この点を注意しながらラズパイPicoやRP2040の133MHz動作を試されてはいかがでしょうか。
- 以上 -