LoginSignup
20

More than 3 years have passed since last update.

Raspberry Pi PicoでFreeRTOSを動かす

Last updated at Posted at 2021-02-03

Pico SDKのソースコードを覗いているとpico-sdk/lib/tinyusb/libの下1FreeRTOSのソースがあったので、動かしてみました。

ソースコード

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の周期で点灯・消灯を繰り返します。

Videotogif.gif

注意点

  • 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の不具合修正)を参照)。

  1. Pico SDKのsubmoduleであるtinyusbの更にsubmoduleのため、cloneの際に--recursiveを指定しないと出てきません。元々tinyusbの他のアーキテクチャ向けのビルドで使われるもので、Pico SDKでtinyusbを使ってもOSなしのコンフィグレーションでビルドされます。 

  2. 当初はPico SDK内のFreeRTOSのソースをそのまま使うつもりだったのですが、Getting Started の手順に従うとrecursive指定がなくてFreeRTOSのソースコードが取得されないのと、recursive指定を行うとFreeRTOSの他にPico SDKでは使用しないリポジトリが大量にcloneされてしまって煩わしいので、結局サンプルソース本体側にsubmoduleとして入れることにしました。 

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20