Pico SDKのソースコードを覗いているとpico-sdk/lib/tinyusb/lib
の下1にFreeRTOSのソースがあったので、動かしてみました。
ソースコード
https://github.com/yunkya2/pico-freertos-sample にあります。
以下の手順でsubmoduleもあわせてcloneしてください2。
$ git clone https://github.com/yunkya2/pico-freertos-sample
$ cd pico-freertos-sample
$ git submodule update --init
環境変数 PICO_SDK_PATH
が設定されていれば、ビルド手順は通常のPico SDK用アプリと同様です。
$ mkdir build
$ cd build
$ cmake ..
$ make
ファイルの説明
pico-freertos-sample/
├── CMakeLists.txt ... 全体をビルドするためのCMakeLists.txt
├── LICENSE ... ライセンス(3項BSD)
├── README.md ... README
├── blink
│ ├── CMakeLists.txt ... サンプルアプリをビルドするCMakeLists.txt
│ └── blink.c ... サンプルアプリのソースコード
├── freertos
│ ├── CMakeLists.txt ... FreeRTOSをビルドしてライブラリを生成するCMakeLists.txt
│ ├── FreeRTOS-Kernel ... このフォルダ以下にFreeRTOSカーネルがcloneされる
│ └── FreeRTOSConfig.h ... FreeRTOSの設定ファイル
└── pico_sdk_import.cmake ... Pico SDKを参照するため設定(pico-sdk/externalからコピー)
アプリのCMakeLists.txtのtarget_link_libraries()に、blink/CMakeLists.txtと同様にfreertosを追加すると、FreeRTOSのライブラリもリンクされます。
target_link_libraries(blink pico_stdlib freertos)
サンプルの内容
指定された周期で指定されたGPIOのLEDを点滅させるタスク(led_task()
)を3つ生成して、GPIO 13~15に繋がったLEDを異なる周期で点滅させます。
struct led_task_arg {
int gpio;
int delay;
};
void led_task(void *p)
{
struct led_task_arg *a = (struct led_task_arg *)p;
gpio_init(a->gpio);
gpio_set_dir(a->gpio, GPIO_OUT);
while (true) {
gpio_put(a->gpio, 1);
vTaskDelay(pdMS_TO_TICKS(a->delay));
gpio_put(a->gpio, 0);
vTaskDelay(pdMS_TO_TICKS(a->delay));
}
}
int main()
{
setup_default_uart();
printf("Start LED blink\n");
struct led_task_arg arg1 = { 15, 100 };
xTaskCreate(led_task, "LED_Task 1", 256, &arg1, 1, NULL);
struct led_task_arg arg2 = { 14, 200 };
xTaskCreate(led_task, "LED_Task 2", 256, &arg2, 1, NULL);
struct led_task_arg arg3 = { 13, 300 };
xTaskCreate(led_task, "LED_Task 3", 256, &arg3, 1, NULL);
vTaskStartScheduler();
while (true)
;
}
実行
Raspberry Pi PicoのGPIO 13,14,15にそれぞれLEDと抵抗(330Ω)を直列に繋いでください。
以下の動画のように点滅します。それぞれ100ms, 200ms, 300msの周期で点灯・消灯を繰り返します。
注意点
- Pico SDKのAPIはシングルタスクでの動作しか考慮されていないはずです。GPIO操作程度の単純なAPIであれば問題ないですが、例えばLED点滅の元にしたSDKサンプルで使われている
sleep_ms()
はFreeRTOSのマルチタスク環境では正常に動作しません。
他にも同様のAPIがあるはずなので、Pico SDKを使って開発するアプリをFreeRTOSで動作させる場合は、FreeRTOSに対応するAPIがあればそれで置き換えたり、vTaskSuspendAll()
/xTaskResumeAll()
を使って処理中のタスク切り替えを防ぐ、などの対応が必要になると思います。 - OpenOCDのkernel aware debugが使えません(原因は未調査)。
- 本記事投稿時点のソースコードではRP2040のハードウェア除算器を用いた除算処理に問題がありましたが、既に修正されています(Raspberry Pi Picoの整数除算について (とPico版FreeRTOSの不具合修正)を参照)。
-
Pico SDKのsubmoduleであるtinyusbの更にsubmoduleのため、cloneの際に--recursiveを指定しないと出てきません。元々tinyusbの他のアーキテクチャ向けのビルドで使われるもので、Pico SDKでtinyusbを使ってもOSなしのコンフィグレーションでビルドされます。 ↩
-
当初はPico SDK内のFreeRTOSのソースをそのまま使うつもりだったのですが、Getting Started の手順に従うとrecursive指定がなくてFreeRTOSのソースコードが取得されないのと、recursive指定を行うとFreeRTOSの他にPico SDKでは使用しないリポジトリが大量にcloneされてしまって煩わしいので、結局サンプルソース本体側にsubmoduleとして入れることにしました。 ↩