TI-C2000にFreeRTOSを実装する

RTOSを導入しようと思ってRTOSについて調べていると、最近はFreeRTOSというRTOSが使いやすく人気ということが分かってきました。そこで実際にFreeRTOSをC2000マイコンに実装して動作する様子を見てみようと思います。

私はこれまで、シングルタスク動作(いわゆるベアメタルプログラミング)最高!という考えで、組み込みソフトのコーディングを行ってきました。(特にアセンブラを用いるとMCUを完全に制御している感覚に陥ることが出来てなお良い…アセンブラ沼怖い…)

ベアメタルプログラミングも楽しくて個人的には好きですが、ロボット制御のように数多くのセンサ入力、データログ取得、モーター制御などを、ほぼ同時に処理するとなると各タスクの管理が難しくなってゆきます。そんな時、「RTOSを実装してタスクの管理はRTOSに任せてしまいたいなぁ」と思うことが多くなってきました。

FreeRTOS

FreeRTOSはマイクロコントローラ向けリアルタイムオペレーティングシステムです。このOSは、もともとReal Time Engineersという会社が権利を所有していました。現在はAmazonがFreeRTOSの権利を買い取りオープンソースで公開しています。

このFreeRTOS、Real Time Engineersが権利を所有していた時から無償利用することが出来たのですが、「GNU GPL v2.0ライセンス」の下で無償公開されていました。そのため、改変した部分や組み合わせた他のコード部分を公開する必要がありました。

Amazonが権利を買い取ってからは「MITライセンス」の下で無償公開されています。「MITライセンス」の下に公開されているため、改変した部分や組み合わせた他のコード部分を公開する必要がなくなりました。コードの公開義務がなくなったことで商用でも利用しやすくなったため、幅広く利用され始めています。

Amazon FreeRTOS(マイクロコントローラー向けIoTオペレーティングシステム)| AWS
FreeRTOS は、マイクロコントローラーおよびマイクロプロセッサ用のリアルタイムのオープンソースオペレーティングシステムであり、低電力の小型デバイスのプログラミング、デプロイ、および保護を容易にします。
FreeRTOS - Wikipedia

TI C2000

TI C2000はリアルタイム処理を行うことに特化したマイコンです。デジタルフィルタやフィードバック制御演算などの数値演算を効率良く行えるように最適化されたアーキテクチャを持っています。また、そのための(FPU,TMU,CLA)といった専用ペリフェラルが用意されています。また、入出力用のADC、PWMも強化されています。ADCは、トリガタイミングや変換終了時の割り込みタイミングを非常に柔軟に設定することが出来ます。

私は、ロボット用のモータードライバや電源制御にC2000マイコンを利用しています。今回は、このC2000マイコンにFreeRTOSを実装してみます。

FreeRTOSを動作させるために利用するマイコンボードは以前製作した下記ボードを使います。

実装されているC2000マイコンはTMS320F28035です。クロック:60MHz, ROM:128kB, RAM:20kBのマイコンです。RAMが少なめなのが気になるところです。実際に動作させてみてROM,RAMの利用状態をチェックしてみます。

※データシート表記のROM,RAMは16-bit wordなので注意、なので、一般的な1byte=8bitで表す場合は2倍すればOK

TMS320F2803x Piccoloマイクロコントローラ データシート (Rev. M 翻訳版)より

実はC2000マイコンには、専用に最適化されたRTOSが用意されていたりします。
SYS/BIOS リアルタイム・カーネルというやつです。

TI-RTOS-MCU オペレーティング・システム (OS) | TI.com
TI TI-RTOS-MCU オペレーティング・システム (OS) のダウンロード、概要、特長、サポート資料を表示し、設計を開始することができます。

専用に設計されているので性能は良いし、機能も沢山あります。
でも、資料も少ないし、使い方も難しそうなので……今回はFreeRTOSを実装しちゃいます。

TI-C2000へFreeRTOSを組み込む

FreeRTOSの準備

FreeRTOSは基本ソフトウェアと移植により変更が必要なソフトウェアで構成されています。FreeRTOSをマイコンに組み込むためには、組み込むマイコンのアーキテクチャに合わせて「portable」フォルダの中身を変更してやる必要があります。

FreeRTOSをダウンロードすると代表的なマイコン(ARM,PIC,AVR)に対応したファイルが用意されているので、大抵はそのファイルを利用することになると思います。しかし、C2000マイコン(C28x)用のファイルは公式には用意されていません。

組み込むマイコンのアーキテクチャに合わせて用意されたファイル
C2000マイコン(C28x)用のファイルは入っていない….

このファイルがとても厄介で、アセンブラでの記述が必要なため、自分で用意するとなると骨が折れます。先行の事例が無いか調査したところ、githubで下記のプロジェクトを見つけました。ありがたく利用させてもらうことにします。

GitHub - IvanZuy/freertos_c28x: FreeRTOS port for TI C2000's C28x based microcontrollers
FreeRTOS port for TI C2000's C28x based microcontrollers - IvanZuy/freertos_c28x

プロジェクトファイルを解凍するとFreeRTOSとC2000マイコンのサンプルプロジェクトが現れます。「portable」フォルダの中にはC28x用のファイルが入っていました。

C2000マイコン(C28x)用のファイル

FreeRTOSのバージョンが「FreeRTOS v9.0.0.」と少し古いので、(C28x)用のファイルのみ流用して、FreeRTOS本体は最新版「FreeRTOS v202007.00」へ更新することにします。FreeRTOSの最新版は下記からダウンロードが可能です。

ERROR: The request could not be satisfied

CCSプロジェクトへの組み込み

サンプルコードを参考にFreeRTOSをCCSプロジェクトに組み込みました。基本的にはFreeRTOSの必要なファイルをCCSプロジェクトフォルダに入れて、includeファイルディレクトリの設定を行うことでコンパイルが通るようになりました。

元の参考にしたプロジェクトでは、デバイス型名がTMS320F28034になっていたのでTMS320F28035に変更しました。また、JTAGからRAMに直接プログラムをロードするようになっていたので、こちらもFlashROMからプログラムをロードするように変更しました。

開発環境は以下となります。
「Code Composer Studio 10.1.0」
「FreeRTOS v202007.00」

動作確認

Lチカさせようと思いましたが面倒だったので、IOポート(GPIO1,GPIO2)出力を直接オシロスコープで観測することにしました。

タスクは2つで2つのGPIOを違う周期でトグルするようになっています。
Task1→1ms間隔でGPIO1をトグル
Task2→10ms間隔でGPIO2をトグル

//*****************************************************************************
// Task1
//*****************************************************************************
void Task1(void * pvParameters){
    while(1){
        if(xSemaphoreTake( xSemaphore, portMAX_DELAY ) == pdTRUE){
            GpioToggle1();
        }
    }
}

//*****************************************************************************
// Task2
//*****************************************************************************
void Task2(void * pvParameters){
    while(1){
        GpioToggle2();
        vTaskDelay(10 / portTICK_PERIOD_MS);
    }
}
//*****************************************************************************
// GpioToggle1
//*****************************************************************************
static void GpioToggle1(void){
    static uint32_t counter = 0;
    counter++;
    if(counter & 1){
        GpioDataRegs.GPACLEAR.bit.GPIO1 = 1;
    }
    else{
        GpioDataRegs.GPASET.bit.GPIO1 = 1;
    }
}

//*****************************************************************************
// GpioToggle2
//*****************************************************************************
static void GpioToggle2(void){
    static uint32_t counter = 0;
    counter++;
    if(counter & 1){
        GpioDataRegs.GPACLEAR.bit.GPIO2 = 1;
    }
    else{
        GpioDataRegs.GPASET.bit.GPIO2 = 1;
    }
}

オシロスコープで出力波形をモニタすると、OSによりタスク切り替えが実行されていることが分かりました。

ROM,RAMの使用状況

RAMの使用量ですが、タスクが少ないためかシングルタスクのソフトとあまり差が無いように感じます。ROMについては1ブロック(FlashA)しか使っていません。今回用意したリンクコマンドファイルでは、RAML0にOSのスタック領域を配置しています。

C2000は演算効率を重視するアーキテクチャ設計となっているため、RAM領域が分割されています。1つの領域があまり大きくないので実装するタスク数を増やしたい場合、RAMの割り当てを工夫する必要がありますね。

もう少し機能を実装してみないと何とも言えませんね。

とりあえず動作確認できましたが、まだRTOSについて良くわからないことだらけです。まずはRTOSを実際に触ってみて慣れるところから初めていきたいと思います。

コメント