1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

zybo Z7-20でFreeRTOSを動かしてみた ~最初のマルチタスク実装~

1
Last updated at Posted at 2026-06-04

はじめに

今回は Zybo Z7-20 上で FreeRTOS を使ってみました。
前半は最小構成として 2つのタスクからUARTへメッセージを送るだけ の動作を確認します。
後半では、GEMを使ったEthernet通信を行うため、ミドルウェアのlwipを組み込み、取得したセンサ値をソケットで上位PCに通信したいと思います。

センサはIICの格安モジュール(BME280+AHT20)を使用します。

今回は、GPIO制御やPL連携まで広げるのではなく、最初に スケジューラが正しく動作しているか複数タスクが切り替わっているかUART出力が問題なく見えるか を確認することを目的にします。

今回使用したコードはgitで公開しています

前半の方針

構成はかなりシンプルです。

  • FreeRTOSで2つのタスクを生成する
  • 各タスクはUARTへ文字列を送信する
  • 1秒ごとに vTaskDelay() で待つ
  • 優先度は同じにする

確認したいのは以下の3点です。

  1. vTaskStartScheduler() 後にFreeRTOSが正常に動くこと
  2. 複数のタスクが動作すること
  3. UARTに継続的にログが出ること

それではやっていきましょう!

PL(FPGA側)の設定

  • まずPLの設定をvivadoで行います
  • FPGA側の設定のポイントは「timer」を最低一つ追加することです
  • この設定が無いと、PS側のvitisのOS設定でFreeRTOSを選択できません
  • 詳しく見ていきます

block design にてzynq7 PSを追加

  • まずは従来通りにzynq7 PSを追加します。「Apply Board Preset」を使ってデフォルトの設定にします
  • これでzyboのハードに合わせた設定が一通り入ります
  • 自動でUART、GEM、SDカード、SPIフラッシュなどが使えるようになります

timerを有効にする

  • デフォルト設定では無効になっている、timerを有効にします
  • PS側で制御できるtimerの「TTC」を有効にします
  • USB1が割り当たっていましたが、使用しないのでTTCに変更します 
     ※2個有効にしていますが1個でもOKです

image.png

センサ接続用(IIC)を追加

  • データ取得用に追加します
  • IICインタフェースはPS側に追加することもできますが、他に使いたい機能と被っていたのでPLで設定します
  • AXI_IICを使用します。デフォルトではboard interfaceがHDMIになっているのでcustomに変更します

image.png

その他:ボード上のLED,SW,BTNを使用

  • ボード上にBTNが4つ、SWが4つあり、AXI_GPIOでアクセス出来るようにします
  • 割り込み端子としても設定します
  • またLEDも4つありますので、こちらも違うAXI_GPIOでアクセス出来るようにします

image.png

割り込み設定

  • SW,BTNの割り込みと、IICの割り込みをconcatで束ねてzynqのIRQ_F2Pに入力します
  • xlconcat は複数の割り込み信号を1本にまとめるための IP です。
    今回の構成では、SW/BTN の割り込みと AXI IIC の割り込みを xlconcat に入力し、まとめた信号を Zynq PS の IRQ_F2P へ接続しています。
  • これにより、PS は複数の割り込み要因を受け取ることができ、ソフトウェア側で発生元を判別して処理します。

image.png

  • zynqの設定でinterrupt Port でIRQ_F2Pを有効にします
  • 下のFIQは優先レベルの高い割り込みを使う場合に設定します
    image.png

PLの全体像

image.png

以上でPL側の設定は完了です

  • bitstreamを生成まで行ってください
  • XSAを作成して、vitisでplatformを作成します

{C6AA35C0-BE83-4BEB-A66E-416D962D2874}.png

  • include bitstream を選択
    {92766613-CA59-4093-9255-3B5F8C1B32B1}.png

  • わかりやすいように、作成したXSAはvitisフォルダにおきます
    {FFE1A788-5DF9-4BF3-A098-958F1F8E6DD2}.png

  • 次のvitisの作業では、このフォルダをworkspaceに設定します

PS側(vitis)の設定

workspace をsetする

VitisにおけるWorkspaceとはプロジェクト(プラットフォーム・アプリケーションなど)をまとめて管理する作業フォルダです。
Vitis起動時に指定するディレクトリで、その中にソースコード・設定情報・ビルド結果などが整理されて保存されます。

  • set workspace を行います
    {65C6830F-9BED-4744-AA8F-B9CE964C87BF}.png

  • XSAを保存したvitisフォルダを選択します
    {92A21781-5E85-4EF6-8541-6EC65D8D53F8}.png

  • update を聞かれますが、updateでOKです
    {85135065-4BF9-4A91-BC30-9E77DDF90A1C}.png

  • vitis componentsからplatformを選択します
    {0CC3A541-D324-4246-9102-7A946617A1B1}.png

  • 保存したXSAを選択します
    {A6688956-5F7D-497A-9DE8-43C98930A466}.png

  • operatingsystem: が standalone(ベアメタル)になっていると思いますので、freertosへ変更します

{287D4904-E7E9-48B2-BBDD-EA8A65B12713}.png

  • finishで完了
  • platformをbuildします
  • 問題なくbuildに成功するはずです
    {C0A69978-24BB-4EC0-8D7C-6F4592AA1055}.png

application を作成する

Vitisにおけるapplicationは、実際にZynqのCPU上で動作するソフトウェア(プログラム)そのものです。
C/C++で記述され、コンパイル後は実行ファイル(.elf)として出力されます。

  • vitis componentsよりapplicationを選択する
    {8F97838A-ED53-4480-B0BA-2E15DEB9CA5F}.png

  • 先ほど作成したplatformを選択します
    {25B9B244-B8D9-403A-905C-3D55FAB87374}.png

  • finishまで進めます

  • Source直下のsrcにファイルを追加します
    {A337FB4B-A5FF-4819-B268-B2E98B0F66C7}.png

  • main.cという名前にします
    {4C98831D-A725-4354-9B5C-81645A252264}.png

  • 下記の「使用したコード」をコピペします

  • buildが通るはずです
    {5990FAAE-17D2-4287-B27B-DB0C307048C0}.png

  • コンパイル後は、ファイルオブジェクトがoutputにできています
    {AFB194BD-3AA6-4A68-9F24-E1791C2569C0}.png

使用したコード

  • 今回使ったコードは以下です。
  • task1task2 は、どちらも無限ループの中で xil_printf() を使って UART に文字列を送信しています。
  • その後、vTaskDelay(pdMS_TO_TICKS(1000)) によって 1秒待機 します。
  • このため、UARTターミナル上ではそれぞれのタスクから、一定周期でメッセージが出力される動作になります。
#include "FreeRTOS.h"
#include "task.h"
#include "xil_printf.h"

static void task1(void *pvParameters)
{
    (void)pvParameters;
    for (;;) {
        xil_printf("hello! zybo from task1\r\n");
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

static void task2(void *pvParameters)
{
    (void)pvParameters;
    for (;;) {
        xil_printf("hello! zybo from task2\r\n");
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

int main(void)
{
    xTaskCreate(task1, "Task1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);
    xTaskCreate(task2, "Task2", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);
    vTaskStartScheduler();

    for (;;);
    return 0;
}

サービスコール紹介

  • RTOS(FreeRTOS)が提供するAPIをサービスコール(システムコール)と呼びます
  • 今回はtask関連の以下のAPIを使用しています

xTaskCreate

  • main() では xTaskCreate() を2回呼び出して、2つのタスクを生成しています。
  • タスク名は Task1 / Task2
  • スタックサイズは configMINIMAL_STACK_SIZE
  • 優先度はどちらも tskIDLE_PRIORITY + 1
  • どちらのタスクも同じ優先度にしているため、FreeRTOSのスケジューラによって順番に実行されます。

vTaskStartScheduler

  • vTaskStartScheduler() を呼ぶことで、FreeRTOSのスケジューラが開始されます。
  • ここまで正常に到達し、なおかつ必要なメモリや設定に問題がなければ、以後は各タスクが実行され続けます。

逆に、ここで動かない場合は以下を疑うことになります。

  • FreeRTOSの設定不備
  • ヒープ不足
  • タスク生成失敗
  • クロックやBSP設定の問題

書き込み

  • JTAGとZYBOを接続します
    image.png

  • app_component の Debugを押すと書き込み開始です

  • ちなみにZYNQのmodeピンは「JTAG」モードにしておいてください
    {ADF1D16C-4809-4EBC-9059-2735D0391651}.png

出力結果

  • 両方のTASKから順番にメッセージが送られていることがわかります
    image.png

まとめ

  • 今回は Zybo Z7-20 上で FreeRTOS を動作させ、2つのタスクを生成して UART にメッセージを出力する最小構成を作成しました。

  • まずは FreeRTOS を利用するために PL 側で TTC Timer を有効化し、AXI IIC や GPIO、割り込み回路を含むハードウェア構成を作成しました。

  • その後、Vitis 上で FreeRTOS アプリケーションを作成し、タスク生成とスケジューラ起動を確認しました。

  • 実行結果からは、同じ優先度の2つのタスクが交互に実行され、UART に継続してメッセージが出力されることを確認できました。

  • これにより、FreeRTOS の基本的なタスク管理とスケジューリングが正常に動作していることが分かります。

  • 次回は今回準備した IIC や Ethernet の仕組みを活用し、BME280/AHT20 から取得したセンサデータを lwIP 経由で上位 PC へ送信する構成に発展させていきたいと思います。

1
1
0

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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?